资讯专栏INFORMATION COLUMN

React Native植入原生Android应用的流程解析

worldligang / 881人阅读

摘要:在应用内添加依赖回到,到的文件级别的里添加依赖最后一行的就是我们新增的,注意这里的版本号要和里的一致。因此,建议用这样的写法,并检查版本号是否和里的一致。

引言

React Native是现在移动开发新的可选方案,也带来了原属于Web领域的React的优秀开发特性。另一方面,React Native的技术栈一经掌握,可以用于iOS、Android及Windows(见此)多个平台,即所说的“learn once, write anywhere”。

开始使用React Native的问题

如何使用React Native?参照官方指南,你会发现官方告诉你的是:请用react-native init命令来创建一个React Native项目。这个项目的根目录结构是这样:

但是,以Android为例,一个普通原生项目的根目录结构却是这样(Android Studio 2.1.2):

可以看到,Android原生项目(上图的Drill根目录)平级于生成的React Native项目的android目录。那么,如果一直以来都是Android原生开发,现在想要引入React Native,考虑部分页面用React Native实现,应该如何做呢?

这就是React Native植入原生应用的问题。显然,react-native init命令生成的项目在结构上不太相符,它的出发点更像是“完全用React Native做一个多平台应用”,但我们可能需要的是“一个原生应用但有部分内容是用React Native做的”。

在本文的时间点,React Native的最新版是0.27。官方对此已给出植入原生Android应用的指南,但它不够准确,也缺少一些细节。因此,本文将提供一个React Native植入原生Android应用的更详细一点的流程。

如果你想了解iOS版的,可以阅读这篇文章。

植入Android流程 基本环境

这篇流程是windows及Android Studio,如果你已经是一个Android Studio原生应用开发者,以及Node.js用户,那么所需的环境你基本已经有了。详情请参考windows环境搭建文字教程以及开始使用React Native,什么都没有也没关系,正好从头搭建。

此外,Android模拟器使用了Genymotion,注册后就可以供个人使用,会比官方模拟器性能要好一些。

新建Android项目

让我们从一个全新的Android原生应用开始。

用Android Studio创建一个新项目,注意Minimum SDK应设置为API 16及以上(React Native要求Android4.1以上的环境):

添加npm组件

到Android原生项目的根目录(也可以新建一个目录,但根目录比较常用)新建一个文件package.json,内容如下(这里起名为react-native-module):

{
  "name": "react-native-module",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start"
  },
  "dependencies": {
    "react": "^15.1.0",
    "react-native": "^0.27.2"
  }
}

下面的dependencies的内容要如何得知呢?答案是参考react-native init生成的项目,毕竟版本号是会不断更新的。如果你已经init生成过项目,可以运行react-native upgrade更新后再参考。

然后,在这个package.json的所在位置,执行:

npm install

安装好所需的npm组件。

添加index.android.js文件

同样在根目录,增加一个文件index.android.js,这是React Native开发的具体内容,是任意的,这里给一个简单的例子:

import React, { Component } from "react";
import { AppRegistry, StyleSheet, Text, View } from "react-native";

class App extends Component {
  render() {
    return (
      
        
          acgtofe.com with react native
        
      
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
  },
  note: {
    fontSize: 20
  }
});

AppRegistry.registerComponent("react-native-module", () => App);

注意上面代码最后的react-native-module这个名字比较重要,可以自定,但后面还会在其他地方用到,需要保持一致。

在Android应用内添加依赖

回到Android Studio,到appbuild.gradle文件(module级别的gradle)里添加依赖:

dependencies {
    compile fileTree(dir: "libs", include: ["*.jar"])
    testCompile "junit:junit:4.12"
    compile "com.android.support:appcompat-v7:23.4.0"
    compile "com.facebook.react:react-native:0.27.2"
}

最后一行的react-native就是我们新增的,注意这里的版本号要和package.json里的一致。

运行一次Gradle Sync,你必然会得到这个错误:

这是因为Android项目默认的依赖包的源jcenter()并不包含最新版的React Native(它只到0.20.1)。新版的React Native都只在npm里发布,因此你需要增加一下依赖包的源,到根目录的build.gradle文件(project级别的gradle)内增加以下内容(从官方的这句注释也可以了解到这一点):

allprojects {
    repositories {
        jcenter()
        maven {
            // All of React Native (JS, Android binaries) is installed from npm
            url "$projectDir/../node_modules/react-native/android"
        }
    }
}

这里的url路径,将取决于你放置node_modules的位置(你可以根据需要选择放置在其他地方)。以上是node_modules位于根目录时的url路径,把它改为"$rootDir/node_modules/react-native/android"也是可以的,它们等效。如何知道这个路径写对了呢?反复试就可以了,如果路径不对,Gradle Sync的时候一定会提示你前面的错误。

你可能在很多别的地方看到的都是这样的写法:

compile "com.facebook.react:react-native:+"

不太建议这样做,因为没有明确的版本号,你无法让系统帮你判断前面的url路径写的是否正确。如果写错,Android将使用发布在jcenter()的旧版React Native,而这将引发其他错误(见后文)。

新建React Native的Activity

新建一个继承自ReactActivity的activity(这里起名为LiveActivity),Android Studio会提醒你必须实现3个方法,一般写成这样:

public class LiveActivity extends ReactActivity {

    @Override
    protected String getMainComponentName() {
        return "react-native-module";
    }

    @Override
    protected boolean getUseDeveloperSupport() {
        return BuildConfig.DEBUG;
    }

    @Override
    protected List getPackages() {
        return Arrays.asList(
                new MainReactPackage()
        );
    }
}

getMainComponentName()的字符串返回值,必须和前面的index.android.js内的组件名一致。

getUseDeveloperSupport()是一个逻辑返回值,表示是否启用开发者模式。这里写BuildConfig.DEBUG就可以自动根据gradle构建的类型(debug或release)来决定。

getPackages是模块列表,一般像上面代码这样就可以。如果你需要在JavaScript里调用原生Java模块,就要把它们添加到这里,具体可以参考这篇文章。

清单文件添加声明

到Android清单文件AndroidManifest.xml添加以下内容(省略了无关部分):



    
    

    
         ... 
        
        
    

前面的权限都是React Native开发环境需要用到的。后面的LiveActivity是刚才的React Native运行界面,DevSettingsActivity则是以下这个Dev Settings的界面:

它也是开发版所必需的。

启动packager server

package.json的位置,打开命令行,运行packager server:

react-native start

也可以用npm start。启动后的状态看起来像这样:

运行起来

这是最后一步了。build这个Android项目,安装到模拟器里,然后打开应用,切换到LiveActivity界面(用按钮跳转,或者直接设置为启动界面都可以),这时候应该只看到一片空白。

ctrl + m(这是Genymotion的用法,事实上,这是Android的Menu键,现在的实体设备基本没有这个键,但摇一摇可以触发)开启调试菜单,选择Dev Settings,打开前面贴过图的DevSettingsActivity,设置Debug server host & port for device为本机ip地址(命令行内ipconfig查看)。最后,回到LiveActivity,开启调试菜单选择Reload JS,等待一会儿,如果你看到了像下图这样的界面:

就说明完成了!对应的,packager server里应该可以看到每一次请求的记录:

接下来,你就可以开始React Native的开发了,改动保存后,重新Reload JS,就可以看到新的效果。

建议及改进

建议使用Android 5.0+的设备(包括模拟器),它们支持直接USB传输packager server返回的那个bundle js文件。如果是Android 5.0+,可以USB连接电脑后(如果是模拟器,那就等于已经连接)运行以下命令:

adb reverse tcp:8081 tcp:8081

然后就可以省略掉前面流程里设置本机ip地址那一步,直接Reload JS。注意设备需要开启USB调试(模拟器不用),而且电脑同时只连接一个设备。

相对于前面设置本机ip地址的方式,这帮你免去了同一WiFi环境、代理等麻烦。

不顺利的情况

虽然流程看起来轻松愉快,但并不怎么能一次成功。下面是我在流程中碰到过的一些问题及其记录,可以用作参考。

版本不匹配

错误提示如下:

参照github上的issue,这个错误的引发原因是packager server的React Native版本和Android应用内的不一致。比如应用内的gradle依赖写的是compile "com.facebook.react:react-native:+"url路径写得不对,结果用的就是jcenter()里的0.20.1的旧版,就会有这个问题。

因此,建议用compile "com.facebook.react:react-native:0.27.2"这样的写法,并检查版本号是否和package.json里的一致。

404

这是说index.android.js文件不存在的错误。但我碰见的是文件就在那,也出这个错误。

这可能是由不正确的缓存引起,我的解决方法:关闭server,删除index.android.js,然后重启server,刷新,得到真正的404,然后还原index.android.js,再刷新即解决。

无法连接到server

先按照Try the following to fix the issue: 下给出的解决方法依次检查和尝试。如果仍不能解决,删除掉node_modules目录,重新npm install,然后重开server。

windows下删除node_modules目录可能有路径过长的问题,推荐用rimraf来删除。

500

这个问题需要具体看server的输出,我这里的错误信息是:Error: Unable to find file with path: ......polyfillsprelude_dev.js。类似前面的无法连接server,我也是删除node_modules后重新安装得到解决。

有用的调试方法

流程中可能碰到的问题可以分为两类,Android应用(client)和server。如果看到错误,打开浏览器访问http://localhost:8081/index.android.bundle?platform=android,如果能看到输出的JavaScript代码,那说明server是比较正常的,更可能是Android应用的问题。反过来,如果浏览器里同样看到错误信息,那更可能就是server的问题。

没有Flow和Nuclide

你可能在开始用React Native的过程中听说了Flow和Nuclide,它们分别是JavaScript类型检查工具及React Native的推荐IDE。

但请注意,在本文的时间点,它们还没有windows版。我是用Atom来开发React Native的。

发布正式版

React Native的开发版是需要有一个packager server来随时发送更新后的bundle js文件的。但如果要得到真正签名的正式版(app-release),你需要把bundle js文件保存到Android应用的资源目录内。这样,正式版不再需要server支持,可以独立运行。

参照官方的发行APK包指南,你只需要这样几步:

创建目录app/src/main/assets

运行以下命令(对应本文流程的目录结构),将bundle js文件保存到资源目录。

react-native bundle --platform android --dev false 
--entry-file index.android.js 
--bundle-output app/src/main/assets/index.android.bundle 
--assets-dest app/src/main/res/

在Android Studio里选择BuildGenerate Signed APK...,生成正式版的apk。

官方有提到使用react.gradle文件的方法,但我觉得像上面这样不用它更简单。

正式版的即时更新

看起来正式版把bundle js文件保存到了apk内,这好像就丢失了React Native的即时更新?对的,但仍然有办法实现它,你可以看看React-Native-Remote-Update,这个项目已经过时了,但里面贴出的原理很值得参考。

现在,你可以用react-native-auto-updater来帮助你实现React Native的即时更新。

参考资料集

我在写本文的过程中参考了下面三个资料集合,觉得非常棒,在此也贴出来:

React-Native学习指南

Android开发技术周报特刊之React Native

react-native-android-guide

结语

React Native的Android版本是去年9月(2015.9.15)才推出,此前只有iOS版。相对来说,Android的相关教程要比iOS少很多。因此,我觉得有这样一份windows + React Native for Android的组合流程会很有帮助。

来尝试新的移动开发方案吧!

(重新编辑自我的博客,原文地址:http://acgtofe.com/posts/2016/06/react-native-embedding-android)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79740.html

相关文章

  • React Native植入原生Android应用流程解析

    摘要:在应用内添加依赖回到,到的文件级别的里添加依赖最后一行的就是我们新增的,注意这里的版本号要和里的一致。因此,建议用这样的写法,并检查版本号是否和里的一致。 引言 React Native是现在移动开发新的可选方案,也带来了原属于Web领域的React的优秀开发特性。另一方面,React Native的技术栈一经掌握,可以用于iOS、Android及Windows(见此)多个平台,即所说...

    荆兆峰 评论0 收藏0
  • SegmentFault 技术周刊 Vol.4 - 这份 Android 有点甜

    摘要:阅读本期周刊,你将快速入门,开启甜蜜之旅。然则的原理负责发送以及处理消息,创建消息队列并不断从队列中取出消息交给,则用于保存消息。 showImg(/img/bVCN99?w=900&h=385); 2016 年 8 月,Android 7.0 Nougat(牛轧糖)正式发布,那么问题来了,你 Marshmallow 了么(¬ -̮ ¬) Cupcake、Donut、Gingerbre...

    jay_tian 评论0 收藏0
  • SegmentFault 技术周刊 Vol.4 - 这份 Android 有点甜

    摘要:阅读本期周刊,你将快速入门,开启甜蜜之旅。然则的原理负责发送以及处理消息,创建消息队列并不断从队列中取出消息交给,则用于保存消息。 showImg(https://segmentfault.com/img/bVCN99?w=900&h=385); 2016 年 8 月,Android 7.0 Nougat(牛轧糖)正式发布,那么问题来了,你 Marshmallow 了么(¬ -̮ ¬)...

    shinezejian 评论0 收藏0
  • React Native多入口实现

    摘要:在调研后得出了两种方案注册多个根组件入口只注册一个入口,根据传递属性选择进入不同的组件注册多个根组件入口这种方案是在中注册多个跟组件。最高占用内存也在左右总体来说单注册入口和多注册入口,占用内存没有明显区别 前言 最近在做原生项目集成RN的时候遇到了一个问题:如果从原生进入RN有多个入口或者说从原生不同的地方可以进入到不同的RN组件,该怎么做?由此展开了调研。在调研后得出了两种方案: ...

    wind5o 评论0 收藏0
  • 跨平台技术演进

    摘要:接下来,我将从原理优缺点等方面为大家分享跨平台技术演进。小程序年是微信小程序飞速发展的一年,年,各大厂商快速跟进,已经有了很大的影响力。下面,我们以微信小程序为例,分析小程序的技术架构。 前言 大家好,我是simbawu ,@BooheeFE Team Leader,关于这篇文章,有问题欢迎来这里讨论。 随着移动互联网的普及和快速发展,手机成了互联网行业最大的流量分发入口。以及随着5G...

    魏宪会 评论0 收藏0

发表评论

0条评论

worldligang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<