• React Native Webview 中input type=file accept=“image/*“ 无法调起相机问题排查及解决


    最近在写一个react native 项目,其中react-native-webview库一些使用着实遇到了不少问题,耗时比较长,现在和大家分享一下。

    图片上传时选择拍照是很常见的功能,写的h5项目一直调用正常。使用方式大概如下:

    1. type="file"
    2. ref={inputRef}
    3. accept="image/*"
    4. capture={'camera' as any}
    5. id="uploadImage"
    6. onChange={handleUploadChange}
    7. />

    在H5下这段代码是正常可以使用的,调起相机和图库选择器,但是使用react-native-webview要注意。

    首先要在AndroidManifest.xml注入权限,大概是如下三个,这个没很认真调研过,有错误可以提出。

            权限注入了之后,我认为一切都可以了,没想到这才是坑的开始。相机死活调不出来,经过查资料,大概有以下几种说法:

    • 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

    然后呢?

    1. import { WebView } from "react-native-webview";
    2. WebView.isFileUploadSupported().then(res => {
    3. if (res === true) {
    4. // file upload is supported
    5. } else {
    6. // not file upload support
    7. }
    8. });

             这是代码,然后,就报错了,遇到了issues/2679这个问题,在这个坑里挣扎了半天,看node-modules导入的源码,并没有找到WebView.isFileUploadSupported这个方法,到最后我也没找到,这只不过是其中的一个弯路而已,最后我放弃了这个。

            因为没找到问题,我就找到了另外一篇文章,是教咱怎么在原生种实现webview调起相机的功能的。然后我就打算给react-native-webview原生实现一个选择相机的功能,地址链接:Android WebView支持input file启用相机/选取照片功能 - 腾讯云开发者社区-腾讯云

            开干,然后在这个坑里爬了半天,基本上把 react-native-webview源码扒了个遍(PS:当然我不是安卓开发,不太懂),然后找到了其中一个文件:

    这个文件包含了点击input 相关的调用逻辑,不是很复杂,主要代码就这段:

    1. if (!needsCameraPermission()) {
    2. if (acceptsImages(acceptTypes)) {
    3. Intent photoIntent = getPhotoIntent();
    4. if (photoIntent != null) {
    5. extraIntents.add(photoIntent);
    6. }
    7. }
    8. if (acceptsVideo(acceptTypes)) {
    9. Intent videoIntent = getVideoIntent();
    10. if (videoIntent != null) {
    11. extraIntents.add(videoIntent);
    12. }
    13. }
    14. }

            这段代码才是下一个坑的开始,因为先入为主的原因,我以为react-native-webview根本就没实现相机的调用,于是我就结合了顶上那篇文章,开始了修改源码的爬坑之旅,由于没有java的经验,折腾了一个多小时后,终于相机出来了😭。

            然后下一个坑出来,还是因为先入为主。点击相机没反应?然后各种查资料,看代码,才发现,getPhotoIntent这个方法:

    1. private Intent getPhotoIntent() {
    2. Intent intent = null;
    3. try {
    4. outputImage = getCapturedFile(MimeType.IMAGE);
    5. Uri outputImageUri = getOutputUri(outputImage);
    6. intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    7. intent.putExtra(MediaStore.EXTRA_OUTPUT, outputImageUri);
    8. } catch (IOException | IllegalArgumentException e) {
    9. Log.e("CREATE FILE", "Error occurred while creating the File", e);
    10. e.printStackTrace();
    11. }
    12. return intent;
    13. }

    TMD,这不就是添加相机的地方吗?以为是这个方法的问题导致相机没有显示:acceptsImages(acceptType),后来发现发现不是,

    1. private Boolean acceptsImages(String types) {
    2. String mimeType = types;
    3. if (types.matches("\\.\\w+")) {
    4. mimeType = getMimeTypeFromExtension(types.replace(".", ""));
    5. }
    6. return mimeType.isEmpty() || mimeType.toLowerCase().contains(MimeType.IMAGE.value);
    7. }

    然后各种找,先入为主害死人啊!添加相机选项的顶上,还有个needsCameraPermission方法,这个方法是获取权限的,我一直以为权限是有的,然后,打断点,发现,这里并没有获取到想要的权限。并且查看手机系统设置-》应用里面的相机权限是禁用,在设置里面打开权限之后,相机调用也正常了,然后我就EMO了。

    很多文章告诉我们,权限并不需要手动获取,只需要加到配置清单中就行了,但实际并不是,相机这种权限还是需要主要跟用户获取的,当然用户同意了之后,以后就不需要再次获取了。

    最终解决方案,大家可以看一下这篇文章,因为我的页面是需要相机权限的,所以我一进入这个页面就发起了权限的获取。React-Native之Android(6.0及以上)权限申请详解 - 腾讯云开发者社区-腾讯云

    示例代码如下:

    1. //请求多个权限
    2. const requestMultiplePermission = async () => {
    3. try {
    4. const permissions = [
    5. PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
    6. PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
    7. PermissionsAndroid.PERMISSIONS.CAMERA,
    8. ];
    9. //返回得是对象类型
    10. const granteds = await PermissionsAndroid.requestMultiple(permissions);
    11. var data = '是否同意地址权限: ';
    12. if (granteds['android.permission.ACCESS_FINE_LOCATION'] === 'granted') {
    13. data = data + '是\n';
    14. } else {
    15. data = data + '否\n';
    16. }
    17. data = data + '是否同意相机权限: ';
    18. if (granteds['android.permission.CAMERA'] === 'granted') {
    19. data = data + '是\n';
    20. } else {
    21. data = data + '否\n';
    22. }
    23. data = data + '是否同意存储权限: ';
    24. if (granteds['android.permission.WRITE_EXTERNAL_STORAGE'] === 'granted') {
    25. data = data + '是\n';
    26. } else {
    27. data = data + '否\n';
    28. }
    29. } catch (err) {
    30. // this.show(err.toString());
    31. }
    32. };
    33. useEffect(() => {
    34. requestMultiplePermission();
    35. }, []);

    这段代码会在用户进入页面时发起一次权限的获取,如果已经有权限了,就不会再次发起了。

    说了这么多,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这个了。

    就到这,希望大家可以开发顺利。

  • 相关阅读:
    记录一次root过程
    sql常用语法记录
    React源码分析(二)渲染机制
    0031力扣191题---位1的个数
    express在nodejs中的基本使用
    我发现 Linux 文档写错了
    把控元宇宙产业的发展脉络
    详细教学——1688关键词搜索API操作流程
    神经网络与深度学习——第4章 前馈神经网络
    SSM框架学习——MyBatis
  • 原文地址:https://blog.csdn.net/lizhen_software/article/details/128029313