记录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调用相册和相机的功能。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)