Android7.0調用相機出現android.os.FileUriExposedException異常

Android  N。。。android

昨天把項目targetSdkVersion改爲了26。問題接踵而來。bash

最嚴重的就是項目中有地方調用到了系統相機拍照功能,拍完返回圖片一張。app

(Android中很多地方須要這樣作的)有兩種實現方法。其實這裏的兩種實現方法原理都是同樣的。都是隱士Intent開啓系統相機。拍完照後返回所拍攝的照片。ide

只不過兩種方法返回的東西不同。ui

一種直接返回圖片this

一種返回啓動相機界面前指定的存儲拍攝圖片的Urispa

第一種方法:code

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE)
                startActivityForResult(intent, TAKE_PHOTO_REQUEST)
複製代碼

這裏咱們只須要指定Intent的actioni就能夠實現了。xml

能夠在onActivityResult的回調中經過intent回傳獲取到圖片對象。對象

Bitmap  photo = intent.getParcelableExtra("data")複製代碼

這樣的圖片對象回傳不用想指定是沒有第二種方法更爲節省內存

項目中也是使用的第二種方法:

root_dir = Environment.getExternalStorageDirectory().toString() + File.separator + Constant.CACHE_PATH
pt_dir = root_dir + File.separator + "bike_operation.jpg"複製代碼

先指定好圖片要存儲的路徑。

下面先說一下N之前的操做。

你只須要以下:

val intentFromCapture = Intent(MediaStore.ACTION_IMAGE_CAPTURE)

  intentFromCapture.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1)
intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(File(pt_dir)))startActivityForResult(intentFromCapture, Constant.PAIZHAO_REQUEST)
複製代碼

經過Uri。fromFile指定一下圖片存儲路徑對應的Uri

就能夠在onActivityResult的回調中再次獲取到這個Uri從而經過解析Uri拿到對應的文件路徑。生成對應的Bitmap。

然而,由於昨天的targetSdkVersion改爲了26在N設備上運行該代碼的時候報了以下錯誤

android.os.FileUriExposedException: file:///storage/emulated/0/mangoebike_operation_cache/bike_damage.jpg exposed beyond app through ClipData.Item.getUri()
複製代碼

文件Uri解析異常Google一下才曉得了就是7.0增長了更爲嚴格的進程間文件數據共享的機制

Uri的獲取方式不能再像往常同樣獲取了。須要以下作法

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.whxxcy.mango_operation.fileProvider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>
複製代碼

清單application節點下面指定provider屬性。authorities屬性能夠本身隨意指定。可是要記得代碼中待會兒還要用到它。這裏咱們就以包名加.fileProvider.字段來指定。

再一個須要咱們指定的就是這個resource屬性了。在res文件目錄下新建xml文件夾再在文件夾中建立file_paths文件。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <external-path
            name="bike_operation"
            path="mangoebike_operation_cache" />
    </paths>
</resources>

複製代碼

path屬性在個人理解是用來拼接Uri的就是你不寫它會在根目錄中去尋找存放文件。

name屬性必須指定。不指定編譯通不過。在個人理解這個name屬性實際上是你在代碼中拍照生成的文件的名字。

指定完這兩個屬性來看代碼:

val intentFromCapture = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
intentFromCapture.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    val contentUri = FileProvider.getUriForFile(this@OperationActivity, packageName + ".fileProvider", File(pt_dir))
    intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, contentUri)     //將拍取的照片保存到指定URI
} else {
    intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(File(pt_dir)))
}
startActivityForResult(intentFromCapture, Constant.PAIZHAO_REQUEST)複製代碼

若是當前sdk版本大於等於24Uri的獲取方式就變成

= FileProvider.getUriForFile(this@OperationActivity, packageName + ".fileProvider", File(pt_dir))複製代碼

參數1: 上下文。參數2: 就是在provider中指定的authitrites。參數3:File對象一開始指定的存儲拍攝照片的路徑

而後在onActivityResult的回調中解析Uri獲得Bitmap對象就能夠啦。。。有描述不許確的地方後續再改正。。。。

相關文章
相關標籤/搜索