Android 7.0使用相機功能
阿新 • • 發佈:2019-01-23
最近在專案中有用到相機的功能,通常用法
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION |Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); //file是圖片路勁 Uri uri = Uri.fromFile(file); intent.putExtra(MediaStore.Images.Media.ORIENTATION, 0); //設定MediaStore.EXTRA_OUTPUT的輸出路徑為imageFileUri intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); activity.startActivityForResult(intent, requestCode);
這樣就可以調轉相機,前兩天還好好的呢,可是今天發現不行了,直接就崩潰了。。錯誤日誌如下,許可權異常了。。。
android.os.FileUriExposedException: file:///storage/emulated/0/DCIM/IMG_1041503431.jpg
看了下原始碼,在targetSdk>=24的時候就得使用content://了
//建立一個圖片儲存的Uri 在7.0上必須使用contentProvider建立,否則會崩
ContentValues contentValues = new ContentValues(1); contentValues.put(MediaStore.Images.Media.DATA, file.getAbsolutePath()); uri=activity.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
這時候在7.0手機上執行發現沒事了,可是在低版本上執行,就又不行了,所以還得做下區分,最終的使用姿勢
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); Uri uri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //建立一個圖片儲存的Uri 在7.0上必須使用contentProvider建立,否則會崩 ContentValues contentValues = new ContentValues(1); contentValues.put(MediaStore.Images.Media.DATA, file.getAbsolutePath()); uri = activity.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues); } else { uri = Uri.fromFile(file); } intent.putExtra(MediaStore.Images.Media.ORIENTATION, 0); //設定MediaStore.EXTRA_OUTPUT的輸出路徑為imageFileUri intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); activity.startActivityForResult(intent, requestCode);
就是判斷下版本>=24的時候就使用contentValues這種方式,當然還有一種就是在清單檔案中註冊contentProvider的方式,如下:
<provider android:name="android.support.v4.content.FileProvider" //固定值 android:authorities="com.test.test.fileprovider"//路徑 前面為包名,後面為fileprovider固定值,使用包名便於區分
android:exported="false"//是否支援其它應用呼叫當前元件 ,要求為flase
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"//固定值
android:resource="@xml/filepaths"/>//在res目錄下定義的filepaths.xml檔案,名字可以自定義
還需要在res資料夾下建立xml資料夾,在建立filePath.xml
<paths>
<!-- xml檔案是唯一設定分享的目錄 ,不能用程式碼設定
1.<files-path>getFilesDir() /data/data//files目錄
2.<cache-path>getCacheDir() /data/data//cache目錄
3.<external-path>Environment.getExternalStorageDirectory()
SDCard/Android/data/你的應用的包名/files/ 目錄
4.<external-files-path> Context#getExternalFilesDir(String) Context.getExternalFilesDir(null).
5.<external-cache-path> Context.getExternalCacheDir().
-->
<!-- path :代表設定的目錄下一級目錄 eg:<external-path path="images/" 整個目錄為Environment.getExternalStorageDirectory()+"/images/"
name: 代表定義在Content中的欄位 eg:name = "myimages" ,並且請求的內容的檔名為default_image.jpg
則 返回一個URI content://com.example.myapp.fileprovider/myimages/default_image.jpg-->
<!--當path 為空時 5個全配置就可以解決-->
<!--下載apk-->
<external-path path="" name="sdcard_files" />
<!--相機相簿裁剪-->
<external-files-path path="" name="camera_has_sdcard"/>
<files-path path="" name="camera_no_sdcard"/>
</paths>
上面註釋各個標籤的意思已經寫清楚了。用哪個看你自己了。。
使用的姿勢如下,代替了contentValues那些
一定要注意這裡的com.test.test.fileprovider一定要與清單檔案中的一樣,否則會報錯滴。。
Uri uriForFile = FileProvider.getUriForFile(getActivity(), "com.renwohua.conch.fileprovider", mCameraFile); intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, uriForFile); intentFromCapture.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intentFromCapture.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
還有一個就是安裝apk,這是都會用的吧。也是前兩天用
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.addCategory(Intent.CATEGORY_DEFAULT);
installIntent.setDataAndType(Uri.fromFile(apkFile),"application/vnd.android.package-archive");
activity.startActivityForResult(installIntent,0x1001);
這樣使用沒有問題,問了監聽是否安裝使用了forResult,可是今天在7.0上就完蛋了。。。。一看還是一樣的錯誤,又不行了,需要使用contentProvider來獲取路徑,真坑啊,忽然就改了,,,幸好還沒上線。。。解決辦法如下:
Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.addCategory(Intent.CATEGORY_DEFAULT); installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
String providerString = getFileProviderString(activity);
Uri uri = FileProvider.getUriForFile(activity.getApplicationContext(), providerString, apkFile);
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
} else {
installIntent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
}
activity.getApplication().startActivity(installIntent);
在這裡不能使用forResult了,因為使用了Intent.FLAG_ACTIVITY_NEW_TASK標記,如果想監聽是否取消另想辦法嘍。。