最近在写一个react native 项目,其中react-native-webview库一些使用着实遇到了不少问题,耗时比较长,现在和大家分享一下。
图片上传时选择拍照是很常见的功能,写的h5项目一直调用正常。使用方式大概如下:
<input
type="file"
ref={inputRef}
accept="image/*"
capture={'camera' as any}
id="uploadImage"
onChange={handleUploadChange}
/>
在H5下这段代码是正常可以使用的,调起相机和图库选择器,但是使用react-native-webview要注意。
首先要在AndroidManifest.xml注入权限,大概是如下三个,这个没很认真调研过,有错误可以提出。
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
权限注入了之后,我认为一切都可以了,没想到这才是坑的开始。相机死活调不出来,经过查资料,大概有以下几种说法:
- 1、原生webview不支持input accept="image",capture="camera"这种方式(原生是真的不支持)。但我使用的是类库react-native-webview,我个人以为是一个问题,然后才被坑下去的。
- 2、xml权限注入的不对,然后各种尝试+各种查哪些权限是干啥用的。
- 3、react-native 版本有问题
- 4、react-native-webview版本有问题
并且在查的过程中还发生一些其他的血案,分享个地址给大家看下:https://github.com/react-native-webview/react-native-webview/issues/2679
官网在介绍如果input调不起相机的话,可以去这个地址看一下:react-native-webview/Guide.md at master · react-native-webview/react-native-webview · GitHub
然后呢?
import { WebView } from "react-native-webview";
WebView.isFileUploadSupported().then(res => {
if (res === true) {
// file upload is supported
} else {
// not file upload support
}
});
这是代码,然后,就报错了,遇到了issues/2679这个问题,在这个坑里挣扎了半天,看node-modules导入的源码,并没有找到WebView.isFileUploadSupported这个方法,到最后我也没找到,这只不过是其中的一个弯路而已,最后我放弃了这个。
因为没找到问题,我就找到了另外一篇文章,是教咱怎么在原生种实现webview调起相机的功能的。然后我就打算给react-native-webview原生实现一个选择相机的功能,地址链接:Android WebView支持input file启用相机/选取照片功能 - 腾讯云开发者社区-腾讯云
开干,然后在这个坑里爬了半天,基本上把 react-native-webview源码扒了个遍(PS:当然我不是安卓开发,不太懂),然后找到了其中一个文件:
这个文件包含了点击input 相关的调用逻辑,不是很复杂,主要代码就这段:
if (!needsCameraPermission()) {
if (acceptsImages(acceptTypes)) {
Intent photoIntent = getPhotoIntent();
if (photoIntent != null) {
extraIntents.add(photoIntent);
}
}
if (acceptsVideo(acceptTypes)) {
Intent videoIntent = getVideoIntent();
if (videoIntent != null) {
extraIntents.add(videoIntent);
}
}
}
这段代码才是下一个坑的开始,因为先入为主的原因,我以为react-native-webview根本就没实现相机的调用,于是我就结合了顶上那篇文章,开始了修改源码的爬坑之旅,由于没有java的经验,折腾了一个多小时后,终于相机出来了😭。
然后下一个坑出来,还是因为先入为主。点击相机没反应?然后各种查资料,看代码,才发现,getPhotoIntent这个方法:
private Intent getPhotoIntent() {
Intent intent = null;
try {
outputImage = getCapturedFile(MimeType.IMAGE);
Uri outputImageUri = getOutputUri(outputImage);
intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputImageUri);
} catch (IOException | IllegalArgumentException e) {
Log.e("CREATE FILE", "Error occurred while creating the File", e);
e.printStackTrace();
}
return intent;
}
TMD,这不就是添加相机的地方吗?以为是这个方法的问题导致相机没有显示:acceptsImages(acceptType),后来发现发现不是,
private Boolean acceptsImages(String types) {
String mimeType = types;
if (types.matches("\\.\\w+")) {
mimeType = getMimeTypeFromExtension(types.replace(".", ""));
}
return mimeType.isEmpty() || mimeType.toLowerCase().contains(MimeType.IMAGE.value);
}
然后各种找,先入为主害死人啊!添加相机选项的顶上,还有个needsCameraPermission方法,这个方法是获取权限的,我一直以为权限是有的,然后,打断点,发现,这里并没有获取到想要的权限。并且查看手机系统设置-》应用里面的相机权限是禁用,在设置里面打开权限之后,相机调用也正常了,然后我就EMO了。
很多文章告诉我们,权限并不需要手动获取,只需要加到配置清单中就行了,但实际并不是,相机这种权限还是需要主要跟用户获取的,当然用户同意了之后,以后就不需要再次获取了。
最终解决方案,大家可以看一下这篇文章,因为我的页面是需要相机权限的,所以我一进入这个页面就发起了权限的获取。React-Native之Android(6.0及以上)权限申请详解 - 腾讯云开发者社区-腾讯云
示例代码如下:
//请求多个权限
const requestMultiplePermission = async () => {
try {
const permissions = [
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
PermissionsAndroid.PERMISSIONS.CAMERA,
];
//返回得是对象类型
const granteds = await PermissionsAndroid.requestMultiple(permissions);
var data = '是否同意地址权限: ';
if (granteds['android.permission.ACCESS_FINE_LOCATION'] === 'granted') {
data = data + '是\n';
} else {
data = data + '否\n';
}
data = data + '是否同意相机权限: ';
if (granteds['android.permission.CAMERA'] === 'granted') {
data = data + '是\n';
} else {
data = data + '否\n';
}
data = data + '是否同意存储权限: ';
if (granteds['android.permission.WRITE_EXTERNAL_STORAGE'] === 'granted') {
data = data + '是\n';
} else {
data = data + '否\n';
}
} catch (err) {
// this.show(err.toString());
}
};
useEffect(() => {
requestMultiplePermission();
}, []);
这段代码会在用户进入页面时发起一次权限的获取,如果已经有权限了,就不会再次发起了。
说了这么多,react-native-webview是支持相机的。
大家在用react-native 相机的时候注意:
1、先看配置清单是否添加权限
2、看下webview是否支持相机,(在系统设置-》应用-》权限中,如果相机权限已经启用,还是调不起相机的话,就要考虑webview是不是不支持)
3、如果安装APP后,相机权限是禁用的,要调用我上面写的方法,主动发起权限申请,webview可以放一个全局的地方申请。
4、input type=file,只有accept="image/*"的时候才有用,并且我测试过:capture={'camera' as any}不是必须的,新版规范中capture也没有camera选项了,只有
capture?: boolean | 'user' | 'environment' | undefined; 这几个值了,没有camera这个了。
就到这,希望大家可以开发顺利。