React Native 原生模塊封裝(IOS篇)
前言
有時候React Native沒有相應(yīng)的模塊, API無法滿足我們的需要時,或者我們需要復(fù)用Object-C, Swift或者Java代碼的時候,而又不是用JavaScript重新實 現(xiàn)一邊,又或者你需要實現(xiàn)某些高性能、多線程的代碼,譬如圖片處理、數(shù)據(jù)庫、或者各種高級擴展等等。
我們把React Native設(shè)計為可以在其基礎(chǔ)上編寫真正的原生代碼,并且可以訪問平臺所有的能力。這是一個相對高級的特性,我們并不認為它應(yīng)當在日常開發(fā)的過程中經(jīng)常出現(xiàn),但具備這樣的能力是很重要的。如果React Native還不支持某個你需要的原生特性,你應(yīng)當可以自己實現(xiàn)該特性的封裝。然后提供出Android或者IOS共用的接口給React Native調(diào)用
用法
第一步:
在React Native中, 一個本地的“原生模塊”其實就是繼承了ReactContextBaseJavaModule的Java類,它可以實現(xiàn)一些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要求派生類實現(xiàn)getName方法。
* 這個函數(shù)用于返回一個字符串名字,這個名字在JavaScript端標記這個模塊。
* 這里我們把這個模塊叫做UserNativeModules,
* 這樣就可以在JavaScript中通過React.NativeModules.UserNativeModules訪問到這個模塊。
* @return
*/
@Override
public String getName() {
return "UserNativeModules";
}
/**
* 要導(dǎo)出一個方法給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這邊要做的最后一件事就是注冊這個模塊。我們需要在應(yīng)用的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<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;
}
}
第三步: 導(dǎo)出包
這個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<ReactPackage> getPackages() {
return Arrays.<ReactPackage>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);
}
}
第四步: React Native中調(diào)用
為了讓你的功能從JavaScript端訪問起來更為方便,通常我們都會把原生模塊封裝成一個JavaScript模塊。這不是必須的,但省下了每次都從NativeModules中獲取對應(yīng)模塊的步驟。這個JS文件也可以用于添加一些其他JavaScript端實現(xiàn)的功能。
/**
* 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 (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit App.js
</Text>
<Text style={styles.instructions}>
{instructions}
</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,
},
});