diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 364f4e9..3d6cd70 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -83,3 +83,17 @@ * CB-5534 Fix video/audio does not stop playing when browser is closed * CB-6172 Fix broken install on case-sensitive file-systems + +### 0.4.0 (Apr 17, 2014) +* CB-6360: [ios] Fix for crash on iOS < 6.0 (closes #37) +* CB-3324: [WP8] Add support for back-button inappbrowser [WP8] if there is no history -> InAppBrowser is closed +* [WP] await async calls, resolve warnings +* [WP] Make InAppBrowser work with embedded files, using system behavior +* CB-6402: [WP8] pass empty string instead of null for [optional] windowFeatures string +* CB-6422: [windows8] use cordova/exec/proxy +* CB-6389 CB-3617: Add clearcache and clearsessioncache options to iOS (like Android) +* Doc update: event name and example param (closes #31) +* CB-6253: [WP] Add Network Capability to WMAppManifest.xml +* CB-6212: [iOS] fix warnings compiled under arm64 64-bit +* CB-6218: Update docs for BB10 +* CB-6460: Update license headers diff --git a/doc/index.md b/doc/index.md index ebc4734..760831a 100644 --- a/doc/index.md +++ b/doc/index.md @@ -76,6 +76,8 @@ instance, or the system browser. - __closebuttoncaption__: set to a string to use as the __Done__ button's caption. Note that you need to localize this value yourself. - __disallowoverscroll__: Set to `yes` or `no` (default is `no`). Turns on/off the UIWebViewBounce property. - __hidden__: set to `yes` to create the browser and load the page, but not show it. The loadstop event fires when loading is complete. Omit or set to `no` (default) to have the browser open and load normally. + - __clearcache__: set to `yes` to have the browser's cookie cache cleared before the new window is opened + - __clearsessioncache__: set to `yes` to have the session cookie cache cleared before the new window is opened - __toolbar__: set to `yes` or `no` to turn the toolbar on or off for the InAppBrowser (defaults to `yes`) - __enableViewportScale__: Set to `yes` or `no` to prevent viewport scaling through a meta tag (defaults to `no`). - __mediaPlaybackRequiresUserAction__: Set to `yes` or `no` to prevent HTML5 audio or video from autoplaying (defaults to `no`). diff --git a/plugin.xml b/plugin.xml index 0d52960..fcb1837 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,8 +1,26 @@ + + version="0.4.1-dev"> InAppBrowser Cordova InAppBrowser Plugin @@ -106,6 +124,10 @@ + + + + @@ -124,6 +146,10 @@ + + + + diff --git a/src/amazon/InAppChromeClient.java b/src/amazon/InAppChromeClient.java index 7f2ddc3..37cf101 100644 --- a/src/amazon/InAppChromeClient.java +++ b/src/amazon/InAppChromeClient.java @@ -1,3 +1,21 @@ +/* + 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. +*/ package org.apache.cordova.inappbrowser; import org.apache.cordova.CordovaWebView; diff --git a/src/android/InAppChromeClient.java b/src/android/InAppChromeClient.java index f3fc741..a2145e6 100644 --- a/src/android/InAppChromeClient.java +++ b/src/android/InAppChromeClient.java @@ -1,3 +1,21 @@ +/* + 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. +*/ package org.apache.cordova.inappbrowser; import org.apache.cordova.CordovaWebView; diff --git a/src/blackberry10/README.md b/src/blackberry10/README.md index 0b16789..f0fa860 100644 --- a/src/blackberry10/README.md +++ b/src/blackberry10/README.md @@ -1,3 +1,21 @@ + # BlackBerry 10 In-App-Browser Plugin The in app browser functionality is entirely contained within common js. There is no native implementation required. diff --git a/src/ios/CDVInAppBrowser.h b/src/ios/CDVInAppBrowser.h index 8e2ab12..0ba07f1 100644 --- a/src/ios/CDVInAppBrowser.h +++ b/src/ios/CDVInAppBrowser.h @@ -45,6 +45,8 @@ @property (nonatomic, assign) BOOL toolbar; @property (nonatomic, copy) NSString* closebuttoncaption; @property (nonatomic, copy) NSString* toolbarposition; +@property (nonatomic, assign) BOOL clearcache; +@property (nonatomic, assign) BOOL clearsessioncache; @property (nonatomic, copy) NSString* presentationstyle; @property (nonatomic, copy) NSString* transitionstyle; @@ -61,7 +63,7 @@ @end -@interface CDVInAppBrowserViewController : UIViewController { +@interface CDVInAppBrowserViewController : UIViewController { @private NSString* _userAgent; NSString* _prevUserAgent; @@ -90,4 +92,10 @@ - (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent browserOptions: (CDVInAppBrowserOptions*) browserOptions; +@end + +@interface CDVInAppBrowserNavigationController : UINavigationController + +@property (nonatomic, weak) id orientationDelegate; + @end \ No newline at end of file diff --git a/src/ios/CDVInAppBrowser.m b/src/ios/CDVInAppBrowser.m index 2b0dc41..8037a91 100644 --- a/src/ios/CDVInAppBrowser.m +++ b/src/ios/CDVInAppBrowser.m @@ -115,6 +115,29 @@ - (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options { CDVInAppBrowserOptions* browserOptions = [CDVInAppBrowserOptions parseOptions:options]; + + if (browserOptions.clearcache) { + NSHTTPCookie *cookie; + NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + for (cookie in [storage cookies]) + { + if (![cookie.domain isEqual: @".^filecookies^"]) { + [storage deleteCookie:cookie]; + } + } + } + + if (browserOptions.clearsessioncache) { + NSHTTPCookie *cookie; + NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + for (cookie in [storage cookies]) + { + if (![cookie.domain isEqual: @".^filecookies^"] && cookie.isSessionOnly) { + [storage deleteCookie:cookie]; + } + } + } + if (self.inAppBrowserViewController == nil) { NSString* originalUA = [CDVUserAgentUtil originalUserAgent]; self.inAppBrowserViewController = [[CDVInAppBrowserViewController alloc] initWithUserAgent:originalUA prevUserAgent:[self.commandDelegate userAgent] browserOptions: browserOptions]; @@ -193,13 +216,14 @@ _previousStatusBarStyle = [UIApplication sharedApplication].statusBarStyle; - UINavigationController* nav = [[UINavigationController alloc] + CDVInAppBrowserNavigationController* nav = [[CDVInAppBrowserNavigationController alloc] initWithRootViewController:self.inAppBrowserViewController]; + nav.orientationDelegate = self.inAppBrowserViewController; nav.navigationBarHidden = YES; // Run later to avoid the "took a long time" log message. dispatch_async(dispatch_get_main_queue(), ^{ if (self.inAppBrowserViewController != nil) { - [self.viewController presentModalViewController:nav animated:YES]; + [self.viewController presentViewController:nav animated:YES completion:nil]; } }); } @@ -465,7 +489,6 @@ self.webView.clearsContextBeforeDrawing = YES; self.webView.clipsToBounds = YES; self.webView.contentMode = UIViewContentModeScaleToFill; - self.webView.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); self.webView.multipleTouchEnabled = YES; self.webView.opaque = YES; self.webView.scalesPageToFit = NO; @@ -478,7 +501,6 @@ self.spinner.clearsContextBeforeDrawing = NO; self.spinner.clipsToBounds = NO; self.spinner.contentMode = UIViewContentModeScaleToFill; - self.spinner.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); self.spinner.frame = CGRectMake(454.0, 231.0, 20.0, 20.0); self.spinner.hidden = YES; self.spinner.hidesWhenStopped = YES; @@ -506,7 +528,6 @@ self.toolbar.clearsContextBeforeDrawing = NO; self.toolbar.clipsToBounds = NO; self.toolbar.contentMode = UIViewContentModeScaleToFill; - self.toolbar.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); self.toolbar.hidden = NO; self.toolbar.multipleTouchEnabled = NO; self.toolbar.opaque = NO; @@ -525,11 +546,16 @@ self.addressLabel.clearsContextBeforeDrawing = YES; self.addressLabel.clipsToBounds = YES; self.addressLabel.contentMode = UIViewContentModeScaleToFill; - self.addressLabel.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); self.addressLabel.enabled = YES; self.addressLabel.hidden = NO; self.addressLabel.lineBreakMode = NSLineBreakByTruncatingTail; - self.addressLabel.minimumScaleFactor = 10.000; + + if ([self.addressLabel respondsToSelector:NSSelectorFromString(@"setMinimumScaleFactor:")]) { + [self.addressLabel setValue:@(10.0/[UIFont labelFontSize]) forKey:@"minimumScaleFactor"]; + } else if ([self.addressLabel respondsToSelector:NSSelectorFromString(@"setMinimumFontSize:")]) { + [self.addressLabel setValue:@(10.0) forKey:@"minimumFontSize"]; + } + self.addressLabel.multipleTouchEnabled = NO; self.addressLabel.numberOfLines = 1; self.addressLabel.opaque = NO; @@ -719,7 +745,7 @@ if ([self respondsToSelector:@selector(presentingViewController)]) { [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil]; } else { - [[self parentViewController] dismissModalViewControllerAnimated:YES]; + [[self parentViewController] dismissViewControllerAnimated:YES completion:nil]; } }); } @@ -885,6 +911,8 @@ self.toolbar = YES; self.closebuttoncaption = nil; self.toolbarposition = kInAppBrowserToolbarBarPositionBottom; + self.clearcache = NO; + self.clearsessioncache = NO; self.enableviewportscale = NO; self.mediaplaybackrequiresuseraction = NO; @@ -935,4 +963,37 @@ return obj; } +@end + +@implementation CDVInAppBrowserNavigationController : UINavigationController + +#pragma mark CDVScreenOrientationDelegate + +- (BOOL)shouldAutorotate +{ + if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotate)]) { + return [self.orientationDelegate shouldAutorotate]; + } + return YES; +} + +- (NSUInteger)supportedInterfaceOrientations +{ + if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(supportedInterfaceOrientations)]) { + return [self.orientationDelegate supportedInterfaceOrientations]; + } + + return 1 << UIInterfaceOrientationPortrait; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) { + return [self.orientationDelegate shouldAutorotateToInterfaceOrientation:interfaceOrientation]; + } + + return YES; +} + + @end diff --git a/src/wp/InAppBrowser.cs b/src/wp/InAppBrowser.cs index 454464d..f5b7b1d 100644 --- a/src/wp/InAppBrowser.cs +++ b/src/wp/InAppBrowser.cs @@ -1,21 +1,38 @@ -using System; -using System.Net; +/* + Licensed 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. +*/ + +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.Serialization; using System.Windows; using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Ink; -using System.Windows.Input; using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Shapes; using Microsoft.Phone.Controls; -using System.Diagnostics; -using System.Runtime.Serialization; -using WPCordovaClassLib.Cordova; -using WPCordovaClassLib.Cordova.Commands; -using WPCordovaClassLib.Cordova.JSON; using Microsoft.Phone.Shell; + +#if WP8 +using System.Threading.Tasks; +using Windows.ApplicationModel; +using Windows.Storage; +using Windows.System; + +//Use alias in case Cordova File Plugin is enabled. Then the File class will be declared in both and error will occur. +using IOFile = System.IO.File; +#else using Microsoft.Phone.Tasks; +#endif namespace WPCordovaClassLib.Cordova.Commands { @@ -41,6 +58,8 @@ namespace WPCordovaClassLib.Cordova.Commands protected bool ShowLocation {get;set;} protected bool StartHidden {get;set;} + protected string NavigationCallbackId { get; set; } + public void open(string options) { // reset defaults on ShowLocation + StartHidden features @@ -52,28 +71,31 @@ namespace WPCordovaClassLib.Cordova.Commands string urlLoc = args[0]; string target = args[1]; string featString = args[2]; + this.NavigationCallbackId = args[3]; - string[] features = featString.Split(','); - foreach (string str in features) + if (!string.IsNullOrEmpty(featString)) { - try + string[] features = featString.Split(','); + foreach (string str in features) { - string[] split = str.Split('='); - switch (split[0]) + try { - case "location": - ShowLocation = split[1].ToLower().StartsWith("yes"); - break; - case "hidden": - StartHidden = split[1].ToLower().StartsWith("yes"); - break; + string[] split = str.Split('='); + switch (split[0]) + { + case "location": + ShowLocation = split[1].StartsWith("yes", StringComparison.OrdinalIgnoreCase); + break; + case "hidden": + StartHidden = split[1].StartsWith("yes", StringComparison.OrdinalIgnoreCase); + break; + } + } + catch (Exception) + { + // some sort of invalid param was passed, moving on ... } } - catch(Exception) - { - // some sort of invalid param was passed, moving on ... - } - } /* _self - opens in the Cordova WebView if url is in the white-list, else it opens in the InAppBrowser @@ -184,7 +206,6 @@ namespace WPCordovaClassLib.Cordova.Commands //throw new NotImplementedException("Windows Phone does not currently support 'insertCSS'"); } - private void ShowCordovaBrowser(string url) { Uri loc = new Uri(url, UriKind.RelativeOrAbsolute); @@ -200,7 +221,7 @@ namespace WPCordovaClassLib.Cordova.Commands if (cView != null) { WebBrowser br = cView.Browser; - br.Navigate(loc); + br.Navigate2(loc); } } @@ -208,13 +229,53 @@ namespace WPCordovaClassLib.Cordova.Commands }); } +#if WP8 + private async void ShowSystemBrowser(string url) + { + var pathUri = new Uri(url, UriKind.Absolute); + if (pathUri.Scheme == Uri.UriSchemeHttp || pathUri.Scheme == Uri.UriSchemeHttps) + { + await Launcher.LaunchUriAsync(pathUri); + return; + } + + var file = await GetFile(pathUri.AbsolutePath.Replace('/', Path.DirectorySeparatorChar)); + if (file != null) + { + await Launcher.LaunchFileAsync(file); + } + else + { + Debug.WriteLine("File not found."); + } + } + + private async Task GetFile(string fileName) + { + //first try to get the file from the isolated storage + var localFolder = ApplicationData.Current.LocalFolder; + if (IOFile.Exists(Path.Combine(localFolder.Path, fileName))) + { + return await localFolder.GetFileAsync(fileName); + } + + //if file is not found try to get it from the xap + var filePath = Path.Combine(Package.Current.InstalledLocation.Path, fileName); + if (IOFile.Exists(filePath)) + { + return await StorageFile.GetFileFromPathAsync(filePath); + } + + return null; + } +#else private void ShowSystemBrowser(string url) { WebBrowserTask webBrowserTask = new WebBrowserTask(); webBrowserTask.Uri = new Uri(url, UriKind.Absolute); webBrowserTask.Show(); } - +#endif private void ShowInAppBrowser(string url) { @@ -225,7 +286,7 @@ namespace WPCordovaClassLib.Cordova.Commands if (browser != null) { //browser.IsGeolocationEnabled = opts.isGeolocationEnabled; - browser.Navigate(loc); + browser.Navigate2(loc); } else { @@ -248,7 +309,7 @@ namespace WPCordovaClassLib.Cordova.Commands browser.Navigating += new EventHandler(browser_Navigating); browser.NavigationFailed += new System.Windows.Navigation.NavigationFailedEventHandler(browser_NavigationFailed); browser.Navigated += new EventHandler(browser_Navigated); - browser.Navigate(loc); + browser.Navigate2(loc); if (StartHidden) { @@ -287,6 +348,8 @@ namespace WPCordovaClassLib.Cordova.Commands bar.IsVisible = !StartHidden; AppBar = bar; + page.BackKeyPress += page_BackKeyPress; + } } @@ -294,6 +357,23 @@ namespace WPCordovaClassLib.Cordova.Commands }); } + void page_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e) + { +#if WP8 + if (browser.CanGoBack) + { + browser.GoBack(); + } + else + { + close(); + } + e.Cancel = true; +#else + browser.InvokeScript("execScript", "history.back();"); +#endif + } + void browser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e) { @@ -326,7 +406,7 @@ namespace WPCordovaClassLib.Cordova.Commands { #if WP8 browser.GoBack(); -#else +#else browser.InvokeScript("execScript", "history.back();"); #endif } @@ -361,13 +441,15 @@ namespace WPCordovaClassLib.Cordova.Commands grid.Children.Remove(browser); } page.ApplicationBar = null; + page.BackKeyPress -= page_BackKeyPress; } } + browser = null; string message = "{\"type\":\"exit\"}"; PluginResult result = new PluginResult(PluginResult.Status.OK, message); result.KeepCallback = false; - this.DispatchCommandResult(result); + this.DispatchCommandResult(result, NavigationCallbackId); }); } } @@ -385,7 +467,7 @@ namespace WPCordovaClassLib.Cordova.Commands string message = "{\"type\":\"loadstop\", \"url\":\"" + e.Uri.OriginalString + "\"}"; PluginResult result = new PluginResult(PluginResult.Status.OK, message); result.KeepCallback = true; - this.DispatchCommandResult(result); + this.DispatchCommandResult(result, NavigationCallbackId); } void browser_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e) @@ -393,7 +475,7 @@ namespace WPCordovaClassLib.Cordova.Commands string message = "{\"type\":\"error\",\"url\":\"" + e.Uri.OriginalString + "\"}"; PluginResult result = new PluginResult(PluginResult.Status.ERROR, message); result.KeepCallback = true; - this.DispatchCommandResult(result); + this.DispatchCommandResult(result, NavigationCallbackId); } void browser_Navigating(object sender, NavigatingEventArgs e) @@ -401,8 +483,33 @@ namespace WPCordovaClassLib.Cordova.Commands string message = "{\"type\":\"loadstart\",\"url\":\"" + e.Uri.OriginalString + "\"}"; PluginResult result = new PluginResult(PluginResult.Status.OK, message); result.KeepCallback = true; - this.DispatchCommandResult(result); + this.DispatchCommandResult(result, NavigationCallbackId); } } + + internal static class WebBrowserExtensions + { + /// + /// Improved method to initiate request to the provided URI. Supports 'data:text/html' urls. + /// + /// The browser instance + /// The requested uri + internal static void Navigate2(this WebBrowser browser, Uri uri) + { + // IE10 does not support data uri so we use NavigateToString method instead + if (uri.Scheme == "data") + { + // we should remove the scheme identifier and unescape the uri + string uriString = Uri.UnescapeDataString(uri.AbsoluteUri); + // format is 'data:text/html, ...' + string html = new System.Text.RegularExpressions.Regex("^data:text/html,").Replace(uriString, ""); + browser.NavigateToString(html); + } + else + { + browser.Navigate(uri); + } + } + } } diff --git a/www/inappbrowser.js b/www/inappbrowser.js index ebcfa24..3535b6f 100644 --- a/www/inappbrowser.js +++ b/www/inappbrowser.js @@ -90,6 +90,8 @@ module.exports = function(strUrl, strWindowName, strWindowFeatures) { iab._eventHandler(eventname); }; + strWindowFeatures = strWindowFeatures || ""; + exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]); return iab; }; diff --git a/www/windows8/InAppBrowserProxy.js b/www/windows8/InAppBrowserProxy.js index d173778..944284e 100644 --- a/www/windows8/InAppBrowserProxy.js +++ b/www/windows8/InAppBrowserProxy.js @@ -108,4 +108,4 @@ var IAB = { module.exports = IAB; -require("cordova/windows8/commandProxy").add("InAppBrowser", module.exports); +require("cordova/exec/proxy").add("InAppBrowser", module.exports);