Refactor hot loading implementation on iOS

Reviewed By: milend

Differential Revision: D2795580

fb-gh-sync-id: ad33ba152e40b622b10bfa0122afd6edc28a11bf
This commit is contained in:
Nick Lockwood
2016-01-04 10:39:07 -08:00
committed by facebook-github-bot-9
parent 54f2586735
commit ed4478a4ff
15 changed files with 193 additions and 145 deletions

View File

@@ -440,6 +440,16 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
object:_parentBridge userInfo:@{@"bridge": self}];
});
}];
#if RCT_DEV
if (RCTGetURLQueryParam(self.bundleURL, @"hot")) {
NSString *path = [self.bundleURL.path substringFromIndex:1]; // strip initial slash
[self enqueueJSCall:@"HMRClient.enable" args:@[@"ios", path]];
}
#endif
}
- (void)didFinishLoading

View File

@@ -41,6 +41,11 @@
*/
@property (nonatomic, copy, readonly) RCTBridgeModuleProviderBlock moduleProvider;
/**
* Used by RCTDevMenu to override the `hot` param of the current bundleURL.
*/
@property (nonatomic, strong, readwrite) NSURL *bundleURL;
@end
@interface RCTBridge (RCTBatchedBridge)

View File

@@ -123,11 +123,11 @@ RCT_EXTERN BOOL RCTBridgeModuleClassIsRegistered(Class);
/**
* URL of the script that was loaded into the bridge.
*/
@property (nonatomic, strong) NSURL *bundleURL;
@property (nonatomic, strong, readonly) NSURL *bundleURL;
/**
* The class of the executor currently being used *or* to be used after the next
* reload.
* The class of the executor currently being used. Changes to this value will
* take effect after the bridge is reloaded.
*/
@property (nonatomic, strong) Class executorClass;

View File

@@ -17,7 +17,6 @@
#import "RCTLog.h"
#import "RCTPerformanceLogger.h"
#import "RCTUtils.h"
#import "RCTBundleURLProcessor.h"
NSString *const RCTReloadNotification = @"RCTReloadNotification";
NSString *const RCTJavaScriptWillStartLoadingNotification = @"RCTJavaScriptWillStartLoadingNotification";
@@ -88,6 +87,9 @@ BOOL RCTBridgeModuleClassIsRegistered(Class cls)
}
@implementation RCTBridge
{
NSURL *_delegateBundleURL;
}
dispatch_queue_t RCTJSThread;
@@ -257,8 +259,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
{
RCTAssertMainThread();
_bundleURL = [self.delegate sourceURLForBridge:self] ?: _bundleURL;
_bundleURL = [[RCTBundleURLProcessor sharedProcessor] process: _bundleURL];
// Only update bundleURL from delegate if delegate bundleURL has changed
NSURL *previousDelegateURL = _delegateBundleURL;
_delegateBundleURL = [self.delegate sourceURLForBridge:self];
if (_delegateBundleURL && ![_delegateBundleURL isEqual:previousDelegateURL]) {
_bundleURL = _delegateBundleURL;
}
// Sanitize the bundle URL
_bundleURL = [RCTConvert NSURL:_bundleURL.absoluteString];

View File

@@ -48,9 +48,9 @@ typedef void (^RCTSourceLoadBlock)(NSError *error, NSData *source);
withBlock:(RCTSourceLoadBlock)loadCallback;
/**
* Indicates wheather Hot Loading is supported or not.
* Note this method will get removed soon, once we support Hot Loading on OSS.
* Indicates whether Hot Loading is supported or not.
* Note: this method will be removed soon, once Hot Loading is supported on OSS.
*/
- (BOOL)isHotLoadingEnabled;
- (BOOL)bridgeSupportsHotLoading:(RCTBridge *)bridge;
@end

View File

@@ -1,18 +0,0 @@
/**
* 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.
*/
@interface RCTBundleURLProcessor : NSObject
+ (id)sharedProcessor;
- (NSString *)getQueryStringValue:(NSString *)attribute;
- (void)setQueryStringValue:(NSString *)value forAttribute:(NSString *)attribute;
- (NSURL *)process:(NSURL *)url;
@end

View File

@@ -1,73 +0,0 @@
/**
* 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 <Foundation/Foundation.h>
#import "RCTBundleURLProcessor.h"
@implementation RCTBundleURLProcessor
NSDictionary *_qsAttributes;
+ (id)sharedProcessor
{
static RCTBundleURLProcessor *sharedProcessor = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedProcessor = [self new];
});
return sharedProcessor;
}
- (instancetype)init
{
// dictionary with additional query string attributes that will get appended
// to the bundle URL
_qsAttributes = [NSMutableDictionary new];
return self;
}
- (NSString *)getQueryStringValue:(NSString *)attribute
{
return [_qsAttributes valueForKey:attribute];
}
- (void)setQueryStringValue:(NSString *)value forAttribute:(NSString *)attribute
{
[_qsAttributes setValue:value forKey:attribute];
}
- (NSURL *)process:(NSURL *)url
{
if (url.isFileURL || [_qsAttributes count] == 0) {
return url;
}
// append either `?` or `&` depending on whether there are query string
// attibutes or not.
NSString *urlString = url.absoluteString;
if ([urlString rangeOfString:@"?"].location == NSNotFound) {
urlString = [urlString stringByAppendingString:@"?"];
} else {
urlString = [urlString stringByAppendingString:@"&"];
}
// array with new query string attributes
NSMutableArray *parts = [NSMutableArray new];
for (id attribute in _qsAttributes) {
if ([urlString rangeOfString:[NSString stringWithFormat:@"%@=", attribute]].location != NSNotFound) {
[NSException raise:@"Cannot override attribute" format:@"Attribute %@ is already present in url: %@", attribute, url.absoluteString];
}
[parts addObject:[NSString stringWithFormat:@"%@=%@", attribute, _qsAttributes[attribute]]];
}
return [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", urlString, [parts componentsJoinedByString:@"&"]]];
}
@end

View File

@@ -105,3 +105,7 @@ RCT_EXTERN NSString *RCTColorToHexString(CGColorRef color);
// Get standard localized string (if it exists)
RCT_EXTERN NSString *RCTUIKitLocalizedString(NSString *string);
// URL manipulation
RCT_EXTERN NSString *RCTGetURLQueryParam(NSURL *URL, NSString *param);
RCT_EXTERN NSURL *RCTURLByReplacingQueryParam(NSURL *URL, NSString *param, NSString *value);

View File

@@ -576,10 +576,53 @@ NSString *RCTColorToHexString(CGColorRef color)
}
}
// (https://github.com/0xced/XCDFormInputAccessoryView/blob/master/XCDFormInputAccessoryView/XCDFormInputAccessoryView.m#L10-L14)
RCT_EXTERN NSString *RCTUIKitLocalizedString(NSString *string)
NSString *RCTUIKitLocalizedString(NSString *string)
{
NSBundle *UIKitBundle = [NSBundle bundleForClass:[UIApplication class]];
return UIKitBundle ? [UIKitBundle localizedStringForKey:string value:string table:nil] : string;
}
NSString *RCTGetURLQueryParam(NSURL *URL, NSString *param)
{
RCTAssertParam(param);
if (!URL) {
return nil;
}
NSURLComponents *components = [NSURLComponents componentsWithURL:URL
resolvingAgainstBaseURL:YES];
for (NSURLQueryItem *item in components.queryItems.reverseObjectEnumerator) {
if ([item.name isEqualToString:param]) {
return item.value;
}
}
return nil;
}
NSURL *RCTURLByReplacingQueryParam(NSURL *URL, NSString *param, NSString *value)
{
RCTAssertParam(param);
if (!URL) {
return nil;
}
NSURLComponents *components = [NSURLComponents componentsWithURL:URL
resolvingAgainstBaseURL:YES];
__block NSInteger paramIndex = NSNotFound;
NSMutableArray *queryItems = [components.queryItems mutableCopy];
[queryItems enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:
^(NSURLQueryItem *item, NSUInteger i, BOOL *stop) {
if ([item.name isEqualToString:param]) {
paramIndex = i;
*stop = YES;
}
}];
NSURLQueryItem *newItem = [NSURLQueryItem queryItemWithName:param value:value];
if (paramIndex == NSNotFound) {
[queryItems addObject:newItem];
} else {
[queryItems replaceObjectAtIndex:paramIndex withObject:newItem];
}
components.queryItems = queryItems;
return components.URL;
}