文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

react-native调用原生安卓android(兼容7.0以上版本)系统相机拍照和选择相册照片,并将返回结果用作头像

2022-06-06 13:52

关注

话不多说,先上效果图

在这里插入图片描述

大致的思路

要从RN中调用原生相机拍照和选择照片思路是这样的,先在原生中创建一个ReactContextBaseJavaModule模块,并在该模块中显示调用原生相机和选择照片的方法。然后,将该模块添加到ReactPackage列表中。最后,在js中导入该模块使用。关于原生模块的创建以及在js中如何调用请参考下面这篇文章:
https://blog.csdn.net/weixin_38824257/article/details/103905668

下面是调用原生拍照和选择相册的具体实现 1.编写提供给RN调用的拍照和选择照片的方法。

首先创建一个继承自ReactContextBaseJavaModule的类。在该类中编写暴露给RN调用的拍照方法,注意这里有一个传入的参数Promise(这个参数不需要从RN中传入),是用于返回数据给RN的。注解@ReactMethod表示该方法是该模块下可被RN调用的方法。


    @ReactMethod
    public void openCamera(Promise promise) {
        //安卓6.0以上需要动态申请权限
        if (hasPermission()) {
            mPromise = promise;
            takePhoto();
        }
    }

检查是否已经获得拍照和读写内存卡的权限,android6.0以上需要用户同意获取。

 private boolean hasPermission() {
        currentActivity = getCurrentActivity();
        //安卓6.0以上动态权限申请
        if (Build.VERSION.SDK_INT >= 23) {
            int checkCallPhonePermission = ContextCompat.checkSelfPermission(reactContext, Manifest.permission.CAMERA);
            if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(currentActivity, PERMISSIONS_STORAGE, OPEN_CAMERA);
                return false;
            } else {
                return true;
            }
        } else {
            return true;
        }
    }

以下是拍照和读写内存卡的权限

 private static String[] PERMISSIONS_STORAGE = {
            "android.permission.CAMERA",
            "android.permission.READ_EXTERNAL_STORAGE",
            "android.permission.WRITE_EXTERNAL_STORAGE"};//权限

下面是调起原生相机的taokePhoto方法,里面为了兼容android7.0以上的系统,需要使用FileProvider共享文件的方式来获取文件uri。使用FileProvider需要再做一些额外的配置。

 private void takePhoto() {
        mIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        File faceDir = getImageDir();
        if (faceDir != null) {
            mFileName = System.currentTimeMillis() + ".jpg";
            File file = new File(faceDir, mFileName);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                //设置7.0以上共享文件,分享路径定义在xml/file_paths.xml
                mUri = FileProvider.getUriForFile(reactContext, "com.github_rn.fileprovider", file);
            } else {
                // 7.0以下,共享文件
                mUri = Uri.fromFile(file);
            }
            mIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            mIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            mIntent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
            mIntent.putExtra(MediaStore.EXTRA_OUTPUT, mUri);
            currentActivity.startActivityForResult(mIntent, CAMERA_CODE);
        }
    }

配置FileProvider,在AndroidManifest.xml文件中的application节点下加入如下配置,注意这里的android:authorities字段需要跟拍照时使用的FileProvider.getUriForFile方法传入的第二个参数一致:

  

然后在res目录下创建xml文件夹,在文件夹下创建file_paths.xml文件。文件的内容如下,path表示需要共享的目录,name名字随便取就可以。


    
    <!--
        
        

还需要在AndroidManifest.xml添加如下权限:


下面是选择相册照片的方法:

 
    @ReactMethod
    public void chooseAlbum(Promise promise) {
        if (hasPermission()) {//申请权限
            mPromise = promise;
            Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            currentActivity.startActivityForResult(intent, ALBUM_CODE);
        }
    }
监听拍照和选择照片返回的结果

在该模块创建时,添加addActivityEventListener方法,方法如下。在initActivityEventListener方法的onActivityResult方法中得到拍照和选择照片返回的结果,并且使用promise将结果返回给RN。

 public MyIntentModule(@NonNull ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
        initActivityEventListener();
    }
    @NonNull
    @Override
    public String getName() {
        return "AlbumModule";
    }
    private void initActivityEventListener() {
        reactContext.addActivityEventListener(new BaseActivityEventListener() {
            @Override
            public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
                if (requestCode == CAMERA_CODE) {
                    if (resultCode == Activity.RESULT_OK) {
                        mPromise.resolve(IMAGE_ROOT_PATH + mFileName);
                    } else if (resultCode == Activity.RESULT_CANCELED) {
                        mPromise.resolve(null);
                    }
                } else if (requestCode == ALBUM_CODE) {
                    if (resultCode == Activity.RESULT_OK) {
                        try {
                            Uri selectedImage = data.getData(); //获取系统返回的照片的Uri
                            String[] filePathColumn = {MediaStore.Images.Media.DATA};
                            Cursor cursor = reactContext.getContentResolver().query(selectedImage,
                                    filePathColumn, null, null, null);//从系统表中查询指定Uri对应的照片
                            cursor.moveToFirst();
                            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                            String path = cursor.getString(columnIndex);  //获取照片路径
                            cursor.close();
                            Log.i("callCamera", "path:" + path);
                            mPromise.resolve(path);
                        } catch (Exception e) {
                            // TODO Auto-generatedcatch block
                            e.printStackTrace();
                            mPromise.resolve(null);
                        }
                    } else if (resultCode == Activity.RESULT_CANCELED) {
                        mPromise.resolve(null);
                    }
                }
            }
        });
    }
在RN中调用并接收返回结果

先导入NativeModules

import {View, Text, StyleSheet, Image, TouchableOpacity, ScrollView, NativeModules, AsyncStorage} from "react-native";

在RN的点击事件中调用拍照或者选择照片方法

//拍照
    openCamera() {
        NativeModules.AlbumModule.openCamera().then((res) => {
            console.log("openCamera--res:" + res);
            if (res) {
                this.setState({
                    imagePath: res,
                });
                this.setHeadImage(res);
            }
        });
    }
    //选择照片
    chooseAlbum(){
        NativeModules.AlbumModule.chooseAlbum().then((res)=>{
            console.log("chooseAlbum--res:" + res);
            if (res) {
                this.setState({
                    imagePath: res,
                });
                this.setHeadImage(res);
            }
        })
    }
    //将照片路径保存到Storage中
    setHeadImage(imagePath) {
        AsyncStorage.setItem(HEAD_IMAGE, imagePath);
    }

最后,在RN中显示该照片。RN中Image组件可以显示手机本地照片,source的路径为:“file:///”+“照片的路径”

}
具体源码地址

运行项目前,需要先用android studio下载好依赖
https://github.com/githubchl/Github_RN


作者:副排长


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯