|
1 | 1 | #if defined(__has_include) |
2 | 2 | #if __has_include("CDVWKWebViewEngine.h") |
3 | 3 |
|
| 4 | +#import <Cordova/NSDictionary+CordovaPreferences.h> |
4 | 5 | #import "CDVWKWebViewEngine.h" |
5 | | -#import "WebViewShared.h" |
| 6 | +#import "CodePush.h" |
6 | 7 |
|
7 | 8 | @implementation CDVWKWebViewEngine (CodePush) |
8 | 9 |
|
| 10 | +NSString* const IdentifierCodePushPath = @"codepush/deploy/versions"; |
9 | 11 | NSString* lastLoadedURL = @""; |
10 | 12 |
|
11 | 13 | #pragma clang diagnostic push |
12 | 14 | #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" |
13 | 15 |
|
14 | 16 | - (id)loadRequest:(NSURLRequest *)request { |
15 | 17 | lastLoadedURL = request.URL.absoluteString; |
16 | | - WebViewShared* webViewShared = [WebViewShared getInstanceOrCreate:self.webViewEngine |
17 | | - andCommandDelegate:self.commandDelegate |
18 | | - andViewController:self.viewController]; |
19 | | - return [webViewShared loadRequest:request]; |
| 18 | + NSURL *readAccessURL; |
| 19 | + |
| 20 | + NSURL* bundleURL = [[NSBundle mainBundle] bundleURL]; |
| 21 | + if (![lastLoadedURL containsString:bundleURL.path] && ![lastLoadedURL containsString:IdentifierCodePushPath]) { |
| 22 | + return [self loadPluginRequest:request]; |
| 23 | + } |
| 24 | + |
| 25 | + if (request.URL.isFileURL) { |
| 26 | + // All file URL requests should be handled with the setServerBasePath in case if it is Ionic app. |
| 27 | + if ([CodePush hasIonicWebViewEngine: self]) { |
| 28 | + NSString* specifiedServerPath = [CodePush getCurrentServerBasePath]; |
| 29 | + if (![specifiedServerPath containsString:IdentifierCodePushPath] || [request.URL.path containsString:IdentifierCodePushPath]) { |
| 30 | + [CodePush setServerBasePath:request.URL.path webView: self]; |
| 31 | + } |
| 32 | + |
| 33 | + return nil; |
| 34 | + } |
| 35 | + |
| 36 | + if ([request.URL.absoluteString containsString:IdentifierCodePushPath]) { |
| 37 | + // If the app is attempting to load a CodePush update, then we can lock the WebView down to |
| 38 | + // just the CodePush "versions" directory. This prevents non-CodePush assets from being accessible, |
| 39 | + // while still allowing us to navigate to a future update, as well as to the binary if a rollback is needed. |
| 40 | + NSString *libraryPath = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0]; |
| 41 | + readAccessURL = [NSURL fileURLWithPathComponents:@[libraryPath, @"NoCloud", @"codepush", @"deploy", @"versions"]]; |
| 42 | + } else { |
| 43 | + // In order to allow the WebView to be navigated from the app bundle to another location, we (for some |
| 44 | + // entirely unknown reason) need to ensure that the "read access URL" is set to the parent of the bundle |
| 45 | + // as opposed to the www folder, which is what the WKWebViewEngine would attempt to set it to by default. |
| 46 | + // If we didn't set this, then the attempt to navigate from the bundle to a CodePush update would fail. |
| 47 | + readAccessURL = [[[NSBundle mainBundle] bundleURL] URLByDeletingLastPathComponent]; |
| 48 | + } |
| 49 | + |
| 50 | + return [(WKWebView*)self.engineWebView loadFileURL:request.URL allowingReadAccessToURL:readAccessURL]; |
| 51 | + } else { |
| 52 | + return [(WKWebView*)self.engineWebView loadRequest: request]; |
| 53 | + } |
| 54 | +} |
| 55 | + |
| 56 | +- (id)loadPluginRequest:(NSURLRequest *)request { |
| 57 | + if (request.URL.fileURL) { |
| 58 | + NSDictionary* settings = self.commandDelegate.settings; |
| 59 | + NSString *bind = [settings cordovaSettingForKey:@"Hostname"]; |
| 60 | + if(bind == nil){ |
| 61 | + bind = @"localhost"; |
| 62 | + } |
| 63 | + NSString *scheme = [settings cordovaSettingForKey:@"iosScheme"]; |
| 64 | + if(scheme == nil || [scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"] || [scheme isEqualToString:@"file"]){ |
| 65 | + scheme = @"ionic"; |
| 66 | + } |
| 67 | + NSString *CDV_LOCAL_SERVER = [NSString stringWithFormat:@"%@://%@", scheme, bind]; |
| 68 | + |
| 69 | + NSURL* startURL = [NSURL URLWithString:((CDVViewController *)self.viewController).startPage]; |
| 70 | + NSString* startFilePath = [self.commandDelegate pathForResource:[startURL path]]; |
| 71 | + NSURL *url = [[NSURL URLWithString:CDV_LOCAL_SERVER] URLByAppendingPathComponent:request.URL.path]; |
| 72 | + if ([request.URL.path isEqualToString:startFilePath]) { |
| 73 | + url = [NSURL URLWithString:CDV_LOCAL_SERVER]; |
| 74 | + } |
| 75 | + if(request.URL.query) { |
| 76 | + url = [NSURL URLWithString:[@"?" stringByAppendingString:request.URL.query] relativeToURL:url]; |
| 77 | + } |
| 78 | + if(request.URL.fragment) { |
| 79 | + url = [NSURL URLWithString:[@"#" stringByAppendingString:request.URL.fragment] relativeToURL:url]; |
| 80 | + } |
| 81 | + request = [NSURLRequest requestWithURL:url]; |
| 82 | + } |
| 83 | + return [(WKWebView*)self.engineWebView loadRequest:request]; |
20 | 84 | } |
21 | 85 |
|
22 | 86 | #pragma clang diagnostic pop |
23 | 87 |
|
24 | 88 | // Fix bug related to unable WKWebView recovery after reinit with loaded codepush update |
25 | 89 | - (void)webView:(WKWebView*)theWebView didFailNavigation:(WKNavigation*)navigation withError:(NSError*)error { |
26 | 90 | // NSURLErrorFailingURLStringErrorKey is URL which caused a load to fail, if it's null then webView was terminated for some reason |
27 | | - if ([[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey] == nil && [lastLoadedURL containsString:[WebViewShared getIdentifierCodePushPath]]) { |
| 91 | + if ([[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey] == nil && [lastLoadedURL containsString:IdentifierCodePushPath]) { |
28 | 92 | NSLog(@"Failed to load webpage with error: %@", [error localizedDescription]); |
29 | 93 | NSLog(@"Trying to reload request with url: %@", lastLoadedURL); |
30 | 94 | // Manually loading codepush start page via loadRequest method of this category |
|
0 commit comments