初识React Native(二)—实现Android上的原生模块(一)
发布日期:2021-05-07 03:17:48 浏览次数:27 分类:原创文章

本文共 4656 字,大约阅读时间需要 15 分钟。

背景(实现的原因):

有时候我们的项目需要:
  1. 访问Android平台上的API时, 但是我们的React Native可能还没有相应的模块包装;
  2. 再或者我们需要复用一些Java代码的时候, 而不是用JavaScript重新实现时;
  3. 又或者我们需要实现一些高性能的, 多线程的(因为JavaScript只跑在一个线程上)的代码, 譬如: 操作数据库, 加载图片等等的时候;
这时候我们可以采用封装的方式, 将这些高级特性(平台上的API)封装成一个模块, 这样可以提高我们的工作效率, 减少许多代码量;
接下来我们来实现Android上的Toast模块, 为什么实现这个模块? 因为这个模块较为简单, 而且我们开发项目时也经常用到; 假设我们的希望从JavaScript发起一个Toast消息(React Native中内置了一个名为ToastAndroid的模块);

实现步骤:

1. 首先我们创建一个原生模块, 将这个模块命名为:ToastModule, 一个原生模块是集成了 ReactContextBaseJavaModule 的Java类, 它可以实现一些JavaScript所需的功能; 在这里我们的目标是在JavaScript的代码里, 当我们点击一个Button的时候, 会弹出一个类似Android里的Toast通知:
代码如下:
public class ToastModule extends ReactContextBaseJavaModule {       private static final String DURATION_SHORT_KEY = "SHORT";    private static final String DURATION_LONG_KEY = "LONG";    public ToastModule(ReactApplicationContext reactContext) {        super(reactContext);    }    @Nullable    @Override    public Map<String, Object> getConstants() {        final Map<String, Object> constants = new HashMap<>();        constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);        constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);        return constants;    }    @ReactMethod    public void show(String message, int duration) {        Toast.makeText(getReactApplicationContext(), message, duration).show();    }    @Override    public String getName() {        return "ToastExample";    }}
> 注意: ReactContextBaseJavaModule 要求派生类实现 getName() 方法, 这个方法用来返回一个字符串(这个字符串很重要, 在后面的JavaScript代码里自定义原生模块的时候, 使用的就是该字符串, 在JavaScript端用来标记这个模块 ) ;
@Override    public String getName() {        //如果模块有RCT前缀,那么这个前缀会被自动清除, 所以返回的字符串如果为RCTToastExample,         //那么在JavaScript端依然通过React.NativeModules.ToastExample访问到这个模块;        return "ToastExample";    }
接下来, 有一个可选的方法getContants()方法, 用来返回需要导出给JavaScript使用的常量(这个方法不一定需要实现, 但是定义一些可以被JavaScript同步访问到的预定义的值时还是非常有用的)
@Nullable    @Override    public Map<String, Object> getConstants() {        final Map<String, Object> constants = new HashMap<>();        constants.put("SHORT", Toast.LENGTH_SHORT);        constants.put("LONG", Toast.LENGTH_LONG);        return constants;    }
在我们自定义的原生模块中, 最后一步就是要导出一个方法给JavaScript使用, 这时候Java方法需要使用到@ReactMethod这个注解, 这个方法的返回值必须为null; 因为React Native的跨语言访问是异步进行的, 所以想要给JavaScript返回一个值的唯一办法是使用回调函数或者发送事件;
@ReactMethod    public void show(String message, int duration) {        Toast.makeText(getReactApplicationContext(), message, duration).show();    }
2.注册模块
> 我们想要使用这个模块, 那么我们首先需要做的事情就是注册这个模块, 这时候我们需要在应用的Package类的 createNativeModules 方法中添加这个模块, 如果我们没注册这个模块, 那么我们无法在JavaScript中访问到这个模块:
public class AnExampleReactPackage implements ReactPackage {       //这个方法为注册我们自定义的模块;    @Override    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {        List<NativeModule> modules = new ArrayList<>();        modules.add(new ToastModule(reactContext));        return modules;    }    //这个方法为注册我们的自定义的组件(以后的原生组件会讲到);    @Override    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {        return Collections.emptyList();    }}
然后这个package需要在MainApplication.java文件中的getPackages()方法中提供, 这个时候我的demo中, 我自己创建了一个新的MyApplication, 继承了Application, 并且实现了ReactApplication, 只不过我们创建完这个Application后 ,我们需要在Android Manifest中的application节点中设置name: MyApplication, 不了解的可以先去看我第一篇文章 :
public class MyApplication extends Application implements ReactApplication {       private final ReactNativeHost reactNativeHost = new ReactNativeHost(this) {        @Override        public boolean getUseDeveloperSupport() {            return BuildConfig.DEBUG;        }        @Override        protected List<ReactPackage> getPackages() {            return Arrays.<ReactPackage>asList(new MainReactPackage(),                     new AnExampleReactPackage());        }    };    ...}
3.运行我们的原生模块:
> 我们通常可以把原生模块封装成一个JavaScript模块, 这样我们从JavaScript端访问起来更加方便, 但是这不是必须的, 但是我依然封装成了JavaScript模块, 我的封装原生模块的ToastModule.js文件:
import { NativeModules } from 'react-native';export default NativeModules.ToastExample;
最后就是在我们React Native界面上使用这个模块了, 在这我生成一个Button, 当我们点击这个Button的时候, 就会弹出这个Toast通知:
...import ToastExample from './ToastModule';......export default class HelloReactNative extends React.Component {    _onPressButton() {        console.log("you tapped the button !");        ToastExample.show('clicked me', ToastExample.SHORT);    }    render() {        return (                <View style={styles.container}>                    ...                    <TouchableNativeFeedback onPress={this._onPressButton}>                        <Text style={styles.button}>Button</Text>                    </TouchableNativeFeedback>                    ...                </View>        )    }}
效果图:

感谢:
上一篇:利用JavaCV实现将视频以帧方式抽取
下一篇:初识React Native(一)—集成到原生Android项目

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2025年04月13日 22时40分58秒