前言

当前 React Native 虽说版本更新比较快,各种组件也提供的很全面了,但是在某些情况下,混合开发的方式才会快速缩短开发周期,原因无非就是原生平台的“底蕴”无疑更深,拥有众多且类型丰富的第三方支持库。很多情况下,运用这些库可以避免苦逼的重复劳动。接下来我们以 [jpush-react-native 插件](https://github.com/jpush/jpush-react-native)为例来看看在 React Native 中如何使用原生的第三方库。

开始

在开始之前,你必须安装以下软件:npm 命令行工具,react-native 命令行工具, Android Studio。jpush-react-native 是[极光推送](https://www.jiguang.cn/)提供的 React Native 版本插件,可以让我们快速集成推送功能。实际上这个插件就是一个混合应用,使用他们自己的原生 SDK,并且封装了一些接口,让开发者可以在 JS 和原生平台之间互相调用。接下来我们只需要三个步骤就可以完成绝大多数原生库在 React Native 中的应用。

先明确两个概念,在 Android Studio 中一个项目往往会包含很多模块(Module),项目中的 build.gradle 配置一般对所有 module 生效。而 Module 中的 build.gradle 则配置了该 Module 所需的依赖或者任务等等。

第一步——安装

在命令行中进入 React Native 项目,然后使用如下两个命令即可完成 jpush-react-native 插件的安装:

npm install jpush-react-native --save

rnpm link jpush-react-native

jpush-react-native 发布到 npm 了,所以使用命令行可以轻松安装。

然而有很多第三方库可能需要原生的安装方式。比如提供 jar 包或者 aar 包的方式在 Android 中很常见,也有可能以 maven 依赖的方式安装。如果是以上方式安装需要做一些调整:

  • jar 包或者 aar 包的方式:

    i. 将依赖包复制到 module 的 libs 文件夹下(如果没有则需要手动创建)

    ii. 在 build.gradle 中添加:
android {
...
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
...
}
...
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
}
  • 以 maven 依赖的方式:

    i. 在项目的 build.gradle 中增加:
allprojects {
repositories {
...
mavenCentral()
maven {
url "https://oss.sonatype.org/content/repositories/snapshots/"
}
}
}

ii. 在 module 的 build.gradle 中添加:

dependencies {
...
compile 'xxx-SNAPSHOT'
}

其中的 xxx 指代 groupId、artifactId 以及版本号(以 : 分隔),一般都会由提供方给出。比如 ActiveAndroid:

compile 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'

第二步——适配(配置)

这一步因第三方库而异,其实大多都是大同小异,有的库甚至不需要配置直接可以“搭建桥梁”使用。jpush-react-native 还是要配置一下的
首先在命令行中运行脚本:

// 将 AppKey 和 Module Name 替换成自己的
npm run configureJPush [AppKey] [Module Name]
  • 配置 AndroidManifest
<meta-data android:name="JPUSH_CHANNEL" android:value="${APP_CHANNEL}"/>
<meta-data android:name="JPUSH_APPKEY" android:value="${JPUSH_APPKEY}"/>

将以上代码复制到你 Module 的 AndroidManifest 下即可。

  • 配置 build.gradle

    打开与 AndroidManifest 同级的 build.gradle 文件,做以下改动:
android {
... defaultConfig {
// 换成自己的包名
applicationId "com.xxx"
...
manifestPlaceholders = [
JPUSH_APPKEY: "xxx", //在此替换你的AppKey,极光官网注册应用获得
APP_CHANNEL: "developer-default" //应用渠道号
]
}
}

到此配置完成。

第三步 搭建桥梁

这一步是最后也是最核心的一步。“搭建桥梁”主要是在 Native 侧提供一些 @ReactMethod 标签的方法,或者在 Native 中处理后回调到 JS,说白了就是要使得 JS 和 Native 可以相互调用。这也是混合开发的优势所在,原生平台提供的库,我们只需要搭建一下桥梁,就可以拿来使用。只要稍微写一点原生的代码,可以省去我们绝大部分工作。许多刚接触 React Native 的人不知道如何在 Native 中打开 JS 的界面(众所周知,JS 的界面由一个个 Component 组成,有自己的路由系统)后面我会写一个简单例子,用 Native 的方式声明注册界面(在 Android 中即为 Activity),然后用 JS 渲染界面,这个问题就迎刃而解了。接下来还是先看看 jpush-react-native 的例子。

首先在你的 Module 下创建一个 ManiActivity 以及 MainApplication 类。RN 0.29 后,需要在 MainApplication 中添加原生模块。

MainActivity.java

public class MainActivity extends ReactActivity implements DefaultHardwareBackBtnHandler {

    @Override
protected String getMainComponentName() {
// 这里返回的名字要与 JS 侧注册的 Component 名字一致
return "PushDemoApp";
} @Override
protected void onPause() {
super.onPause();
JPushInterface.onPause(this);
} @Override
protected void onResume() {
super.onResume();
JPushInterface.onResume(this);
}
}

接下来需要在 MainApplication 中增加原生模块

MainApplication.java

public class MainApplication extends Application implements ReactApplication {    

    private boolean SHUTDOWN_TOAST = false;
private boolean SHUTDOWN_LOG = false; private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
} @Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new JPushPackage(SHUTDOWN_TOAST, SHUTDOWN_LOG)
);
}
}; @Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
}

这样就完成了。在 Android Studio 中 sync 一下,可以看到 jpush-react-native 作为 Library Module 导进来了。打开 JPushModule 类,看到其中的 onReceive 方法,通知的处理都在这一块。在极光推送后台发送通知(也可以使用 服务端 sdk)后,客户端 sdk 收到通知后会回调到 onReceive 方法,在 onReceive 中可以做一些定制化的操作。比如收到通知后,点击通知打开特定的界面:

public static class JPushReceiver extends BroadcastReceiver {
public JPushReceiver() {
HeadlessJsTaskService.acquireWakeLockNow(mRAC);
} @Override
public void onReceive(Context context, Intent data) {
...
} else if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(data.getAction())) {
Logger.d(TAG, "用户点击打开了通知");
Intent intent = new Intent();
intent.setClassName(context.getPackageName(), context.getPackageName() + ".MainActivity");
intent.putExtras(bundle);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
// 如果需要跳转到指定的界面,那么需要同时启动 MainActivity 及指定界面(SecondActivity):
// If you need to open appointed Activity, you need to start MainActivity and
// appointed Activity at the same time.
Intent detailIntent = new Intent();
detailIntent.setClassName(context.getPackageName(), context.getPackageName() + ".SecondActivity");
detailIntent.putExtras(bundle);
Intent[] intents = {intent, detailIntent};
// 同时启动 MainActivity 以及 SecondActivity
context.startActivities(intents);
// 或者回调 JS 的某个方法
}
} ... @ReactMethod
public void finishActivity() {
Activity activity = getCurrentActivity();
if (activity != null) {
activity.finish();
}
}

上面的例子中,我们在收到点击通知的事件时,打开一个特定的界面。这个界面在 Native 中创建(这样做的好处在于还可以实现一些特定的需求,比如收到通知后,如果存在 SecondActivity,则让位于 SecondActivity 之上的界面全部弹出,如果不存在,则创建等等之类的需求),但是还是用 JS 的代码来渲染界面,这对于熟悉 JS 的同学来说,再好不过。要做到这一点,首先我们创建一个 SecondActivity (与 MainActivity 同级)类:

SecondActivity.java

public class SecondActivity extends ReactActivity {

    @Override
protected String getMainComponentName() {
// 注意这个名字与 JS 对应的 Component 中
// AppRegistry.registerComponent 方法的第一个参数相同
return "SecondActivity";
}
}

然后在 AndroidManifest 注册 SecondActivity:

AndroidManifest

<activity android:name=".SecondActivity" />

在 React Native 项目下新建一个文件夹 react-native-android,专门用来存放 js 相关的文件。新建 second.js 文件:

second.js

'use strict';

import React from 'react';
import ReactNative from 'react-native'; const {
AppRegistry,
View,
Text,
TouchableHighlight,
StyleSheet,
NativeModules,
} = ReactNative; var JPushModule = NativeModules.JPushModule; export default class second extends React.Component {
constructor(props) {
super(props);
} onBackPress = () => {
let navigator = this.props.navigator;
if (navigator != undefined) {
this.props.navigator.pop();
} else {
console.log("finishing second activity");
JPushModule.finishActivity();
}
} onButtonPress = () => {
console.log("will jump to setting page");
let navigator = this.props.navigator;
if (navigator != undefined) {
this.props.navigator.push({
name: "setActivity"
});
} else { } } render() {
return (
<View>
<TouchableHighlight
style={styles.backBtn}
underlayColor = '#e4083f'
activeOpacity = {0.5}
onPress = {this.onBackPress}>
<Text>
Back
</Text>
</TouchableHighlight>
<Text
style={styles.welcome}>
Welcome !
</Text>
<TouchableHighlight underlayColor = '#e4083f'
activeOpacity = {0.5}
style = {styles.btnStyle}
onPress = {this.onButtonPress}>
<Text style={styles.btnTextStyle}>
Jump To Setting page!
</Text>
</TouchableHighlight>
</View>
);
}
} var styles = StyleSheet.create({
backBtn: {
padding: 10,
marginTop: 10,
marginLeft: 10,
borderWidth: 1,
borderColor: '#3e83d7',
backgroundColor: '#3e83d7',
borderRadius: 8,
alignSelf: 'flex-start'
},
welcome: {
textAlign: 'center',
margin: 10,
},
btnStyle: {
marginTop: 10,
borderWidth: 1,
borderColor: '#3e83d7',
borderRadius: 8,
backgroundColor: '#3e83d7',
alignSelf: 'center',
justifyContent: 'center'
},
btnTextStyle: {
textAlign: 'center',
fontSize: 25,
color: '#ffffff'
},
}); AppRegistry.registerComponent('SecondActivity', () => second);

就这样,大功告成!接下来可以在 index.android.js 中注册路由,使得在 JS 中也可以跳转到这个界面。源码请戳这里

总结

以上就是在 React Native 中以混合的方式开发应用的大概过程。用这种方式可以马上使用丰富的原生平台第三方库,只是在 Native 部分需要写些代码,但是花费的代价远远小于自己用 JS 的方式再实现一遍。


作者:KenChoi - 极光

原文:你不可不知的 React Native 混合用法(Android 篇)

知乎专栏:极光日报

你不可不知的 React Native 混合用法(Android 篇)的更多相关文章

  1. 《React Native 精解与实战》书籍连载「Android 平台与 React Native 混合开发」

    此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...

  2. React Native 混合开发与实现

    关于 微信公众号:前端呼啦圈(Love-FED) 我的博客:劳卜的博客 知乎专栏:前端呼啦圈 前言 随着 React 的盛行,其移动开发框架 React Native 也收到了广大开发者的青睐,以下简 ...

  3. React Native App设置&Android版发布

    React Native系列 <逻辑性最强的React Native环境搭建与调试> <ReactNative开发工具有这一篇足矣> <解决React Native un ...

  4. React Native移植原生Android

    (一)前言 之前已经写过了有关React Native移植原生Android项目的文章,不过因为RN版本更新的原因吧,跟着以前的文章可能会出现一些问题,对于初学者来讲还是会有很多疑难的困惑的,而且官方 ...

  5. 将React Native集成至Android原生应用

    将React Native集成至Android原生应用 Android Studio 2.1 Preview 4生成的空项目 react-native 环境 0.22.2 初次编译后apk有1.1M, ...

  6. React Native hot reloading & Android & iOS

    React Native hot reloading & Android & iOS https://facebook.github.io/react-native/docs/debu ...

  7. 《React Native 精解与实战》书籍连载「iOS 平台与 React Native 混合开发」

    此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...

  8. React Native混合开发中必须要学会点FlexBox布局

    在前面的案例中,界面的搭建都是采用CSS的布局,基于盒子模型,依赖 display属性 , position属性, float属性.但对于那些特殊布局非常不方便,比如,垂直居中. 一种全新的针对web ...

  9. 【React Native开发】React Native移植原生Android项目(4)

    ),React Native技术交流4群(458982758),请不要反复加群!欢迎各位大牛,React Native技术爱好者加入交流!同一时候博客左側欢迎微信扫描关注订阅号,移动技术干货,精彩文章 ...

随机推荐

  1. Nginx 相关介绍(Nginx是什么?能干嘛?个人觉得写得比较好的文章,转载过来)

    Nginx的产生 没有听过Nginx?那么一定听过它的"同行"Apache吧!Nginx同Apache一样都是一种WEB服务器.基于REST架构风格,以统一资源描述符(Unifor ...

  2. Mysql Join语法以及性能优化

    引言 内外联结的区别是内联结将去除所有不符合条件的记录,而外联结则保留其中部分.外左联结与外右联结的区别在于如果用A左联结B则A中所有记录都会保留在结果中,此时B中只有符合联结条件的记录,而右联结相反 ...

  3. linux centOS下怎么配置web服务器

    | 浏览:4503 | 更新:2011-12-07 17:45 1 2 3 分步阅读 下是我在配置web服务时作的一些记录,高手飘开或者看了指点一下,不胜感激,第一次配置,很多细节需要自己优化.适合环 ...

  4. MVC错误(一)

    目录规范后将相应的文件放到该放的地方后,应修改require_once();中的路径 调试php代码时先打开WampServer,再在浏览器中输入localhost/文件夹名/index.php

  5. STL中 map 和 multimap

    1. 所在头文件<map>. 命名空间std, 声明如下: namespace std{ template <class Key,class T, class Compare = l ...

  6. Eclipse集成tomcat

    1.window --> Preferences 2.搜索runtime,选择Runtime Environments,点击add按钮 3.选择tomacat的版本,我的版本是7.x的,所以选择 ...

  7. (4)WePHP 模板引入CSS js

    模板有两个定义了两个常量 父类已经定义好了 //模板常量 $dirStr=dirname($_SERVER['SCRIPT_NAME']); $dirStr=$dirStr=='\\'?NULL:$d ...

  8. ssh的配置[待写]

    开机自启:/etc/rc.local /etc/init.d/ssh start 将 /etc/ssh/sshd_confg中PermitRootLogin no 改为yes,重新启动ssh服务.

  9. javascript的那些事儿你都懂了吗

    javascript从开始的验证表单的脚本语言发展到现在能运行在服务器上,其影响力不断的提升.自己作为一个做前端的,编写js是必不可少,从自己学习js的历程来看其实也是比较吃力.要 学好它,还是的花费 ...

  10. 编写高质量代码改善C#程序的157个建议——建议110:用类来代替enum

    建议110:用类来代替enum 枚举(enum)用来表示一组固定的值.例如,为了表示星期信息,我们可以定义枚举Week: enum Week { Monday, Tuesday, Wednesday, ...