React-Native 開發中,從模拟器切換到真機你必須要做的是:打開AppDelegate.m,将
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
修改為
jsCodeLocation = [NSURL URLWithString:@"http://【你的IP】:8081/index.ios.bundle?platform=ios&dev=true"];
, 從真機切換到模拟器,你又得修改一次,如此反複。更煩的是,團隊開發的時候,有人不小心把他的IP push上去了,你pull下來的時候一編譯運作,怎麼自己修改的JS代碼都不起作用呢?然後各種log,最後發現,尼瑪,連接配接到别人IP去了。反正就是各種坑。
如果你也遇到以上的問題,那就繼續看下去哈。
解決這個問題,其實很簡單,隻要我們判斷一下如果是在模拟器上運作的話就用localhost,如果是真機的話就是用計算機的IP,Objective-C 也為我們提供了這樣一個宏:
TARGET_OS_SIMULATOR
用來判斷是否是在模拟器上運作,是以我們可以很簡單的寫出下面的代碼:
#if TARGET_OS_SIMULATOR
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
#else
#warning "DEBUG DEVICE"
NSString *serverIP = 【你的IP】;
NSString *jsCodeUrlString = [NSString stringWithFormat:@"http://%@:8081/index.ios.bundle?platform=ios&dev=true", serverIP];
jsCodeLocation = [NSURL URLWithString:jsCodeUrlString];
#endif
這樣,就完成了。但是如果是 release 的話想使用打包的檔案咋辦? 我們可以直接判斷:如果是在 debug 下的話就是用上面的代碼,否則則是用 bundle,如下:
#if DEBUG
#if TARGET_OS_SIMULATOR
#warning "DEBUG SIMULATOR"
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
#else
#warning "DEBUG DEVICE"
NSString *serverIP = 【你的IP】;
NSString *jsCodeUrlString = [NSString stringWithFormat:@"http://%@:8081/index.ios.bundle?platform=ios&dev=true", serverIP];
jsCodeLocation = [NSURL URLWithString:jsCodeUrlString];
#endif
#else
//release
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
這樣,我們就能在 debug 和 release 都不用修改代碼了。但是,有個問題,這個【你的IP】很是礙眼啊,公司和家裡的 IP 肯定不一樣啊,不還是得改。而且如果将這代碼 push 到伺服器,其他人也還是要改,根本問題還是不能解決。如果我們能動态擷取到計算機的 IP 問題就解決了。是的,接下來我們要做的就是這個,在終端上擷取 IP 的指令是(Linux和Mac OS):
ifconfig
:

但是這樣會擷取到一堆資訊,我們需要的隻是一個 IP。通過下面的指令,我們可以擷取到我們要的那一行資訊:
ifconfig | grep inet\\ | tail -1
通過
grep
指令可以進行文本的檢索,再通過
tail -【number】
指令來從文本末尾開始選擇要顯示的行數(預設是10行),我們隻要一行,然後從這一行中再取出 IP。 最後通過指令:
ifconfig | grep inet\\ | tail -1 | cut -d " " -f 2
即可擷取到最終想要的 IP 了。
其中,
cut -d " "
表示将文本按空格分割,
-f 2
表示顯示分割後的第二個元素,也就是 IP 位址了。
好了,現在擷取到 IP 位址了。我們知道,XCode 提供了一個在編譯時運作腳本的功能,如圖:
然後粘貼如下代碼将擷取到的 IP 寫入到 plist 檔案中。
INFOPLIST="${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
echo "writing to $INFOPLIST"
PLISTCMD="Add :SERVER_IP string $(ifconfig | grep inet\\ | tail -1 | cut -d " " -f 2)"
echo -n "$INFOPLIST" | xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD" || true
PLISTCMD="Set :SERVER_IP $(ifconfig | grep inet\\ | tail -1 | cut -d " " -f 2)"
echo -n "$INFOPLIST" | xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD" || true
這樣,每次編譯程式的時候就會将 IP 寫入到 plist 檔案了。
這一步完成後,就可以将前面的 【你的IP】直接從 plist 檔案那取了。如下:
NSString *serverIP = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"SERVER_IP"];
到這,基本就完成了。但是還有個問題:如果我們還想在真機上運作并且在 Chrome 上進行 Debug,那我們還需修改一下 RCTWebSocketExecutor.m 這個檔案。将這個檔案的 init 方法替換成一下代碼即可:
- (instancetype)init
{
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
NSInteger port = [standardDefaults integerForKey:@"websocket-executor-port"] ?: 8081;
#if TARGET_OS_SIMULATOR
NSString *URLString = [NSString stringWithFormat:@"http://localhost:%zd/debugger-proxy", port];
#else
NSString *serverIP = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"SERVER_IP"];
NSString *URLString = [NSString stringWithFormat:@"http://%@:%zd/debugger-proxy", serverIP, port];
#endif
return [self initWithURL:[RCTConvert NSURL:URLString]];
}
##總結##
通過判斷目前運作裝置的宏以及編譯時通過腳本将 IP 寫入 plist 檔案我們就可以實作動态的設定 IP 了,以後我們就不需要反複修改 IP 了。另外,通過
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
的方式運作的時候,我們也可以将打包的指令寫到腳本上,這樣就不用再通過終端去打包了。
##補充##
通過這些天的實踐,出現了一個問題,有時候用
grep
來篩選 IP 的時候,找到的不一定準确,因為我們現在通過
grep
找出 IP 之後,取的是最後個 IP 。而如果這時候我們運作了 android的模拟器就會出現下面的情況:
這時我們使用的就是最後一個 IP,也就是模拟器的 IP 了。實在想不到好的解決方案,是以根據現在的規律,暴力的将指令改成了:
ifconfig | grep 'inet 192' | head -1 | cut -d " " -f 2
,現在是直接檢索 inet 192 然後擷取第一個 IP。由于能力有限,隻能想到這個方法了,如果大家有更好的方法來擷取,可以評論指點下我哈。
參考資料:
http://c.biancheng.net/cpp/view/7005.html
http://www.cnblogs.com/peida/archive/2012/11/07/2758084.html
http://www.jb51.net/article/41872.htm
http://www.cnblogs.com/end/archive/2012/02/21/2360965.html
https://github.com/facebook/react-native/issues/4245
http://moduscreate.com/automated-ip-configuration-for-react-native-development/