Topics - SquarePants1991/RNTopics GitHub Wiki
Fork React Native代码。Clone代码到本地,切换到v0.52.0-rc.0 tag,然后建立自己的分支。这样方便做修改以及生成podspecs。
git clone https://github.com/SquarePants1991/react-native.git
git checkout v0.52.0-rc.0
git branch ht52rc0
git checkout ht52rc0
React Native源码中提供了一个脚本工具向本地的pod repo副本中写入RN的完整podspecs。我在我的github上建立了一个私有pod repo,我将它在本地命名为htspecs
,可以使用pod repo
命令查看本地的pod repo。
htspecs
- Type: git (master)
- URL: [email protected]:SquarePants1991/HTPodSpecs.git
- Path: /Users/ocean/.cocoapods/repos/htspecs
使用RN源码下./scripts/process-podspecs.sh
生成podspecs。从脚本代码可以看出,需要注册SPEC_REPO
环境变量来控制podspecs被放到那个repo下。使用下面命令注册我的htspecs
repo。
export SPEC_REPO=htspecs
接着在RN源码根目录下运行
./scripts/process-podspecs.sh
你可能会因为下面的错误失败。
- ERROR | [iOS] xcodebuild: /Users/ocean/Documents/Projects/RNPods/react-native-0.52/ReactCommon/yoga/yoga/YGNodePrint.cpp:208:46: error: implicit conversion loses integer precision: 'size_type' (aka 'unsigned long') to 'const uint32_t' (aka 'const unsigned int') [-Werror,-Wshorten-64-to-32]
这是因为yoga库开启了-Wall, -Werror
编译选项,所有的警告被当作错误,然而在使用clang编译的时候会有一个-Wshorten-64-to-32
警告,可能yoga的作者测试没有覆盖到,这个警告就被当作了错误,从而lint失败。这里我们可以先跳过lint。通过注册环境变量export SKIP_LINT=1
就可以跳过lint了。执行完export SKIP_LINT=1
后再运行./scripts/process-podspecs.sh
基本就不会有问题了。
生成成功后,我们可以去~/.cocoapods/repos/htspecs/
查看,应该会有下面这些文件夹。注意htspecs
应该换成你的repo名字。
DoubleConversion/
Folly/
GLog/
React/
yoga/
上传很简单,把~/.cocoapods/repos/htspecs/
下的代码sync到master上就OK了。
为了验证,我们先更新下repo。
pod repo update
然后使用pod search React
。就可以看见你的私有repo里的React了。可以从下面的Versions: 0.52.0-rc.0 [htspecs repo]
看出这个Pod出自我的htspecs。
-> React (0.52.0-rc.0)
A framework for building native apps using React
pod 'React', '~> 0.52.0-rc.0'
- Homepage: http://facebook.github.io/react-native/
- Source: https://github.com/facebook/react-native.git
- Versions: 0.52.0-rc.0 [htspecs repo]
- Subspecs:
- React/Core (0.52.0-rc.0)
如果你以为前面两步走完就OK了,那就太顺利了。接着我们通过两种集成方式验证这个Pod的可用性,首先是静态库集成,就是不用framework。 新建demo项目,配置Podfile。这里我将HTPodSpecs作为首选source,这样pod install时会优先去HTPodSpecs里找React的Pod。
source '[email protected]:SquarePants1991/HTPodSpecs.git'
source 'https://github.com/CocoaPods/Specs.git'
#use_frameworks!
target 'RNPodTest_Example' do
pod 'RNPodTest', :path => '../'
pod 'React', '0.52.0-rc0', :subspecs => [
'Core',
'CxxBridge',
'ART',
'RCTAnimation',
'RCTActionSheet',
'RCTBlob',
'RCTCameraRoll',
'RCTGeolocation',
'RCTImage',
'RCTNetwork',
'RCTPushNotification',
'RCTSettings',
'RCTText',
'RCTVibration',
'RCTWebSocket',
'RCTLinkingIOS',
'DevSupport',
]
target 'RNPodTest_Tests' do
inherit! :search_paths
end
end
接着执行pod install
。然后发现yoga安装失败了。
Analyzing dependencies
Fetching podspec for `RNPodTest` from `../`
Downloading dependencies
Installing DoubleConversion (1.1.5)
Installing Folly (2016.09.26.00)
Installing GLog (0.3.4)
Using RNPodTest (0.1.0)
Installing React (0.52.0-rc.0)
Installing boost (1.59.0)
Installing yoga (0.52.0-rc.0.React)
[!] Error installing yoga
[!] /usr/bin/git clone /Users/ocean/Documents/Projects/RNPods/react-native-0.52 /var/folders/zb/yn8531qj6kgc4y8ybr7cqdn00000gp/T/d20180109-38625-1wl6qwc --template= --single-branch --depth 1 --branch v0.52.0-rc.0
我们去看下yoga的podspec。惊奇的发现source指向的是本地路径,可能是我脚本使用的不是那么正确吧。不管这些,手动修正。
"source": {
"git": "/Users/ocean/Documents/Projects/RNPods/react-native-0.52",
"tag": "v0.52.0-rc.0"
},
改成
"source": {
"git": "https://github.com/facebook/react-native.git",
"tag": "v0.52.0-rc.0"
},
然后再次同步到master分支。接着pod update
demo项目。因为repo内容改变了,所以需要pod update
。或者你也可以单独更新某个repo pod repo update htspecs
,更新成功后再pod install
。这次一切OK。
Analyzing dependencies
Fetching podspec for `RNPodTest` from `../`
Downloading dependencies
Installing DoubleConversion (1.1.5)
Installing Folly (2016.09.26.00)
Installing GLog (0.3.4)
Using RNPodTest (0.1.0)
Installing React (0.52.0-rc.0)
Installing boost (1.59.0)
Installing yoga (0.52.0-rc.0.React)
Generating Pods project
Integrating client project
Sending stats
Pod installation complete! There are 18 dependencies from the Podfile and 7 total pods installed.
然后我们就可以开心的运行项目了。然而并不开心,新的错误又来了。。。
Users/ocean/Documents/Projects/Demos/RNPodTest/RNPodTest/Example/Pods/yoga/ReactCommon/yoga/yoga/YGNodePrint.cpp:208:46: error: implicit conversion loses integer precision: 'size_type' (aka 'unsigned long') to 'const uint32_t' (aka 'const unsigned int') [-Werror,-Wshorten-64-to-32]
const uint32_t childCount = node->children.size();
~~~~~~~~~~ ~~~~~~~~~~~~~~~^~~~~~
1 error generated.
这个其实就是我们在lint时忽略的错误。为什么会有这个错误呢?我们可以再看yoga的podspec,其中有这样一段配置。
"compiler_flags": [
"-fno-omit-frame-pointer",
"-fexceptions",
"-Wall",
"-Werror",
"-std=c++1y",
"-fPIC"
],
其中-Wall
表示启用所有警告,-Werror
表示把警告当作错误,这是个不错的习惯,但是百密一疏,clang下有一个-Wshorten-64-to-32
的警告,大致就是精度损失的警告,结果就被当作错误,导致编译失败了。为了解决这个问题,目前我的方案就是把"-Werror"暂时去掉。去掉后再次把~/.cocoapods/repos/htspecs
下的podspec同步到master上。再次pod update
。 然后Build demo项目。
接着新的错误出现了,'RCTTVRemoteHandler.h' file not found
,于是我在项目中搜索了下关键字RCTTVRemoteHandler.h
。
在RCTRootView
中找到了有价值的参考代码。
#if TARGET_OS_TV
#import "RCTTVRemoteHandler.h"
#import "RCTTVNavigationEventEmitter.h"
#endif
出错的代码并没有使用#if TARGET_OS_TV
来处理RCTTVRemoteHandler.h
的导入。出错代码在RCTModalHostView.m
中。怎么办呢?改源代码吧。将RCTModalHostView.m
中的#import "RCTTVRemoteHandler.h"
使用#if TARGET_OS_TV
进行处理。
#if TARGET_OS_TV
#import "RCTTVRemoteHandler.h"
#endif
既然改了源代码,podspec里的source就得做相应改变。React和yoga的source都得改,将其中的git地址换成你修改过的源码地址。当然别忘了把你改过的代码commit,push到你的github上。
"source": {
"git": "https://github.com/facebook/react-native.git",
"tag": "v0.52.0-rc.0"
},
改成
"source": {
"git": "https://github.com/SquarePants1991/react-native.git",
"branch": "ht52rc0"
},
因为我后面会一直在ht52rc0
分支上修改代码,为了方便,我将source直接指向了这个分支。再次将htspecs同步到master。然后pod update
。Build项目,终于一切OK了。
现在我们把Podfile里的use_frameworks!
取消注释,来通过动态库集成ReactNative。再次pod update
。然后Build项目。错误还是难免的。yoga又是第一个冒出来的。
While building module 'yoga' imported from /Users/ocean/Documents/Projects/Demos/RNPodTest/RNPodTest/Example/Pods/React/React/Views/UIView+React.h:13:
In file included from <module-includes>:1:
In file included from /Users/ocean/Documents/Projects/Demos/RNPodTest/RNPodTest/Example/Pods/Target Support Files/yoga/yoga-umbrella.h:15:
/Users/ocean/Documents/Projects/Demos/RNPodTest/RNPodTest/Example/Pods/yoga/ReactCommon/yoga/yoga/YGNodePrint.h:10:10: fatal error: 'string' file not found
#include <string>
^~~~~~~~
1 error generated.
为什么报错呢?由于UIView+React.h
导入了<yoga/YGEnums.h>
,因为是framework,系统导入了yoga整个module,然而yoga-umbrella.h里包含了yoga的所有头文件。包括不想暴露出去包括C++引用的头文件。UIView+React.h
作为OC文件引入了包含#include <string>
的YGNodePrint.h
,从而导致YGNodePrint.h
也按照OC的规则编译,自然是找不到<string>
。怎么解决呢?少暴露点头文件就好了,修改yoga的podspec文件。增加public_header_files
。这样就不会把所有头文件都暴露出来了。
"public_header_files": [
"ReactCommon/yoga/yoga/Yoga.h",
"ReactCommon/yoga/yoga/YGMacros.h",
"ReactCommon/yoga/yoga/YGEnums.h"
]
继续同步htspecs的repo,然后pod install,Build项目。没错,错误还在继续。又蹦出来个错误。在RCTNativeAnimatedNodesManager.h
中。
...
#import <RCTAnimation/RCTValueAnimatedNode.h> 'RCTAnimation/RCTValueAnimatedNode.h' file not found
为什么不存在呢?我们去看下React
的podspec,RCTAnimation
是React
的subspec,它在React
中是这样配置的。其中有一个header_dir
保证了Pods/Headers/Private
下会有RCTAnimation
子目录,从而可以使用#import <RCTAnimation/xxx.h>
的方式导入RCTAnimation
下的头文件。然而。。。use_framework!之后Pods/Headers
直接就空了。所以header_dir
相当与就没有用了。
{
"name": "RCTAnimation",
"dependencies": {
"React/Core": [
]
},
"source_files": "Libraries/NativeAnimation/{Drivers/*,Nodes/*,*}.{h,m}",
"header_dir": "RCTAnimation"
},
那怎么解决呢?最粗暴的方式就是把导入代码直接改了。
#import <RCTAnimation/RCTValueAnimatedNode.h>
改成
#import <React/RCTValueAnimatedNode.h>
可以直接在Demo中把Pod的代码改掉,看看效果。Build。。。接着出错。这次是#import <fishhook/fishhook.h>
,原理和上面的一样。
#import <fishhook/fishhook.h>
改成
#import <React/fishhook.h>
继续Build,终于成功了。。。当然别忘了把这2个改动同步到你的rn源代码中。
因为我一直在同一个分支修改代码,如果遇到修改代码,push后pod update代码还是老代码的情况。可以尝试清除项目里的Pods目录和~/Library/Caches/CocoaPods/Pods/Release/
下相应的文件再pod install
。