RN与Android原生交互

场景:在RN界面中需要调用原生的拍照和选择相册功能,将拍照或者选择的照片的路径回传给RN
【RN与Android原生交互】

步骤如下: 1、RN的界面跳转到原生Activity,并接收从原生回传的数据

import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Text, View, TouchableOpacity, NativeModules, DeviceEventEmitter } from 'react-native'; export default class Main extends Component { render() { return ( { NativeModules.TakePhotoModule.selectPhoto(); }}> 跳转到原生拍照或相册 ); } componentDidMount(){ this.listener = DeviceEventEmitter.addListener('msg',(path)=>{ console.log('====React Native界面,收到数据: + path==',path); }) } componentWillUnMount(){ this.listener && this.listener.remove(); } }const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, welcome: { fontSize: 20, textAlign: 'center', margin: 10, }, instructions: { textAlign: 'center', color: '#333333', marginBottom: 5, }, });

2、创建一个原生Module,在里面添加RN需要调用的跳转原生Activity的方法和原生调用的需要回传数据到RN界面的方法
package com.test; import android.app.Activity; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Environment; import android.provider.MediaStore; import android.util.Log; import com.facebook.react.bridge.ActivityEventListener; import com.facebook.react.bridge.BaseActivityEventListener; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.modules.core.DeviceEventManagerModule; import java.io.File; import java.io.IOException; import static android.app.Activity.RESULT_OK; /** * Created by qq on 2018/05/27. */public class TakePhotoModule extends ReactContextBaseJavaModule { private ReactApplicationContext reactContext; public TakePhotoModule(ReactApplicationContext reactContext) { super(reactContext); this.reactContext = reactContext; }@Override public String getName() { return "TakePhotoModule"; } /** 从RN界面里面调用该方法,跳转到原生Activity **/ @ReactMethod public void selectPhoto(){ Intent intent = new Intent(getCurrentActivity(),PhotoSelectActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); reactContext.startActivity(intent); } /** 从原生Activity里面调用该方法,回传数据给RN界面 **/ public void sendDataToJS(String path){ Log.i("msg", "sendDataToJS: ===path=="+path); this.reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit("msg",path); }}

3、创建一个原生ReactPackage,添加Module模块
package com.test; import android.util.Log; import com.facebook.react.ReactPackage; import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.ViewManager; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Created by qq on 2018/05/27. */public class TakePhotoPackage implements ReactPackage { public TakePhotoModule mModule; @Override public List createNativeModules(ReactApplicationContext reactContext) { List list = new ArrayList<>(); mModule = new TakePhotoModule(reactContext); list.add(mModule); return list; }@Override public List> createJSModules() { return Collections.emptyList(); }@Override public List createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); } }

4、在MainApplication里添加该ReactPackage
package com.test; import android.app.Application; import com.facebook.react.ReactApplication; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; import com.facebook.react.shell.MainReactPackage; import com.facebook.soloader.SoLoader; import java.util.Arrays; import java.util.List; public class MainApplication extends Application implements ReactApplication {private static final TakePhotoPackage mCommPackage = new TakePhotoPackage(); public static TakePhotoPackage getReactPackage() { return mCommPackage; } private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { @Override public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; }@Override protected List getPackages() { return Arrays.asList( new MainReactPackage(), mCommPackage ); } }; @Override public ReactNativeHost getReactNativeHost() { return mReactNativeHost; }@Override public void onCreate() { super.onCreate(); SoLoader.init(this, /* native exopackage */ false); } }

5、原生Activity回传数据给RN
package com.test; import android.annotation.TargetApi; import android.content.ContentUris; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.provider.DocumentsContract; import android.provider.MediaStore; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.ImageView; import android.widget.TextView; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; public class PhotoSelectActivity extends AppCompatActivity implements OnClickListener{ private TextView tvTakePhoto; private TextView tvSelectAblumn; private TextView tvFinish; private ImageView iv; public static final int TAKE_PHOTO = 1; public static final int CROP_PHOTO = 2; public static final int CHOOSE_PHOTO = 3; private Uri imageUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_photo_select); tvTakePhoto = (TextView) findViewById(R.id.tv_take_photo); tvSelectAblumn = (TextView) findViewById(R.id.tv_select_ablumn); tvFinish = (TextView) findViewById(R.id.tv_finish); iv = (ImageView) findViewById(R.id.iv); tvTakePhoto.setOnClickListener(this); tvSelectAblumn.setOnClickListener(this); tvFinish.setOnClickListener(this); }@Override public void onClick(View v) { switch (v.getId()){ case R.id.tv_take_photo: { File outputImage = new File(Environment.getExternalStorageDirectory(), "tempImg" + ".jpg"); try { if (outputImage.exists()) { outputImage.delete(); } outputImage.createNewFile(); } catch (IOException e) { e.printStackTrace(); } imageUri = Uri.fromFile(outputImage); Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intent, TAKE_PHOTO); }break; case R.id.tv_select_ablumn: { Intent intent = new Intent("android.intent.action.GET_CONTENT"); intent.setType("image/*"); startActivityForResult(intent,CHOOSE_PHOTO); //打开相册 }break; case R.id.tv_finish: { Log.i("qq", "onClick: imageUri=="+imageUri); MainApplication.getReactPackage().mModule.sendDataToJS(imageUri.getPath()); //Intent intent = new Intent(); ////把返回数据存入Intent //intent.putExtra("img", imageUri); ////设置返回数据 //this.setResult(1002, intent); Intent intent = new Intent(this,MainActivity.class); startActivity(intent); this.finish(); } break; } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case TAKE_PHOTO: if (resultCode == RESULT_OK) { Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(imageUri, "image/*"); intent.putExtra("scale", true); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intent, CROP_PHOTO); // 启动裁剪程序 } break; case CROP_PHOTO: if (resultCode == RESULT_OK) { try { Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver() .openInputStream(imageUri)); iv.setImageBitmap(bitmap); } catch (FileNotFoundException e) { e.printStackTrace(); } } break; case CHOOSE_PHOTO: if (resultCode == RESULT_OK){ //判断手机系统版本号 if (Build.VERSION.SDK_INT >= 19){ //4.4及以上系统使用这个方法处理图片 handleImageOnKitKat(data); }else { //4.4以下系统使用这个放出处理图片 handleImageBeforeKitKat(data); } }break; } } @TargetApi(19) private void handleImageOnKitKat(Intent data){ String imagePath = null; Uri uri = data.getData(); imageUri = uri; if (DocumentsContract.isDocumentUri(this,uri)){ //如果是document类型的Uri,则通过document id处理 String docId = DocumentsContract.getDocumentId(uri); if ("com.android.providers.media.documents".equals(uri.getAuthority())){ String id = docId.split(":")[1]; //解析出数字格式的id String selection = MediaStore.Images.Media._ID + "=" + id; imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,selection); }else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())){ Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),Long.valueOf(docId)); imagePath = getImagePath(contentUri,null); } }else if ("content".equalsIgnoreCase(uri.getScheme())){ //如果是content类型的Uri,则使用普通方式处理 imagePath = getImagePath(uri,null); }else if ("file".equalsIgnoreCase(uri.getScheme())){ //如果是file类型的Uri,直接获取图片路径即可 imagePath = uri.getPath(); } diaplayImage(imagePath); //根据图片路径显示图片 }private void handleImageBeforeKitKat(Intent data){ Uri uri = data.getData(); String imagePath = getImagePath(uri,null); diaplayImage(imagePath); }private String getImagePath(Uri uri,String selection){ String path = null; //通过Uri和selection来获取真实的图片路径 Cursor cursor = getContentResolver().query(uri,null,selection,null,null); if (cursor != null){ if (cursor.moveToFirst()){ path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); } cursor.close(); } return path; }private void diaplayImage(String imagePath){ if (imagePath != null){ Bitmap bitmap = BitmapFactory.decodeFile(imagePath); iv.setImageBitmap(bitmap); }else { Log.i("qq", "diaplayImage: imagePath为空"); } }}

    推荐阅读