React Native是啥宙刘?
是一款用JavaScriptScript編寫原生(Android贯底,iOS)應用的框架碉渡。
原理是啥岗屏?
總體來看默蚌,整套React Native框架分為三層冻晤,如下圖所示:
image.png
- Java層:該層主要提供了Android的UI渲染器UIManager(將JavaScript映射成Android Widget)以及一些其他的功能組件(例如:Fresco、Okhttp)等绸吸。
- C++層:該層主要完成了Java與JavaScript的通信以及執(zhí)行JavaScript代碼兩件工作鼻弧。JSCore设江,即JavaScriptCore,JS解析的核心部分攘轩,IOS使用的是內(nèi)置的JavaScriptCore叉存,Androis上使用的是 https://webkit.org 家的jsc.so。
- JavaScript層:該層提供了各種供開發(fā)者使用的組件以及一些工具庫度帮。
通訊機制
關于整個RN的通信機制歼捏,可以用一句話來概括:
JNI作為C++與Java的橋梁,JSC作為C++與JavaScript的橋梁笨篷,而C++最終連接了Java與JavaScript瞳秽。
RN應用通信橋結構圖如下所示:
image
Java 調(diào)用 JS
image
JS 調(diào)用 Java
image
啟動流程
image
JavaScript層組件渲染
image
從上圖我們可以很容易看出,Java層的組件渲染分為以下幾步:
- JS層通過C++層把創(chuàng)建View的請求發(fā)送給Java層的UIManagerModule率翅。
- UIManagerModule通過UIImplentation對操作請求進行包裝练俐。
- 包裝后的操作請求被發(fā)送到View處理隊列UIViewOperationQueue隊列中等待處理。
- 實際處理View時冕臭,根據(jù)class name查詢對應的ViewNManager腺晾,然后調(diào)用原生View的方法對View進行相應的操作。
用RN寫APP是怎樣的一種體驗
Hello World快速體驗
下載安裝Node浴韭,依次執(zhí)行(讀條)下面幾行代碼
npm install -g create-react-native-app
create-react-native-app AwesomeProject
cd AwesomeProject
npm start
順利執(zhí)行完后顯示如下結果丘喻,
image
根據(jù)提示可以通過掃碼在手機上看到代碼運行效果
項目目錄結構
image
React Native使用JSX寫項目的。
JSX is a syntax extension to JavaScript.
Introducing JSX
Basic
Hello World
image
布局
image
列表
image
網(wǎng)絡請求
網(wǎng)絡請求
自定義控件
image
RN Android混合開發(fā)
環(huán)境版本
react-native-cli: 2.0.1
react-native: 0.57.1
項目初始化
choco install -y nodejs.install python2 jdk8
npm install -g react-native-cli
1. Install Android Studio
2. Install the Android SDK
3. Configure the ANDROID_HOME environment variable
Preparing the Android device
react-native init AwesomeProject
cd AwesomeProject
react-native run-android
從Android主入口到JS主入口
JS 工程目錄結構
image
App.js
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View} from 'react-native';
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',
});
type
Props = {};
export default class App extends Component<Props> {
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>
</View>
);
}
}
app.json
{
"name": "AwesomeProject",
"displayName": "AwesomeProject"
}
index.js
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);
JS 工程中的Android 工程結構
MainApplication.java
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()
);
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
}
MainActivity.java
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "AwesomeProject";
}
}
ReactActivity.java
public abstract class ReactActivity extends Activity
implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDelegate.onCreate(savedInstanceState);
}
@Override
protected void onPause() {
super.onPause();
mDelegate.onPause();
}
@Override
protected void onResume() {
super.onResume();
mDelegate.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
mDelegate.onDestroy();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
mDelegate.onActivityResult(requestCode, resultCode, data);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return mDelegate.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
}
ReactActivityDelegate.java
protected void onCreate(Bundle savedInstanceState) {
loadApp(mMainComponentName);
}
protected void loadApp(String appKey) {
mReactRootView = createRootView();
mReactRootView.startReactApplication(
getReactNativeHost().getReactInstanceManager(),
appKey,
getLaunchOptions());
getPlainActivity().setContentView(mReactRootView);
}
protected ReactRootView createRootView() {
return new ReactRootView(getContext());
}
ReactNativeHost.java
public abstract class ReactNativeHost {
protected ReactInstanceManager createReactInstanceManager() {
ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START);
ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()
.setApplication(mApplication)
.setJSMainModulePath(getJSMainModuleName())
.setUseDeveloperSupport(getUseDeveloperSupport())
.setRedBoxHandler(getRedBoxHandler())
.setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
.setJSIModulesPackage(getJSIModulePackage())
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE);
for (ReactPackage reactPackage : getPackages()) {
builder.addPackage(reactPackage);
}
String jsBundleFile = getJSBundleFile();
if (jsBundleFile != null) {
builder.setJSBundleFile(jsBundleFile);
} else {
builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
}
ReactInstanceManager reactInstanceManager = builder.build();
ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END);
return reactInstanceManager;
}
Android的 生命周期事件 是如何分發(fā)到 JS的世界 中的
ReactActivityDelegate.java
protected void onPause() {
getReactNativeHost().getReactInstanceManager().onHostPause(getPlainActivity());
}
protected void onResume() {
getReactNativeHost().getReactInstanceManager().onHostResume(getPlainActivity(), (DefaultHardwareBackBtnHandler) getPlainActivity());
}
protected void onDestroy() {
getReactNativeHost().getReactInstanceManager().onHostDestroy(getPlainActivity());
}
ReactInstanceManager.java
public void onHostPause() {
moveToBeforeResumeLifecycleState();
}
private synchronized void moveToBeforeResumeLifecycleState() {
currentContext.onHostPause();
}
ReactContext.java
public void onHostPause() {
for (LifecycleEventListener listener : mLifecycleEventListeners) {
listener.onHostPause();
}
}
LifecycleEventListener
image
Android 調(diào) RN
1. Java 發(fā)送事件
RCTDeviceEventEmitter.java
...
private void sendEvent(ReactContext reactContext,
String eventName,
@Nullable WritableMap params) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
...
WritableMap params = Arguments.createMap();
...
sendEvent(reactContext, "keyboardWillShow", params);
2. JavaScript 接受事件
import { DeviceEventEmitter } from 'react-native';
...
var ScrollResponderMixin = {
mixins: [Subscribable.Mixin],
componentWillMount: function() {
...
this.addListenerOn(DeviceEventEmitter,
'keyboardWillShow',
this.scrollResponderKeyboardWillShow);
...
},
scrollResponderKeyboardWillShow:function(e: Event) {
this.keyboardWillOpenTo = e;
this.props.onKeyboardWillShow && this.props.onKeyboardWillShow(e);
},
RN 調(diào) Android
1. 聲明JavaModule
- extends ReactContextBaseJavaModule
- getName()
- @ReactMethod
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);
}
@Override
public String getName() {
return "ToastExample";
}
@ReactMethod
public void show(String message, int duration) {
Toast.makeText(getReactApplicationContext(), message, duration).show();
}
}
2. 注冊JavaModule
CustomToastPackage.java
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 ToastModule(reactContext));
return modules;
}
}
MainApplication.java
// MainApplication.java
...
import com.your-app-name.CustomToastPackage; // <-- Add this line with your package name.
...
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new CustomToastPackage()); // <-- Add this line with your package name.
}
3. 在JavaScript中使用JavaModule
Wrap the native module in a JavaScript module
/**
* This exposes the native ToastExample module as a JS module. This has a
* function 'show' which takes the following parameters:
*
* 1. String message: A string with the text to toast
* 2. int duration: The duration of the toast. May be ToastExample.SHORT or
* ToastExample.LONG
*/
import {NativeModules} from 'react-native';
module.exports = NativeModules.ToastExample;
Use the module
import ToastExample from './ToastExample';
ToastExample.show('Awesome', ToastExample.SHORT);