Android webview打开相机闪退报android.os.FileUriExposedException 问题解决记录

1.背景

最近优化公司的一款老app。app采用vue+webview+android。为实现产品奇奇怪怪的需求把targetSdkVersion从23升级到了26.然后就出现了UI框架打开相机时闪退的问题。通过错误日志定位到问题android.os.FileUriExposedException.

2.问题产生原因

 android7.0后加了私有目录被限制访问所以,Uri.fromFile(file)方法访问file://url会出现android.os.FileUriExposedException异常。

3.解决方案

3.1;在AndroidManifest.xml 清单文件中加入provider。

<application
...
<activity
..
 </activity>

 <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/file_paths" />
        
 </provider>
<application

3.2.在res->xml目录下新建file_paths.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>

3.3

在具体保存代码修改

        //imageUri = Uri.fromFile(file);
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M){
            imageUri = Uri.fromFile(file);
        }
        else {
            imageUri= FileProvider.getUriForFile(this, this.getPackageName() + ".provider", file);
        }

注释掉的是原来代码。在android7.0以上用FileProvider.getUriForFile(context,context.getPackageName() + ".provider", file);替换Uri.fromFile(file);

 

4.可能有的小伙伴和我一样是webview+H5开发的,然后使用html打开的相机。那么在哪修改imageUri 呢。我是这样做的


4.1打开相机html代码
 <van-uploader v-model="fileList" max-count="1" preview-size="150px" upload-text="点击打开相机,拍照"
            :after-read="afterRead" multiple accept="image/*" />

  4.2webview里重写WebChromeClient

mWebView.setWebChromeClient(mWebChromeClient);
private WebChromeClient mWebChromeClient = new WebChromeClient() {

        @Override
        public void onGeolocationPermissionsShowPrompt(final String origin, final GeolocationPermissions.Callback callback) {
            callback.invoke(origin, true, true);
        }

        //>5.0.1
        @Override
        public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
            mUploadCallbackAboveL = filePathCallback;
            take();
            return true;
        }
        //<3.0

        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
            mUploadMessage = uploadMsg;
            take();
        }

        //>3.0+
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
            mUploadMessage = uploadMsg;
            take();
        }

        //>4.1.1
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
            mUploadMessage = uploadMsg;
            take();
        }
    };

 take()方法里修改

private void take() {
        File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp");
        if (!imageStorageDir.exists()) {
            imageStorageDir.mkdirs();
        }
        File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
        //imageUri = Uri.fromFile(file);
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M){
            imageUri = Uri.fromFile(file);
        }
        else {
            imageUri= FileProvider.getUriForFile(this, this.getPackageName() + ".provider", file);
        }
        final List<Intent> cameraIntents = new ArrayList<Intent>();
        final Intent captureIntent = new Intent("android.media.action.IMAGE_CAPTURE");
        captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        startActivityForResult(captureIntent, FILECHOOSER_RESULTCODE);
}
 

 




posted @ 2021-11-17 10:44  拖肥  阅读(998)  评论(0编辑  收藏  举报