天天看點

android 适配7.0,Android7.0适配心得(一)_拍照相容

1、在Android7.0上調用系統相機拍照,裁切照片的适配

android 适配7.0,Android7.0适配心得(一)_拍照相容

在Android7.0以前,若是你想調用系統相機拍照能夠經過如下代碼來進行:java

File file = new File(Environment.getExternalStorageDirectory(), "/pic/" + System.currentTimeMillis() + ".jpg");

if (!file.getParentFile().exists()){

file.getParentFile().mkdirs();

}

Uri imageUri = Uri.fromFile(file);

Intent intent = new Intent();

intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//設定Action為拍照

intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片儲存到指定URI

startActivityForResult(intent, 1);

在Android7.0上使用上述方式調用系統相拍照會抛出以下異常:android

android.os.FileUriExposedException: file:storage/emulated/0/temp/1474956193735.jpg exposed beyond app through Intent.getData()

at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799)

at android.net.Uri.checkFileUriExposed(Uri.java:2346)

at android.content.Intent.prepareToLeaveProcess(Intent.java:8933)

at android.content.Intent.prepareToLeaveProcess(Intent.java:8894)

at android.app.Instrumentation.execStartActivity(Instrumentation.java:1517)

at android.app.Activity.startActivityForResult(Activity.java:4223)

at android.app.Activity.startActivityForResult(Activity.java:4182)

這是因為Android7.0執行了“StrictMode API 政策禁”的緣由,不過能夠用FileProvider來解決這一問題,

如今咱們就來一步一步的解決這個問題。web

使用FileProvidertomcat

一、在manifest清單檔案中注冊provider安全

android:authorities="com.bj.bs.fileprovider"

android:grantUriPermissions="true"

android:exported="false">

android:resource="@xml/file_paths" />

心得:exported:要求必須為false,為true則會報安全異常。grantUriPermissions:true,表示授予 URI 臨時通路權限。伺服器

二、指定共享的目錄app

為了指定共享的目錄咱們須要在資源(res)目錄下建立一個xml目錄,而後建立一個名為“file_paths”(名字能夠随便起,隻要和在manifest注冊的provider所引用的resource保持一緻便可)的資源檔案,内容以下:ide

files-path 表明的根目錄: Context.getFilesDir()

external-path 表明的根目錄: Environment.getExternalStorageDirectory()

cache-path 表明的根目錄: getCacheDir()svg

心得:上述代碼中path=”“,是有特殊意義的,它代碼根目錄,也就是說你能夠向其它的應用共享根目錄及其子目錄下任何一個檔案了,若是你将path設為path=”pictures”,

那麼它表明着根目錄下的pictures目錄(eg:/storage/emulated/0/pictures),若是你向其它應用分享pictures目錄範圍以外的檔案是不行的。網站

三、使用FileProvider

上述準備工做作完以後,如今咱們就能夠使用FileProvider了。

仍是以調用系統相機拍照為例,咱們須要将上述拍照代碼修改成以下:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");

if (!file.getParentFile().exists())file.getParentFile().mkdirs();

Uri imageUri = FileProvider.getUriForFile(context, "com.bj.bs.fileprovider", file); // 經過FileProvider建立一個content類型的Uri

Intent intent = new Intent();

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加這一句表示對目标應用臨時受權該Uri所表明的檔案

intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//設定Action為拍照

intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片儲存到指定URI

startActivityForResult(intent, 1);

上述代碼中主要有兩處改變:

将以前Uri的scheme類型為file的Uri改為了有FileProvider建立一個content類型的Uri。

添加了intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);來對目标應用臨時受權該Uri所表明的檔案。

心得:上述代碼經過FileProvider的Uri getUriForFile (Context context, String authority, File file)

靜态方法來擷取Uri,該方法中authority參數就是清單檔案中注冊provider的android:authorities=”com.jph.takephoto.fileprovider”。

對Web伺服器如tomcat,IIS比較熟悉的小夥伴,都隻知道為了網站内容的安全和高效,Web伺服器都支援為網站内容設定一個虛拟目錄,其實FileProvider也有殊途同歸之處。

将getUriForFile方法擷取的Uri列印出來以下:

content://com.bj.bs.fileprovider/camera_photos/temp/1474960080319.jpg`。

其中camera_photos就是file_paths.xml中paths的name。

由于上述指定的path為path=”“,是以content://com.bj.bs.fileprovider/camera_photos/表明的真實路徑就是根目錄,即:/storage/emulated/0/。

content://com.bj.bs.fileprovider/camera_photos/temp/1474960080319.jpg表明的真實路徑是:/storage/emulated/0/temp/1474960080319.jpg。

裁切照片

在Android7.0以前,你能夠經過以下方法來裁切照片:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");

if (!file.getParentFile().exists())file.getParentFile().mkdirs();

Uri outputUri = Uri.fromFile(file);

Uri imageUri=Uri.fromFile(new File("/storage/emulated/0/temp/1474960080319.jpg"));

Intent intent = new Intent("com.android.camera.action.CROP");

intent.setDataAndType(imageUri, "image/*");

intent.putExtra("crop", "true");

intent.putExtra("aspectX", 1);

intent.putExtra("aspectY", 1);

intent.putExtra("scale", true);

intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);

intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());

intent.putExtra("noFaceDetection", true); // no face detection

startActivityForResult(intent, 2);

和拍照同樣,上述代碼在Android7.0上一樣會引發android.os.FileUriExposedException異常,解決辦法就是上文說說的使用FileProvider。

而後,将上述代碼改成以下便可:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");

if (!file.getParentFile().exists())file.getParentFile().mkdirs();

Uri outputUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider",file);

Uri imageUri=FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", new File("/storage/emulated/0/temp/1474960080319.jpg");//經過FileProvider建立一個content類型的Uri

Intent intent = new Intent("com.android.camera.action.CROP");

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

intent.setDataAndType(imageUri, "image/*");

intent.putExtra("crop", "true");

intent.putExtra("aspectX", 1);

intent.putExtra("aspectY", 1);

intent.putExtra("scale", true);

intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);

intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());

intent.putExtra("noFaceDetection", true); // no face detection

startActivityForResult(intent, 2);

源碼

android 适配7.0,Android7.0适配心得(一)_拍照相容