從 Android 7.0 開始,Android SDK 中的 StrictMode 策略禁止開發人員在應用外部公開 file:// URI。具體表現爲,當咱們在應用中使用包含 file:// URI 的 Intent 離開本身的應用時,程序會發生FileUriExposedException 異常html
這裏咱們要使用到的 FileProvider
,就是 ContentProvider
的一個特殊子類,幫助咱們將訪問受限的 file:// URI 轉化爲能夠受權共享的 content:// URI。android
首先 要去 Manifest文件裏註冊FileProviderapp
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.FileProvider" //此處的屬性值後面獲取URI用到 android:grantUriPermissions="true" android:exported="false">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/>
</provider>
</application>
其次在 res 目錄下新建一個 xml 文件夾 裏邊添加一個xml文件 名字好比:path.xmlide
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="my_images" path="."/> <!-- 此處的name能夠隨便取--!> </paths>
元素必須包含一到多個子元素。這些子元素用於指定共享文件的目錄路徑,必須是這些元素之一:ui
<files-path>:內部存儲空間應用私有目錄下的 files/ 目錄,等同於 Context.getFilesDir() 所獲取的目錄路徑;this
<cache-path>:內部存儲空間應用私有目錄下的 cache/ 目錄,等同於 Context.getCacheDir() 所獲取的目錄路徑;spa
<external-path>:外部存儲空間根目錄,等同於 Environment.getExternalStorageDirectory() 所獲取的目錄路徑;code
<external-files-path>:外部存儲空間應用私有目錄下的 files/ 目錄,等同於 Context.getExternalFilesDir(null) 所獲取的目錄路徑;orm
<external-cache-path>:外部存儲空間應用私有目錄下的 cache/ 目錄,等同於 Context.getExternalCacheDir();xml
獲取URI的方法:
在Android7.0如下 獲取相冊圖片URI的方式:
Uri uri= Uri.from ( file );
Android 7.0+獲取相冊圖片的方式:
//注意此處的 第二個參數必須與 Manifest文件中Provider 的 android:authorities 一致
Uri contentUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".FileProvider", outputFile);
Android 7.0如下 安裝應用:
Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); installIntent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); startActivity(installIntent);
Android 7.0+ 安裝應用:
//採用FileProvider的方式訪問文件
File apkFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app_sample.apk");
Uri apkUri = FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID+".FileProvider", apkFile);
Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//添加此處 是臨時對文件的受權 必須加上此句 installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive"); startActivity(installIntent);
調用相機的時候:
public void camera() { Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); tempFile = new File(Environment.getExternalStorageDirectory(),PHOTO_FILE_NAME); Uri uri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { uri = FileProvider.getUriForFile(this, "com.camera.fileprovider",tempFile);
//此處爲Uri臨時受權 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { uri = Uri.fromFile(tempFile); } intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(intent, PHOTO_REQUEST_CAMERA); }
裁剪圖片:
public static void cropImageUri(Activity activity, Uri orgUri, Uri desUri, int aspectX, int aspectY, int width, int height, int requestCode) { Intent intent = new Intent("com.android.camera.action.CROP"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//此處爲Uri臨時受權 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } intent.setDataAndType(orgUri, "image/*"); //此處的Uri爲 輸入Uri用FileProvider的方式獲取 intent.putExtra("crop", "true"); intent.putExtra("aspectX", aspectX); intent.putExtra("aspectY", aspectY); intent.putExtra("outputX", width); intent.putExtra("outputY", height); intent.putExtra("scale", true); //將剪切的圖片保存到目標Uri中 intent.putExtra(MediaStore.EXTRA_OUTPUT, desUri);//此處的Uri爲輸出Uri 須要用Uri.fromFile()的方式獲取 intent.putExtra("return-data", false); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); activity.startActivityForResult(intent, requestCode); }