有时候React Native没有相应的模块, API无法满足我们的需要时,或者我们>需要复用Object-C, Swift或者Java代码的时候,而又不是用JavaScript重新实 现一边,又或者你需要实现某些高性能、多线程的代码,譬如图片处理、数据库、或者各种高级扩展等等。
我们把React Native设计为可以在其基础上编写真正的原生代码,并且可以访问平台所有的能力。这是一个相对高级的特性,我们并不认为它应当在日常开发的过程中经常出现,但具备这样的能力是很重要的。如果React Native还不支持某个你需要的原生特性,你应当可以自己实现该特性的封装。然后提供出Android或者IOS共用的接口给React Native调用
在React Native中, 一个本地的“原生模块”其实就是继承了ReactContextBaseJavaModule的Java类,它可以实现一些JavaScript所需的功能。
package com.my;
import android.widget.Toast;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
/**
* Created by scottwang on 2018/1/5.
*/
public class UserNativeModules extends ReactContextBaseJavaModule {
public UserNativeModules(ReactApplicationContext reactContext) {
super(reactContext);
}
/**
* ReactContextBaseJavaModule要求派生类实现getName方法。
* 这个函数用于返回一个字符串名字,这个名字在JavaScript端标记这个模块。
* 这里我们把这个模块叫做UserNativeModules,
* 这样就可以在JavaScript中通过React.NativeModules.UserNativeModules访问到这个模块。
* @return
*/
@Override
public String getName() {
return "UserNativeModules";
}
/**
* 要导出一个方法给JavaScript使用,Java方法需要使用注解@ReactMethod。
* 方法的返回类型必须为void。React Native的跨语言访问是异步进行的。
* @param name
* @param password
*/
@ReactMethod
public void userLogin(String name, String password) {
Toast.makeText(getReactApplicationContext(), name+" : "+password,Toast.LENGTH_LONG).show();
}
}
在Java这边要做的最后一件事就是注册这个模块。我们需要在应用的Package类的createNativeModules方法中添加这个模块。如果模块没有被注册,它也无法在JavaScript中被访问到。
package com.my;
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 createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List createNativeModules(
ReactApplicationContext reactContext) {
List modules = new ArrayList<>();
modules.add(new UserNativeModules(reactContext));
return modules;
}
}
这个package需要在Application.java文件的getPackages方法中提供。
package com.my;
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 final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List getPackages() {
return Arrays.asList(
new MainReactPackage(),
new UserReactPackage()
);
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
}
为了让你的功能从JavaScript端访问起来更为方便,通常我们都会把原生模块封装成一个JavaScript模块。这不是必须的,但省下了每次都从NativeModules中获取对应模块的步骤。这个JS文件也可以用于添加一些其他JavaScript端实现的功能。
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
Button,
Alert
} from 'react-native';
import { NativeModules } from 'react-native';
var UserNativeModules = NativeModules.UserNativeModules;
const instructions = Platform.select({
ios: 'Press Cmd+R to reload,\n' +
'Cmd+D or shake for dev menu',
android: 'Double tap R on your keyboard to reload,\n' +
'Shake or press menu button for dev menu',
});
const onButtonPress = () => {
Alert.alert('Button has been pressed!');
UserNativeModules.userLogin("User Id","password");
};
export default class App extends Component {
render() {
return (
Welcome to React Native!
To get started, edit App.js
{instructions}
);
}
}
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,
},
});