天天看點

React-Native頻繁修改IP,煩嗎

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

React-Native頻繁修改IP,煩嗎

但是這樣會擷取到一堆資訊,我們需要的隻是一個 IP。通過下面的指令,我們可以擷取到我們要的那一行資訊:

ifconfig | grep inet\\ | tail -1

React-Native頻繁修改IP,煩嗎

通過

grep

指令可以進行文本的檢索,再通過

tail -【number】

指令來從文本末尾開始選擇要顯示的行數(預設是10行),我們隻要一行,然後從這一行中再取出 IP。 最後通過指令:

ifconfig | grep inet\\ | tail -1 | cut -d " " -f 2

即可擷取到最終想要的 IP 了。

React-Native頻繁修改IP,煩嗎

其中,

cut -d " "

表示将文本按空格分割,

-f 2

表示顯示分割後的第二個元素,也就是 IP 位址了。

好了,現在擷取到 IP 位址了。我們知道,XCode 提供了一個在編譯時運作腳本的功能,如圖:

React-Native頻繁修改IP,煩嗎

然後粘貼如下代碼将擷取到的 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
           
React-Native頻繁修改IP,煩嗎

這樣,每次編譯程式的時候就會将 IP 寫入到 plist 檔案了。

React-Native頻繁修改IP,煩嗎

這一步完成後,就可以将前面的 【你的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的模拟器就會出現下面的情況:

React-Native頻繁修改IP,煩嗎

這時我們使用的就是最後一個 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/