Last active
March 19, 2016 15:43
-
-
Save rtfpessoa/9634c898d339239e2289 to your computer and use it in GitHub Desktop.
React native automatic server ip generation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright (c) 2015-present, Facebook, Inc. | |
* All rights reserved. | |
* | |
* This source code is licensed under the BSD-style license found in the | |
* LICENSE file in the root directory of this source tree. An additional grant | |
* of patent rights can be found in the PATENTS file in the same directory. | |
*/ | |
#import "AppDelegate.h" | |
#import "RCTRootView.h" | |
@implementation AppDelegate | |
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions | |
{ | |
NSURL *jsCodeLocation; | |
#if TARGET_OS_SIMULATOR | |
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"]; | |
#else | |
/** | |
* Loading JavaScript code - uncomment the one you want. | |
* | |
* OPTION 1 | |
* Load from development server. Start the server from the repository root: | |
* | |
* $ npm start | |
* | |
* To run on device, change `localhost` to the IP address of your computer | |
* (you can get this by typing `ifconfig` into the terminal and selecting the | |
* `inet` value under `en0:`) and make sure your computer and iOS device are | |
* on the same Wi-Fi network. | |
*/ | |
NSString *serverIP = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"SERVER_IP"]; | |
NSString *jsCodeUrlString = [NSString stringWithFormat:@"http://%@:8081/index.ios.bundle?platform=ios&dev=true", serverIP]; | |
NSString *jsBundleUrlString = [jsCodeUrlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; | |
jsCodeLocation = [NSURL URLWithString:jsBundleUrlString]; | |
/** | |
* OPTION 2 | |
* Load from pre-bundled file on disk. The static bundle is automatically | |
* generated by "Bundle React Native code and images" build step. | |
*/ | |
// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; | |
#endif | |
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation | |
moduleName:@"ThirdFactor" | |
initialProperties:nil | |
launchOptions:launchOptions]; | |
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright (c) 2015-present, Facebook, Inc. | |
* All rights reserved. | |
* | |
* This source code is licensed under the BSD-style license found in the | |
* LICENSE file in the root directory of this source tree. An additional grant | |
* of patent rights can be found in the PATENTS file in the same directory. | |
*/ | |
#import "RCTDefines.h" | |
#if RCT_DEV // Debug executors are only supported in dev mode | |
#import "RCTWebSocketExecutor.h" | |
#import "RCTConvert.h" | |
#import "RCTLog.h" | |
#import "RCTUtils.h" | |
#import "RCTSRWebSocket.h" | |
typedef void (^RCTWSMessageCallback)(NSError *error, NSDictionary<NSString *, id> *reply); | |
@interface RCTWebSocketExecutor () <RCTSRWebSocketDelegate> | |
@end | |
@implementation RCTWebSocketExecutor | |
{ | |
RCTSRWebSocket *_socket; | |
dispatch_queue_t _jsQueue; | |
NSMutableDictionary<NSNumber *, RCTWSMessageCallback> *_callbacks; | |
dispatch_semaphore_t _socketOpenSemaphore; | |
NSMutableDictionary<NSString *, NSString *> *_injectedObjects; | |
NSURL *_url; | |
} | |
RCT_EXPORT_MODULE() | |
- (instancetype)initWithURL:(NSURL *)URL | |
{ | |
RCTAssertParam(URL); | |
if ((self = [self init])) { | |
_url = URL; | |
} | |
return self; | |
} | |
- (void)setUp | |
{ | |
if (!_url) { | |
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?role=client", port]; | |
#else | |
NSString *serverIP = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"SERVER_IP"]; | |
NSString *URLString = [NSString stringWithFormat:@"http://%@:%zd/debugger-proxy?role=client", serverIP, port]; | |
#endif | |
_url = [RCTConvert NSURL:URLString]; | |
} | |
_jsQueue = dispatch_queue_create("com.facebook.React.WebSocketExecutor", DISPATCH_QUEUE_SERIAL); | |
_socket = [[RCTSRWebSocket alloc] initWithURL:_url]; | |
_socket.delegate = self; | |
_callbacks = [NSMutableDictionary new]; | |
_injectedObjects = [NSMutableDictionary new]; | |
[_socket setDelegateDispatchQueue:_jsQueue]; | |
NSURL *startDevToolsURL = [NSURL URLWithString:@"/launch-chrome-devtools" relativeToURL:_url]; | |
[NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:startDevToolsURL] delegate:nil]; | |
if (![self connectToProxy]) { | |
RCTLogError(@"Connection to %@ timed out. Are you running node proxy? If " | |
"you are running on the device, check if you have the right IP " | |
"address in `RCTWebSocketExecutor.m`.", _url); | |
[self invalidate]; | |
return; | |
} | |
NSInteger retries = 3; | |
BOOL runtimeIsReady = [self prepareJSRuntime]; | |
while (!runtimeIsReady && retries > 0) { | |
runtimeIsReady = [self prepareJSRuntime]; | |
retries--; | |
} | |
if (!runtimeIsReady) { | |
RCTLogError(@"Runtime is not ready for debugging.\n " | |
"- Make sure Packager server is running.\n" | |
"- Make sure Chrome is running and not paused on a breakpoint or exception and try reloading again."); | |
[self invalidate]; | |
return; | |
} | |
} | |
- (BOOL)connectToProxy | |
{ | |
_socketOpenSemaphore = dispatch_semaphore_create(0); | |
[_socket open]; | |
long connected = dispatch_semaphore_wait(_socketOpenSemaphore, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 2)); | |
return connected == 0; | |
} | |
- (BOOL)prepareJSRuntime | |
{ | |
__block NSError *initError; | |
dispatch_semaphore_t s = dispatch_semaphore_create(0); | |
[self sendMessage:@{@"method": @"prepareJSRuntime"} waitForReply:^(NSError *error, NSDictionary<NSString *, id> *reply) { | |
initError = error; | |
dispatch_semaphore_signal(s); | |
}]; | |
long runtimeIsReady = dispatch_semaphore_wait(s, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC)); | |
return runtimeIsReady == 0 && initError == nil; | |
} | |
- (void)webSocket:(RCTSRWebSocket *)webSocket didReceiveMessage:(id)message | |
{ | |
NSError *error = nil; | |
NSDictionary<NSString *, id> *reply = RCTJSONParse(message, &error); | |
NSNumber *messageID = reply[@"replyID"]; | |
RCTWSMessageCallback callback = _callbacks[messageID]; | |
if (callback) { | |
callback(error, reply); | |
} | |
} | |
- (void)webSocketDidOpen:(RCTSRWebSocket *)webSocket | |
{ | |
dispatch_semaphore_signal(_socketOpenSemaphore); | |
} | |
- (void)webSocket:(RCTSRWebSocket *)webSocket didFailWithError:(NSError *)error | |
{ | |
dispatch_semaphore_signal(_socketOpenSemaphore); | |
dispatch_async(dispatch_get_main_queue(), ^{ | |
// Give the setUp method an opportunity to report an error first | |
RCTLogError(@"WebSocket connection failed with error %@", error); | |
}); | |
} | |
- (void)sendMessage:(NSDictionary<NSString *, id> *)message waitForReply:(RCTWSMessageCallback)callback | |
{ | |
static NSUInteger lastID = 10000; | |
dispatch_async(_jsQueue, ^{ | |
if (!self.valid) { | |
NSError *error = [NSError errorWithDomain:@"WS" code:1 userInfo:@{ | |
NSLocalizedDescriptionKey: @"Runtime is not ready for debugging. Make sure Packager server is running." | |
}]; | |
callback(error, nil); | |
return; | |
} | |
NSNumber *expectedID = @(lastID++); | |
_callbacks[expectedID] = [callback copy]; | |
NSMutableDictionary<NSString *, id> *messageWithID = [message mutableCopy]; | |
messageWithID[@"id"] = expectedID; | |
[_socket send:RCTJSONStringify(messageWithID, NULL)]; | |
}); | |
} | |
- (void)executeApplicationScript:(NSData *)script sourceURL:(NSURL *)URL onComplete:(RCTJavaScriptCompleteBlock)onComplete | |
{ | |
NSDictionary<NSString *, id> *message = @{ | |
@"method": @"executeApplicationScript", | |
@"url": RCTNullIfNil(URL.absoluteString), | |
@"inject": _injectedObjects, | |
}; | |
[self sendMessage:message waitForReply:^(NSError *error, NSDictionary<NSString *, id> *reply) { | |
onComplete(error); | |
}]; | |
} | |
- (void)flushedQueue:(RCTJavaScriptCallback)onComplete | |
{ | |
[self _executeJSCall:@"flushedQueue" arguments:@[] callback:onComplete]; | |
} | |
- (void)callFunctionOnModule:(NSString *)module | |
method:(NSString *)method | |
arguments:(NSArray *)args | |
callback:(RCTJavaScriptCallback)onComplete | |
{ | |
[self _executeJSCall:@"callFunctionReturnFlushedQueue" arguments:@[module, method, args] callback:onComplete]; | |
} | |
- (void)invokeCallbackID:(NSNumber *)cbID | |
arguments:(NSArray *)args | |
callback:(RCTJavaScriptCallback)onComplete | |
{ | |
[self _executeJSCall:@"invokeCallbackAndReturnFlushedQueue" arguments:@[cbID, args] callback:onComplete]; | |
} | |
- (void)_executeJSCall:(NSString *)method arguments:(NSArray *)arguments callback:(RCTJavaScriptCallback)onComplete | |
{ | |
RCTAssert(onComplete != nil, @"callback was missing for exec JS call"); | |
NSDictionary<NSString *, id> *message = @{ | |
@"method": method, | |
@"arguments": arguments | |
}; | |
[self sendMessage:message waitForReply:^(NSError *socketError, NSDictionary<NSString *, id> *reply) { | |
if (socketError) { | |
onComplete(nil, socketError); | |
return; | |
} | |
NSString *result = reply[@"result"]; | |
id objcValue = RCTJSONParse(result, NULL); | |
onComplete(objcValue, nil); | |
}]; | |
} | |
- (void)injectJSONText:(NSString *)script asGlobalObjectNamed:(NSString *)objectName callback:(RCTJavaScriptCompleteBlock)onComplete | |
{ | |
dispatch_async(_jsQueue, ^{ | |
_injectedObjects[objectName] = script; | |
onComplete(nil); | |
}); | |
} | |
- (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block | |
{ | |
RCTExecuteOnMainThread(block, NO); | |
} | |
- (void)executeAsyncBlockOnJavaScriptQueue:(dispatch_block_t)block | |
{ | |
dispatch_async(dispatch_get_main_queue(), block); | |
} | |
- (void)invalidate | |
{ | |
_socket.delegate = nil; | |
[_socket closeWithCode:1000 reason:@"Invalidated"]; | |
_socket = nil; | |
} | |
- (BOOL)isValid | |
{ | |
return _socket != nil && _socket.readyState == RCTSR_OPEN; | |
} | |
- (void)dealloc | |
{ | |
RCTAssert(!self.valid, @"-invalidate must be called before -dealloc"); | |
} | |
@end | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
echo "Writing server ip to $info_plist" | |
info_plist="${TARGET_BUILD_DIR}/${INFOPLIST_PATH}" | |
server_ip=$(ifconfig en0 | grep 'inet ' | awk '{print $2}') | |
plist_cmd_add="Add :SERVER_IP string $server_ip" | |
plist_cmd_set="Set :SERVER_IP $server_ip" | |
echo -n "$info_plist" | xargs -0 /usr/libexec/PlistBuddy -c "$plist_cmd_add" || true | |
echo -n "$info_plist" | xargs -0 /usr/libexec/PlistBuddy -c "$plist_cmd_set" || true | |
echo "Server ip was written successfully to $info_plist" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment