Repository: cordova-plugin-wkwebview-engine Updated Branches: refs/heads/master [created] 0cda51fe9
Added wkwebview-engine plugin. Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-wkwebview-engine/repo Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-wkwebview-engine/commit/40f6b453 Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-wkwebview-engine/tree/40f6b453 Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-wkwebview-engine/diff/40f6b453 Branch: refs/heads/master Commit: 40f6b4538cb063a7de9a454190d652247c5dadee Parents: Author: Shazron Abdullah <[email protected]> Authored: Thu Nov 6 16:08:59 2014 -0800 Committer: Shazron Abdullah <[email protected]> Committed: Thu Nov 6 16:08:59 2014 -0800 ---------------------------------------------------------------------- README.md | 20 ++++ plugin.xml | 38 +++++++ src/ios/CDVWKWebViewEngine.h | 27 +++++ src/ios/CDVWKWebViewEngine.m | 189 ++++++++++++++++++++++++++++++++++ src/ios/CDVWKWebViewUIDelegate.h | 28 +++++ src/ios/CDVWKWebViewUIDelegate.m | 123 ++++++++++++++++++++++ 6 files changed, 425 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cordova-plugin-wkwebview-engine/blob/40f6b453/README.md ---------------------------------------------------------------------- diff --git a/README.md b/README.md new file mode 100644 index 0000000..a3f7931 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +Cordova WKWebView Engine +====== + +This plugin makes Cordova use the WKWebView component (new in iOS 8.0) instead of the default UIWebView component. + +This will also install the Cordova Local Web Server plugin (TODO: move this into Labs) + +Permissions +----------- + +#### config.xml + + <feature name="CDVWKWebViewEngine"> + <param name="ios-package" value="CDVWKWebViewEngine" /> + </feature> + +Supported Platforms +------------------- + +- iOS http://git-wip-us.apache.org/repos/asf/cordova-plugin-wkwebview-engine/blob/40f6b453/plugin.xml ---------------------------------------------------------------------- diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..2643b94 --- /dev/null +++ b/plugin.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" + xmlns:rim="http://www.blackberry.com/ns/widgets" + xmlns:android="http://schemas.android.com/apk/res/android" + id="org.apache.cordova.labs.wkwebviewengine" + version="0.1.0"> + <name>Cordova WKWebView Engine</name> + <description>Cordova WKWebView Engine Plugin</description> + <license>Apache 2.0</license> + <keywords>cordova,wkwebview,webview</keywords> + + <engines> + <engine name="cordova" version=">3.7.0" /> + </engines> + + <!-- this plugin will be moved to labs soon --> + <dependency id="io.shaz.plugin.cordova-local-webserver" url="https://github.com/shazron/CordovaLocalWebServer.git" version=">=2.1.0" /> + + <!-- ios --> + <platform name="ios"> + <config-file target="config.xml" parent="/*"> + <feature name="CDVWKWebViewEngine"> + <param name="ios-package" value="CDVWKWebViewEngine" /> + </feature> + <preference name="CordovaWebViewEngine" value="CDVWKWebViewEngine" /> + </config-file> + + <framework src="WebKit.framework" weak="true" /> + + <header-file src="src/ios/CDVWKWebViewEngine.h" /> + <source-file src="src/ios/CDVWKWebViewEngine.m" /> + <header-file src="src/ios/CDVWKWebViewUIDelegate.h" /> + <source-file src="src/ios/CDVWKWebViewUIDelegate.m" /> + + </platform> + +</plugin> http://git-wip-us.apache.org/repos/asf/cordova-plugin-wkwebview-engine/blob/40f6b453/src/ios/CDVWKWebViewEngine.h ---------------------------------------------------------------------- diff --git a/src/ios/CDVWKWebViewEngine.h b/src/ios/CDVWKWebViewEngine.h new file mode 100644 index 0000000..753a07f --- /dev/null +++ b/src/ios/CDVWKWebViewEngine.h @@ -0,0 +1,27 @@ +/* + 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 CDVWKWebViewEngine : CDVPlugin <CDVWebViewEngineProtocol, WKScriptMessageHandler> + +@property (nonatomic, strong, readonly) id <WKUIDelegate> uiDelegate; + +@end http://git-wip-us.apache.org/repos/asf/cordova-plugin-wkwebview-engine/blob/40f6b453/src/ios/CDVWKWebViewEngine.m ---------------------------------------------------------------------- diff --git a/src/ios/CDVWKWebViewEngine.m b/src/ios/CDVWKWebViewEngine.m new file mode 100644 index 0000000..94ef0b2 --- /dev/null +++ b/src/ios/CDVWKWebViewEngine.m @@ -0,0 +1,189 @@ +/* + 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 "CDVWKWebViewEngine.h" +#import "CDVWKWebViewUIDelegate.h" + +#import <objc/message.h> + +#define CDV_BRIDGE_NAME @"cordova" + +@interface CDVWKWebViewEngine () + +@property (nonatomic, strong, readwrite) UIView* engineWebView; +@property (nonatomic, strong, readwrite) id <WKUIDelegate> uiDelegate; + +@end + +// see forwardingTargetForSelector: selector comment for the reason for this pragma +#pragma clang diagnostic ignored "-Wprotocol" + +@implementation CDVWKWebViewEngine + +@synthesize engineWebView = _engineWebView; + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super init]; + if (self) { + self.uiDelegate = [[CDVWKWebViewUIDelegate alloc] initWithTitle:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]]; + + WKUserContentController* userContentController = [[WKUserContentController alloc] init]; + [userContentController addScriptMessageHandler:self name:CDV_BRIDGE_NAME]; + + WKWebViewConfiguration* configuration = [[WKWebViewConfiguration alloc] init]; + configuration.userContentController = userContentController; + + WKWebView* wkWebView = [[WKWebView alloc] initWithFrame:frame configuration:configuration]; + + wkWebView.UIDelegate = self.uiDelegate; + + self.engineWebView = wkWebView; + + NSLog(@"Using WKWebView"); + } + + return self; +} + +- (void)pluginInitialize +{ + // viewController would be available now. we attempt to set all possible delegates to it, by default + + WKWebView* wkWebView = (WKWebView*)_engineWebView; + + if ([self.viewController conformsToProtocol:@protocol(WKUIDelegate)]) { + wkWebView.UIDelegate = (id <WKUIDelegate>)self.viewController; + } + + if ([self.viewController conformsToProtocol:@protocol(WKNavigationDelegate)]) { + wkWebView.navigationDelegate = (id <WKNavigationDelegate>)self.viewController; + } + + if ([self.viewController conformsToProtocol:@protocol(WKScriptMessageHandler)]) { + [wkWebView.configuration.userContentController addScriptMessageHandler:(id < WKScriptMessageHandler >)self.viewController name:@"cordova"]; + } + + [self updateSettings:self.commandDelegate.settings]; +} + +// We implement this here because certain versions of iOS 8 do not implement this +// in WKWebView, so we need to test for this during runtime. +// It is speculated that this selector will be available in iOS 8.2 for WKWebView +- (void)loadFileURL:(NSURL*)url allowingReadAccessToURL:(NSURL*)readAccessURL +{ + SEL wk_sel = @selector(loadFileURL:allowingReadAccessToURL:); + __weak CDVWKWebViewEngine* weakSelf = self; + + // UIKit operations have to be on the main thread. This method does not need to be synchronous + dispatch_async(dispatch_get_main_queue(), ^{ + if ([_engineWebView respondsToSelector:wk_sel] && [[url scheme] isEqualToString:@"file"]) { + ((id (*)(id, SEL, id, id))objc_msgSend)(_engineWebView, wk_sel, url, readAccessURL); + } else { + [weakSelf loadRequest:[NSURLRequest requestWithURL:url]]; + } + }); +} + +- (void)updateSettings:(NSDictionary*)settings +{ + WKWebView* wkWebView = (WKWebView*)_engineWebView; + + wkWebView.configuration.preferences.minimumFontSize = [settings cordovaFloatSettingForKey:@"MinimumFontSize" defaultValue:0.0]; + wkWebView.configuration.allowsInlineMediaPlayback = [settings cordovaBoolSettingForKey:@"AllowInlineMediaPlayback" defaultValue:NO]; + wkWebView.configuration.mediaPlaybackRequiresUserAction = [settings cordovaBoolSettingForKey:@"MediaPlaybackRequiresUserAction" defaultValue:YES]; + wkWebView.configuration.suppressesIncrementalRendering = [settings cordovaBoolSettingForKey:@"SuppressesIncrementalRendering" defaultValue:NO]; + wkWebView.configuration.mediaPlaybackAllowsAirPlay = [settings cordovaBoolSettingForKey:@"MediaPlaybackAllowsAirPlay" defaultValue:YES]; + + /* + wkWebView.configuration.preferences.javaScriptEnabled = [settings cordovaBoolSettingForKey:@"JavaScriptEnabled" default:YES]; + wkWebView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = [settings cordovaBoolSettingForKey:@"JavaScriptCanOpenWindowsAutomatically" default:NO]; + */ +} + +- (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 and UIWebView implement the below: +// loadHTMLString:baseURL: +// loadRequest: +- (id)forwardingTargetForSelector:(SEL)aSelector +{ + return _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 + NSString* commandJson = [jsonEntry JSONString]; + static NSUInteger maxLogLength = 1024; + NSString* commandString = ([commandJson length] > maxLogLength) ? + [NSString stringWithFormat : @"%@[...]", [commandJson substringToIndex:maxLogLength]] : + commandJson; + + DLog(@"FAILED pluginJSON = %@", commandString); +#endif + } +} + +@end http://git-wip-us.apache.org/repos/asf/cordova-plugin-wkwebview-engine/blob/40f6b453/src/ios/CDVWKWebViewUIDelegate.h ---------------------------------------------------------------------- diff --git a/src/ios/CDVWKWebViewUIDelegate.h b/src/ios/CDVWKWebViewUIDelegate.h new file mode 100644 index 0000000..33a179b --- /dev/null +++ b/src/ios/CDVWKWebViewUIDelegate.h @@ -0,0 +1,28 @@ +/* + 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 CDVWKWebViewUIDelegate : NSObject <WKUIDelegate> + +@property (nonatomic, copy) NSString* title; + +- (instancetype)initWithTitle:(NSString*)title; + +@end http://git-wip-us.apache.org/repos/asf/cordova-plugin-wkwebview-engine/blob/40f6b453/src/ios/CDVWKWebViewUIDelegate.m ---------------------------------------------------------------------- diff --git a/src/ios/CDVWKWebViewUIDelegate.m b/src/ios/CDVWKWebViewUIDelegate.m new file mode 100644 index 0000000..c9e5ce9 --- /dev/null +++ b/src/ios/CDVWKWebViewUIDelegate.m @@ -0,0 +1,123 @@ +/* + 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 "CDVWKWebViewUIDelegate.h" + +@implementation CDVWKWebViewUIDelegate + +- (instancetype)initWithTitle:(NSString*)title +{ + self = [super init]; + if (self) { + self.title = title; + } + + return self; +} + +- (void) webView:(WKWebView*)webView runJavaScriptAlertPanelWithMessage:(NSString*)message + initiatedByFrame:(WKFrameInfo*)frame completionHandler:(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]; +} + +@end --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
