React Native 原生模块封装(Android)
近来实验室维护老项目,迁移完src目录下的文件之后才发现android原生的文件也发生了变动,开例时听老师大致讲了讲,明白了这些模块的作用,遂准备进行迁移。然而笔者没有任何android经验,遂开始学习这块的知识,并记录下来!
一、为什么要进行原生模块封装?
我们看react native官网关于这一块的表述: 有时候 App 需要访问平台 API,但 React Native 可能还没有相应的模块包装;或者你需要复用一些 Java 代码,而不是用 Javascript 重新实现一遍;又或者你需要实现某些高性能的、多线程的代码,譬如图片处理、数据库、或者各种高级扩展等等。 我们把 React Native 设计为可以在其基础上编写真正的原生代码,并且可以访问平台所有的能力。这是一个相对高级的特性,我们并不认为它应当在日常开发的过程中经常出现,但具备这样的能力是很重要的。如果 React Native 还不支持某个你需要的原生特性,你应当可以自己实现该特性的封装。
官网上对这块已经说很清楚了,另外相信看到这的朋友肯定是抱着目的来的!废话不多少,进入正题!
二、封装步骤
1.第一步 创建原生模块
一个原生模块是一个继承了ReactContextBaseJavaModule的 Java 类,它可以实现一些 JavaScript 所需的功能。我们这里的目标是可以在 JavaScript 里写ToastExample.show(‘Awesome’, ToastExample.SHORT);,来调起一个短暂的 Toast 通知。 我们首先来创建一个原生模块名为UserNativeModules.java,放置在android/app/src/main/java/com/your-app-name/目录下。
package com.wifidemo;
import android.widget.Toast;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class UserNativeModules extends ReactContextBaseJavaModule {
public UserNativeModules(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "UserNativeModules";
}
@ReactMethod
public void userLogin(String name, String password) {
Toast.makeText(getReactApplicationContext(), name+" : "+password,Toast.LENGTH_LONG).show();
}
}
2.第二步 注册模块
在 Java 这边要做的最后一件事就是注册这个模块。我们需要在应用的 Package 类的createNativeModules方法中添加这个模块。如果模块没有被注册,它也无法在 JavaScript 中被访问到。
创建一个新的 Java 类并命名为UserReactPackage.java,放置到android/app/src/main/java/com/your-app-name/目录下,其具体代码如下:
package com.wifidemo;
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 UserReactPackage 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 UserNativeModules(reactContext));
return modules;
}
}
3.第三步: 导出包
这个package需要在MainApplication.java文件的getPackages方法中提供。
package com.wifidemo;
import android.app.Application;
import android.content.Context;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(new UserReactPackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, false);
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
Class<?> aClass = Class.forName("com.wifidemo.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
第四步 React Native中调用
为了让你的功能从JavaScript端访问起来更为方便,通常我们都会把原生模块封装成一个JavaScript模块。这不是必须的,但省下了每次都从NativeModules中获取对应模块的步骤。这个JS文件也可以用于添加一些其他JavaScript端实现的功能。
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, Button, Alert} from 'react-native';
import {NativeModules} from 'react-native';
var UserNative = NativeModules.UserNativeModules;
const onButtonPress = () => {
console.log('+++++++++');
UserNative.userLogin('lrt', 'lrt');
};
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>To get started, edit App.js</Text>
<Button
onPress={onButtonPress}
title="Learn More"
color="#841584"
accessibilityLabel="Learn more about this purple button"
/>
</View>
);
}
}
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,
},
});
运行结果
点击前
|
点击后
|
最后
可以看到,点击learn more后,会出现一个toast,就是我们自己写的方法!至此已经完成,后边可以根据自己项目的需要,添加更多的module和package 这个项目的完整代码我已经上传到了github(项目地址),可以直接拉下来npm install之后直接运行!
|