在RN中实现Android原生模块和UI封装
一.封装原生Module
有时候现有的RN没有相关模块来访问一些android底层功能api,我们可以尝试封装一个android原生的模块,然后js端去调用模块的api实现。比如集成第三方的sdk,js层需要调用sdk api,我们就可以封装一个android模块集成sdk再给到js去调用。
1. 创建模块
新建一个java类,该类要继承 ReactContextBaseJavaModule
新建 RnModule.java文件
//RnModule.java
package com.your-app-name;
import android.widget.Toast;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.Map;
import java.util.HashMap;
public class RnModule extends ReactContextBaseJavaModule {
private static ReactApplicationContext reactContext;
public RnModule(ReactApplicationContext context) {
super(context);
reactContext = context;
}
}
2. 实现getName方法
实现ReactContextBaseJavaModule类中的 getName方法,该方法的返回值作为js中引入原生模块的标识
package com.your-app-name;
import android.widget.Toast;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.Map;
import java.util.HashMap;
public class RnModule extends ReactContextBaseJavaModule {
private static ReactApplicationContext reactContext;
public RnModule(ReactApplicationContext context) {
super(context);
reactContext = context;
}
**
@Override
public String getName() {
return "RnModule";
}
**
}
3. 注册模块
实现了模块后我们要注册才能生效
步骤:1.先将自定义的原生模块添加packge中去 2.然后将这个package提供出去
1. 新建一个java类,该类要实现ReactPackage接口,将上面定义的模块在Package类的createNativeModules方法add进去
新建 RnPackage.java 文件
// RnPackage.java
package com.your-app-name;
import com.facebook.react.ReactPackage;
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;
public class CustomToastPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new RnModule(reactContext));//将实现的module增加进去
return modules;
}
}
2.在MainApplication.java用getPackages方法将上面的package提供出去
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new RnPackage()); // <-- 添加这一行,类名替换成你的Package类的名字 name.
return packages;
}
4. 在js层使用
import { NativeModules } from 'react-native';
export default NativeModules.RnModule;//RnMuduel为原生模块中getName()中返回的字符串
----------------到此已经完成原生模块的创建和js层引入使用,接下来在原生模块中添加方法-----------------
5.原生模块导出给js层调用方法
- 导出给js层的方法,Java 方法需要使用注解
@ReactMethod
原生模块:
@ReactMethod
public void show(String message, int duration) {
}
js层:
RnModule.show('你好',100)
- 给js层返回参数,callback或者Promise
原生模块:
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Promise;
public class RnModule extends ReactContextBaseJavaModule {
...
//callback方式
@ReactMethod
public void show(String message, int duration,Callback successCallback) {
successCallback.invoke('成功')
}
//Promise 方式
@ReactMethod
public void show(String message, int duration,Promise) {
Promise.resolve('成功')//Promise.reject(err)
}
...
js层:
//callback方式
RnModule.show('你好',100,(msg)=>{console.log(msg)//成功})
//Promise 方式
RnModule.show('你好',100).then((msg)=>{console.log(msg)//成功}).catch((err)=>{})
6.原生模块发送事件给js层
在js层不调用原生模块方法下,如何往js层发送通知和数据
比如:原生模块有一些事件监听逻辑,只有在触发的时候才会调用,而js层需要知道该事件触发和相应的回调参数
通过使用ReactContext上的getJsModule方法获得RCTDeviceEventEmitter引用实现
原生模块:
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Promise;
public class RnModule extends ReactContextBaseJavaModule {
...
private void sendEvent(String eventName,
@Nullable WritableMap params) {
this.getReactApplicationContext()
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
//在对应的逻辑中触发事件
sendEvent("event",params)// "event":为事件名称
"params":触发事件的回调参数
...
js层:js层去监听原生模块的触发的事件
import { NativeEventEmitter, NativeModules } from 'react-native';
const eventEmitter = new NativeEventEmitter(NativeModules.RnModule);
this.eventListener=eventEmitter.addListener('event', (params) => {
console.log(params)
});
//注意要销毁:this.eventListener.remove();
二.封装原生View
构建一个原生UI组件,给到js层使用
1.创建自定义的原生视图
比如实现一个ImageView图片展示组件
1.创建ReactImageView.java
2.在ReactImageView类中自定义实现UI和逻辑
例如:
public class MyFragment extends FrameLayout {
public ReactImageView(ReactContext context){
super(context)
//相关逻辑
}
//接收js组件传过来的props参数,提供方法给ViewManager调用
public void setSrc(String src){
this.src=src
}
}
2.创建ViewManager子类
1.创建 ReactImageManager.java文件,
2.定义ReactImageManager类,继承SimpleViewManager<ReactImageView>,其中ReactImageView就是我们上面自定义的原生视图
3.实现getName方法
4.在createViewInstance中实例化创建这个视图
5.通过@ReactProp注解来接收,js调用组件时传过来的属性值(类似props方式)。然后在自定义的原生视图中有对应的方法接收参数
例如:
public class ReactImageManager extends SimpleViewManager<ReactImageView> {
public static final String REACT_CLASS = "RCTImageView";
ReactApplicationContext mCallerContext;
public ReactImageManager(ReactApplicationContext reactContext) {
mCallerContext = reactContext;
}
@Override
public String getName() {
return REACT_CLASS;
}
@Override
public ReactImageView createViewInstance(ThemedReactContext context) {
return new ReactImageView(context);//实例化创建这个视图
}
@ReactProp(name = "src")
public void setSrc(ReactImageView view, String src) {
view.setSrc(src);//在自定义的原生视图中(ReactImageView.java)有对应的setSrc方法来获取参数
}
}
3.注册ViewManager
和模块注册一样的,唯一不同的是将UI模块在Package类的createViewManagers方法add进去
新建 RnPackage.java 文件
// RnPackage.java
package com.your-app-name;
import com.facebook.react.ReactPackage;
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;
public class CustomToastPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {//注册UI
List<ViewManager> managers=new ArrayList<>()
managers.add(new ReactImageManager())
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {//注册模块
List<NativeModule> modules = new ArrayList<>();
modules.add(new RnModule(reactContext));//将实现的module增加进去
return modules;
}
}
4.在js层使用
MyViewManager.jsx
import { requireNativeComponent } from 'react-native';
export default requireNativeComponent('RCTImageView')
MyView.js
import RCTImageView from './MyViewManager'
const MyView=()=>{
return (
<RCTImageView
style={{}}
src="htpps://www.baidu.com"
/>
)
}
\