diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2020-08-31 23:07:20 +0200 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2020-08-31 23:07:20 +0200 |
| commit | 22721a013bdd10d5eb395ba18453585f5f3f1f7f (patch) | |
| tree | 5a920e31d6026ed5dc55265e5fd057febccc50e3 /StoneIsland/platforms/ios/CordovaLib/Classes/Private | |
| parent | d22d51a1ae49680015326857360eb699f31efced (diff) | |
rebuild the ios platform and the plugins
Diffstat (limited to 'StoneIsland/platforms/ios/CordovaLib/Classes/Private')
21 files changed, 990 insertions, 1401 deletions
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.m index 054d655d..175ed398 100644 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.m +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.m @@ -24,16 +24,18 @@ - (NSString*)cdv_JSONString { - NSError* error = nil; - NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self - options:0 - error:&error]; + @autoreleasepool { + NSError* error = nil; + NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self + options:0 + error:&error]; - if (error != nil) { - NSLog(@"NSArray JSONString error: %@", [error localizedDescription]); - return nil; - } else { - return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + if (error != nil) { + NSLog(@"NSArray JSONString error: %@", [error localizedDescription]); + return nil; + } else { + return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + } } } @@ -43,16 +45,18 @@ - (NSString*)cdv_JSONString { - NSError* error = nil; - NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self - options:NSJSONWritingPrettyPrinted - error:&error]; + @autoreleasepool { + NSError* error = nil; + NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self + options:NSJSONWritingPrettyPrinted + error:&error]; - if (error != nil) { - NSLog(@"NSDictionary JSONString error: %@", [error localizedDescription]); - return nil; - } else { - return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + if (error != nil) { + NSLog(@"NSDictionary JSONString error: %@", [error localizedDescription]); + return nil; + } else { + return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + } } } @@ -62,30 +66,34 @@ - (id)cdv_JSONObject { - NSError* error = nil; - id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding] - options:NSJSONReadingMutableContainers - error:&error]; - - if (error != nil) { - NSLog(@"NSString JSONObject error: %@, Malformed Data: %@", [error localizedDescription], self); - } + @autoreleasepool { + NSError* error = nil; + id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding] + options:NSJSONReadingMutableContainers + error:&error]; + + if (error != nil) { + NSLog(@"NSString JSONObject error: %@, Malformed Data: %@", [error localizedDescription], self); + } - return object; + return object; + } } - (id)cdv_JSONFragment { - NSError* error = nil; - id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding] - options:NSJSONReadingAllowFragments - error:&error]; + @autoreleasepool { + NSError* error = nil; + id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding] + options:NSJSONReadingAllowFragments + error:&error]; - if (error != nil) { - NSLog(@"NSString JSONObject error: %@", [error localizedDescription]); - } + if (error != nil) { + NSLog(@"NSString JSONObject error: %@", [error localizedDescription]); + } - return object; + return object; + } } @end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.h index 510b6ebf..f39e066a 100644 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.h +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.h @@ -17,7 +17,7 @@ under the License. */ -#import "CDVPlugin.h" +#import <Cordova/CDVPlugin.h> @interface CDVGestureHandler : CDVPlugin diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.m index 242ac55b..34ed4633 100644 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.m +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.m @@ -37,13 +37,13 @@ self.lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressGestures:)]; self.lpgr.minimumPressDuration = 0.45f; - self.lpgr.allowableMovement = 100.0f; + self.lpgr.allowableMovement = 200.0f; // 0.45 is ok for 'regular longpress', 0.05-0.08 is required for '3D Touch longpress', // but since this will also kill onclick handlers (not ontouchend) it's optional. if ([self.commandDelegate.settings objectForKey:@"suppresses3dtouchgesture"] && [[self.commandDelegate.settings objectForKey:@"suppresses3dtouchgesture"] boolValue]) { - self.lpgr.minimumPressDuration = 0.05f; + self.lpgr.minimumPressDuration = 0.15f; } NSArray *views = self.webView.subviews; @@ -64,11 +64,7 @@ - (void)handleLongPressGestures:(UILongPressGestureRecognizer*)sender { - if ([sender isEqual:self.lpgr]) { - if (sender.state == UIGestureRecognizerStateBegan) { - NSLog(@"Ignoring a longpress in order to suppress the magnifying glass."); - } - } + } @end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.h index f9b0bffa..37dab40b 100644 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.h +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.h @@ -17,7 +17,7 @@ under the License. */ -#import "CDVPlugin.h" +#import <Cordova/CDVPlugin.h> @interface CDVHandleOpenURL : CDVPlugin diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.m index 72199b9c..400cb9de 100644 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.m +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.m @@ -18,7 +18,7 @@ */ #import "CDVHandleOpenURL.h" -#import "CDV.h" +#import <Cordova/CDV.h> @implementation CDVHandleOpenURL diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.h index ee89e1a8..14c6a66d 100644 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.h +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.h @@ -17,8 +17,10 @@ under the License. */ -#import "CDVPlugin.h" -#import "CDVWhitelist.h" +#import <Cordova/CDVPlugin.h> +#import <Cordova/CDVWhitelist.h> + +#define CDVWebViewNavigationType int typedef NS_ENUM(NSInteger, CDVIntentAndNavigationFilterValue) { CDVIntentAndNavigationFilterValueIntentAllowed, @@ -29,6 +31,6 @@ typedef NS_ENUM(NSInteger, CDVIntentAndNavigationFilterValue) { @interface CDVIntentAndNavigationFilter : CDVPlugin <NSXMLParserDelegate> + (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url intentsWhitelist:(CDVWhitelist*)intentsWhitelist navigationsWhitelist:(CDVWhitelist*)navigationsWhitelist; -+ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue; -+ (BOOL)shouldOpenURLRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType; ++ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue; ++ (BOOL)shouldOpenURLRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType; @end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.m index 2b13849f..a098be2b 100644 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.m +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.m @@ -46,7 +46,15 @@ - (void)parserDidStartDocument:(NSXMLParser*)parser { // file: url <allow-navigations> are added by default - self.allowNavigations = [[NSMutableArray alloc] initWithArray:@[ @"file://" ]]; + // navigation to the scheme used by the app is also allowed + self.allowNavigations = [[NSMutableArray alloc] initWithArray:@[ @"file://"]]; + + // If the custom app scheme is defined, append it to the allow navigation as default + NSString* scheme = ((CDVViewController*)self.viewController).appScheme; + if (scheme) { + [self.allowNavigations addObject: [NSString stringWithFormat:@"%@://", scheme]]; + } + // no intents are added by default self.allowIntents = [[NSMutableArray alloc] init]; } @@ -75,10 +83,10 @@ { // a URL can only allow-intent OR allow-navigation, if both are specified, // only allow-navigation is allowed - + BOOL allowNavigationsPass = [navigationsWhitelist URLIsAllowed:url logFailure:NO]; BOOL allowIntentPass = [intentsWhitelist URLIsAllowed:url logFailure:NO]; - + if (allowNavigationsPass && allowIntentPass) { return CDVIntentAndNavigationFilterValueNavigationAllowed; } else if (allowNavigationsPass) { @@ -86,7 +94,7 @@ } else if (allowIntentPass) { return CDVIntentAndNavigationFilterValueIntentAllowed; } - + return CDVIntentAndNavigationFilterValueNoneAllowed; } @@ -95,57 +103,47 @@ return [[self class] filterUrl:url intentsWhitelist:self.allowIntentsWhitelist navigationsWhitelist:self.allowNavigationsWhitelist]; } -+ (BOOL)shouldOpenURLRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType +#define CDVWebViewNavigationTypeLinkClicked 0 +#define CDVWebViewNavigationTypeLinkOther -1 + ++ (BOOL)shouldOpenURLRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType { - return (UIWebViewNavigationTypeLinkClicked == navigationType || - (UIWebViewNavigationTypeOther == navigationType && - [[request.mainDocumentURL absoluteString] isEqualToString:[request.URL absoluteString]] - ) - ); + return ( + navigationType == CDVWebViewNavigationTypeLinkClicked || + navigationType == CDVWebViewNavigationTypeLinkOther + ); } -+ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue ++ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue { NSString* allowIntents_whitelistRejectionFormatString = @"ERROR External navigation rejected - <allow-intent> not set for url='%@'"; NSString* allowNavigations_whitelistRejectionFormatString = @"ERROR Internal navigation rejected - <allow-navigation> not set for url='%@'"; - + NSURL* url = [request URL]; - + switch (filterValue) { case CDVIntentAndNavigationFilterValueNavigationAllowed: return YES; case CDVIntentAndNavigationFilterValueIntentAllowed: - // only allow-intent if it's a UIWebViewNavigationTypeLinkClicked (anchor tag) OR - // it's a UIWebViewNavigationTypeOther, and it's an internal link + // only allow-intent if it's a CDVWebViewNavigationTypeLinkClicked (anchor tag) or CDVWebViewNavigationTypeOther and it's an internal link if ([[self class] shouldOpenURLRequest:request navigationType:navigationType]){ -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 - // CB-11895; openURL with a single parameter is deprecated in iOS 10 - // see https://useyourloaf.com/blog/openurl-deprecated-in-ios10 - if ([[UIApplication sharedApplication] respondsToSelector:@selector(openURL:options:completionHandler:)]) { - [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; - } else { - [[UIApplication sharedApplication] openURL:url]; - } -#else - // fall back if on older SDK - [[UIApplication sharedApplication] openURL:url]; -#endif + [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; } - + // consume the request (i.e. no error) if it wasn't handled above return NO; case CDVIntentAndNavigationFilterValueNoneAllowed: // allow-navigation attempt failed for sure NSLog(@"%@", [NSString stringWithFormat:allowNavigations_whitelistRejectionFormatString, [url absoluteString]]); // anchor tag link means it was an allow-intent attempt that failed as well - if (UIWebViewNavigationTypeLinkClicked == navigationType) { + if (CDVWebViewNavigationTypeLinkClicked == navigationType) { NSLog(@"%@", [NSString stringWithFormat:allowIntents_whitelistRejectionFormatString, [url absoluteString]]); } return NO; } } -- (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType +- (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType { return [[self class] shouldOverrideLoadWithRequest:request navigationType:navigationType filterValue:[self filterUrl:request.URL]]; } diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.h index 6a9ee77e..e973e373 100644 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.h +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.h @@ -17,11 +17,11 @@ under the License. */ -#import "CDVPlugin.h" -#import "CDVWebViewEngineProtocol.h" +#import <Cordova/CDVPlugin.h> -@interface CDVUIWebViewEngine : CDVPlugin <CDVWebViewEngineProtocol> +@interface CDVLaunchScreen : CDVPlugin -@property (nonatomic, strong, readonly) id <UIWebViewDelegate> uiWebViewDelegate; +- (void)show:(CDVInvokedUrlCommand*)command; +- (void)hide:(CDVInvokedUrlCommand*)command; @end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m index d77f1913..9ff062af 100644 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.h +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m @@ -17,25 +17,23 @@ under the License. */ -#import <UIKit/UIKit.h> -#import "CDVAvailability.h" +#import "CDVLaunchScreen.h" +#import <Cordova/CDVViewController.h> -/** - * Distinguishes top-level navigations from sub-frame navigations. - * shouldStartLoadWithRequest is called for every request, but didStartLoad - * and didFinishLoad is called only for top-level navigations. - * Relevant bug: CB-2389 - */ -@interface CDVUIWebViewDelegate : NSObject <UIWebViewDelegate>{ - __weak NSObject <UIWebViewDelegate>* _delegate; - NSInteger _loadCount; - NSInteger _state; - NSInteger _curLoadToken; - NSInteger _loadStartPollCount; -} +@implementation CDVLaunchScreen -- (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate; +- (void)show:(CDVInvokedUrlCommand*)command +{ + if ([self.viewController isKindOfClass:[CDVViewController class]]) { + [(CDVViewController*)self.viewController showLaunchScreen:YES]; + } +} -- (BOOL)request:(NSURLRequest*)newRequest isEqualToRequestAfterStrippingFragments:(NSURLRequest*)originalRequest; +- (void)hide:(CDVInvokedUrlCommand*)command +{ + if ([self.viewController isKindOfClass:[CDVViewController class]]) { + [(CDVViewController*)self.viewController showLaunchScreen:NO]; + } +} @end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLocalStorage/CDVLocalStorage.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLocalStorage/CDVLocalStorage.h deleted file mode 100644 index dec6ab3b..00000000 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLocalStorage/CDVLocalStorage.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVPlugin.h" - -#define kCDVLocalStorageErrorDomain @"kCDVLocalStorageErrorDomain" -#define kCDVLocalStorageFileOperationError 1 - -@interface CDVLocalStorage : CDVPlugin - -@property (nonatomic, readonly, strong) NSMutableArray* backupInfo; - -- (BOOL)shouldBackup; -- (BOOL)shouldRestore; -- (void)backup:(CDVInvokedUrlCommand*)command; -- (void)restore:(CDVInvokedUrlCommand*)command; - -+ (void)__fixupDatabaseLocationsWithBackupType:(NSString*)backupType; -// Visible for testing. -+ (BOOL)__verifyAndFixDatabaseLocationsWithAppPlistDict:(NSMutableDictionary*)appPlistDict - bundlePath:(NSString*)bundlePath - fileManager:(NSFileManager*)fileManager; -@end - -@interface CDVBackupInfo : NSObject - -@property (nonatomic, copy) NSString* original; -@property (nonatomic, copy) NSString* backup; -@property (nonatomic, copy) NSString* label; - -- (BOOL)shouldBackup; -- (BOOL)shouldRestore; - -@end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLocalStorage/CDVLocalStorage.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLocalStorage/CDVLocalStorage.m deleted file mode 100644 index 252dfaf1..00000000 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLocalStorage/CDVLocalStorage.m +++ /dev/null @@ -1,487 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVLocalStorage.h" -#import "CDV.h" - -@interface CDVLocalStorage () - -@property (nonatomic, readwrite, strong) NSMutableArray* backupInfo; // array of CDVBackupInfo objects -@property (nonatomic, readwrite, weak) id <UIWebViewDelegate> webviewDelegate; - -@end - -@implementation CDVLocalStorage - -@synthesize backupInfo, webviewDelegate; - -- (void)pluginInitialize -{ - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResignActive) - name:UIApplicationWillResignActiveNotification object:nil]; - BOOL cloudBackup = [@"cloud" isEqualToString : self.commandDelegate.settings[[@"BackupWebStorage" lowercaseString]]]; - - self.backupInfo = [[self class] createBackupInfoWithCloudBackup:cloudBackup]; -} - -#pragma mark - -#pragma mark Plugin interface methods - -+ (NSMutableArray*)createBackupInfoWithTargetDir:(NSString*)targetDir backupDir:(NSString*)backupDir targetDirNests:(BOOL)targetDirNests backupDirNests:(BOOL)backupDirNests rename:(BOOL)rename -{ - /* - This "helper" does so much work and has so many options it would probably be clearer to refactor the whole thing. - Basically, there are three database locations: - - 1. "Normal" dir -- LIB/<nested dires WebKit/LocalStorage etc>/<normal filenames> - 2. "Caches" dir -- LIB/Caches/<normal filenames> - 3. "Backup" dir -- DOC/Backups/<renamed filenames> - - And between these three, there are various migration paths, most of which only consider 2 of the 3, which is why this helper is based on 2 locations and has a notion of "direction". - */ - NSMutableArray* backupInfo = [NSMutableArray arrayWithCapacity:3]; - - NSString* original; - NSString* backup; - CDVBackupInfo* backupItem; - - // ////////// LOCALSTORAGE - - original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/file__0.localstorage":@"file__0.localstorage"]; - backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")]; - backup = [backup stringByAppendingPathComponent:(rename ? @"localstorage.appdata.db" : @"file__0.localstorage")]; - - backupItem = [[CDVBackupInfo alloc] init]; - backupItem.backup = backup; - backupItem.original = original; - backupItem.label = @"localStorage database"; - - [backupInfo addObject:backupItem]; - - // ////////// WEBSQL MAIN DB - - original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/Databases.db":@"Databases.db"]; - backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")]; - backup = [backup stringByAppendingPathComponent:(rename ? @"websqlmain.appdata.db" : @"Databases.db")]; - - backupItem = [[CDVBackupInfo alloc] init]; - backupItem.backup = backup; - backupItem.original = original; - backupItem.label = @"websql main database"; - - [backupInfo addObject:backupItem]; - - // ////////// WEBSQL DATABASES - - original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/file__0":@"file__0"]; - backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")]; - backup = [backup stringByAppendingPathComponent:(rename ? @"websqldbs.appdata.db" : @"file__0")]; - - backupItem = [[CDVBackupInfo alloc] init]; - backupItem.backup = backup; - backupItem.original = original; - backupItem.label = @"websql databases"; - - [backupInfo addObject:backupItem]; - - return backupInfo; -} - -+ (NSMutableArray*)createBackupInfoWithCloudBackup:(BOOL)cloudBackup -{ - // create backup info from backup folder to caches folder - NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - NSString* cacheFolder = [appLibraryFolder stringByAppendingPathComponent:@"Caches"]; - NSString* backupsFolder = [appDocumentsFolder stringByAppendingPathComponent:@"Backups"]; - - // create the backups folder, if needed - [[NSFileManager defaultManager] createDirectoryAtPath:backupsFolder withIntermediateDirectories:YES attributes:nil error:nil]; - - [self addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:backupsFolder] skip:!cloudBackup]; - - return [self createBackupInfoWithTargetDir:cacheFolder backupDir:backupsFolder targetDirNests:NO backupDirNests:NO rename:YES]; -} - -+ (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL*)URL skip:(BOOL)skip -{ - NSError* error = nil; - BOOL success = [URL setResourceValue:[NSNumber numberWithBool:skip] forKey:NSURLIsExcludedFromBackupKey error:&error]; - - if (!success) { - NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error); - } - return success; -} - -+ (BOOL)copyFrom:(NSString*)src to:(NSString*)dest error:(NSError* __autoreleasing*)error -{ - NSFileManager* fileManager = [NSFileManager defaultManager]; - - if (![fileManager fileExistsAtPath:src]) { - NSString* errorString = [NSString stringWithFormat:@"%@ file does not exist.", src]; - if (error != NULL) { - (*error) = [NSError errorWithDomain:kCDVLocalStorageErrorDomain - code:kCDVLocalStorageFileOperationError - userInfo:[NSDictionary dictionaryWithObject:errorString - forKey:NSLocalizedDescriptionKey]]; - } - return NO; - } - - // generate unique filepath in temp directory - CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault); - CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef); - NSString* tempBackup = [[NSTemporaryDirectory() stringByAppendingPathComponent:(__bridge NSString*)uuidString] stringByAppendingPathExtension:@"bak"]; - CFRelease(uuidString); - CFRelease(uuidRef); - - BOOL destExists = [fileManager fileExistsAtPath:dest]; - - // backup the dest - if (destExists && ![fileManager copyItemAtPath:dest toPath:tempBackup error:error]) { - return NO; - } - - // remove the dest - if (destExists && ![fileManager removeItemAtPath:dest error:error]) { - return NO; - } - - // create path to dest - if (!destExists && ![fileManager createDirectoryAtPath:[dest stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:error]) { - return NO; - } - - // copy src to dest - if ([fileManager copyItemAtPath:src toPath:dest error:error]) { - // success - cleanup - delete the backup to the dest - if ([fileManager fileExistsAtPath:tempBackup]) { - [fileManager removeItemAtPath:tempBackup error:error]; - } - return YES; - } else { - // failure - we restore the temp backup file to dest - [fileManager copyItemAtPath:tempBackup toPath:dest error:error]; - // cleanup - delete the backup to the dest - if ([fileManager fileExistsAtPath:tempBackup]) { - [fileManager removeItemAtPath:tempBackup error:error]; - } - return NO; - } -} - -- (BOOL)shouldBackup -{ - for (CDVBackupInfo* info in self.backupInfo) { - if ([info shouldBackup]) { - return YES; - } - } - - return NO; -} - -- (BOOL)shouldRestore -{ - for (CDVBackupInfo* info in self.backupInfo) { - if ([info shouldRestore]) { - return YES; - } - } - - return NO; -} - -/* copy from webkitDbLocation to persistentDbLocation */ -- (void)backup:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - - NSError* __autoreleasing error = nil; - CDVPluginResult* result = nil; - NSString* message = nil; - - for (CDVBackupInfo* info in self.backupInfo) { - if ([info shouldBackup]) { - [[self class] copyFrom:info.original to:info.backup error:&error]; - - if (callbackId) { - if (error == nil) { - message = [NSString stringWithFormat:@"Backed up: %@", info.label]; - NSLog(@"%@", message); - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:message]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } else { - message = [NSString stringWithFormat:@"Error in CDVLocalStorage (%@) backup: %@", info.label, [error localizedDescription]]; - NSLog(@"%@", message); - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:message]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - } - } - } -} - -/* copy from persistentDbLocation to webkitDbLocation */ -- (void)restore:(CDVInvokedUrlCommand*)command -{ - NSError* __autoreleasing error = nil; - CDVPluginResult* result = nil; - NSString* message = nil; - - for (CDVBackupInfo* info in self.backupInfo) { - if ([info shouldRestore]) { - [[self class] copyFrom:info.backup to:info.original error:&error]; - - if (error == nil) { - message = [NSString stringWithFormat:@"Restored: %@", info.label]; - NSLog(@"%@", message); - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:message]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } else { - message = [NSString stringWithFormat:@"Error in CDVLocalStorage (%@) restore: %@", info.label, [error localizedDescription]]; - NSLog(@"%@", message); - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:message]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } - } - } -} - -+ (void)__fixupDatabaseLocationsWithBackupType:(NSString*)backupType -{ - [self __verifyAndFixDatabaseLocations]; - [self __restoreLegacyDatabaseLocationsWithBackupType:backupType]; -} - -+ (void)__verifyAndFixDatabaseLocations -{ - NSBundle* mainBundle = [NSBundle mainBundle]; - NSString* bundlePath = [[mainBundle bundlePath] stringByDeletingLastPathComponent]; - NSString* bundleIdentifier = [[mainBundle infoDictionary] objectForKey:@"CFBundleIdentifier"]; - NSString* appPlistPath = [bundlePath stringByAppendingPathComponent:[NSString stringWithFormat:@"Library/Preferences/%@.plist", bundleIdentifier]]; - - NSMutableDictionary* appPlistDict = [NSMutableDictionary dictionaryWithContentsOfFile:appPlistPath]; - BOOL modified = [[self class] __verifyAndFixDatabaseLocationsWithAppPlistDict:appPlistDict - bundlePath:bundlePath - fileManager:[NSFileManager defaultManager]]; - - if (modified) { - BOOL ok = [appPlistDict writeToFile:appPlistPath atomically:YES]; - [[NSUserDefaults standardUserDefaults] synchronize]; - NSLog(@"Fix applied for database locations?: %@", ok ? @"YES" : @"NO"); - } -} - -+ (BOOL)__verifyAndFixDatabaseLocationsWithAppPlistDict:(NSMutableDictionary*)appPlistDict - bundlePath:(NSString*)bundlePath - fileManager:(NSFileManager*)fileManager -{ - NSString* libraryCaches = @"Library/Caches"; - NSString* libraryWebKit = @"Library/WebKit"; - - NSArray* keysToCheck = [NSArray arrayWithObjects: - @"WebKitLocalStorageDatabasePathPreferenceKey", - @"WebDatabaseDirectory", - nil]; - - BOOL dirty = NO; - - for (NSString* key in keysToCheck) { - NSString* value = [appPlistDict objectForKey:key]; - // verify key exists, and path is in app bundle, if not - fix - if ((value != nil) && ![value hasPrefix:bundlePath]) { - // the pathSuffix to use may be wrong - OTA upgrades from < 5.1 to 5.1 do keep the old path Library/WebKit, - // while Xcode synced ones do change the storage location to Library/Caches - NSString* newBundlePath = [bundlePath stringByAppendingPathComponent:libraryCaches]; - if (![fileManager fileExistsAtPath:newBundlePath]) { - newBundlePath = [bundlePath stringByAppendingPathComponent:libraryWebKit]; - } - [appPlistDict setValue:newBundlePath forKey:key]; - dirty = YES; - } - } - - return dirty; -} - -+ (void)__restoreLegacyDatabaseLocationsWithBackupType:(NSString*)backupType -{ - // on iOS 6, if you toggle between cloud/local backup, you must move database locations. Default upgrade from iOS5.1 to iOS6 is like a toggle from local to cloud. - NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - - NSMutableArray* backupInfo = [NSMutableArray arrayWithCapacity:0]; - - if ([backupType isEqualToString:@"cloud"]) { -#ifdef DEBUG - NSLog(@"\n\nStarted backup to iCloud! Please be careful." - "\nYour application might be rejected by Apple if you store too much data." - "\nFor more information please read \"iOS Data Storage Guidelines\" at:" - "\nhttps://developer.apple.com/icloud/documentation/data-storage/" - "\nTo disable web storage backup to iCloud, set the BackupWebStorage preference to \"local\" in the Cordova config.xml file\n\n"); -#endif - // We would like to restore old backups/caches databases to the new destination (nested in lib folder) - [backupInfo addObjectsFromArray:[self createBackupInfoWithTargetDir:appLibraryFolder backupDir:[appDocumentsFolder stringByAppendingPathComponent:@"Backups"] targetDirNests:YES backupDirNests:NO rename:YES]]; - [backupInfo addObjectsFromArray:[self createBackupInfoWithTargetDir:appLibraryFolder backupDir:[appLibraryFolder stringByAppendingPathComponent:@"Caches"] targetDirNests:YES backupDirNests:NO rename:NO]]; - } else { - // For ios6 local backups we also want to restore from Backups dir -- but we don't need to do that here, since the plugin will do that itself. - [backupInfo addObjectsFromArray:[self createBackupInfoWithTargetDir:[appLibraryFolder stringByAppendingPathComponent:@"Caches"] backupDir:appLibraryFolder targetDirNests:NO backupDirNests:YES rename:NO]]; - } - - NSFileManager* manager = [NSFileManager defaultManager]; - - for (CDVBackupInfo* info in backupInfo) { - if ([manager fileExistsAtPath:info.backup]) { - if ([info shouldRestore]) { - NSLog(@"Restoring old webstorage backup. From: '%@' To: '%@'.", info.backup, info.original); - [self copyFrom:info.backup to:info.original error:nil]; - } - NSLog(@"Removing old webstorage backup: '%@'.", info.backup); - [manager removeItemAtPath:info.backup error:nil]; - } - } - - [[NSUserDefaults standardUserDefaults] setBool:[backupType isEqualToString:@"cloud"] forKey:@"WebKitStoreWebDataForBackup"]; -} - -#pragma mark - -#pragma mark Notification handlers - -- (void)onResignActive -{ - UIDevice* device = [UIDevice currentDevice]; - NSNumber* exitsOnSuspend = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIApplicationExitsOnSuspend"]; - - BOOL isMultitaskingSupported = [device respondsToSelector:@selector(isMultitaskingSupported)] && [device isMultitaskingSupported]; - - if (exitsOnSuspend == nil) { // if it's missing, it should be NO (i.e. multi-tasking on by default) - exitsOnSuspend = [NSNumber numberWithBool:NO]; - } - - if (exitsOnSuspend) { - [self backup:nil]; - } else if (isMultitaskingSupported) { - __block UIBackgroundTaskIdentifier backgroundTaskID = UIBackgroundTaskInvalid; - - backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ - [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID]; - backgroundTaskID = UIBackgroundTaskInvalid; - NSLog(@"Background task to backup WebSQL/LocalStorage expired."); - }]; - CDVLocalStorage __weak* weakSelf = self; - [self.commandDelegate runInBackground:^{ - [weakSelf backup:nil]; - - [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID]; - backgroundTaskID = UIBackgroundTaskInvalid; - }]; - } -} - -- (void)onAppTerminate -{ - [self onResignActive]; -} - -- (void)onReset -{ - [self restore:nil]; -} - -@end - -#pragma mark - -#pragma mark CDVBackupInfo implementation - -@implementation CDVBackupInfo - -@synthesize original, backup, label; - -- (BOOL)file:(NSString*)aPath isNewerThanFile:(NSString*)bPath -{ - NSFileManager* fileManager = [NSFileManager defaultManager]; - NSError* __autoreleasing error = nil; - - NSDictionary* aPathAttribs = [fileManager attributesOfItemAtPath:aPath error:&error]; - NSDictionary* bPathAttribs = [fileManager attributesOfItemAtPath:bPath error:&error]; - - NSDate* aPathModDate = [aPathAttribs objectForKey:NSFileModificationDate]; - NSDate* bPathModDate = [bPathAttribs objectForKey:NSFileModificationDate]; - - if ((nil == aPathModDate) && (nil == bPathModDate)) { - return NO; - } - - return [aPathModDate compare:bPathModDate] == NSOrderedDescending || bPathModDate == nil; -} - -- (BOOL)item:(NSString*)aPath isNewerThanItem:(NSString*)bPath -{ - NSFileManager* fileManager = [NSFileManager defaultManager]; - - BOOL aPathIsDir = NO, bPathIsDir = NO; - BOOL aPathExists = [fileManager fileExistsAtPath:aPath isDirectory:&aPathIsDir]; - - [fileManager fileExistsAtPath:bPath isDirectory:&bPathIsDir]; - - if (!aPathExists) { - return NO; - } - - if (!(aPathIsDir && bPathIsDir)) { // just a file - return [self file:aPath isNewerThanFile:bPath]; - } - - // essentially we want rsync here, but have to settle for our poor man's implementation - // we get the files in aPath, and see if it is newer than the file in bPath - // (it is newer if it doesn't exist in bPath) if we encounter the FIRST file that is newer, - // we return YES - NSDirectoryEnumerator* directoryEnumerator = [fileManager enumeratorAtPath:aPath]; - NSString* path; - - while ((path = [directoryEnumerator nextObject])) { - NSString* aPathFile = [aPath stringByAppendingPathComponent:path]; - NSString* bPathFile = [bPath stringByAppendingPathComponent:path]; - - BOOL isNewer = [self file:aPathFile isNewerThanFile:bPathFile]; - if (isNewer) { - return YES; - } - } - - return NO; -} - -- (BOOL)shouldBackup -{ - return [self item:self.original isNewerThanItem:self.backup]; -} - -- (BOOL)shouldRestore -{ - return [self item:self.backup isNewerThanItem:self.original]; -} - -@end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLogger/CDVLogger.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLogger/CDVLogger.h index eeba63ca..7cfb3063 100644 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLogger/CDVLogger.h +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLogger/CDVLogger.h @@ -17,7 +17,7 @@ under the License. */ -#import "CDVPlugin.h" +#import <Cordova/CDVPlugin.h> @interface CDVLogger : CDVPlugin diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m deleted file mode 100644 index 67691217..00000000 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m +++ /dev/null @@ -1,399 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -// -// Testing shows: -// -// In all cases, webView.request.URL is the previous page's URL (or empty) during the didStartLoad callback. -// When loading a page with a redirect: -// 1. shouldStartLoading (requestURL is target page) -// 2. didStartLoading -// 3. shouldStartLoading (requestURL is redirect target) -// 4. didFinishLoad (request.URL is redirect target) -// -// Note the lack of a second didStartLoading ** -// -// When loading a page with iframes: -// 1. shouldStartLoading (requestURL is main page) -// 2. didStartLoading -// 3. shouldStartLoading (requestURL is one of the iframes) -// 4. didStartLoading -// 5. didFinishLoad -// 6. didFinishLoad -// -// Note there is no way to distinguish which didFinishLoad maps to which didStartLoad ** -// -// Loading a page by calling window.history.go(-1): -// 1. didStartLoading -// 2. didFinishLoad -// -// Note the lack of a shouldStartLoading call ** -// Actually - this is fixed on iOS6. iOS6 has a shouldStart. ** -// -// Loading a page by calling location.reload() -// 1. shouldStartLoading -// 2. didStartLoading -// 3. didFinishLoad -// -// Loading a page with an iframe that fails to load: -// 1. shouldStart (main page) -// 2. didStart -// 3. shouldStart (iframe) -// 4. didStart -// 5. didFailWithError -// 6. didFinish -// -// Loading a page with an iframe that fails to load due to an invalid URL: -// 1. shouldStart (main page) -// 2. didStart -// 3. shouldStart (iframe) -// 5. didFailWithError -// 6. didFinish -// -// This case breaks our logic since there is a missing didStart. To prevent this, -// we check URLs in shouldStart and return NO if they are invalid. -// -// Loading a page with an invalid URL -// 1. shouldStart (main page) -// 2. didFailWithError -// -// TODO: Record order when page is re-navigated before the first navigation finishes. -// - -#import "CDVUIWebViewDelegate.h" - -// #define VerboseLog NSLog -#define VerboseLog(...) do { \ -} while (0) - -typedef enum { - STATE_IDLE = 0, - STATE_WAITING_FOR_LOAD_START = 1, - STATE_WAITING_FOR_LOAD_FINISH = 2, - STATE_IOS5_POLLING_FOR_LOAD_START = 3, - STATE_IOS5_POLLING_FOR_LOAD_FINISH = 4, - STATE_CANCELLED = 5 -} State; - -static NSString *stripFragment(NSString* url) -{ - NSRange r = [url rangeOfString:@"#"]; - - if (r.location == NSNotFound) { - return url; - } - return [url substringToIndex:r.location]; -} - -@implementation CDVUIWebViewDelegate - -- (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate -{ - self = [super init]; - if (self != nil) { - _delegate = delegate; - _loadCount = -1; - _state = STATE_IDLE; - } - return self; -} - -- (BOOL)request:(NSURLRequest*)newRequest isEqualToRequestAfterStrippingFragments:(NSURLRequest*)originalRequest -{ - if (originalRequest.URL && newRequest.URL) { - NSString* originalRequestUrl = [originalRequest.URL absoluteString]; - NSString* newRequestUrl = [newRequest.URL absoluteString]; - - NSString* baseOriginalRequestUrl = stripFragment(originalRequestUrl); - NSString* baseNewRequestUrl = stripFragment(newRequestUrl); - return [baseOriginalRequestUrl isEqualToString:baseNewRequestUrl]; - } - - return NO; -} - -- (BOOL)isPageLoaded:(UIWebView*)webView -{ - NSString* readyState = [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"]; - - return [readyState isEqualToString:@"loaded"] || [readyState isEqualToString:@"complete"]; -} - -- (BOOL)isJsLoadTokenSet:(UIWebView*)webView -{ - NSString* loadToken = [webView stringByEvaluatingJavaScriptFromString:@"window.__cordovaLoadToken"]; - - return [[NSString stringWithFormat:@"%ld", (long)_curLoadToken] isEqualToString:loadToken]; -} - -- (void)setLoadToken:(UIWebView*)webView -{ - _curLoadToken += 1; - [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.__cordovaLoadToken=%ld", (long)_curLoadToken]]; -} - -- (NSString*)evalForCurrentURL:(UIWebView*)webView -{ - return [webView stringByEvaluatingJavaScriptFromString:@"location.href"]; -} - -- (void)pollForPageLoadStart:(UIWebView*)webView -{ - if (_state != STATE_IOS5_POLLING_FOR_LOAD_START) { - return; - } - if (![self isJsLoadTokenSet:webView]) { - VerboseLog(@"Polled for page load start. result = YES!"); - _state = STATE_IOS5_POLLING_FOR_LOAD_FINISH; - [self setLoadToken:webView]; - if ([_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) { - [_delegate webViewDidStartLoad:webView]; - } - [self pollForPageLoadFinish:webView]; - } else { - VerboseLog(@"Polled for page load start. result = NO"); - // Poll only for 1 second, and then fall back on checking only when delegate methods are called. - ++_loadStartPollCount; - if (_loadStartPollCount < (1000 * .05)) { - [self performSelector:@selector(pollForPageLoadStart:) withObject:webView afterDelay:.05]; - } - } -} - -- (void)pollForPageLoadFinish:(UIWebView*)webView -{ - if (_state != STATE_IOS5_POLLING_FOR_LOAD_FINISH) { - return; - } - if ([self isPageLoaded:webView]) { - VerboseLog(@"Polled for page load finish. result = YES!"); - _state = STATE_IDLE; - if ([_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) { - [_delegate webViewDidFinishLoad:webView]; - } - } else { - VerboseLog(@"Polled for page load finish. result = NO"); - [self performSelector:@selector(pollForPageLoadFinish:) withObject:webView afterDelay:.05]; - } -} - -- (BOOL)shouldLoadRequest:(NSURLRequest*)request -{ - NSString* scheme = [[request URL] scheme]; - NSArray* allowedSchemes = [NSArray arrayWithObjects:@"mailto",@"tel",@"blob",@"sms",@"data", nil]; - if([allowedSchemes containsObject:scheme]) { - return YES; - } - else { - return [NSURLConnection canHandleRequest:request]; - } -} - -- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType -{ - BOOL shouldLoad = YES; - - if ([_delegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) { - shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; - } - - VerboseLog(@"webView shouldLoad=%d (before) state=%d loadCount=%d URL=%@", shouldLoad, _state, _loadCount, request.URL); - - if (shouldLoad) { - // When devtools refresh occurs, it blindly uses the same request object. If a history.replaceState() has occured, then - // mainDocumentURL != URL even though it's a top-level navigation. - BOOL isDevToolsRefresh = (request == webView.request); - BOOL isTopLevelNavigation = isDevToolsRefresh || [request.URL isEqual:[request mainDocumentURL]]; - if (isTopLevelNavigation) { - // Ignore hash changes that don't navigate to a different page. - // webView.request does actually update when history.replaceState() gets called. - if ([self request:request isEqualToRequestAfterStrippingFragments:webView.request]) { - NSString* prevURL = [self evalForCurrentURL:webView]; - if ([prevURL isEqualToString:[request.URL absoluteString]]) { - VerboseLog(@"Page reload detected."); - } else { - VerboseLog(@"Detected hash change shouldLoad"); - return shouldLoad; - } - } - - switch (_state) { - case STATE_WAITING_FOR_LOAD_FINISH: - // Redirect case. - // We expect loadCount == 1. - if (_loadCount != 1) { - NSLog(@"CDVWebViewDelegate: Detected redirect when loadCount=%ld", (long)_loadCount); - } - break; - - case STATE_IDLE: - case STATE_IOS5_POLLING_FOR_LOAD_START: - case STATE_CANCELLED: - // Page navigation start. - _loadCount = 0; - _state = STATE_WAITING_FOR_LOAD_START; - break; - - default: - { - NSString* description = [NSString stringWithFormat:@"CDVWebViewDelegate: Navigation started when state=%ld", (long)_state]; - NSLog(@"%@", description); - _loadCount = 0; - _state = STATE_WAITING_FOR_LOAD_START; - - NSDictionary* errorDictionary = @{NSLocalizedDescriptionKey : description}; - NSError* error = [[NSError alloc] initWithDomain:@"CDVUIWebViewDelegate" code:1 userInfo:errorDictionary]; - [self webView:webView didFailLoadWithError:error]; - } - } - } else { - // Deny invalid URLs so that we don't get the case where we go straight from - // webViewShouldLoad -> webViewDidFailLoad (messes up _loadCount). - shouldLoad = shouldLoad && [self shouldLoadRequest:request]; - } - VerboseLog(@"webView shouldLoad=%d (after) isTopLevelNavigation=%d state=%d loadCount=%d", shouldLoad, isTopLevelNavigation, _state, _loadCount); - } - return shouldLoad; -} - -- (void)webViewDidStartLoad:(UIWebView*)webView -{ - VerboseLog(@"webView didStartLoad (before). state=%d loadCount=%d", _state, _loadCount); - BOOL fireCallback = NO; - switch (_state) { - case STATE_IDLE: - break; - - case STATE_CANCELLED: - fireCallback = YES; - _state = STATE_WAITING_FOR_LOAD_FINISH; - _loadCount += 1; - break; - - case STATE_WAITING_FOR_LOAD_START: - if (_loadCount != 0) { - NSLog(@"CDVWebViewDelegate: Unexpected loadCount in didStart. count=%ld", (long)_loadCount); - } - fireCallback = YES; - _state = STATE_WAITING_FOR_LOAD_FINISH; - _loadCount = 1; - break; - - case STATE_WAITING_FOR_LOAD_FINISH: - _loadCount += 1; - break; - - case STATE_IOS5_POLLING_FOR_LOAD_START: - [self pollForPageLoadStart:webView]; - break; - - case STATE_IOS5_POLLING_FOR_LOAD_FINISH: - [self pollForPageLoadFinish:webView]; - break; - - default: - NSLog(@"CDVWebViewDelegate: Unexpected didStart with state=%ld loadCount=%ld", (long)_state, (long)_loadCount); - } - VerboseLog(@"webView didStartLoad (after). state=%d loadCount=%d fireCallback=%d", _state, _loadCount, fireCallback); - if (fireCallback && [_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) { - [_delegate webViewDidStartLoad:webView]; - } -} - -- (void)webViewDidFinishLoad:(UIWebView*)webView -{ - VerboseLog(@"webView didFinishLoad (before). state=%d loadCount=%d", _state, _loadCount); - BOOL fireCallback = NO; - switch (_state) { - case STATE_IDLE: - break; - - case STATE_WAITING_FOR_LOAD_START: - NSLog(@"CDVWebViewDelegate: Unexpected didFinish while waiting for load start."); - break; - - case STATE_WAITING_FOR_LOAD_FINISH: - if (_loadCount == 1) { - fireCallback = YES; - _state = STATE_IDLE; - } - _loadCount -= 1; - break; - - case STATE_IOS5_POLLING_FOR_LOAD_START: - [self pollForPageLoadStart:webView]; - break; - - case STATE_IOS5_POLLING_FOR_LOAD_FINISH: - [self pollForPageLoadFinish:webView]; - break; - } - VerboseLog(@"webView didFinishLoad (after). state=%d loadCount=%d fireCallback=%d", _state, _loadCount, fireCallback); - if (fireCallback && [_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) { - [_delegate webViewDidFinishLoad:webView]; - } -} - -- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error -{ - VerboseLog(@"webView didFailLoad (before). state=%d loadCount=%d", _state, _loadCount); - BOOL fireCallback = NO; - - switch (_state) { - case STATE_IDLE: - break; - - case STATE_WAITING_FOR_LOAD_START: - if ([error code] == NSURLErrorCancelled) { - _state = STATE_CANCELLED; - } else { - _state = STATE_IDLE; - } - fireCallback = YES; - break; - - case STATE_WAITING_FOR_LOAD_FINISH: - if ([error code] != NSURLErrorCancelled) { - if (_loadCount == 1) { - _state = STATE_IDLE; - fireCallback = YES; - } - _loadCount = -1; - } else { - fireCallback = YES; - _state = STATE_CANCELLED; - _loadCount -= 1; - } - break; - - case STATE_IOS5_POLLING_FOR_LOAD_START: - [self pollForPageLoadStart:webView]; - break; - - case STATE_IOS5_POLLING_FOR_LOAD_FINISH: - [self pollForPageLoadFinish:webView]; - break; - } - VerboseLog(@"webView didFailLoad (after). state=%d loadCount=%d, fireCallback=%d", _state, _loadCount, fireCallback); - if (fireCallback && [_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) { - [_delegate webView:webView didFailLoadWithError:error]; - } -} - -@end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.m deleted file mode 100644 index f571d80a..00000000 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.m +++ /dev/null @@ -1,202 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVUIWebViewEngine.h" -#import "CDVUIWebViewDelegate.h" -#import "CDVUIWebViewNavigationDelegate.h" -#import "NSDictionary+CordovaPreferences.h" - -#import <objc/message.h> - -@interface CDVUIWebViewEngine () - -@property (nonatomic, strong, readwrite) UIView* engineWebView; -@property (nonatomic, strong, readwrite) id <UIWebViewDelegate> uiWebViewDelegate; -@property (nonatomic, strong, readwrite) CDVUIWebViewNavigationDelegate* navWebViewDelegate; - -@end - -@implementation CDVUIWebViewEngine - -@synthesize engineWebView = _engineWebView; - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super init]; - if (self) { - self.engineWebView = [[UIWebView alloc] initWithFrame:frame]; - NSLog(@"Using UIWebView"); - } - - return self; -} - -- (void)pluginInitialize -{ - // viewController would be available now. we attempt to set all possible delegates to it, by default - - UIWebView* uiWebView = (UIWebView*)_engineWebView; - - if ([self.viewController conformsToProtocol:@protocol(UIWebViewDelegate)]) { - self.uiWebViewDelegate = [[CDVUIWebViewDelegate alloc] initWithDelegate:(id <UIWebViewDelegate>)self.viewController]; - uiWebView.delegate = self.uiWebViewDelegate; - } else { - self.navWebViewDelegate = [[CDVUIWebViewNavigationDelegate alloc] initWithEnginePlugin:self]; - self.uiWebViewDelegate = [[CDVUIWebViewDelegate alloc] initWithDelegate:self.navWebViewDelegate]; - uiWebView.delegate = self.uiWebViewDelegate; - } - - [self updateSettings:self.commandDelegate.settings]; -} - -- (void)evaluateJavaScript:(NSString*)javaScriptString completionHandler:(void (^)(id, NSError*))completionHandler -{ - NSString* ret = [(UIWebView*)_engineWebView stringByEvaluatingJavaScriptFromString:javaScriptString]; - - if (completionHandler) { - completionHandler(ret, nil); - } -} - -- (id)loadRequest:(NSURLRequest*)request -{ - [(UIWebView*)_engineWebView loadRequest:request]; - return nil; -} - -- (id)loadHTMLString:(NSString*)string baseURL:(NSURL*)baseURL -{ - [(UIWebView*)_engineWebView loadHTMLString:string baseURL:baseURL]; - return nil; -} - -- (NSURL*)URL -{ - return [[(UIWebView*)_engineWebView request] URL]; -} - -- (BOOL) canLoadRequest:(NSURLRequest*)request -{ - return (request != nil); -} - -- (void)updateSettings:(NSDictionary*)settings -{ - UIWebView* uiWebView = (UIWebView*)_engineWebView; - - uiWebView.scalesPageToFit = [settings cordovaBoolSettingForKey:@"EnableViewportScale" defaultValue:NO]; - uiWebView.allowsInlineMediaPlayback = [settings cordovaBoolSettingForKey:@"AllowInlineMediaPlayback" defaultValue:NO]; - uiWebView.mediaPlaybackRequiresUserAction = [settings cordovaBoolSettingForKey:@"MediaPlaybackRequiresUserAction" defaultValue:YES]; - uiWebView.mediaPlaybackAllowsAirPlay = [settings cordovaBoolSettingForKey:@"MediaPlaybackAllowsAirPlay" defaultValue:YES]; - uiWebView.keyboardDisplayRequiresUserAction = [settings cordovaBoolSettingForKey:@"KeyboardDisplayRequiresUserAction" defaultValue:YES]; - uiWebView.suppressesIncrementalRendering = [settings cordovaBoolSettingForKey:@"SuppressesIncrementalRendering" defaultValue:NO]; - uiWebView.gapBetweenPages = [settings cordovaFloatSettingForKey:@"GapBetweenPages" defaultValue:0.0]; - uiWebView.pageLength = [settings cordovaFloatSettingForKey:@"PageLength" defaultValue:0.0]; - - id prefObj = nil; - - // By default, DisallowOverscroll is false (thus bounce is allowed) - BOOL bounceAllowed = !([settings cordovaBoolSettingForKey:@"DisallowOverscroll" defaultValue:NO]); - - // prevent webView from bouncing - if (!bounceAllowed) { - if ([uiWebView respondsToSelector:@selector(scrollView)]) { - ((UIScrollView*)[uiWebView scrollView]).bounces = NO; - } else { - for (id subview in self.webView.subviews) { - if ([[subview class] isSubclassOfClass:[UIScrollView class]]) { - ((UIScrollView*)subview).bounces = NO; - } - } - } - } - - NSString* decelerationSetting = [settings cordovaSettingForKey:@"UIWebViewDecelerationSpeed"]; - if (![@"fast" isEqualToString:decelerationSetting]) { - [uiWebView.scrollView setDecelerationRate:UIScrollViewDecelerationRateNormal]; - } - - NSInteger paginationBreakingMode = 0; // default - UIWebPaginationBreakingModePage - prefObj = [settings cordovaSettingForKey:@"PaginationBreakingMode"]; - if (prefObj != nil) { - NSArray* validValues = @[@"page", @"column"]; - NSString* prefValue = [validValues objectAtIndex:0]; - - if ([prefObj isKindOfClass:[NSString class]]) { - prefValue = prefObj; - } - - paginationBreakingMode = [validValues indexOfObject:[prefValue lowercaseString]]; - if (paginationBreakingMode == NSNotFound) { - paginationBreakingMode = 0; - } - } - uiWebView.paginationBreakingMode = paginationBreakingMode; - - NSInteger paginationMode = 0; // default - UIWebPaginationModeUnpaginated - prefObj = [settings cordovaSettingForKey:@"PaginationMode"]; - if (prefObj != nil) { - NSArray* validValues = @[@"unpaginated", @"lefttoright", @"toptobottom", @"bottomtotop", @"righttoleft"]; - NSString* prefValue = [validValues objectAtIndex:0]; - - if ([prefObj isKindOfClass:[NSString class]]) { - prefValue = prefObj; - } - - paginationMode = [validValues indexOfObject:[prefValue lowercaseString]]; - if (paginationMode == NSNotFound) { - paginationMode = 0; - } - } - uiWebView.paginationMode = paginationMode; -} - -- (void)updateWithInfo:(NSDictionary*)info -{ - UIWebView* uiWebView = (UIWebView*)_engineWebView; - - id <UIWebViewDelegate> uiWebViewDelegate = [info objectForKey:kCDVWebViewEngineUIWebViewDelegate]; - NSDictionary* settings = [info objectForKey:kCDVWebViewEngineWebViewPreferences]; - - if (uiWebViewDelegate && - [uiWebViewDelegate conformsToProtocol:@protocol(UIWebViewDelegate)]) { - self.uiWebViewDelegate = [[CDVUIWebViewDelegate alloc] initWithDelegate:(id <UIWebViewDelegate>)self.viewController]; - uiWebView.delegate = self.uiWebViewDelegate; - } - - if (settings && [settings isKindOfClass:[NSDictionary class]]) { - [self updateSettings:settings]; - } -} - -// This forwards the methods that are in the header that are not implemented here. -// Both WKWebView and UIWebView implement the below: -// loadHTMLString:baseURL: -// loadRequest: -- (id)forwardingTargetForSelector:(SEL)aSelector -{ - return _engineWebView; -} - -- (UIView*)webView -{ - return self.engineWebView; -} - -@end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.m deleted file mode 100644 index bc56fdde..00000000 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.m +++ /dev/null @@ -1,153 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVUIWebViewNavigationDelegate.h" -#import <Cordova/CDVViewController.h> -#import <Cordova/CDVCommandDelegateImpl.h> -#import <Cordova/CDVUserAgentUtil.h> -#import <objc/message.h> - -@implementation CDVUIWebViewNavigationDelegate - -- (instancetype)initWithEnginePlugin:(CDVPlugin*)theEnginePlugin -{ - self = [super init]; - if (self) { - self.enginePlugin = theEnginePlugin; - } - - return self; -} - -/** - When web application loads Add stuff to the DOM, mainly the user-defined settings from the Settings.plist file, and - the device's data such as device ID, platform version, etc. - */ -- (void)webViewDidStartLoad:(UIWebView*)theWebView -{ - NSLog(@"Resetting plugins due to page load."); - CDVViewController* vc = (CDVViewController*)self.enginePlugin.viewController; - - [vc.commandQueue resetRequestId]; - [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginResetNotification object:self.enginePlugin.webView]]; -} - -/** - Called when the webview finishes loading. This stops the activity view. - */ -- (void)webViewDidFinishLoad:(UIWebView*)theWebView -{ - NSLog(@"Finished load of: %@", theWebView.request.URL); - CDVViewController* vc = (CDVViewController*)self.enginePlugin.viewController; - - // It's safe to release the lock even if this is just a sub-frame that's finished loading. - [CDVUserAgentUtil releaseLock:vc.userAgentLockToken]; - - /* - * Hide the Top Activity THROBBER in the Battery Bar - */ - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; - - [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:self.enginePlugin.webView]]; -} - -- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error -{ - CDVViewController* vc = (CDVViewController*)self.enginePlugin.viewController; - - [CDVUserAgentUtil releaseLock:vc.userAgentLockToken]; - - NSString* message = [NSString stringWithFormat:@"Failed to load webpage with error: %@", [error localizedDescription]]; - NSLog(@"%@", message); - - NSURL* errorUrl = vc.errorURL; - if (errorUrl) { - errorUrl = [NSURL URLWithString:[NSString stringWithFormat:@"?error=%@", [message stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLPathAllowedCharacterSet]] relativeToURL:errorUrl]; - NSLog(@"%@", [errorUrl absoluteString]); - if(error.code != NSURLErrorCancelled) { - [theWebView loadRequest:[NSURLRequest requestWithURL:errorUrl]]; - } - } -} - -- (BOOL)defaultResourcePolicyForURL:(NSURL*)url -{ - /* - * If a URL is being loaded that's a file url, just load it internally - */ - if ([url isFileURL]) { - return YES; - } - - return NO; -} - -- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType -{ - NSURL* url = [request URL]; - CDVViewController* vc = (CDVViewController*)self.enginePlugin.viewController; - - /* - * Execute any commands queued with cordova.exec() on the JS side. - * The part of the URL after gap:// is irrelevant. - */ - if ([[url scheme] isEqualToString:@"gap"]) { - [vc.commandQueue fetchCommandsFromJs]; - // The delegate is called asynchronously in this case, so we don't have to use - // flushCommandQueueWithDelayedJs (setTimeout(0)) as we do with hash changes. - [vc.commandQueue executePending]; - return NO; - } - - /* - * Give plugins the chance to handle the url - */ - BOOL anyPluginsResponded = NO; - BOOL shouldAllowRequest = NO; - - for (NSString* pluginName in vc.pluginObjects) { - CDVPlugin* plugin = [vc.pluginObjects objectForKey:pluginName]; - SEL selector = NSSelectorFromString(@"shouldOverrideLoadWithRequest:navigationType:"); - if ([plugin respondsToSelector:selector]) { - anyPluginsResponded = YES; - shouldAllowRequest = (((BOOL (*)(id, SEL, id, int))objc_msgSend)(plugin, selector, request, navigationType)); - if (!shouldAllowRequest) { - break; - } - } - } - - if (anyPluginsResponded) { - return shouldAllowRequest; - } - - /* - * Handle all other types of urls (tel:, sms:), and requests to load a url in the main webview. - */ - BOOL shouldAllowNavigation = [self defaultResourcePolicyForURL:url]; - if (shouldAllowNavigation) { - return YES; - } else { - [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]]; - } - - return NO; -} - -@end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.h new file mode 100644 index 00000000..47e26d1e --- /dev/null +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.h @@ -0,0 +1,29 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import <WebKit/WebKit.h> +#import <Cordova/CDV.h> + +@interface CDVWebViewEngine : CDVPlugin <CDVWebViewEngineProtocol, WKScriptMessageHandler, WKNavigationDelegate> + +@property (nonatomic, strong, readonly) id <WKUIDelegate> uiDelegate; + +- (void)allowsBackForwardNavigationGestures:(CDVInvokedUrlCommand*)command; + +@end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m new file mode 100644 index 00000000..a07bf290 --- /dev/null +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m @@ -0,0 +1,607 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVWebViewEngine.h" +#import "CDVWebViewUIDelegate.h" +#import "CDVWebViewProcessPoolFactory.h" +#import <Cordova/NSDictionary+CordovaPreferences.h> +#import "CDVURLSchemeHandler.h" + +#import <objc/message.h> + +#define CDV_BRIDGE_NAME @"cordova" +#define CDV_WKWEBVIEW_FILE_URL_LOAD_SELECTOR @"loadFileURL:allowingReadAccessToURL:" + +@interface CDVWebViewWeakScriptMessageHandler : NSObject <WKScriptMessageHandler> + +@property (nonatomic, weak, readonly) id<WKScriptMessageHandler>scriptMessageHandler; + +- (instancetype)initWithScriptMessageHandler:(id<WKScriptMessageHandler>)scriptMessageHandler; + +@end + + +@interface CDVWebViewEngine () + +@property (nonatomic, strong, readwrite) UIView* engineWebView; +@property (nonatomic, strong, readwrite) id <WKUIDelegate> uiDelegate; +@property (nonatomic, weak) id <WKScriptMessageHandler> weakScriptMessageHandler; +@property (nonatomic, strong) CDVURLSchemeHandler * schemeHandler; +@property (nonatomic, readwrite) NSString *CDV_ASSETS_URL; +@property (nonatomic, readwrite) Boolean cdvIsFileScheme; + +@end + +// see forwardingTargetForSelector: selector comment for the reason for this pragma +#pragma clang diagnostic ignored "-Wprotocol" + +@implementation CDVWebViewEngine + +@synthesize engineWebView = _engineWebView; + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super init]; + if (self) { + if (NSClassFromString(@"WKWebView") == nil) { + return nil; + } + + self.engineWebView = [[WKWebView alloc] initWithFrame:frame]; + } + + return self; +} + +- (WKWebViewConfiguration*) createConfigurationFromSettings:(NSDictionary*)settings +{ + WKWebViewConfiguration* configuration = [[WKWebViewConfiguration alloc] init]; + configuration.processPool = [[CDVWebViewProcessPoolFactory sharedFactory] sharedProcessPool]; + if (settings == nil) { + return configuration; + } + + configuration.allowsInlineMediaPlayback = [settings cordovaBoolSettingForKey:@"AllowInlineMediaPlayback" defaultValue:NO]; + + // Set the media types that are required for user action for playback + WKAudiovisualMediaTypes mediaType = WKAudiovisualMediaTypeAll; // default + + // targetMediaType will always exist, either from user's "config.xml" or default ("defaults.xml"). + id targetMediaType = [settings cordovaSettingForKey:@"MediaTypesRequiringUserActionForPlayback"]; + if ([targetMediaType isEqualToString:@"none"]) { + mediaType = WKAudiovisualMediaTypeNone; + } else if ([targetMediaType isEqualToString:@"audio"]) { + mediaType = WKAudiovisualMediaTypeAudio; + } else if ([targetMediaType isEqualToString:@"video"]) { + mediaType = WKAudiovisualMediaTypeVideo; + } else if ([targetMediaType isEqualToString:@"all"]) { + mediaType = WKAudiovisualMediaTypeAll; + } else { + NSLog(@"Invalid \"MediaTypesRequiringUserActionForPlayback\" was detected. Fallback to default value of \"all\" types."); + } + configuration.mediaTypesRequiringUserActionForPlayback = mediaType; + + configuration.suppressesIncrementalRendering = [settings cordovaBoolSettingForKey:@"SuppressesIncrementalRendering" defaultValue:NO]; + + /* + * If the old preference key "MediaPlaybackAllowsAirPlay" exists, use it or default to "YES". + * Check if the new preference key "AllowsAirPlayForMediaPlayback" exists and overwrite the "MediaPlaybackAllowsAirPlay" value. + */ + BOOL allowsAirPlayForMediaPlayback = [settings cordovaBoolSettingForKey:@"MediaPlaybackAllowsAirPlay" defaultValue:YES]; + if([settings cordovaSettingForKey:@"AllowsAirPlayForMediaPlayback"] != nil) { + allowsAirPlayForMediaPlayback = [settings cordovaBoolSettingForKey:@"AllowsAirPlayForMediaPlayback" defaultValue:YES]; + } + configuration.allowsAirPlayForMediaPlayback = allowsAirPlayForMediaPlayback; + + /* + * Sets Custom User Agents + * - (Default) "userAgent" is set the the clean user agent. + * E.g. + * UserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148" + * + * - If "OverrideUserAgent" is set, it will overwrite the entire "userAgent" value. The "AppendUserAgent" will be iggnored if set. + * Notice: The override logic is handled in the "pluginInitialize" method. + * E.g. + * OverrideUserAgent = "foobar" + * UserAgent = "foobar" + * + * - If "AppendUserAgent" is set and "OverrideUserAgent" is not set, the user defined "AppendUserAgent" will be appended to the "userAgent" + * E.g. + * AppendUserAgent = "foobar" + * UserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 foobar" + */ + NSString *userAgent = configuration.applicationNameForUserAgent; + if ( + [settings cordovaSettingForKey:@"OverrideUserAgent"] == nil && + [settings cordovaSettingForKey:@"AppendUserAgent"] != nil + ) { + userAgent = [NSString stringWithFormat:@"%@ %@", userAgent, [settings cordovaSettingForKey:@"AppendUserAgent"]]; + } + configuration.applicationNameForUserAgent = userAgent; + + if (@available(iOS 13.0, *)) { + NSString *contentMode = [settings cordovaSettingForKey:@"PreferredContentMode"]; + if ([contentMode isEqual: @"mobile"]) { + configuration.defaultWebpagePreferences.preferredContentMode = WKContentModeMobile; + } else if ([contentMode isEqual: @"desktop"]) { + configuration.defaultWebpagePreferences.preferredContentMode = WKContentModeDesktop; + } + + } + + return configuration; +} + +- (void)pluginInitialize +{ + // viewController would be available now. we attempt to set all possible delegates to it, by default + CDVViewController* vc = (CDVViewController*)self.viewController; + NSDictionary* settings = self.commandDelegate.settings; + + NSString *scheme = [settings cordovaSettingForKey:@"scheme"]; + + // If scheme is file or nil, then default to file scheme + self.cdvIsFileScheme = [scheme isEqualToString: @"file"] || scheme == nil; + + NSString *hostname = @""; + if(!self.cdvIsFileScheme) { + if(scheme == nil || [WKWebView handlesURLScheme:scheme]){ + scheme = @"app"; + } + vc.appScheme = scheme; + + hostname = [settings cordovaSettingForKey:@"hostname"]; + if(hostname == nil){ + hostname = @"localhost"; + } + + self.CDV_ASSETS_URL = [NSString stringWithFormat:@"%@://%@", scheme, hostname]; + } + + CDVWebViewUIDelegate* uiDelegate = [[CDVWebViewUIDelegate alloc] initWithTitle:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]]; + uiDelegate.allowNewWindows = [settings cordovaBoolSettingForKey:@"AllowNewWindows" defaultValue:NO]; + self.uiDelegate = uiDelegate; + + CDVWebViewWeakScriptMessageHandler *weakScriptMessageHandler = [[CDVWebViewWeakScriptMessageHandler alloc] initWithScriptMessageHandler:self]; + + WKUserContentController* userContentController = [[WKUserContentController alloc] init]; + [userContentController addScriptMessageHandler:weakScriptMessageHandler name:CDV_BRIDGE_NAME]; + + if(self.CDV_ASSETS_URL) { + NSString *scriptCode = [NSString stringWithFormat:@"window.CDV_ASSETS_URL = '%@';", self.CDV_ASSETS_URL]; + WKUserScript *wkScript = [[WKUserScript alloc] initWithSource:scriptCode injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]; + + if (wkScript) { + [userContentController addUserScript:wkScript]; + } + } + + WKWebViewConfiguration* configuration = [self createConfigurationFromSettings:settings]; + configuration.userContentController = userContentController; + + // Do not configure the scheme handler if the scheme is default (file) + if(!self.cdvIsFileScheme) { + self.schemeHandler = [[CDVURLSchemeHandler alloc] initWithVC:vc]; + [configuration setURLSchemeHandler:self.schemeHandler forURLScheme:scheme]; + } + + // re-create WKWebView, since we need to update configuration + WKWebView* wkWebView = [[WKWebView alloc] initWithFrame:self.engineWebView.frame configuration:configuration]; + wkWebView.UIDelegate = self.uiDelegate; + + /* + * This is where the "OverrideUserAgent" is handled. This will replace the entire UserAgent + * with the user defined custom UserAgent. + */ + if ([settings cordovaSettingForKey:@"OverrideUserAgent"] != nil) { + wkWebView.customUserAgent = [settings cordovaSettingForKey:@"OverrideUserAgent"]; + } + + self.engineWebView = wkWebView; + + if ([self.viewController conformsToProtocol:@protocol(WKUIDelegate)]) { + wkWebView.UIDelegate = (id <WKUIDelegate>)self.viewController; + } + + if ([self.viewController conformsToProtocol:@protocol(WKNavigationDelegate)]) { + wkWebView.navigationDelegate = (id <WKNavigationDelegate>)self.viewController; + } else { + wkWebView.navigationDelegate = (id <WKNavigationDelegate>)self; + } + + if ([self.viewController conformsToProtocol:@protocol(WKScriptMessageHandler)]) { + [wkWebView.configuration.userContentController addScriptMessageHandler:(id < WKScriptMessageHandler >)self.viewController name:CDV_BRIDGE_NAME]; + } + + [self updateSettings:settings]; + + // check if content thread has died on resume + NSLog(@"%@", @"CDVWebViewEngine will reload WKWebView if required on resume"); + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(onAppWillEnterForeground:) + name:UIApplicationWillEnterForegroundNotification object:nil]; + + NSLog(@"Using WKWebView"); + + [self addURLObserver]; +} + +- (void)onReset { + [self addURLObserver]; +} + +static void * KVOContext = &KVOContext; + +- (void)addURLObserver { + if(!IsAtLeastiOSVersion(@"9.0")){ + [self.webView addObserver:self forKeyPath:@"URL" options:0 context:KVOContext]; + } +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context +{ + if (context == KVOContext) { + if (object == [self webView] && [keyPath isEqualToString: @"URL"] && [object valueForKeyPath:keyPath] == nil){ + NSLog(@"URL is nil. Reloading WKWebView"); + [(WKWebView*)_engineWebView reload]; + } + } else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; + } +} + +- (void) onAppWillEnterForeground:(NSNotification*)notification { + if ([self shouldReloadWebView]) { + NSLog(@"%@", @"CDVWebViewEngine reloading!"); + [(WKWebView*)_engineWebView reload]; + } +} + +- (BOOL)shouldReloadWebView +{ + WKWebView* wkWebView = (WKWebView*)_engineWebView; + return [self shouldReloadWebView:wkWebView.URL title:wkWebView.title]; +} + +- (BOOL)shouldReloadWebView:(NSURL*)location title:(NSString*)title +{ + BOOL title_is_nil = (title == nil); + BOOL location_is_blank = [[location absoluteString] isEqualToString:@"about:blank"]; + + BOOL reload = (title_is_nil || location_is_blank); + +#ifdef DEBUG + NSLog(@"%@", @"CDVWebViewEngine shouldReloadWebView::"); + NSLog(@"CDVWebViewEngine shouldReloadWebView title: %@", title); + NSLog(@"CDVWebViewEngine shouldReloadWebView location: %@", [location absoluteString]); + NSLog(@"CDVWebViewEngine shouldReloadWebView reload: %u", reload); +#endif + + return reload; +} + + +- (id)loadRequest:(NSURLRequest*)request +{ + if ([self canLoadRequest:request]) { // can load, differentiate between file urls and other schemes + if(request.URL.fileURL && self.cdvIsFileScheme) { + NSURL* readAccessUrl = [request.URL URLByDeletingLastPathComponent]; + return [(WKWebView*)_engineWebView loadFileURL:request.URL allowingReadAccessToURL:readAccessUrl]; + } else if (request.URL.fileURL) { + NSURL* startURL = [NSURL URLWithString:((CDVViewController *)self.viewController).startPage]; + NSString* startFilePath = [self.commandDelegate pathForResource:[startURL path]]; + NSURL *url = [[NSURL URLWithString:self.CDV_ASSETS_URL] URLByAppendingPathComponent:request.URL.path]; + if ([request.URL.path isEqualToString:startFilePath]) { + url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%@", self.CDV_ASSETS_URL, startURL]]; + } + if(request.URL.query) { + url = [NSURL URLWithString:[@"?" stringByAppendingString:request.URL.query] relativeToURL:url]; + } + if(request.URL.fragment) { + url = [NSURL URLWithString:[@"#" stringByAppendingString:request.URL.fragment] relativeToURL:url]; + } + request = [NSURLRequest requestWithURL:url]; + } + return [(WKWebView*)_engineWebView loadRequest:request]; + } else { // can't load, print out error + NSString* errorHtml = [NSString stringWithFormat: + @"<!doctype html>" + @"<title>Error</title>" + @"<div style='font-size:2em'>" + @" <p>The WebView engine '%@' is unable to load the request: %@</p>" + @" <p>Most likely the cause of the error is that the loading of file urls is not supported in iOS %@.</p>" + @"</div>", + NSStringFromClass([self class]), + [request.URL description], + [[UIDevice currentDevice] systemVersion] + ]; + return [self loadHTMLString:errorHtml baseURL:nil]; + } +} + +- (id)loadHTMLString:(NSString*)string baseURL:(NSURL*)baseURL +{ + return [(WKWebView*)_engineWebView loadHTMLString:string baseURL:baseURL]; +} + +- (NSURL*) URL +{ + return [(WKWebView*)_engineWebView URL]; +} + +- (BOOL) canLoadRequest:(NSURLRequest*)request +{ + // See: https://issues.apache.org/jira/browse/CB-9636 + SEL wk_sel = NSSelectorFromString(CDV_WKWEBVIEW_FILE_URL_LOAD_SELECTOR); + + // if it's a file URL, check whether WKWebView has the selector (which is in iOS 9 and up only) + if (request.URL.fileURL) { + return [_engineWebView respondsToSelector:wk_sel]; + } else { + return YES; + } +} + +- (void)updateSettings:(NSDictionary*)settings +{ + WKWebView* wkWebView = (WKWebView*)_engineWebView; + + wkWebView.configuration.preferences.minimumFontSize = [settings cordovaFloatSettingForKey:@"MinimumFontSize" defaultValue:0.0]; + + /* + wkWebView.configuration.preferences.javaScriptEnabled = [settings cordovaBoolSettingForKey:@"JavaScriptEnabled" default:YES]; + wkWebView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = [settings cordovaBoolSettingForKey:@"JavaScriptCanOpenWindowsAutomatically" default:NO]; + */ + + // By default, DisallowOverscroll is false (thus bounce is allowed) + BOOL bounceAllowed = !([settings cordovaBoolSettingForKey:@"DisallowOverscroll" defaultValue:NO]); + + // prevent webView from bouncing + if (!bounceAllowed) { + if ([wkWebView respondsToSelector:@selector(scrollView)]) { + ((UIScrollView*)[wkWebView scrollView]).bounces = NO; + } else { + for (id subview in wkWebView.subviews) { + if ([[subview class] isSubclassOfClass:[UIScrollView class]]) { + ((UIScrollView*)subview).bounces = NO; + } + } + } + } + + NSString* decelerationSetting = [settings cordovaSettingForKey:@"WKWebViewDecelerationSpeed"]; + + if (![@"fast" isEqualToString:decelerationSetting]) { + [wkWebView.scrollView setDecelerationRate:UIScrollViewDecelerationRateNormal]; + } else { + [wkWebView.scrollView setDecelerationRate:UIScrollViewDecelerationRateFast]; + } + + wkWebView.allowsBackForwardNavigationGestures = [settings cordovaBoolSettingForKey:@"AllowBackForwardNavigationGestures" defaultValue:NO]; + wkWebView.allowsLinkPreview = [settings cordovaBoolSettingForKey:@"Allow3DTouchLinkPreview" defaultValue:YES]; +} + +- (void)updateWithInfo:(NSDictionary*)info +{ + NSDictionary* scriptMessageHandlers = [info objectForKey:kCDVWebViewEngineScriptMessageHandlers]; + NSDictionary* settings = [info objectForKey:kCDVWebViewEngineWebViewPreferences]; + id navigationDelegate = [info objectForKey:kCDVWebViewEngineWKNavigationDelegate]; + id uiDelegate = [info objectForKey:kCDVWebViewEngineWKUIDelegate]; + + WKWebView* wkWebView = (WKWebView*)_engineWebView; + + if (scriptMessageHandlers && [scriptMessageHandlers isKindOfClass:[NSDictionary class]]) { + NSArray* allKeys = [scriptMessageHandlers allKeys]; + + for (NSString* key in allKeys) { + id object = [scriptMessageHandlers objectForKey:key]; + if ([object conformsToProtocol:@protocol(WKScriptMessageHandler)]) { + [wkWebView.configuration.userContentController addScriptMessageHandler:object name:key]; + } + } + } + + if (navigationDelegate && [navigationDelegate conformsToProtocol:@protocol(WKNavigationDelegate)]) { + wkWebView.navigationDelegate = navigationDelegate; + } + + if (uiDelegate && [uiDelegate conformsToProtocol:@protocol(WKUIDelegate)]) { + wkWebView.UIDelegate = uiDelegate; + } + + if (settings && [settings isKindOfClass:[NSDictionary class]]) { + [self updateSettings:settings]; + } +} + +// This forwards the methods that are in the header that are not implemented here. +// Both WKWebView implement the below: +// loadHTMLString:baseURL: +// loadRequest: +- (id)forwardingTargetForSelector:(SEL)aSelector +{ + return _engineWebView; +} + +- (UIView*)webView +{ + return self.engineWebView; +} + +#pragma mark WKScriptMessageHandler implementation + +- (void)userContentController:(WKUserContentController*)userContentController didReceiveScriptMessage:(WKScriptMessage*)message +{ + if (![message.name isEqualToString:CDV_BRIDGE_NAME]) { + return; + } + + CDVViewController* vc = (CDVViewController*)self.viewController; + + NSArray* jsonEntry = message.body; // NSString:callbackId, NSString:service, NSString:action, NSArray:args + CDVInvokedUrlCommand* command = [CDVInvokedUrlCommand commandFromJson:jsonEntry]; + CDV_EXEC_LOG(@"Exec(%@): Calling %@.%@", command.callbackId, command.className, command.methodName); + + if (![vc.commandQueue execute:command]) { +#ifdef DEBUG + NSError* error = nil; + NSString* commandJson = nil; + NSData* jsonData = [NSJSONSerialization dataWithJSONObject:jsonEntry + options:0 + error:&error]; + + if (error == nil) { + commandJson = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + } + + static NSUInteger maxLogLength = 1024; + NSString* commandString = ([commandJson length] > maxLogLength) ? + [NSString stringWithFormat : @"%@[...]", [commandJson substringToIndex:maxLogLength]] : + commandJson; + + NSLog(@"FAILED pluginJSON = %@", commandString); +#endif + } +} + +#pragma mark WKNavigationDelegate implementation + +- (void)webView:(WKWebView*)webView didStartProvisionalNavigation:(WKNavigation*)navigation +{ + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginResetNotification object:webView]]; +} + +- (void)webView:(WKWebView*)webView didFinishNavigation:(WKNavigation*)navigation +{ + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:webView]]; +} + +- (void)webView:(WKWebView*)theWebView didFailProvisionalNavigation:(WKNavigation*)navigation withError:(NSError*)error +{ + [self webView:theWebView didFailNavigation:navigation withError:error]; +} + +- (void)webView:(WKWebView*)theWebView didFailNavigation:(WKNavigation*)navigation withError:(NSError*)error +{ + CDVViewController* vc = (CDVViewController*)self.viewController; + + NSString* message = [NSString stringWithFormat:@"Failed to load webpage with error: %@", [error localizedDescription]]; + NSLog(@"%@", message); + + NSURL* errorUrl = vc.errorURL; + if (errorUrl) { + NSCharacterSet *charSet = [NSCharacterSet URLFragmentAllowedCharacterSet]; + errorUrl = [NSURL URLWithString:[NSString stringWithFormat:@"?error=%@", [message stringByAddingPercentEncodingWithAllowedCharacters:charSet]] relativeToURL:errorUrl]; + NSLog(@"%@", [errorUrl absoluteString]); + [theWebView loadRequest:[NSURLRequest requestWithURL:errorUrl]]; + } +} + +- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView +{ + [webView reload]; +} + +- (BOOL)defaultResourcePolicyForURL:(NSURL*)url +{ + // all file:// urls are allowed + if ([url isFileURL]) { + return YES; + } + + return NO; +} + +- (void) webView: (WKWebView *) webView decidePolicyForNavigationAction: (WKNavigationAction*) navigationAction decisionHandler: (void (^)(WKNavigationActionPolicy)) decisionHandler +{ + NSURL* url = [navigationAction.request URL]; + CDVViewController* vc = (CDVViewController*)self.viewController; + + /* + * Give plugins the chance to handle the url + */ + BOOL anyPluginsResponded = NO; + BOOL shouldAllowRequest = NO; + + for (NSString* pluginName in vc.pluginObjects) { + CDVPlugin* plugin = [vc.pluginObjects objectForKey:pluginName]; + SEL selector = NSSelectorFromString(@"shouldOverrideLoadWithRequest:navigationType:"); + if ([plugin respondsToSelector:selector]) { + anyPluginsResponded = YES; + // https://issues.apache.org/jira/browse/CB-12497 + int navType = (int)navigationAction.navigationType; + shouldAllowRequest = (((BOOL (*)(id, SEL, id, int))objc_msgSend)(plugin, selector, navigationAction.request, navType)); + if (!shouldAllowRequest) { + break; + } + } + } + + if (anyPluginsResponded) { + return decisionHandler(shouldAllowRequest); + } + + /* + * Handle all other types of urls (tel:, sms:), and requests to load a url in the main webview. + */ + BOOL shouldAllowNavigation = [self defaultResourcePolicyForURL:url]; + if (shouldAllowNavigation) { + return decisionHandler(YES); + } else { + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]]; + } + + return decisionHandler(NO); +} + +#pragma mark - Plugin interface + +- (void)allowsBackForwardNavigationGestures:(CDVInvokedUrlCommand*)command; +{ + id value = [command argumentAtIndex:0]; + if (!([value isKindOfClass:[NSNumber class]])) { + value = [NSNumber numberWithBool:NO]; + } + + WKWebView* wkWebView = (WKWebView*)_engineWebView; + wkWebView.allowsBackForwardNavigationGestures = [value boolValue]; +} + +@end + +#pragma mark - CDVWebViewWeakScriptMessageHandler + +@implementation CDVWebViewWeakScriptMessageHandler + +- (instancetype)initWithScriptMessageHandler:(id<WKScriptMessageHandler>)scriptMessageHandler +{ + self = [super init]; + if (self) { + _scriptMessageHandler = scriptMessageHandler; + } + return self; +} + +- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message +{ + [self.scriptMessageHandler userContentController:userContentController didReceiveScriptMessage:message]; +} + +@end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewProcessPoolFactory.h index 9138deba..b1562891 100644 --- a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.h +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewProcessPoolFactory.h @@ -6,9 +6,9 @@ to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 - + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -17,13 +17,11 @@ under the License. */ -#import <UIKit/UIKit.h> -#import "CDVUIWebViewEngine.h" - -@interface CDVUIWebViewNavigationDelegate : NSObject <UIWebViewDelegate> - -@property (nonatomic, weak) CDVPlugin* enginePlugin; +#import <WebKit/WebKit.h> -- (instancetype)initWithEnginePlugin:(CDVPlugin*)enginePlugin; +@interface CDVWebViewProcessPoolFactory : NSObject +@property (nonatomic, retain) WKProcessPool* sharedPool; ++(instancetype) sharedFactory; +-(WKProcessPool*) sharedProcessPool; @end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewProcessPoolFactory.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewProcessPoolFactory.m new file mode 100644 index 00000000..577624e0 --- /dev/null +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewProcessPoolFactory.m @@ -0,0 +1,49 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import <Foundation/Foundation.h> +#import <WebKit/WebKit.h> +#import "CDVWebViewProcessPoolFactory.h" + +static CDVWebViewProcessPoolFactory *factory = nil; + +@implementation CDVWebViewProcessPoolFactory + ++ (instancetype)sharedFactory +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + factory = [[CDVWebViewProcessPoolFactory alloc] init]; + }); + + return factory; +} + +- (instancetype)init +{ + if (self = [super init]) { + _sharedPool = [[WKProcessPool alloc] init]; + } + return self; +} + +- (WKProcessPool*) sharedProcessPool { + return _sharedPool; +} +@end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewUIDelegate.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewUIDelegate.h new file mode 100644 index 00000000..8ae39b67 --- /dev/null +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewUIDelegate.h @@ -0,0 +1,32 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import <WebKit/WebKit.h> + +@interface CDVWebViewUIDelegate : NSObject <WKUIDelegate> +{ + NSMutableArray<UIViewController*>* windows; +} + +@property (nonatomic, copy) NSString* title; +@property (nonatomic, assign) BOOL allowNewWindows; + +- (instancetype)initWithTitle:(NSString*)title; + +@end diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewUIDelegate.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewUIDelegate.m new file mode 100644 index 00000000..784af8df --- /dev/null +++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewUIDelegate.m @@ -0,0 +1,163 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVWebViewUIDelegate.h" + +@implementation CDVWebViewUIDelegate + +- (instancetype)initWithTitle:(NSString*)title +{ + self = [super init]; + if (self) { + self.title = title; + windows = [[NSMutableArray alloc] init]; + } + + return self; +} + +- (void) webView:(WKWebView*)webView runJavaScriptAlertPanelWithMessage:(NSString*)message + initiatedByFrame:(WKFrameInfo*)frame completionHandler:(void (^)(void))completionHandler +{ + UIAlertController* alert = [UIAlertController alertControllerWithTitle:self.title + message:message + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction* action) + { + completionHandler(); + [alert dismissViewControllerAnimated:YES completion:nil]; + }]; + + [alert addAction:ok]; + + UIViewController* rootController = [UIApplication sharedApplication].delegate.window.rootViewController; + + [rootController presentViewController:alert animated:YES completion:nil]; +} + +- (void) webView:(WKWebView*)webView runJavaScriptConfirmPanelWithMessage:(NSString*)message + initiatedByFrame:(WKFrameInfo*)frame completionHandler:(void (^)(BOOL result))completionHandler +{ + UIAlertController* alert = [UIAlertController alertControllerWithTitle:self.title + message:message + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction* action) + { + completionHandler(YES); + [alert dismissViewControllerAnimated:YES completion:nil]; + }]; + + [alert addAction:ok]; + + UIAlertAction* cancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction* action) + { + completionHandler(NO); + [alert dismissViewControllerAnimated:YES completion:nil]; + }]; + [alert addAction:cancel]; + + UIViewController* rootController = [UIApplication sharedApplication].delegate.window.rootViewController; + + [rootController presentViewController:alert animated:YES completion:nil]; +} + +- (void) webView:(WKWebView*)webView runJavaScriptTextInputPanelWithPrompt:(NSString*)prompt + defaultText:(NSString*)defaultText initiatedByFrame:(WKFrameInfo*)frame + completionHandler:(void (^)(NSString* result))completionHandler +{ + UIAlertController* alert = [UIAlertController alertControllerWithTitle:self.title + message:prompt + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction* action) + { + completionHandler(((UITextField*)alert.textFields[0]).text); + [alert dismissViewControllerAnimated:YES completion:nil]; + }]; + + [alert addAction:ok]; + + UIAlertAction* cancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction* action) + { + completionHandler(nil); + [alert dismissViewControllerAnimated:YES completion:nil]; + }]; + [alert addAction:cancel]; + + [alert addTextFieldWithConfigurationHandler:^(UITextField* textField) { + textField.text = defaultText; + }]; + + UIViewController* rootController = [UIApplication sharedApplication].delegate.window.rootViewController; + + [rootController presentViewController:alert animated:YES completion:nil]; +} + +- (WKWebView*) webView:(WKWebView*)webView createWebViewWithConfiguration:(WKWebViewConfiguration*)configuration forNavigationAction:(WKNavigationAction*)navigationAction windowFeatures:(WKWindowFeatures*)windowFeatures +{ + if (!navigationAction.targetFrame.isMainFrame) { + if (self.allowNewWindows) { + WKWebView* v = [[WKWebView alloc] initWithFrame:webView.frame configuration:configuration]; + v.UIDelegate = webView.UIDelegate; + v.navigationDelegate = webView.navigationDelegate; + + UIViewController* vc = [[UIViewController alloc] init]; + vc.modalPresentationStyle = UIModalPresentationOverCurrentContext; + vc.view = v; + + [windows addObject:vc]; + + UIViewController* rootController = [UIApplication sharedApplication].delegate.window.rootViewController; + [rootController presentViewController:vc animated:YES completion:nil]; + return v; + } else { + [webView loadRequest:navigationAction.request]; + } + } + + return nil; +} + +- (void)webViewDidClose:(WKWebView*)webView +{ + for (UIViewController* vc in windows) { + if (vc.view == webView) { + [vc dismissViewControllerAnimated:YES completion:nil]; + [windows removeObject:vc]; + break; + } + } + + // We do not allow closing the primary WebView +} + + +@end |
