React Native Android 混合开发实战教程 (1),flutter 瀑布流
{"name": "RNHybrid","version": "0.0.1","private": true,"scripts": {"start": "node node_modules/react-native/local-cli/cli.js start"}}
第二步:在为 package.json 添加 react-native
在该目录下执行:
npm install --save react-native
执行完上述命令之后,你会看到如下警告:
其中,有一条警告npm WARN react-native@0.55.4 requires a peer of react@16.3.1 but none is installed
告诉我们需要安装react@16.3.1
:
npm install --save react@16.3.1
至此,一个不含 Android 和 iOS 模块的 React Native 项目便创建好了。**[此过程所遇到的更多问题可查阅:React Native 与 Android 混合开发讲解的视频教程](
)**
提示:npm 会在你的目录下创建一个
node_modules
,node_modules
体积很大且是动态生成了,建议将其添加到.gitignore
文件中;
通过 react-native init 来初始化一个 React Native 项目
除了上述方式之外,我们也可以通过react-native init
命令来初始化一个 React Native 项目。
reac
t-native init RNHybrid
上述命令会初始化一个完成的名为 RNHybrid 的 React Native 项目,然后我们将里面的android
和ios
目录删除,替换成已存在 Android 和 iOS 项目。
2. 添加 React Native 所需要的依赖
在上文中我们已经创建了个一个 React Native 项目,接下来我们来看一下如何将这个 React Native 项目和我们已经存在的 Native 项目进行融合。
在进行融合之前我们需要将已经存在的 Native 项目放到我们创建的 RNHybrid 下,比如:我有一个名为RNHybridAndroid
的 Android 项目,将其放到 RNHybrid 目录下:
RNHybrid├── RNHybridAndroid├── package.json├── node_modules└── .gitignore
第一步:配置 maven
接下来我们需要为已经存在的 RNHybridAndroid 项目添加 React Native 依赖,在RNHybrid/RNHybridAndroid/app/build.gradle
文件中添加如下代码:
dependencies {compile 'com.android.support:appcompat-v7:23.0.1'...compile "com.facebook.react:react-native:+" // From node_modules}
然后,我们为 RNHybridAndroid 项目配置使用的本地 React Native maven 目录,在RNHybrid/RNHybridAndroid/build.gradle
文件中添加如下代码:
allprojects {repositories {mavenLocal()maven {// All of React Native (JS, Obj-C sources, Android binaries) is installed from npmurl "$rootDir/../node_modules/react-native/android"}...}...}
提示:为确保你配置的目录正确,可以通过在 Android Studio 中运行 Gradle sync 看是否有 “Failed to resolve: com.facebook.react:react-native:0.x.x" 的错误出现,没有错误则说明配置正确,否则说明配置路由有问题。 **[此过程所遇到的更多问题可查阅:React Native 与 Android 混合开发讲解的视频教程](
)**
第二步:配置权限
接下来我们为 APP 运行配置所需要的权限:检查你项目中的AndroidManifest.xml
文件中看是否有如下权限:
<uses-permission android:name="android.permission.INTERNET" />
如果没有,则需要将上述权限添加到AndroidManifest.xml
中。
另外,如果你需要用到 RN 的
Dev Settings
功能:
则需要在AndroidManifest.xml
文件中添加如下代码:
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
提示:上述图片就是 RN 开发调试弹框中的
Dev Settings
功能,打开该功能会弹出上图的一个界面,这个界面就是 DevSettingsActivity。
第三步:指定要 ndk 需要兼容的架构(重要)
Android 不能同时加载多种架构的 so 库,现在很多 Android 第三方 sdks 对 abi 的支持比较全,可能会包含 armeabi, armeabi-v7a,x86, arm64-v8a,x86_64 五种 abi,如果不加限制直接引用会自动编译出支持 5 种 abi 的 APK,而 Android 设备会从这些 abi 进行中优先选择某一个,比如:arm64-v8a,但如果其他 sdk 不支持这个架构的 abi 的话就会出现 crash。如下图:
怎么解决呢:
在app/gradle
文件中添加如下代码:
defaultConfig {....ndk {abiFilters "armeabi-v7a", "x86"}}
上述代码的意思是,限制打包的 so 库只包含armeabi-v7a
与x86
。**[此过程所遇到的更多问题可查阅:React Native 与 Android 混合开发讲解的视频教程](
)**
可参考:[libgnustl_shared.so" is 32-bit instead of 64-bit](
)
3.创建 index.js 并添加你的 React Native 代码
通过上述两步,我们已经为 RNHybridAndroid 项目添加了 React Native 依赖,接下来我们来开发一些 JS 代码。
在 RNHybrid 目录下创建一个index.js
文件并添加如下代码:
import { AppRegistry } from 'react-native';import App from './App';
AppRegistry.registerComponent('App1', () => App);
上述代码,AppRegistry.registerComponent('App1', () => App);
目的是向 React Native 注册一个名为App1
的组件,然后我会在第四步给大家介绍如何在 Android 中加载并显示出这个组件。
另外,在上述代码中我们引用了一个App.js
文件:
import React, { Component } from 'react';import {Platform,StyleSheet,Text,View} from 'react-native';
type Props = {};export default class App extends Component<Props> {render() {return (<View style={styles.container}><Text style={styles.welcome}>this is App</Text></View>);}}
const styles = StyleSheet.create({container: {flex: 1,justifyContent: 'center',alignItems: 'center',backgroundColor: '#F5FCFF',},welcome: {fontSize: 20,textAlign: 'center',margin: 10,}});
这个App.js
文件代表了我们 React Native 的一个页面,在这个页面中显示了this is App
的文本内容。
以上就是为本次演示所添加的 React Native 代码,你也可以根据需要添加更多的 React Native 代码以及组件出来。
4. 为 React Native 创建一个 Activity 来作为容器
经过上述 3、4 步,我们已经为 RNHybridAndroid 项目添加了 React Native 依赖,并且创建一些 React Native 代码和注册了一个名为App1
的组件,接下来我们来学习下如何在 RNHybridAndroid 项目中使用这个App1
组件。
创建 RNPageActivity
首先我们需要创建一个 Activity 来作为 React Native 的容器,
public class RNPageActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {private ReactRootView mReactRootView;private ReactInstanceManager mReactInstanceManager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
mReactRootView = new ReactRootView(this);mReactInstanceManager = ReactInstanceManager.builder().setApplication(getApplication()).setBundleAssetName("index.android.bundle").setJSMainModulePath("index").addPackage(new MainReactPackage()).setUseDeveloperSupport(BuildConfig.DEBUG).setInitialLifecycleState(LifecycleState.RESUMED).build();// 这个"App1"名字一定要和我们在 index.js 中注册的名字保持一致 AppRegistry.registerComponent()mReactRootView.startReactApplication(mReactInstanceManager, "App1", null);
setContentView(mReactRootView);}
@Overridepublic void invokeDefaultOnBackPressed() {super.onBackPressed();}}
参数说明
setBundleAssetName
:打包时放在assets
目录下的 JS bundle 包的名字,App release 之后会从该目录下加载 JS bundle;setJSMainModulePath
:JS bundle 中主入口的文件名,也就是我们上文中创建的那个index.js
文件;addPackage
:向 RN 添加 Native Moudle,在上述代码中我们添加了new MainReactPackage()
这个是必须的,另外,如果我们创建一些其他的 Native Moudle 也需要通过addPackage
的方式将其注册到 RN 中。需要指出的是 RN 除了这个方法外,也提供了一个addPackages
方法用于批量向 RN 添加 Native Moudle;setUseDeveloperSupport
:设置 RN 是否开启开发者模式(debugging,reload,dev memu),比如我们常用开发者弹框;setInitialLifecycleState
:通过这个方法来设置 RN 初始化时所处的生命周期状态,一般设置成LifecycleState.RESUMED
就行,和下文讲的 Activity 容器的生命周期状态关联;mReactRootView.startReactApplication
:它的第一个参数是mReactInstanceManager
,第二个参数是我们在index.js
中注册的组件的名字,第三个参数接受一个Bundle
来作为 RN 初始化时传递给 JS 的初始化数据,它的具体用法我会在**[React Android 混合开发讲解的视频教程](
)**中再具体的讲解;
在中AndroidManifest.xml
注册一个 RNPageActivity
Android 系统要求,每一个要打开的 Activity 都要在AndroidManifest.xml
中进行注册:
<activityandroid:name=".RNPageActivity"android:configChanges="keyboard|keyboardHidden|orientation|screenSize"android:windowSoftInputMode="adjustResize"android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
上述代码中我们为
RNPageActivity
添加了一个@style/Theme.AppCompat.Light.NoActionBar
类型的 theme,这也是 React Native UI 组件所要求的主题。
为 ReactInstanceManager 添加 Activity 的生命周期回调
一个 ReactInstanceManager 可以被多个 activities 或 fragments 共享,所以我们需要在 Activity 的生命周期中回调 ReactInstanceManager 的对于的方法。
@Overrideprotected void onPause() {super.onPause();
if (mReactInstanceManager != null) {mReactInstanceManager.onHostPause(this);}}
@Overrideprotected void onResume() {super.onResume();
if (mReactInstanceManager != null) {mReactInstanceManager.onHostResume(this, this);}}
@Overridepublic void onBackPressed() {if (mReactInstanceManager != null) {mReactInstanceManager.onBackPressed();} else {super.onBackPressed();}}
@Overrideprotected void onDestroy() {super.onDestroy();
if (mReactInstanceManager != null) {mReactInstanceManager.onHostDestroy(this);}if (mReactRootView != null) {mReactRootView.unmountReactApplication();}}
从上述代码中你会发现有个不属于 Activity 生命周期中的方法onBackPressed
,添加它的目的主要是为了当用户单击手机的返回键之后将事件传递给 JS,如果 JS 消费了这个事件,Native 就不再消费了,如果 JS 没有消费这个事件那么 RN 会回调invokeDefaultOnBackPressed
代码。
@Overridepublic void invokeDefaultOnBackPressed() {super.onBackPressed();}
**[此过程更细致的讲解可查阅:React Native 与 Android 混合开发讲解的视频教程](
)**
添加开发者菜单
在 RN 中有个很好用的工具开发者菜单,我们平时调试 RN 应用时对它的使用频率很高,接下来我们来为 RNHybridAndroid 添加开着菜单。
public boolean onKeyUp(int keyCode, KeyEvent event) {if (getUseDeveloperSupport()) {if (keyCode == KeyEvent.KEYCODE_MENU) {//Ctrl + M 打开 RN 开发者菜单 mReactInstanceManager.showDevOptionsDialog();return true;}}return super.onKeyUp(keyCode, event);}
通过上代码即可监听Ctrl + M
来打开 RN 开发者菜单。
评论