1010#import " RCTJavaScriptLoader.h"
1111
1212#import " RCTBridge.h"
13- #import " RCTInvalidating.h"
14- #import " RCTLog.h"
15- #import " RCTRedBox.h"
13+ #import " RCTConvert.h"
1614#import " RCTSourceCode.h"
1715#import " RCTUtils.h"
1816
19- #define NO_REMOTE_MODULE @" Could not fetch module bundle %@ . Ensure node server is running.\n\n If it timed out, try reloading."
20- #define NO_LOCAL_BUNDLE @" Could not load local bundle %@ . Ensure file exists."
21-
22- #define CACHE_DIR @" RCTJSBundleCache"
23-
24- #pragma mark - Application Engine
25-
26- /* *
27- * TODO:
28- * - Add window resize rotation events matching the DOM API.
29- * - Device pixel ration hooks.
30- * - Source maps.
31- */
3217@implementation RCTJavaScriptLoader
3318{
3419 __weak RCTBridge *_bridge;
3520}
3621
37- /* *
38- * `CADisplayLink` code copied from Ejecta but we've placed the JavaScriptCore
39- * engine in its own dedicated thread.
40- *
41- * TODO: Try adding to the `RCTJavaScriptExecutor`'s thread runloop. Removes one
42- * additional GCD dispatch per frame and likely makes it so that other UIThread
43- * operations don't delay the dispatch (so we can begin working in JS much
44- * faster.) Event handling must still be sent via a GCD dispatch, of course.
45- *
46- * We must add the display link to two runloops in order to get setTimeouts to
47- * fire during scrolling. (`NSDefaultRunLoopMode` and `UITrackingRunLoopMode`)
48- * TODO: We can invent a `requestAnimationFrame` and
49- * `requestAvailableAnimationFrame` to control if callbacks can be fired during
50- * an animation.
51- * http://stackoverflow.com/questions/12622800/why-does-uiscrollview-pause-my-cadisplaylink
52- *
53- */
5422- (instancetype )initWithBridge : (RCTBridge *)bridge
5523{
5624 if ((self = [super init ])) {
@@ -61,92 +29,87 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
6129
6230- (void )loadBundleAtURL : (NSURL *)scriptURL onComplete : (void (^)(NSError *))onComplete
6331{
32+ NSURL *originalURL = scriptURL;
33+ if (!scriptURL.scheme || [scriptURL isFileURL ]) {
34+ scriptURL = [RCTConvert NSURL: scriptURL.path];
35+ }
36+
6437 if (scriptURL == nil ) {
6538 NSError *error = [NSError errorWithDomain: @" JavaScriptLoader" code: 1 userInfo: @{
66- NSLocalizedDescriptionKey : @" No script URL provided"
39+ NSLocalizedDescriptionKey : originalURL ? [ NSString stringWithFormat: @" Script URL ' %@ ' could not be found. " , originalURL] : @" No script URL provided. "
6740 }];
6841 onComplete (error);
6942 return ;
7043 }
7144
72- if ([scriptURL isFileURL ]) {
73- NSString *bundlePath = [[NSBundle bundleForClass: [self class ]] resourcePath ];
74- NSString *localPath = [scriptURL.absoluteString substringFromIndex: @" file://" .length];
75-
76- if (![localPath hasPrefix: bundlePath]) {
77- NSString *absolutePath = [NSString stringWithFormat: @" %@ /%@ " , bundlePath, localPath];
78- scriptURL = [NSURL fileURLWithPath: absolutePath];
79- }
80- }
81-
8245 NSURLSessionDataTask *task = [[NSURLSession sharedSession ] dataTaskWithURL: scriptURL completionHandler:
8346 ^(NSData *data, NSURLResponse *response, NSError *error) {
8447
85- // Handle general request errors
86- if (error) {
87- if ([[error domain ] isEqualToString: NSURLErrorDomain ]) {
88- NSString *desc = [@" Could not connect to development server. Ensure node server is running and available on the same network - run 'npm start' from react-native root\n\n URL: " stringByAppendingString: [scriptURL absoluteString ]];
89- NSDictionary *userInfo = @{
90- NSLocalizedDescriptionKey : desc,
91- NSLocalizedFailureReasonErrorKey : [error localizedDescription ],
92- NSUnderlyingErrorKey : error,
93- };
94- error = [NSError errorWithDomain: @" JSServer"
95- code: error.code
96- userInfo: userInfo];
97- }
98- onComplete (error);
99- return ;
100- }
101-
102- // Parse response as text
103- NSStringEncoding encoding = NSUTF8StringEncoding;
104- if (response.textEncodingName != nil ) {
105- CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding ((CFStringRef)response.textEncodingName );
106- if (cfEncoding != kCFStringEncodingInvalidId ) {
107- encoding = CFStringConvertEncodingToNSStringEncoding (cfEncoding);
108- }
109- }
110- NSString *rawText = [[NSString alloc ] initWithData: data encoding: encoding];
111-
112- // Handle HTTP errors
113- if ([response isKindOfClass: [NSHTTPURLResponse class ]] && [(NSHTTPURLResponse *)response statusCode ] != 200 ) {
114- NSDictionary *userInfo;
115- NSDictionary *errorDetails = RCTJSONParse (rawText, nil );
116- if ([errorDetails isKindOfClass: [NSDictionary class ]] &&
117- [errorDetails[@" errors" ] isKindOfClass: [NSArray class ]]) {
118- NSMutableArray *fakeStack = [[NSMutableArray alloc ] init ];
119- for (NSDictionary *err in errorDetails[@" errors" ]) {
120- [fakeStack addObject: @{
121- @" methodName" : err[@" description" ] ?: @" " ,
122- @" file" : err[@" filename" ] ?: @" " ,
123- @" lineNumber" : err[@" lineNumber" ] ?: @0
124- }];
125- }
126- userInfo = @{
127- NSLocalizedDescriptionKey : errorDetails[@" message" ] ?: @" No message provided" ,
128- @" stack" : fakeStack,
129- };
130- } else {
131- userInfo = @{NSLocalizedDescriptionKey : rawText};
132- }
133- error = [NSError errorWithDomain: @" JSServer"
134- code: [(NSHTTPURLResponse *)response statusCode ]
135- userInfo: userInfo];
136-
137- onComplete (error);
138- return ;
139- }
140- RCTSourceCode *sourceCodeModule = _bridge.modules [RCTBridgeModuleNameForClass ([RCTSourceCode class ])];
141- sourceCodeModule.scriptURL = scriptURL;
142- sourceCodeModule.scriptText = rawText;
48+ // Handle general request errors
49+ if (error) {
50+ if ([[error domain ] isEqualToString: NSURLErrorDomain ]) {
51+ NSString *desc = [@" Could not connect to development server. Ensure node server is running and available on the same network - run 'npm start' from react-native root\n\n URL: " stringByAppendingString: [scriptURL absoluteString ]];
52+ NSDictionary *userInfo = @{
53+ NSLocalizedDescriptionKey : desc,
54+ NSLocalizedFailureReasonErrorKey : [error localizedDescription ],
55+ NSUnderlyingErrorKey : error,
56+ };
57+ error = [NSError errorWithDomain: @" JSServer"
58+ code: error.code
59+ userInfo: userInfo];
60+ }
61+ onComplete (error);
62+ return ;
63+ }
14364
144- [_bridge enqueueApplicationScript: rawText url: scriptURL onComplete: ^(NSError *scriptError) {
145- dispatch_async (dispatch_get_main_queue (), ^{
146- onComplete (scriptError);
147- });
148- }];
149- }];
65+ // Parse response as text
66+ NSStringEncoding encoding = NSUTF8StringEncoding;
67+ if (response.textEncodingName != nil ) {
68+ CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding ((CFStringRef)response.textEncodingName );
69+ if (cfEncoding != kCFStringEncodingInvalidId ) {
70+ encoding = CFStringConvertEncodingToNSStringEncoding (cfEncoding);
71+ }
72+ }
73+ NSString *rawText = [[NSString alloc ] initWithData: data encoding: encoding];
74+
75+ // Handle HTTP errors
76+ if ([response isKindOfClass: [NSHTTPURLResponse class ]] && [(NSHTTPURLResponse *)response statusCode ] != 200 ) {
77+ NSDictionary *userInfo;
78+ NSDictionary *errorDetails = RCTJSONParse (rawText, nil );
79+ if ([errorDetails isKindOfClass: [NSDictionary class ]] &&
80+ [errorDetails[@" errors" ] isKindOfClass: [NSArray class ]]) {
81+ NSMutableArray *fakeStack = [[NSMutableArray alloc ] init ];
82+ for (NSDictionary *err in errorDetails[@" errors" ]) {
83+ [fakeStack addObject: @{
84+ @" methodName" : err[@" description" ] ?: @" " ,
85+ @" file" : err[@" filename" ] ?: @" " ,
86+ @" lineNumber" : err[@" lineNumber" ] ?: @0
87+ }];
88+ }
89+ userInfo = @{
90+ NSLocalizedDescriptionKey : errorDetails[@" message" ] ?: @" No message provided" ,
91+ @" stack" : fakeStack,
92+ };
93+ } else {
94+ userInfo = @{NSLocalizedDescriptionKey : rawText};
95+ }
96+ error = [NSError errorWithDomain: @" JSServer"
97+ code: [(NSHTTPURLResponse *)response statusCode ]
98+ userInfo: userInfo];
99+
100+ onComplete (error);
101+ return ;
102+ }
103+ RCTSourceCode *sourceCodeModule = _bridge.modules [RCTBridgeModuleNameForClass ([RCTSourceCode class ])];
104+ sourceCodeModule.scriptURL = scriptURL;
105+ sourceCodeModule.scriptText = rawText;
106+
107+ [_bridge enqueueApplicationScript: rawText url: scriptURL onComplete: ^(NSError *scriptError) {
108+ dispatch_async (dispatch_get_main_queue (), ^{
109+ onComplete (scriptError);
110+ });
111+ }];
112+ }];
150113
151114 [task resume ];
152115}
0 commit comments