近期开始研究Facebook f8app项目,目标是理解Facebook官方React Native f8app的整体技术架构,给公司目前几个的React Native项目开发提供官方经验借鉴,并对原生开发和React Native开发进行框架层面的融合。
本文分析f8app android代码的结构和技术实现,阅读本文的前提是熟悉Android开发。
f8app android代码结构分析
ReactNative项目Android相关的代码都在android目录下,可以直接使用Android Studio打开这个目录方便查看和修改。android目录结构如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45├── F8v2.iml
├── app
│ ├── app.iml
│ ├── build.gradle
│ ├── proguard-rules.pro
│ ├── react.gradle
│ └── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ └── facebook
│ │ └── f8
│ │ └── MainActivity.java
│ └── res
│ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_notification.png
│ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_notification.png
│ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_notification.png
│ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_notification.png
│ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_notification.png
│ ├── raw
│ │ └── third_party_notices.html
│ └── values
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── local.properties
└── settings.gradle
在android Studio下显示如下:

MainActivity 代码分析
通过AndroidManifest.xml可以知道App的页面入口Activity是android/app/src/main/java/com/facebook/f8/MainActivity.java,代码比较简单,继承了ReactActivity,关键的方法是getJSBundleFile,可以看到使用了CodePush推送更新技术,返回了一个bundle文件,分析代码可知默认的bundle文件是index.android.bundle。
CodePush是微软提供的一个开发者服务,支持对React Native和Cordova App在不重新安装App的前提下热更新App,是目前很流行的一种App热部署技术。
getPackages方法初始化了CodePush,初始了ReactNativePushNotificationPackage推送服务,初始化了用到的一些RN第三方包:
- FBSDKPackage是Android Facebook SDK的React Native封装,让React Native App能够使用Facebook的接口,提供了Facebook用户登录token,分享等功能;
- LinearGradientPackage是一个渐变UI控件;
- RNSharePackage是个分享插件,提供了通过Android Intent.ACTION_SEND分享文字和链接的简单分享功能;
- RNSendIntentPackage是一个发送Android Intent的插件,提供了通过Intent拨打电话,发送短信,在系统日历添加事件提醒等功能。
- ReactNativePushNotificationPackage是一个本地和远程通知推送插件,可以接受Google GCM推送的消息,并在状态栏上显示。
1 | public class MainActivity extends ReactActivity { |
可以查看settings.gradle,发现f8app Android引用了5个子工程,子工程源码放在../node_modules目录下。
1 | rootProject.name = 'F8v2' |
可以看到,可以通在settings.gradle引入工程的方法增加新的自定义RN插件。实际上,这些插件是通过rnpm install命令安装的。React Native Package Manager (RNPM) 是一个简化React Native插件安装体验的工具。
下面我们分析react-native-linear-gradient插件看看插件是如何实现的。
React Native android 插件实现分析
LinearGradientView是一个典型的原生UI插件,可以先看看官方的文档NativeComponentsAndroid, 我感觉这个文档有点过时,没有提到ReactPackage。ReactPackage接口是现在RN插件的主入口。LinearGradientPackage实现了ReactPackage接口
ReactPackage接口代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35/**
* Main interface for providing additional capabilities to the catalyst framework by couple of
* different means:
* 1) Registering new native modules
* 2) Registering new JS modules that may be accessed from native modules or from other parts of the
* native code (requiring JS modules from the package doesn't mean it will automatically be included
* as a part of the JS bundle, so there should be a corresponding piece of code on JS side that will
* require implementation of that JS module so that it gets bundled)
* 3) Registering custom native views (view managers) and custom event types
* 4) Registering natively packaged assets/resources (e.g. images) exposed to JS
*
* TODO(6788500, 6788507): Implement support for adding custom views, events and resources
*/
public interface ReactPackage {
/**
* @param reactContext react application context that can be used to create modules
* @return list of native modules to register with the newly created catalyst instance
*/
List<NativeModule> createNativeModules(ReactApplicationContext reactContext);
/**
* @return list of JS modules to register with the newly created catalyst instance.
*
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
* will be automatically included in the JS bundle.
*/
List<Class<? extends JavaScriptModule>> createJSModules();
/**
* @return a list of view managers that should be registered with {@link UIManagerModule}
*/
List<ViewManager> createViewManagers(ReactApplicationContext reactContext);
}
LinearGradientPackage类主要实现了createViewManagers方法,返回了一个LinearGradientManager实例,代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class LinearGradientPackage implements ReactPackage {
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(
new LinearGradientManager());
}
}
下面看LinearGradientManager类,包含了一个LinearGradientView实例,LinearGradientView是渐变View的具体实现,通过@ReactProp注解可以在js层设置渐变View的一些属性,例如渐变颜色,渐变开始和结束位置等的。代码如下:
1 | public class LinearGradientManager extends SimpleViewManager<LinearGradientView> { |
CodePush 热更新技术介绍
f8app使用了CodePush技术热更新App,可以先看下微软官方的文档React Native Client SDK。
CodePush提供了对React Native App的热更新能力,目前只能对js bundle进行热更新,如果原生代码修改了是不能热更新的,只能通过重新安装App的方式升级。
CodePush的一个问题是是对React Native版本的兼容性,由于React Native版本更新很快,CodePush是由微软而不是Facebook维护的,所以对React Native0.18以前的版本支持有各种兼容问题,具体参考文档。
CodePush的具体配置可以参考这篇文章,配置需要注意的事项还是挺多的,我参考这篇文章配置成功了,本文不做详细介绍。
总结
本文分析了f8app android代码结构,以react-native-linear-gradient插件为例子分析了React Native插件的结构,介绍了CodePush热更新技术,通过本文可以对f8app有比较初步的认识。
下篇文章将分析React Native js代码,这块是f8app的核心实现,代码量比较大。