记录webView接入h5界面时,调起相册、文件、相机无效的解决办法

记录webView接入h5界面时,调起相册、文件、相机无效的解决办法,第1张

记录webView接入h5界面时,调起相册、文件、相机无效的解决办法。

在开发项目时,接入一个h5界面。使用webview时,发现界面显示正常,但是按钮不论怎么点都无效,但是m站和ios都正常。后来上网查了相关资料,才发现原来这块是需要Android这边自己在webview这边开发的。需要重写WebChromeClient。

这里有一个需要区分的概念就是WebChromeClient和WebViewClient,因时间和精力关系只做简单的学习和介绍。

WebViewClient只和影响view有关系的事件到来时,会通过WebViewClient内的方法回调通知开发者。

WebChromeClient则是和浏览器有关的事件进行回调。

一句话区分就是WebViewClient只和显示有关系,而WebChromeClient则是和js交互有关(如d窗等)。

WebChromeClient

想要实现和js的打开相册、相机等交互,必须重写两个方法,分别适配4.1~5.0以及5.0以上版本。

//For Android 4.1  - 5.0
public void openFileChooser(ValueCallback uploadMsg, String acceptType,
    String capture) {
}

//For 5.0+
@Override
public boolean onShowFileChooser(WebView webView,
    ValueCallback filePathCallback,
    WebChromeClient.FileChooserParams fileChooserParams) {
    return true;
}

在了解这个方法前,可以先简单了解一下h5界面是如何调用本地的相册以及其他功能。如下所示



accept 和capture分别对应openFileChooser的acceptType和capture,因此我们只需要和h5约定好accept的值就可以做相对应的处理了,uploadMsg则是这个方法的回调。

也许你会奇怪onShowFileChooser中并没有这样acceptType和capture,但实际上有一个fileChooserParams。可以通过fileChooserParams.getAcceptTypes()[0]的方式获取到acceptType。

比如我们可以和h5约定accepty="image/*"是打开相册、accepty=“camera/*”是打开相机。然后分别在webview中处理就可以了。

来简单实现一下。

第一步,设置WebChromeClient。

        customWebview.setWebChromeClient(new WebChromeClient() {
                //For Android 4.1  - 5.0
                public void openFileChooser(ValueCallback uploadMsg, String acceptType,
                    String capture) {
                    //这是一个全局变量
                    filePathCallback = uploadMsg;
                    if (acceptType != null) {
                        openCustomServiceProcess(acceptType);
                    }
                }

                //For 5.0+
                @Override
                public boolean onShowFileChooser(WebView webView,
                    ValueCallback filePathCallback,
                    WebChromeClient.FileChooserParams fileChooserParams) {
                    //这是一个全局变量
                    filesPathCallback = filePathCallback;
                    if (fileChooserParams != null
                        && fileChooserParams.getAcceptTypes() != null) {
                        openCustomServiceProcess(fileChooserParams.getAcceptTypes()[0]);
                    }
                    return true;
                }
            });

openCustomServiceProcess是根据acceptType分别处理调用相册或者相机等功能。

/**
 * 根据actionType判断是打开相册、打开文件、还是打开相机
 *
 * @param type h5 actionType
 */
private void openCustomServiceProcess(String type) {
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    if (!TextUtils.isEmpty(type)) {
        intent.setType(type);
        //如果是打开图片
        if (type.equals("image/*")) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                intent.addCategory(Intent.CATEGORY_OPENABLE);
            }
        } else if (type.equals("camera/*")) {
            //如果是打开相机 REQUEST_CODE_CAMERA是自定义的requestCode 只需要是唯一常数即可
            sendCameraIntent(REQUEST_CODE_CAMERA);
            return;
        }
    } else {
        //如果是打开所有文件
        intent.setType("*/*");
    }
		//调用起文件查看器,根据是否设置Intent.CATEGORY_OPENABLE判断打开的分类是图片库还是所有文件
    this.startActivityForResult(Intent.createChooser(intent, "请选择文件"), REQUEST_CODE_FILE);
}
/**
 * 调起相机
 */
private void sendCameraIntent(int requestCode) {
        if (mCameraFile == null) {
            mCameraFile = new File(AppUtils.getCameraImagePath(CustomWebViewActivity.this));
        }
        mCameraFile.getParentFile().mkdirs();
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            imageUri = FileProvider.getUriForFile(CustomWebViewActivity.this,
                getApplicationContext().getPackageName() + ".fileprovider",
                mCameraFile);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        } else {
            imageUri = Uri.fromFile(mCameraFile);
        }
        if (requestCode == REQUEST_CODE_CAMERA_KF) {
            intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        }
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        startActivityForResult(intent, requestCode);
    }

到这一步基本上就已经可以调用起相册或者相机了,但是很快就会发现有一个问题,只能调用一次。原来是每次使用回调以后,必须都有一个返回值,通过mUploadMsg或者filesPathCallback的onReceiveValue方法,切记一定要返回值,即使data为空也需要传null回去。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == Activity.RESULT_OK) {
        switch (requestCode) {
            case REQUEST_CODE_FILE:
            case REQUEST_CODE_CAMERA:
                if (filePathCallback != null) {
                    Uri result = data == null ? null : data.getData();
                    if (result != null) {
                        filePathCallback.onReceiveValue(result);
                    } else {
                        filePathCallback.onReceiveValue(Uri.EMPTY);
                    }
                    filePathCallback = null;
                }
                //将文件回传给h5
                if (filesPathCallback != null) {
                    Uri[] result = null;
                    if (data != null) {
                        String dataString = data.getDataString();
                        ClipData clipData = data.getClipData();
                        if (clipData != null) {
                            int itemCount = clipData.getItemCount();
                            result = new Uri[itemCount];
                            for (int i = 0; i < itemCount; i++) {
                                ClipData.Item item = clipData.getItemAt(i);
                                result[i] = item.getUri();
                            }
                        }
                        if (dataString != null) {
                            result = new Uri[] { Uri.parse(dataString) };
                        }
                    } else if (requestCode == REQUEST_CODE_CAMERA) {
                        result = new Uri[] { imageUri };
                    }
                    if (result == null) {
                        filesPathCallback.onReceiveValue(new Uri[] {});
                    } else {
                        filesPathCallback.onReceiveValue(result);
                    }
                    filesPathCallback = null;
                }
                break;
            default:

                break;
        }
    } else {
        switch (requestCode) {
            //如果返回为空时,返回null
            case REQUEST_CODE_FILE:
            case REQUEST_CODE_CAMERA_KF:
                if (filePathCallback != null) {
                    filePathCallback.onReceiveValue(Uri.EMPTY);
                    filePathCallback = null;
                }
                if (filesPathCallback != null) {
                    filesPathCallback.onReceiveValue(new Uri[] {});
                    filesPathCallback = null;
                }
                break;
            default:
                com.gaotu100.superclass.base.logger.MyLogger.d("1");
                break;
        }
    }
}

至此算是完成了app内嵌h5调用相册和相机的功能。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/996449.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存