ReactNative入坑: iOS原生项目集成ReactNavite(二)

** 创建一个简单的ReactNative 程序 **

使用下面三个命令可以创建一个简单的ReactNative程序,并在iOS模拟器上运行 (无论是运行在安卓还是iOS模拟器上,都需要在开启模拟器的情况下运行程序)

react-native init AwesomeProject
cd AwesomeProject
react-native run-ios

** 那么如何将ReactNative的界面嵌入到iOS程序中那?**

  1. 首先将新创建的 AwesomeProject 程序目录下的 package.jsonindex.ios.js 文件拷贝自己的原生程序目录下面 (自己新建目录统一放置也可以)
  2. 在命令行 切换到 package.json 所在的目录,并执行
    sudo npm install 输入密码后回车,等待执行成功
  3. 在Podfile中加入
pod 'Yoga',  :path => './node_modules/react-native/ReactCommon/yoga'
pod 'React', :path => './node_modules/react-native', :subspecs => [
        'Core',
        'BatchedBridge',
        'DevSupport',
        'ART',
        'RCTActionSheet',
        'RCTAnimation',
        'RCTImage',
        'RCTNetwork',
        'RCTText',
        'RCTWebSocket',
        'RCTLinkingIOS',
]
# 这是一份基础的添加库列表,其他如有需要继续添加
  1. 执行 pod update --verbose 等待更新成功

好的,已经将关于RN的准备工作做完了,下面还要对原生程序进行一点小改造:

  • a. 设置程序Info.plist文件中的 App Transport Security Settings
    确保http协议可以正常通信
    Paste_Image.png
  • b. 在程序中添加:
    // ----------第一种方式----------
    #import <React/RCTRootView.h>
    NSString * strUrl = @"http://localhost:8081/index.ios.bundle?platform=ios";
    NSURL * jsCodeLocation = [NSURL URLWithString:strUrl];
    
    RCTRootView * rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                         moduleName:@"AwesomeProject"
                                                  initialProperties:nil
                                                      launchOptions:nil];
    rootView.frame = self.view.bounds;
    [self.view addSubview:rootView];
    
    // ----------第二种方式----------
    #import <React/RCTRootView.h>
    #import <React/RCTBundleURLProvider.h>
    [[RCTBundleURLProvider sharedSettings] setEnableDev:YES];
    NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
    RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                        moduleName:@"AwesomeProject"
                                                 initialProperties:nil
                                                     launchOptions:nil];
    rootView.frame = self.view.bounds;
    [self.view addSubview:rootView];
  • c. 运行Packager:
    跳转到包含node_module目录的文件夹,运行
    npm start or react-native start (两个命令都可以)
    命令行出现 :** Loading dependency graph, done.** 即表示本地服务已成功开启
  1. 如果忘记这一步会出现:Could not connect to development server
  1. 如果出现 Packager can't listen on port 8081
    Most likely another process is already using this port 或端口被占用之类的,多半是其他命令窗口已经Start服务了,检查下,找到后 control + C 关闭它
  2. 此提示是基于以下版本,如果版本不同可能会提示不一样
    react-native-cli: 2.0.1
    react-native: 0.42.3
  • d. 在Xcode com+R 运行项目

请确保** cocoapods版本在1.2.0以上 ** 否则可能会出现 找不到头文件 的错误
查看cocoapods版本,在命令行执行 pod --version


** iOS打包React Native资源 **

在正式测试打包的时候,就需要将RN的资源进行打包成离线资源,放到项目中,使项目在其他机器上也能正常运行
React Native的 react-native bundle 命令是用来进行打包的命令,
其中我们常使用的一些命令选项:

  • --entry-file ,ios或者android入口的js名称,比如index.ios.js
  • --platform ,平台名称(ios或者android)
  • --dev ,设置为false的时候将会对JavaScript代码进行优化处理。
  • --bundle-output, 生成的jsbundle文件的名称,比如./ios/bundle/index.ios.jsbundle
  • --assets-dest 图片以及其他资源存放的目录,比如./react-native/image

** 打包的命令:**
react-native bundle --entry-file index.ios.js --platform ios --dev false --bundle-output ./bundles/index.ios.jsbundle --assets-dest ./bundles
** 正式打包时候的代码:**

    NSURL * jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"index.ios" withExtension:@"jsbundle"];
    
    RCTRootView * rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                         moduleName:@"RNInit"
                                                  initialProperties:nil
                                                      launchOptions:nil];


** iOS真机运行React Native **

将刚才打包生成的bundles的文件夹,拖入iOS 工程,放到主工程下面

image.png

iOS中导入bundle的路径需要改一下

    // #import <React/RCTRootView.h>
    // #import <React/RCTBundleURLProvider.h>
    NSURL *jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"index.ios" withExtension:@"jsbundle" subdirectory:@"bundles"];
    RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                        moduleName:@"AwesomeProject"
                                                 initialProperties:nil
                                                     launchOptions:nil];
    rootView.frame = self.view.bounds;
    [self.view addSubview:rootView];

index.ios.js 中的代码也需要改一下,才能将图片的路径搞对,不然会出现本地图片不显示的问题

import { AppRegistry } from 'react-native';
import App from './js/yourapp';
import { Platform } from 'react-native';
import { setCustomSourceTransformer } from 'react-native/Libraries/Image/resolveAssetSource';

// 更改一下图片的查找方法,以便在真机能正确查找路径
setCustomSourceTransformer(function (resolver) {
    if (Platform.OS === 'ios'
        && !resolver.serverUrl
        && !resolver.bundlePath
        && resolver.asset.type === 'png') {
        resolver.bundlePath = 'bundles/';
    }
    return resolver.defaultAsset();
});

AppRegistry.registerComponent('test', () => App);


** iOS真机实时调试React Native **

在调试的时候,我比较习惯使用真机运行查看,介绍下如何在真机调试React Native:

在项目中加入一个名字为ip.txt的文件,将自己电脑的ip地址写入文件,占用1行,记得加入target中
剩下的和使用模拟器一样的步骤启动,npm start
正常运行项目,即可


** 将ReactNative 嵌入iOS 中时,会碰到一些问题 **

1. 不知道需要Pod里的React的subspecs填哪些?

可以去打开 ./node_modules/react-native/React.podspec 这个文件里面有React的subspecs 的全部声明

2. 更新pod 出现 Yoga 依赖错误

类似于这种 Yoga (= 0.42.3.React) required by React/Core (0.42.3)

详细错误:

[!] Unable to satisfy the following requirements:

- `Yoga (= 0.42.3.React)` required by `React/Core (0.42.3)`

None of your spec sources contain a spec satisfying the dependency: `Yoga (= 0.42.3.React)`.

You have either:
 * out-of-date source repos which you can update with `pod repo update`.
 * mistyped the name or version.
 * not added the source repo that hosts the Podspec to your Podfile.

Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default.

解决方法:
在Podfile文件加上
pod 'Yoga', :path => './node_modules/react-native/ReactCommon/yoga'
路径中的./node_modules需要替换为自己项目中的node_modules目录路径

3. 运行程序出现 Native module cannot be null

第一次将RN嵌入到iOS中后,运行程序出现 Native module cannot be null

Paste_Image.png

解决方法:
出现上述错误,是因为少引入了一个部件 RCTNetwork ,将 RCTNetwork 加入到 Reactsubspecs 中。
以下是三个基础部件,如果需要其他 subspecs 自己继续往下加就好了

pod 'React', :path => './node_modules/react-native', :subspecs => [
        'Core',
        'BatchedBridge',
        'DevSupport',
        'ART',
        'RCTActionSheet',
        'RCTAnimation',
        'RCTImage',
        'RCTNetwork',
        'RCTText',
        'RCTWebSocket',
        'RCTLinkingIOS',
]
# 这是一份基础的添加库列表

4. 编译出现 jschelpers/JavaScriptCore.h file not found ❗️

第一个可能的问题:cocoapods版本低于1.2.0,去网上查找升级cocoapods的方法解决
第二个可能的问题:0.45 版本以后 React缺少依赖,更新Podfile解决

pod 'Yoga',  :path => '../node_modules/react-native/ReactCommon/yoga'
pod 'React', :path => '../node_modules/react-native', :subspecs => [
         'Core',
         'BatchedBridge', # 0.45 版本以后需要添加
         'RCTText',
         'RCTWebSocket',
         'RCTNetwork',
    ]

(真的坑啊。。。)

5. 出现 error: bundling: UnableToResolveError: Unable to resolve module AccessibilityInfo

详细信息:

error: bundling: UnableToResolveError: Unable to resolve module `AccessibilityInfo` from `/Users/Test/Desktop/cardloan_react/node_modules/react-native/Libraries/react-native/react-native-implementation.js`: Module does not exist in the module map or in these directories:
  /Users/Test/Desktop/cardloan_react/node_modules/react-native/node_modules
,   /Users/Test/Desktop/cardloan_react/node_modules

解决办法:
调用npm start -- --reset-cache 重新开启服务,重新运行解决

6. 出现 Unhandled JS Exception: Cannot read property 'string' of undefined

报错到系统的js文件:
Unhandled JS Exception: Cannot read property 'string' of undefined就是报错到系统的 React.PropTypes.string
遇到这种情况,你需要在js文件夹下执行下 npm list 如果过出现 ERR 就表明是依赖库错误,需要删除 node_modules 重新 install 一下



** 注意 **: 本文描述中出现的 ./node_modules/react-native 记得替换成自己项目中的 node_modules 目录的路径
** Tips **:
./ 为当前文件所在的文件夹
../ 为当前文件所在的文件夹的上级文件夹

其他文章

ReactNative入坑: ReactNative入门(一)
ReactNative入坑: iOS原生项目集成ReactNavite(二)
ReactNative入坑: react-navigation库(三)
ReactNative入坑: codepush热更新(四)
ReactNative入坑: 一些常用控件的使用(五)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容