Webview调用相册相机失败等问题(h5交互问题)

  • Post author:
  • Post category:其他



1.FileProvider用于解决高版本的android系统出现的调用相机和相册不成功的问题



①.  权限申请



建议在你的BaseActivity中去增加两个方法。




public void onPermissionRequests(String permission, OnBooleanListener onBooleanListener) {
    onPermissionListener = onBooleanListener;
    Log.d("MainActivity", "0");
    if (ContextCompat.checkSelfPermission(this,
            permission)
            != PackageManager.PERMISSION_GRANTED) {
        // Should we show an explanation?
        Log.d("MainActivity", "1");
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.READ_CONTACTS)) {
            //权限已有
            onPermissionListener.onClick(true);
        } else {
            //没有权限,申请一下
            ActivityCompat.requestPermissions(this,
                    new String[]{permission},
                    1);
        }
    }else{
        onPermissionListener.onClick(true);
        Log.d("MainActivity", "2"+ContextCompat.checkSelfPermission(this,
                permission));
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == 1) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //权限通过
            if (onPermissionListener != null) {
                onPermissionListener.onClick(true);
            }
        } else {
            //权限拒绝
            if (onPermissionListener != null) {
                onPermissionListener.onClick(false);
            }
        }
        return;
    }
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}


然后在你需要申请权限的地方调用这个方法就可以了



onPermissionRequests


②.  7.0相机问题





Android7.0中尝试传递 file:// URI 会触发 FileUriExposedException,因为在Android7.0之后Google认为直接使用本地

的根目录即file:// URI是不安全的操作,直接访问会抛出FileUriExposedExCeption异常,这就意味着在Android7.0以前

我们访问相机拍照存储时,如果使用URI的方式直接存储剪裁图片就会造成这个异常,那么如何解决这个问题呢?

Google为我们提供了FileProvider类,进行一种特殊的内容提供,FileProvider时ContentProvide的子类,它使用了和

内容提供器类似的机制来对数据进行保护,可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性。下面

就让我们看一下如何使用这个内容提供者进行数据访问的:

使用FileProvider获取Uri就会将以前的file:// URI准换成content:// URI,实现一种安全的应用间数据访问,内容提

供者作为Android的四大组件之一,使用同样需要在清单文件AndroidManifest.xml中进行注册的,注册方法如下:

首先


是准备工作,先在res文件夹下添加xml文件夹,然后创建一个文件file_paths,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">

    <!--填写你要所要申请访问的目录地址,name最好是你的目录名,path是你要申请的目录-->
    <external-path name="camera_photos" path="."  />
</paths>


然后在AndroidManifest.xml文件中添加


<!-- 这里直接复制就可以,需要注意的是authorities,以你的包名加上fileprovider,因为他需要唯一 -->
<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="包名.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths"/>
</provider>


这样准备工作就做好了,不要纠结着FileProvider,到时候直接用就可以,下面是调用代码:


Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File photoFile = createImagePathFile(MainActivity.this);
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);

/*
* 这里就是高版本需要注意的,需用使用FileProvider来获取Uri,同时需要注意getUriForFile
* 方法第二个参数要与AndroidManifest.xml中provider的里面的属性authorities的值一致
* */
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
imageUriFromCamera = FileProvider.getUriForFile(MainActivity.this,
        "包名.fileprovider", photoFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUriFromCamera);
startActivityForResult(intent, GET_IMAGE_BY_CAMERA_U);


然后就没有然后了,结尾附几个Demo,很简单:


https://github.com/xuezj/FileProviderDemo


https://github.com/zhengzhong1/Android6.0PermissionsDemo



https://github.com/HelloWmz/PhotoDemo



2


.直接在webview中点击事件调用摄像头和相册就得重写webcromeClient方法

WebViewClient webViewClient = new WebViewClient() {
    public OkHttpClient client = new OkHttpClient();

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        view.loadUrl(url);
        return true;
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {

        // ------5.0以上手机执行------
        Uri uri = request.getUrl();
        String url = uri.toString();
        return shouldInterceptRequest(view, url);
    }


    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        String newUrl = StringUtil.getNewUrl(url);
        Utils.CommonUtilLog(TAG, "old url=" + url);
        Utils.CommonUtilLog(TAG, "new url=" + newUrl);


        if (newUrl.equals(url)) {
            return super.shouldInterceptRequest(view, url);
        }


        Request request1 = new Request.Builder()
                .url(newUrl)
                .build();
        Response response = null;
        try {
            response = client.newCall(request1).execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
        String type = Utils.getMimeType(newUrl);
        Utils.CommonUtilLog(TAG, "type=" + type);
        return new WebResourceResponse(type, response.header("content-encoding", "utf-8"), response.body().byteStream());
    }

};

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {
        mWebView.goBack();
        return true;
    }

    return super.onKeyDown(keyCode, event);
}

@Override
protected void onPause() {
    super.onPause();

}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mWebView != null) {
        mWebView.clearHistory();
        ((ViewGroup) mWebView.getParent()).removeView(mWebView);
        mWebView.loadUrl("about:blank");
        mWebView.stopLoading();
        mWebView.setWebChromeClient(null);
        mWebView.setWebViewClient(null);
        mWebView.destroy();
        mWebView = null;
    }
}

/*
*=====HTML5调相机相册======
* 重写WebChromeClient方法
*/

WebChromeClient webChromeClient = new WebChromeClient() {
    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        super.onProgressChanged(view, newProgress);

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


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

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

    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
        mUploadMessage = uploadMsg;
        take();
    }
};
private void take() {
    File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp");        // Create the storage directory if it does not exist
    if (!imageStorageDir.exists()) {
        imageStorageDir.mkdirs();
    }
    File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
    imageUri = Uri.fromFile(file);
    final List<Intent> cameraIntents = new ArrayList();
    final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    final PackageManager packageManager = getPackageManager();
    final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
    for (ResolveInfo res : listCam) {
        final String packageName = res.activityInfo.packageName;
        final Intent i = new Intent(captureIntent);
        i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
        i.setPackage(packageName);
        i.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        cameraIntents.add(i);

    }
    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
    i.addCategory(Intent.CATEGORY_OPENABLE);
    i.setType("image/*");
    Intent chooserIntent = Intent.createChooser(i, "Image Chooser");
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
    RemoteWebActivity.this.startActivityForResult(chooserIntent, FILE_CHOOSER_RESULT_CODE);
}

@SuppressWarnings("null")
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void onActivityResultAboveL(int requestCode, int resultCode, Intent data) {
    if (requestCode != FILE_CHOOSER_RESULT_CODE
            || mUploadCallbackAboveL == null) {
        return;
    }
    Uri[] results = null;
    if (resultCode == Activity.RESULT_OK) {
        if (data == null) {

            results = new Uri[]{imageUri};
        } else {
            String dataString = data.getDataString();
            ClipData clipData = data.getClipData();
            if (clipData != null) {
                results = new Uri[clipData.getItemCount()];
                for (int i = 0; i < clipData.getItemCount(); i++) {
                    ClipData.Item item = clipData.getItemAt(i);
                    results[i] = item.getUri();
                }
            }
            if (dataString != null)
                results = new Uri[]{Uri.parse(dataString)};
        }
    }
    if (results != null) {
        mUploadCallbackAboveL.onReceiveValue(results);
        mUploadCallbackAboveL = null;
    } else {
        results = new Uri[]{imageUri};
        mUploadCallbackAboveL.onReceiveValue(results);
        mUploadCallbackAboveL = null;
    }
    return;
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == FILE_CHOOSER_RESULT_CODE) {
        if (null == mUploadMessage && null == mUploadCallbackAboveL) return;
        Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
        if (mUploadCallbackAboveL != null) {
            onActivityResultAboveL(requestCode, resultCode, data);
        } else if (mUploadMessage != null) {
            if (result != null) {
                String path = getPath(getApplicationContext(),
                        result);
                Uri uri = Uri.fromFile(new File(path));
                mUploadMessage
                        .onReceiveValue(uri);
            } else {
                mUploadMessage.onReceiveValue(imageUri);
            }
            mUploadMessage = null;

        }
    }
}

@SuppressLint("NewApi")
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {
    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
    // DocumentProvider
    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
        // ExternalStorageProvider
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];
            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/" + split[1];
            }                // TODO handle non-primary volumes
        } else if (isDownloadsDocument(uri)) {
            final String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
            return getDataColumn(context, contentUri, null, null);
        }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {
        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }
    return null;
}
public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {column};
    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
        if (cursor != null && cursor.moveToFirst()) {
            final int column_index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(column_index);
        }
    } finally {
        if (cursor != null) cursor.close();
    }
    return null;
}
public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is DownloadsProvider.
 */
public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}


在h5界面必须有那么一行代码



<div

class

=”

jdmodel-first-bottom

“>





<img

class

=”

jdmodel-first-bottom-button



src

=”

/statics/jdmodel/css/image/bottom.png

“/>









<input

type

=”

file



id

=”

cameraInput



style

=”

display: none



accept

=”

image/*

“/>









<img

class

=”

jdmodel-first-bottom-photograph



src

=”

/statics/jdmodel/css/image/photograph.png



id

=”

photoBtnId

“/>









</div>


返回后的图片会放到id为cameraInput的界面位置!!!