Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/209.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/379.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
android.os.FileUrieExposedException:file:///storage/emulated/0/test.txt 通过Intent.getData()在应用程序之外公开_Android_Android File_Android 7.0 Nougat - Fatal编程技术网

android.os.FileUrieExposedException:file:///storage/emulated/0/test.txt 通过Intent.getData()在应用程序之外公开

android.os.FileUrieExposedException:file:///storage/emulated/0/test.txt 通过Intent.getData()在应用程序之外公开,android,android-file,android-7.0-nougat,Android,Android File,Android 7.0 Nougat,当我试图打开文件时,应用程序正在崩溃。它在安卓牛轧糖下工作,但在安卓牛轧糖上崩溃。只有当我试图从SD卡而不是系统分区打开文件时,它才会崩溃。一些许可问题 示例代码: File file = new File("/storage/emulated/0/test.txt"); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "text/*"); intent.setFl

当我试图打开文件时,应用程序正在崩溃。它在安卓牛轧糖下工作,但在安卓牛轧糖上崩溃。只有当我试图从SD卡而不是系统分区打开文件时,它才会崩溃。一些许可问题

示例代码:

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.FileUrieExposedException: file:///storage/emulated/0/test.txt 暴露在应用程序之外 Intent.getData()

编辑:


当针对Android Nougat时,
file://
URI不再被允许。我们应该使用
content://
uri。但是,我的应用程序需要打开根目录中的文件。有什么想法吗?

如果您的
targetSdkVersion
为24或更高

你的选择是:

  • 将您的
    targetSdkVersion
    降至23或更低,或

  • 将您的内容放入内部存储,然后有选择地将其提供给其他应用程序

  • 例如:

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

    (from)

    如果您的
    targetSdkVersion>=24
    ,则我们必须使用
    FileProvider
    类授予对特定文件或文件夹的访问权限,以便其他应用程序可以访问这些文件或文件夹。我们创建自己的类继承
    FileProvider
    ,以确保我们的FileProvider不会与导入的依赖项中声明的FileProvider发生冲突,如上所述

    文件://
    URI替换为
    内容://
    URI的步骤:


    • 下的
      AndroidManifest.xml
      中添加一个FileProvider
      标记首先,您需要向AndroidManifest添加一个提供程序

        <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>
      

      编辑:我在文件路径中添加了sd卡的根文件夹。我已经测试了这段代码,它确实有效。

      除了使用
      文件提供程序的解决方案之外,还有另一种解决方法。简而言之

      StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
      StrictMode.setVmPolicy(builder.build());
      
      Application.onCreate()
      中。通过这种方式,虚拟机忽略文件
      URI
      exposure

      方法

      builder.detectFileUriExposure()
      
      File dir = new File(Environment.getExternalStorageDirectory(), "ColorStory");
      File imgFile = new File(dir, "0.png");
      Intent sendIntent = new Intent(Intent.ACTION_VIEW);
      sendIntent.setType("image/*");
      sendIntent.setAction(Intent.ACTION_SEND);
      sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + imgFile));
      sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      startActivity(Intent.createChooser(sendIntent, "Share images..."));
      
      启用文件暴露检查,这也是未设置VmPolicy时的默认行为

      我遇到了一个问题,如果我使用
      内容://
      URI
      发送东西,一些应用程序就无法理解它。并且不允许降级
      目标SDK
      版本。在这种情况下,我的解决方案很有用

      更新:


      如注释中所述,StrictMode是诊断工具,不应用于此问题。当我一年前发布这个答案时,许多应用程序只能接收文件URI。当我试图向它们发送文件提供程序uri时,它们就崩溃了。这在大多数应用程序中都是固定的,所以我们应该使用FileProvider解决方案。

      我使用了上面给出的Palash的答案,但它有点不完整,我必须提供这样的权限

      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);
      
      Intent-Intent=新意图(Intent.ACTION\u视图);
      Uri;
      if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.N){
      uri=FileProvider.getUriForFile(这是getPackageName()+“.provider”,新文件(路径));
      List resinfo List=getPackageManager().queryInputActivities(intent,PackageManager.MATCH_DEFAULT_仅限);
      对于(ResolveInfo ResolveInfo:ResInfo列表){
      字符串packageName=resolveInfo.activityInfo.packageName;
      grantUriPermission(packageName、uri、Intent.FLAG_GRANT_uri_PERMISSION | Intent.FLAG_GRANT_READ_uri_PERMISSION);
      }
      }否则{
      uri=uri.fromFile(新文件(路径));
      }
      setDataAndType(uri,“application/vnd.android.package归档”);
      intent.setFlags(intent.FLAG\u活动\u新任务);
      星触觉(意向);
      
      @palash k的答案是正确的,适用于内部存储文件,但在我的情况下,我也想从外部存储打开文件,当从SD卡和usb等外部存储打开文件时,我的应用程序崩溃,但我通过修改已接受答案中的provider_path.xml解决了这个问题

      更改提供者路径.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>
      
      这有助于我修复外部存储文件的崩溃,希望这能帮助一些和我有相同问题的人
      :)

      使用文件提供程序是一种方法。 但您可以使用以下简单的解决方法:

      警告:它将在下一个Android版本中修复-

      替换:

      startActivity(intent);
      


      如果您的应用程序以API 24+为目标,并且您仍然希望/需要使用file://intents,则可以使用hacky方法禁用运行时检查:

      if(Build.VERSION.SDK_INT>=24){
         try{
            Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
            m.invoke(null);
         }catch(Exception e){
            e.printStackTrace();
         }
      }
      
      方法
      StrictMode.DisableDeathonfileureExposure
      隐藏并记录为:

      /**
      * Used by lame internal apps that haven't done the hard work to get
      * themselves off file:// Uris yet.
      */
      
      问题是,我的应用程序并不是跛脚的,而是不想因为使用content://意图而瘫痪,而这一点在很多应用程序中是不理解的。例如,使用content://scheme打开mp3文件提供的应用程序比使用file://scheme打开mp3文件提供的应用程序少得多。我不想通过限制我的应用程序的功能来为谷歌的设计缺陷买单


      谷歌希望开发者使用content scheme,但该系统并没有为此做好准备,多年来,应用程序使用的是文件而不是“内容”,文件可以编辑和保存,而通过content scheme提供的文件不能(可以吗?)。

      如果
      targetSdkVersion
      高于24,则用于授予访问权限

      创建一个xml文件(路径:res\xml)provider\u Path.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>
      
      <application
                  android:name=".main.MainApp"
                  android:allowBackup="true"
                  android:icon="@drawable/ic_app"
                  android:label="@string/application_name"
                  android:logo="@drawable/ic_app_logo"
                  android:theme="@style/MainAppBaseTheme">
      
              <provider
                      android:name="androidx.core.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>
      
         <?xml version="1.0" encoding="utf-8"?>
          <paths xmlns:android="http://schemas.android.com/apk/res/android">
              <external-path name="external_files" path="."/>
          </paths>
      
      <?xml version="1.0" encoding="utf-8"?>
      <paths xmlns:android="http://schemas.android.com/apk/res/android">
          <external-path name="external_files" path="."/>
      </paths>
      
      <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="com.lomza.moviesroom.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/file_paths" />
      </provider>
      
      <?xml version="1.0" encoding="utf-8"?>
      <paths>
        <files-path name="movies_csv_files" path="."/>
      </paths>
      
      替换

      Uri uri = Uri.fromFile(fileImagePath);
      

      编辑:在使用
      意图包含URI时,请确保添加以下行:

      intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      

      你可以走了。希望有帮助。

      只需将以下代码粘贴到activity onCreate()中即可

      它将忽略URI暴露

      此答案已完成

      此答案适用于-您已经有一个应用程序的目标值低于24,现在您正在升级到targetSDKVersion>=24

      在安卓N中,只有暴露给第三方应用程序的文件uri被更改。(不是
       android:name="androidx.core.content.FileProvider"
      
      Uri uri = Uri.fromFile(fileImagePath);
      
      Uri uri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider",fileImagePath);
      
      intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      
      StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build());
      
      File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName + ".pdf");
          intent = new Intent(Intent.ACTION_VIEW);
          //Log.e("pathOpen", file.getPath());
      
          Uri contentUri;
          contentUri = Uri.fromFile(file);
          intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
      
          if (Build.VERSION.SDK_INT >= 24) {
      
              Uri apkURI = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", file);
              intent.setDataAndType(apkURI, "application/pdf");
              intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      
          } else {
      
              intent.setDataAndType(contentUri, "application/pdf");
          }
      
      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
      <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
      
      <application
      
      <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>
      
      </application>
      
      val playIntent = Intent(Intent.ACTION_VIEW, uri)
      intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
      
      StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); 
      StrictMode.setVmPolicy(builder.build());
      
      Java.Lang.ClassLoader cl = _this.Context.ClassLoader;
      Java.Lang.Class strictMode = cl.LoadClass("android.os.StrictMode");                
      System.IntPtr ptrStrictMode = JNIEnv.FindClass("android/os/StrictMode");
      var method = JNIEnv.GetStaticMethodID(ptrStrictMode, "disableDeathOnFileUriExposure", "()V");                
      JNIEnv.CallStaticVoidMethod(strictMode.Handle, method);
      
      String storage = Environment.getExternalStorageDirectory().toString() + "/test.txt";
      File file = new File(storage);
      Uri uri;
      if (Build.VERSION.SDK_INT < 24) {
          uri = Uri.fromFile(file);
      } else {
          uri = Uri.parse(file.getPath()); // My work-around for new SDKs, worked for me in Android 10 using Solid Explorer Text Editor as the external editor.
      }
      Intent viewFile = new Intent(Intent.ACTION_VIEW);
      viewFile.setDataAndType(uri, "text/plain");
      startActivity(viewFile);
      
      ContentValues values = new ContentValues();
      values.put(MediaStore.Video.Media.DATA, videoFilePath);
      Uri contentUri = context.getContentResolver().insert(
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
      
      intent.setType("video/*");
      intent.putExtra(Intent.EXTRA_STREAM, contentUri);
      intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      activity.startActivity(intent);
      
      StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
          StrictMode.setVmPolicy(builder.build());
      
      File dir = new File(Environment.getExternalStorageDirectory(), "ColorStory");
      File imgFile = new File(dir, "0.png");
      Intent sendIntent = new Intent(Intent.ACTION_VIEW);
      sendIntent.setType("image/*");
      sendIntent.setAction(Intent.ACTION_SEND);
      sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + imgFile));
      sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      startActivity(Intent.createChooser(sendIntent, "Share images..."));
      
      enter code here
      public Uri getImageUri(Context context, Bitmap inImage)
      {
          ByteArrayOutputStream bytes = new ByteArrayOutputStream();
          inImage.compress(Bitmap.CompressFormat.PNG, 100, bytes);
          String path = MediaStore.Images.Media.insertImage(context.getContentResolver(), 
          inImage, "Title", null);
          return Uri.parse(path);
      }
      
       val intent = Intent()
       intent.setAction(Intent.ACTION_VIEW)
       val file = File(currentUri)
       intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
       val contentURI = getContentUri(context!!, file.absolutePath)
       intent.setDataAndType(contentURI,"image/*")
       startActivity(intent)
      
      private fun getContentUri(context:Context, absPath:String):Uri? {
              val cursor = context.getContentResolver().query(
                  MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                  arrayOf<String>(MediaStore.Images.Media._ID),
                  MediaStore.Images.Media.DATA + "=? ",
                  arrayOf<String>(absPath), null)
              if (cursor != null && cursor.moveToFirst())
              {
                  val id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID))
                  return Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, Integer.toString(id))
              }
              else if (!absPath.isEmpty())
              {
                  val values = ContentValues()
                  values.put(MediaStore.Images.Media.DATA, absPath)
                  return context.getContentResolver().insert(
                      MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
              }
              else
              {
                  return null
              }
          }
      
      <application
                  android:name=".main.MainApp"
                  android:allowBackup="true"
                  android:icon="@drawable/ic_app"
                  android:label="@string/application_name"
                  android:logo="@drawable/ic_app_logo"
                  android:theme="@style/MainAppBaseTheme">
      
              <provider
                      android:name="androidx.core.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>
      
         <?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 myPhotoFileUri = FileProvider.getUriForFile(getActivity(), getActivity().getApplicationContext().getPackageName() + ".provider", myPhotoFile);               
          intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
          intent.putExtra(MediaStore.EXTRA_OUTPUT, myPhotoFileUri);
      
      public class GenericFileProvider extends FileProvider {}
      
      StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build()); 
      
       <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
       <uses-permission android:name="android.permission.CAMERA" />
      
      Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                      if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
                          startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
                      }
      
      @Override
                  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
                      super.onActivityResult(requestCode, resultCode, data);
                      if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
                          Bundle extras = data.getExtras();
                          Bitmap imageBitmap = (Bitmap) extras.get("data");
                          // CALL THIS METHOD TO GET THE URI FROM THE BITMAP
                          Uri tempUri = getImageUri(getApplicationContext(), imageBitmap);
                          //DO SOMETHING WITH URI
                      }
                  } 
      
      public Uri getImageUri(Context inContext, Bitmap inImage) {
              ByteArrayOutputStream bytes = new ByteArrayOutputStream();
              inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
              String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
              return Uri.parse(path);
          }
      
      As of Android N, in order to work around this issue, you need to use the FileProvider API
      
      <manifest ...>
          <application ...>
              <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>
          </application>
      </manifest>
      
      <?xml version="1.0" encoding="utf-8"?>
      <paths xmlns:android="http://schemas.android.com/apk/res/android">
          <external-path name="external_files" path="."/>
      </paths>
      
      File file = ...;
      Intent install = new Intent(Intent.ACTION_VIEW);
      install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
      // Old Approach
          install.setDataAndType(Uri.fromFile(file), mimeType);
      // End Old approach
      // New Approach
          Uri apkURI = FileProvider.getUriForFile(
                                   context, 
                                   context.getApplicationContext()
                                   .getPackageName() + ".provider", file);
          install.setDataAndType(apkURI, mimeType);
          install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      // End New Approach
          context.startActivity(install);
      
      <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="com.lomza.moviesroom.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/file_paths" />
      </provider>
      
      <?xml version="1.0" encoding="utf-8"?>
      <paths>
        <files-path name="movies_csv_files" path="."/>
      </paths>
      
      fun goToFileIntent(context: Context, file: File): Intent {
          val intent = Intent(Intent.ACTION_VIEW)
          val contentUri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file)
          val mimeType = context.contentResolver.getType(contentUri)
          intent.setDataAndType(contentUri, mimeType)
          intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
      
          return intent
      }
      
      File fl = new File(url);
          Uri uri = Uri.fromFile(fl);
          Intent intent = new Intent(Intent.ACTION_VIEW);
          if (android.os.Build.VERSION.SDK_INT>=24)
          {
              Context context = getApplicationContext();
              uri = FileProvider.getUriForFile(
                      context,
                      context.getApplicationContext()
                              .getPackageName() + ".provider", fl);
              intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
          }
          intent.setDataAndType(uri, mimetype);
          intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
          startActivity(intent);
      
       val uri = if (Build.VERSION.SDK_INT < 24) Uri.fromFile(file) else Uri.parse(file.path)
                      val shareIntent = Intent().apply {
                          action = Intent.ACTION_SEND
                          type = "application/pdf"
                          putExtra(Intent.EXTRA_STREAM, uri)
                          putExtra(
                              Intent.EXTRA_SUBJECT,
                              "Purchase Bill..."
                          )
                          putExtra(
                              Intent.EXTRA_TEXT,
                              "Sharing Bill purchase items..."
                          )
                      }
                      startActivity(Intent.createChooser(shareIntent, "Share Via"))