दिलचस्प पोस्ट
== और === के बीच अंतर php / mysql सबसे अच्छा पेड़ संरचना कैसे एक std :: vector फेरबदल? JSIA में इकाई फ़्रेमवर्क ऑब्जेक्ट को सीरियल करना क्या मैं अनुक्रमों को दोहराकर जावा में स्ट्रिंग्स बढ़ा सकता हूँ? जावा हाइब्रिड – एप्लेट + एप्लिकेशन क्या है? पायथन: स्ट्रिंग से पहुंच वर्ग की संपत्ति मैं सूची <T> 'सी' में विधि जोड़ने के लिए ओवरराइड कैसे करूं? यह कैसे निर्धारित किया जाता है कि कोई बहुभुज जटिल / उत्तल / गैर-कोनवेक्स है? पूर्ण / स्थिर बच्चों के साथ मूल कंटेनर की ऑटो ऊंचाई PHP में एक एसोसिएटिव सरणी को सॉर्ट करना मैं सीएसएस विरासत को कैसे रोकूं? JSP में मैं जावा स्क्रिप्टलेट को कैसे जावास्क्रिप्ट मान देता हूं? सी ++ / सीएलआई में चार * और सिस्टम :: स्ट्रिंग के बीच कन्वर्ट करने का सबसे अच्छा तरीका क्या है? पायथन में stdout पर मुद्रित करने के लिए सी साझा लाइब्रेरी को मैं कैसे रोकूं?

android.os.FileUriExposedException: फ़ाइल: ///storage/emulated/0/test.txt Intent.getData () के माध्यम से ऐप से परे खुलासा

कोई फ़ाइल खोलने का प्रयास करते समय ऐप क्रैश हो जाता है यह एंड्रॉइड एन के नीचे काम करता है, लेकिन एंड्रॉइड एन पर यह क्रैश हो जाता है। यह केवल क्रैश हो जाता है जब मैं एसडी कार्ड से फाइल खोलने की कोशिश करता हूं, न कि सिस्टम पार्टिशन से। कुछ अनुमति समस्या है?

नमूना कोड:

File file = new File("/storage/emulated/0/test.txt"); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "text/*"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); // Crashes on this line 

लॉग इन करें:

 android.os.FileUriExposedException: file:///storage/emulated/0/test.txt exposed beyond app through Intent.getData() 

संपादित करें:

एंड्रॉइड एन को लक्षित करते समय, file:// यूआरआई अब और अनुमति नहीं है हमें इसके बजाय content:// यूआरआई का उपयोग करना चाहिए। हालांकि, मेरे ऐप को रूट निर्देशिकाओं में फाइल खोलने की जरूरत है कोई विचार?

वेब के समाधान से एकत्रित समाधान "android.os.FileUriExposedException: फ़ाइल: ///storage/emulated/0/test.txt Intent.getData () के माध्यम से ऐप से परे खुलासा"

यदि आपका लक्ष्य एसडीके विवरण 24 या अधिक है, तो हमें अन्य अनुप्रयोगों के लिए उन्हें सुलभ बनाने के लिए विशेष फ़ाइल या फ़ोल्डर तक पहुंचने के लिए FileProvider क्लास का उपयोग करना होगा। हम यह सुनिश्चित करने के लिए कि हमारे FileProvider आयातित निर्भरता में घोषित FileProviders के साथ कोई विरोधाभास नहीं है, के लिए FileProvider को प्राप्त करने FileProvider हमारा अपना वर्ग बनाते हैं जैसा कि यहां बताया गया है

फ़ाइल को बदलने के लिए चरण: // सामग्री के साथ यूरी: // उरी:

  • FileProvider का विस्तार करने वाला वर्ग जोड़ें

     public class GenericFileProvider extends FileProvider { } 
  • टैग के तहत AndroidManifest.xml में एक FileProvider टैग जोड़ें android:authorities लिए एक अनन्य प्राधिकरण निर्दिष्ट करें android:authorities संघर्षों से बचने के लिए android:authorities विशेषता, आयातित निर्भरता ${applicationId}.provider और अन्य सामान्यतः उपयोग किए जाने वाले अधिकारियों को निर्दिष्ट कर सकती है।

 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" ... <application ... <provider android:name=".GenericFileProvider" android:authorities="${applicationId}.my.package.name.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/> </provider> </application> </manifest> 
  • फिर res फ़ोल्डर के अंतर्गत xml फ़ोल्डर में एक provider_paths.xml फ़ाइल बनाएँ यदि वह मौजूद नहीं है तो फ़ोल्डर को बनाने के लिए आवश्यक हो सकता है फ़ाइल की सामग्री नीचे दी गई है यह बताता है कि हम बाहरी फ़ोल्डर में रूट फ़ोल्डर (path=".") पर पहुंच को बाह्य नामों के साथ साझा करना चाहते हैं।
 <?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="."/> </paths> 
  • अंतिम चरण में नीचे दिए गए कोड की लाइन को बदलने में है

     Uri photoURI = Uri.fromFile(createImageFile()); 

    सेवा मेरे

     Uri photoURI = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".my.package.name.provider", createImageFile()); 
  • संपादित करें: यदि सिस्टम को आपकी फ़ाइल खोलने के उद्देश्य का उपयोग कर रहे हैं, तो आपको निम्न कोड कोड जोड़ने की आवश्यकता हो सकती है:

     intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 

उम्मीद है कि यह मदद मिलेगी … 🙂

कृपया देखें, पूर्ण कोड और समाधान यहां समझाया गया है।

FileProvider का उपयोग करने के समाधान के अलावा, इसके आसपास काम करने का एक और तरीका है। सीधे शब्दों में कहें

 StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build()); 

Application.onCreate() में। इस तरह से वीएम फाइल URI एक्सपोजर की उपेक्षा करता है।

तरीका

 builder.detectFileUriExposure() 

फ़ाइल एक्सपोज़र जांच को सक्षम करता है, जो कि डिफ़ॉल्ट व्यवहार भी है यदि हम एक VmPolicy सेटअप नहीं करते हैं

मुझे एक समस्या का सामना करना पड़ा है कि अगर मैं कुछ content:// भेजने के लिए content:// URI का उपयोग करता हूं, तो कुछ ऐप्स इसे समझ नहीं सकते हैं। और target SDK संस्करण को डाउनग्रेड करने की अनुमति नहीं है इस मामले में मेरा समाधान उपयोगी है

यदि आपका targetSdkVersion 24 या अधिक है, तो आप file: उपयोग नहीं कर सकते हैं file: एंड्रॉइड 7.0+ उपकरणों पर Intents में Uri मान ।

आपकी पसंद हैं:

  1. अपने targetSdkVersion को 23 या उससे कम या छोड़ दें, या

  2. अपनी सामग्री को आंतरिक संग्रहण पर रखो, फिर इसे अन्य ऐप्स के लिए चुनिंदा रूप से उपलब्ध कराने के लिए FileProvider का उपयोग करें

उदाहरण के लिए:

 Intent i=new Intent(Intent.ACTION_VIEW, FileProvider.getUriForFile(this, AUTHORITY, f)); i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivity(i); 

( इस नमूना परियोजना से )

यदि आपका एपीआई एपीआई 24 + का लक्ष्य रखता है, और फिर भी आप चाहते हैं / फ़ाइल का उपयोग करना चाहते हैं: // इंटेंट्स, तो आप रनटाइम चेक अक्षम करने के लिए हैमी तरीके से उपयोग कर सकते हैं:

 if(Build.VERSION.SDK_INT>=24){ try{ Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure"); m.invoke(null); }catch(Exception e){ e.printStackTrace(); } } 

विधि StrictMode.disableDeathOnFileUriExposure छिपा हुआ है और के रूप में दस्तावेज है:

 /** * Used by lame internal apps that haven't done the hard work to get * themselves off file:// Uris yet. */ 

समस्या यह है कि मेरा ऐप लंगड़ा नहीं है, बल्कि सामग्री का उपयोग करके इसे अपंग नहीं होना चाहता है: // इनटेंट्स जो वहां से बहुत से ऐप को समझ नहीं पाते हैं। उदाहरण के लिए, सामग्री के साथ एमपी 3 फाइल को खोलना: // योजना फाइल से अधिक की तुलना में बहुत कम ऐप्स प्रदान करती है: // योजना मैं अपने ऐप की कार्यक्षमता को सीमित करके Google के डिजाइन दोषों के लिए भुगतान नहीं करना चाहता हूं

Google डेवलपर्स को सामग्री योजना का उपयोग करना चाहता है, लेकिन सिस्टम इसके लिए तैयार नहीं है, कई सालों तक ऐप को "सामग्री" न करने वाली फ़ाइलों का उपयोग करने के लिए बनाया गया था, फ़ाइलों को संपादित और सहेजा जा सकता है, जबकि कंटेंट स्कीम पर फाइल की गई फाइलें नहीं हो सकतीं वे?)।

सबसे पहले आपको अपने एंड्रॉयड मैनिफेन्स में प्रदाता को जोड़ने की जरूरत है

  <application ...> <activity> .... </activity> <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.your.package.fileProvider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application> 

अब एक्सएमएल संसाधन फ़ोल्डर में एक फाइल बनाइए (अगर आप एंड्रॉइड स्टूडियो का इस्तेमाल करते हुए आप file_paths को हाइलाइट करने के बाद Alt + Enter हिट कर सकते हैं और एक एक्सएमएल संसाधन विकल्प बना सकते हैं)

फ़ाइल_पैथस फ़ाइल में अगला दर्ज करें

 <?xml version="1.0" encoding="utf-8"?> <paths> <external-path path="Android/data/com.your.package/" name="files_root" /> <external-path path="." name="external_storage_root" /> </paths> 

यह उदाहरण बाहरी मार्ग के लिए है जो आप यहां अधिक विकल्पों के लिए पुन: प्राप्त कर सकते हैं। यह आपको उन फ़ाइलों को साझा करने की अनुमति देगा जो उस फ़ोल्डर में हैं और इसके उप-फ़ोल्डर

अब जो सब छोड़ दिया गया है, वह आशय बनाने के लिए है:

  MimeTypeMap mime = MimeTypeMap.getSingleton(); String ext = newFile.getName().substring(newFile.getName().lastIndexOf(".") + 1); String type = mime.getMimeTypeFromExtension(ext); try { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Uri contentUri = FileProvider.getUriForFile(getContext(), "com.your.package.fileProvider", newFile); intent.setDataAndType(contentUri, type); } else { intent.setDataAndType(Uri.fromFile(newFile), type); } startActivityForResult(intent, ACTIVITY_VIEW_ATTACHMENT); } catch (ActivityNotFoundException anfe) { Toast.makeText(getContext(), "No activity found to open this attachment.", Toast.LENGTH_LONG).show(); } 

संपादित करें : मैंने file_paths में एसडी कार्ड के मूल फ़ोल्डर को जोड़ा। मैंने इस कोड का परीक्षण किया है और यह काम करता है

अगर TargetSdkVersion 24 से अधिक है, तो FileProvider का उपयोग पहुंच प्रदान करने के लिए किया जाता है।

एक XML फ़ाइल बनाएं (पथ: res \ xml) provider_paths.xml

 <?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="."/> </paths> 

AndroidManifest.xml में प्रदाता जोड़ें

  <provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/> </provider> 

और प्रतिस्थापित करें

 Uri uri = Uri.fromFile(fileImagePath); 

सेवा मेरे

 Uri uri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider",fileImagePath); 

और आप जाने के लिए अच्छा है आशा करता हूँ की ये काम करेगा।

@palash k उत्तर सही है और आंतरिक भंडारण फ़ाइलों के लिए काम किया है, लेकिन मेरे मामले में मैं बाहरी भंडारण से भी फाइल खोलना चाहता हूं, मेरा ऐप दुर्घटनाग्रस्त हो गया जब ओडी फाइल एसडी कार्ड और यूएसबी जैसे बाह्य भंडारण से हो, लेकिन मैं इसे संशोधित करके समस्या हल करने का प्रबंधन करता हूं accept_paths.xml स्वीकृत उत्तर से

नीचे की तरह provider_paths.xml को बदलें

 <?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path path="Android/data/${applicationId}/" name="files_root" /> <root-path name="root" path="/" /> </paths> 

और जावा वर्ग में (स्वीकार्य उत्तर के रूप में कोई बदलाव नहीं, केवल एक छोटा संपादन)

 Uri uri=FileProvider.getUriForFile(getActivity(), BuildConfig.APPLICATION_ID+".provider", File) 

यह मुझे बाह्य भंडार से फाइलों के लिए दुर्घटना को ठीक करने में मदद करता है, आशा है कि यह एक ही मुद्दे को मेरा एक के रूप में रखने में मदद करेगा 🙂

फ़ाइल प्रदाता का उपयोग करना जाने का तरीका है लेकिन आप इस सरल समाधान का उपयोग कर सकते हैं:

चेतावनी : यह अगले एंड्रॉइड रिलीज में तय हो जाएगा – https://issuetracker.google.com/issues/37122890#comment4

बदलने के:

 startActivity(intent); 

द्वारा

 startActivity(Intent.createChooser(intent, "Your title")); 

मैंने पलाश के ऊपर दिए गए उत्तर का प्रयोग किया था लेकिन यह कुछ अपूर्ण था, मुझे इस तरह की अनुमति देना था

 Intent intent = new Intent(Intent.ACTION_VIEW); Uri uri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { uri = FileProvider.getUriForFile(this, getPackageName() + ".provider", new File(path)); List<ResolveInfo> resInfoList = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); for (ResolveInfo resolveInfo : resInfoList) { String packageName = resolveInfo.activityInfo.packageName; grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); } }else { uri = Uri.fromFile(new File(path)); } intent.setDataAndType(uri, "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent);