diff --git a/Examples/UIExplorer/UIExplorer/AppDelegate.m b/Examples/UIExplorer/UIExplorer/AppDelegate.m index c25414370..9b6bc835f 100644 --- a/Examples/UIExplorer/UIExplorer/AppDelegate.m +++ b/Examples/UIExplorer/UIExplorer/AppDelegate.m @@ -9,6 +9,7 @@ #import "AppDelegate.h" +#import "RCTDevelopmentViewController.h" #import "RCTRootView.h" @implementation AppDelegate @@ -41,7 +42,7 @@ rootView.moduleName = @"UIExplorerApp"; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - UIViewController *rootViewController = [[UIViewController alloc] init]; + UIViewController *rootViewController = [[RCTDevelopmentViewController alloc] init]; rootViewController.view = rootView; self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; diff --git a/ReactKit/Base/RCTDevelopmentViewController.h b/ReactKit/Base/RCTDevelopmentViewController.h new file mode 100644 index 000000000..029f45f60 --- /dev/null +++ b/ReactKit/Base/RCTDevelopmentViewController.h @@ -0,0 +1,14 @@ +/** + * 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 + +@interface RCTDevelopmentViewController : UIViewController + +@end diff --git a/ReactKit/Base/RCTDevelopmentViewController.m b/ReactKit/Base/RCTDevelopmentViewController.m new file mode 100644 index 000000000..9b414b14f --- /dev/null +++ b/ReactKit/Base/RCTDevelopmentViewController.m @@ -0,0 +1,89 @@ +/** + * 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 "RCTDevelopmentViewController.h" + +#import "RCTRedBox.h" +#import "RCTRootView.h" + +@interface RCTDevelopmentViewController () { + BOOL _liveReload; +} + +@property (nonatomic, readonly) RCTRootView *RCTView; + +@end + +@implementation RCTDevelopmentViewController + +- (BOOL)canBecomeFirstResponder +{ + return YES; +} + +- (RCTRootView *)RCTView +{ + return (RCTRootView *)self.view; +} + +- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event +{ + if (motion == UIEventSubtypeMotionShake) + { + NSString *debugTitle = self.RCTView.executorClass == nil ? @"Enable Debugging" : @"Disable Debugging"; + NSString *liveReloadTitle = _liveReload ? @"Disable Live Reload" : @"Enable Live Reload"; + UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"React Native: Development" + delegate:self + cancelButtonTitle:@"Cancel" + destructiveButtonTitle:nil + otherButtonTitles:@"Reload", debugTitle, liveReloadTitle, nil]; + actionSheet.actionSheetStyle = UIBarStyleBlack; + [actionSheet showInView:self.view]; + } +} + +- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex +{ + if (buttonIndex == 0) { + [self.RCTView reload]; + } else if (buttonIndex == 1) { + self.RCTView.executorClass = self.RCTView.executorClass == nil ? NSClassFromString(@"RCTWebSocketExecutor") : nil; + [self.RCTView reload]; + } else if (buttonIndex == 2) { + _liveReload = !_liveReload; + [self _pollAndReload]; + } +} + +- (void)_pollAndReload +{ + if (_liveReload) { + NSURL *url = [self.RCTView scriptURL]; + NSURL *longPollURL = [[NSURL alloc] initWithString:@"/onchange" relativeToURL:url]; + [self performSelectorInBackground:@selector(_checkForUpdates:) withObject:longPollURL]; + } +} + +- (void)_checkForUpdates:(NSURL *)URL +{ + NSMutableURLRequest *longPollRequest = [NSMutableURLRequest requestWithURL:URL]; + longPollRequest.timeoutInterval = 30; + NSHTTPURLResponse *response; + [NSURLConnection sendSynchronousRequest:longPollRequest returningResponse:&response error:nil]; + + dispatch_async(dispatch_get_main_queue(), ^{ + if (_liveReload && response.statusCode == 205) { + [[RCTRedBox sharedInstance] dismiss]; + [self.RCTView reload]; + } + [self _pollAndReload]; + }); +} + +@end diff --git a/ReactKit/ReactKit.xcodeproj/project.pbxproj b/ReactKit/ReactKit.xcodeproj/project.pbxproj index 234793aed..c742711d8 100644 --- a/ReactKit/ReactKit.xcodeproj/project.pbxproj +++ b/ReactKit/ReactKit.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 000E6CEB1AB0E980000CDF4D /* RCTSourceCode.m in Sources */ = {isa = PBXBuildFile; fileRef = 000E6CEA1AB0E980000CDF4D /* RCTSourceCode.m */; }; + 00C1A2B31AC0B7E000E89A1C /* RCTDevelopmentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 00C1A2B21AC0B7E000E89A1C /* RCTDevelopmentViewController.m */; }; 134FCB361A6D42D900051CC8 /* RCTSparseArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 83BEE46D1A6D19BC00B5863B /* RCTSparseArray.m */; }; 134FCB3D1A6E7F0800051CC8 /* RCTContextExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */; }; 134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3C1A6E7F0800051CC8 /* RCTWebViewExecutor.m */; }; @@ -76,6 +77,8 @@ /* Begin PBXFileReference section */ 000E6CE91AB0E97F000CDF4D /* RCTSourceCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSourceCode.h; sourceTree = ""; }; 000E6CEA1AB0E980000CDF4D /* RCTSourceCode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSourceCode.m; sourceTree = ""; }; + 00C1A2B11AC0B7E000E89A1C /* RCTDevelopmentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDevelopmentViewController.h; sourceTree = ""; }; + 00C1A2B21AC0B7E000E89A1C /* RCTDevelopmentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevelopmentViewController.m; sourceTree = ""; }; 13442BF21AA90E0B0037E5B0 /* RCTAnimationType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAnimationType.h; sourceTree = ""; }; 13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPointerEvents.h; sourceTree = ""; }; 13442BF41AA90E0B0037E5B0 /* RCTViewControllerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTViewControllerProtocol.h; sourceTree = ""; }; @@ -365,6 +368,8 @@ 83CBBA591A601E9000E9B192 /* RCTRedBox.m */, 830A229C1A66C68A008503DA /* RCTRootView.h */, 830A229D1A66C68A008503DA /* RCTRootView.m */, + 00C1A2B11AC0B7E000E89A1C /* RCTDevelopmentViewController.h */, + 00C1A2B21AC0B7E000E89A1C /* RCTDevelopmentViewController.m */, 83BEE46C1A6D19BC00B5863B /* RCTSparseArray.h */, 83BEE46D1A6D19BC00B5863B /* RCTSparseArray.m */, 83CBBA961A6020BB00E9B192 /* RCTTouchHandler.h */, @@ -494,6 +499,7 @@ 13B0801A1A69489C00A75B9A /* RCTNavigator.m in Sources */, 830BA4551A8E3BDA00D53203 /* RCTCache.m in Sources */, 137327E71AA5CF210034F82E /* RCTTabBar.m in Sources */, + 00C1A2B31AC0B7E000E89A1C /* RCTDevelopmentViewController.m in Sources */, 14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */, 134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */, 13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */,