探索一个 React Native 应用是如何启动的 — Ios 篇

上一篇讲到了在 Android 环境下一个 React Native 应用是如何启动的。这次咱们来探索一下 Ios 环境。

和上文的思路一样,咱们可以按照以下三个步骤来:

  1. 找到整个应用的入口文件
  2. 找到 native 端和 React Native 相连接的方法
  3. 找到 React Native 的入口文件

找到整个应用的入口文件

用 Xcode 打开项目目录下的 ios 文件夹,在和项目名称相对应的文件夹的下面找到 main.m 文件。此文件就是整个 ios 应用的入口。

ios 文件目录

打开 main.m 文件之后可以看到下面的代码:

1
2
3
4
5
6
7
8
9
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

主函数 main 主要是调用 UIApplicationMain 函数。UIApplicationMain 函数是初始化程序的核心,它接收 4 个参数:
1、参数个数
2、参数内容
3、表示要创建的应用程序对象( app 的象征,该类必须是 UIApplication 或者它的子类)。如果传 nil 默认就表示 UIApplication 类。UIApplication 是单例模式,一个应用程序只有一个 UIApplication 对象或子对象;
4、表示给应用程序指定一个代理对象,该类必须遵守 UIApplicationDelegate 协议。

所以总的过程大概就是 UIApplicationMain 函数创建 UIApplication,然后再根据第四个参数创建 delegate 对象,并将该 delegate 对象赋值给 UIApplication 对象中的 delegate 属性。

这里再翻译一下,就是一个应用要有一个 UIApplication 作为主体来接收各类 events,然后还要有一个 UIApplicationDelegate 来处理 events。UIApplicationMain 函数会自动创建 UIApplication,所以咱们下面就来看一下 UIApplicationDelegate 是如何处理的。

找到 native 端和 React Native 相连接的方法

打开 AppDelegate.m 文件,native 和 js 连接的方法就在里面。

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
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *jsCodeLocation;
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"AwesomeProject"
initialProperties:nil
launchOptions:launchOptions];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
@end

在 AppDelegate.m 里面最主要的一个方法是 didFinishLaunchingWithOptions,它是在程序刚刚启动的时候执行的,所以可以在这里做一些程序启动需要的准备工作。而且 AppDelegate 是全局的,我们也可以在这里写一些全局变量或者方法。

RCTRootView

RCTRootView 是一个 UIView 容器,就是用户所能看到的所有视图都源于 RCTRootView,它也将所有的 React Natvie 视图封装在了原生组件中。

  • initWithBundleURL
    当应用开始运行的时候,RCTRootView 将会从 initWithBundleURL 的参数中加载应用:(本地调试的时候是直接在本地服务器中的 index.ios 加载,发布时设置有所不同)

  • moduleName
    在 index.ios.js 中注册的应用的名字

  • initialProperties
    必须是NSDictionary的一个实例。这一字典参数会在内部被转化为一个可供 JS 组件调用的 JSON 对象。

找到 React Native 的入口文件

所以在本地调试的时候,initWithBundleURL 会加载本地打包的 index.ios 包。这个包就是我们的 js 文件。那么整个 js 的入口文件就是 index.ios.js 文件:

1
2
3
4
import { AppRegistry } from 'react-native'
import AwesomeProject from './js/app'
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject)

在入口文件中,我们注册了一个名为 AwesomeProject 的 app,然后所有的逻辑都会从这个入口开始写。

支持原创