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为空");
}
}}
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- Docker应用:容器间通信与Mariadb数据库主从复制
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量
- android第三方框架(五)ButterKnife
- 第326天
- Shell-Bash变量与运算符
- Android中的AES加密-下
- 逻辑回归的理解与python示例
- 带有Hilt的Android上的依赖注入
- Guava|Guava RateLimiter与限流算法