diff --git a/package.json b/package.json index d6e0f9a..9c329de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cordova-plugin-hostedwebapp", - "version": "0.3.0", + "version": "0.3.1", "description": "Hosted Web App Plugin", "cordova": { "id": "cordova-plugin-hostedwebapp", diff --git a/plugin.xml b/plugin.xml index 7b5d021..6b9c3ed 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,7 +1,7 @@ + version="0.3.1"> HostedWebApp Hosted Web App Plugin MIT License diff --git a/src/ios/CDVHostedWebApp.h b/src/ios/CDVHostedWebApp.h index d0e7274..b385b10 100644 --- a/src/ios/CDVHostedWebApp.h +++ b/src/ios/CDVHostedWebApp.h @@ -13,20 +13,20 @@ @interface CDVHostedWebApp : CDVPlugin { - CVDWebViewNotificationDelegate *notificationDelegate; - NSDictionary *manifest; + CVDWebViewNotificationDelegate* notificationDelegate; + NSDictionary* manifest; } -@property (nonatomic, strong, readonly) NSDictionary *manifest; +@property (nonatomic, strong, readonly) NSDictionary* manifest; --(void) loadManifest:(CDVInvokedUrlCommand*)command; +- (void)loadManifest:(CDVInvokedUrlCommand*)command; --(void) getManifest:(CDVInvokedUrlCommand*)command; +- (void)getManifest:(CDVInvokedUrlCommand*)command; --(void) enableOfflinePage:(CDVInvokedUrlCommand*)command; +- (void)enableOfflinePage:(CDVInvokedUrlCommand*)command; --(void) disableOfflinePage:(CDVInvokedUrlCommand*)command; +- (void)disableOfflinePage:(CDVInvokedUrlCommand*)command; --(void) injectPluginScript:(CDVInvokedUrlCommand *)command; +- (void)injectPluginScript:(CDVInvokedUrlCommand*)command; @end diff --git a/src/ios/CDVHostedWebApp.m b/src/ios/CDVHostedWebApp.m index 635df4a..35f2757 100644 --- a/src/ios/CDVHostedWebApp.m +++ b/src/ios/CDVHostedWebApp.m @@ -19,25 +19,29 @@ @interface CDVHostedWebApp () @implementation CVDWebViewNotificationDelegate -- (void)webViewDidStartLoad:(UIWebView*)theWebView { - [self.wrappedDelegate webViewDidStartLoad: theWebView]; +- (void)webViewDidStartLoad:(UIWebView*)theWebView +{ + [self.wrappedDelegate webViewDidStartLoad:theWebView]; [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:kCDVHostedWebAppWebViewDidStartLoad object:theWebView]]; } -- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { +- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType +{ [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:kCDVHostedWebAppWebViewShouldStartLoadWithRequest object:request]]; return [self.wrappedDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; } -- (void)webViewDidFinishLoad:(UIWebView *)webView { +- (void)webViewDidFinishLoad:(UIWebView*)webView +{ [self.wrappedDelegate webViewDidFinishLoad:webView]; [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:kCDVHostedWebAppWebViewDidFinishLoad object:webView]]; } -- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { +- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error +{ [self.wrappedDelegate webView:webView didFailLoadWithError:error]; [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:kCDVHostedWebAppWebViewDidFailLoadWithError object:error]]; @@ -49,7 +53,7 @@ @implementation CDVHostedWebApp @synthesize manifest; -static NSString * const defaultManifestFileName = @"manifest.json"; +static NSString* const defaultManifestFileName = @"manifest.json"; - (void)pluginInitialize { @@ -57,7 +61,7 @@ - (void)pluginInitialize // observe notifications from network-information plugin to detect when device is offline [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(updateConnectivityStatus:) + selector:@selector(networkReachabilityChanged:) name:kReachabilityChangedNotification object:nil]; @@ -79,6 +83,18 @@ - (void)pluginInitialize name:kCDVHostedWebAppWebViewDidFailLoadWithError object:nil]; + // observe notifications from app when it pauses + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appStateChange) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; + + // observe notifications from app when it resumes + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appStateChange) + name:UIApplicationWillEnterForegroundNotification + object:nil]; + // enable offline support by default self.enableOfflineSupport = YES; @@ -103,8 +119,8 @@ - (void)pluginInitialize } // loads the specified W3C manifest --(void) loadManifest:(CDVInvokedUrlCommand *)command { - +- (void)loadManifest:(CDVInvokedUrlCommand*)command +{ CDVPluginResult* pluginResult = nil; NSString* manifestFileName = [command.arguments objectAtIndex:0]; @@ -119,8 +135,8 @@ -(void) loadManifest:(CDVInvokedUrlCommand *)command { } // returns the currently loaded manifest --(void) getManifest:(CDVInvokedUrlCommand *)command { - +- (void)getManifest:(CDVInvokedUrlCommand*)command +{ CDVPluginResult* pluginResult = nil; if (self.manifest != nil) { pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:self.manifest]; @@ -132,32 +148,32 @@ -(void) getManifest:(CDVInvokedUrlCommand *)command { } // enables offline page support --(void) enableOfflinePage:(CDVInvokedUrlCommand *)command { - +- (void)enableOfflinePage:(CDVInvokedUrlCommand*)command +{ self.enableOfflineSupport = YES; - CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:true]; + CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:true]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } // disables offline page support --(void) disableOfflinePage:(CDVInvokedUrlCommand *)command { - +- (void)disableOfflinePage:(CDVInvokedUrlCommand*)command +{ self.enableOfflineSupport = NO; CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:true]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } --(void) injectPluginScript:(CDVInvokedUrlCommand *)command { - +- (void)injectPluginScript:(CDVInvokedUrlCommand*)command +{ NSArray* scriptList = @[[command.arguments objectAtIndex:0]]; - BOOL result = [self injectScripts: scriptList]; + BOOL result = [self injectScripts:scriptList]; CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:result]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } // loads a manifest file and parses it --(NSDictionary *) loadManifestFile:(NSString *)manifestFileName { - +- (NSDictionary*)loadManifestFile:(NSString*)manifestFileName +{ self.manifestError = nil; if (manifestFileName == nil) { @@ -170,13 +186,13 @@ -(NSDictionary *) loadManifestFile:(NSString *)manifestFileName { return nil; } - NSData *manifestData = [NSData dataWithContentsOfFile:filePath]; + NSData* manifestData = [NSData dataWithContentsOfFile:filePath]; if (manifestData == nil) { self.manifestError = [NSString stringWithFormat:@"Error reading manifest file: %@", manifestFileName]; return nil; } - NSError *error = nil; + NSError* error = nil; id parsedManifest = [NSJSONSerialization JSONObjectWithData:manifestData options:0 error:&error]; if (error) { @@ -195,18 +211,18 @@ -(NSDictionary *) loadManifestFile:(NSString *)manifestFileName { return nil; } --(BOOL) injectScripts:(NSArray *)scriptList { - +- (BOOL)injectScripts:(NSArray*)scriptList +{ NSString* content = @""; for (NSString* scriptName in scriptList) { NSURL* scriptUrl = [NSURL URLWithString:scriptName relativeToURL:[NSURL URLWithString:@"www/"]]; NSString* scriptPath = scriptUrl.absoluteString; - NSError *error = nil; + NSError* error = nil; NSString* fileContents = nil; if (scriptUrl.scheme == nil) { - fileContents = [NSString stringWithContentsOfFile: [[NSBundle mainBundle] pathForResource: scriptPath ofType:nil] encoding:NSUTF8StringEncoding error:&error]; + fileContents = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:scriptPath ofType:nil] encoding:NSUTF8StringEncoding error:&error]; } else { @@ -225,7 +241,7 @@ -(BOOL) injectScripts:(NSArray *)scriptList { return[(UIWebView*)self.webView stringByEvaluatingJavaScriptFromString:content] != nil; } -- (BOOL) isCordovaEnabled +- (BOOL)isCordovaEnabled { BOOL enableCordova = NO; NSObject* setting = [self.manifest objectForKey:@"mjs_api_access"]; @@ -262,7 +278,7 @@ - (BOOL) isCordovaEnabled return enableCordova; } --(BOOL) isMatchingRuleForPage:(NSDictionary*) rule withPlatformCheck: (BOOL) checkPlatform +- (BOOL)isMatchingRuleForPage:(NSDictionary*)rule withPlatformCheck:(BOOL)checkPlatform { // ensure rule applies to current platform if (checkPlatform) @@ -295,7 +311,7 @@ -(BOOL) isMatchingRuleForPage:(NSDictionary*) rule withPlatformCheck: (BOOL) che NSArray* match = nil; if ([setting isKindOfClass:[NSArray class]]) { - match = (NSArray*) setting; + match = (NSArray*)setting; } else if ([setting isKindOfClass:[NSString class]]) { @@ -304,7 +320,7 @@ -(BOOL) isMatchingRuleForPage:(NSDictionary*) rule withPlatformCheck: (BOOL) che if (match != nil) { - CDVWhitelist *whitelist = [[CDVWhitelist alloc] initWithArray:match]; + CDVWhitelist* whitelist = [[CDVWhitelist alloc] initWithArray:match]; NSURL* url = ((UIWebView*)self.webView).request.URL; isURLMatch = [whitelist URLIsAllowed:url]; } @@ -338,7 +354,7 @@ - (void)createOfflineView [self.offlineView loadRequest:[NSURLRequest requestWithURL:offlinePageURL]]; } else { - NSString *offlinePageTemplate = @"
%@
"; + NSString* offlinePageTemplate = @"
%@
"; [self.offlineView loadHTMLString:[NSString stringWithFormat:offlinePageTemplate, @"It looks like you are offline. Please reconnect to use this application."] baseURL:nil]; @@ -347,26 +363,31 @@ - (void)createOfflineView [self.viewController.view sendSubviewToBack:self.webView]; } -// Handles notifications from the network-information plugin and shows the offline page whenever -// network connectivity is lost. It restores the original view once the network is up again. -- (void)updateConnectivityStatus:(NSNotification*)notification +- (void)networkReachabilityChanged:(NSNotification*)notification { if ([[notification name] isEqualToString:kReachabilityChangedNotification]) { CDVReachability* reachability = [notification object]; - if ((reachability != nil) && [reachability isKindOfClass:[CDVReachability class]]) { - BOOL isOffline = (reachability.currentReachabilityStatus == NotReachable); - NSLog (@"Received a network connectivity change notification. The device is currently %@.", isOffline ? @"offLine" : @"online"); - if (self.enableOfflineSupport) { - if (isOffline) { - [self.offlineView setHidden:NO]; + [self updateConnectivityStatus:reachability]; + } +} + +// Handles notifications from the network-information plugin and shows the offline page whenever +// network connectivity is lost. It restores the original view once the network is up again. +- (void)updateConnectivityStatus:(CDVReachability*)reachability +{ + if ((reachability != nil) && [reachability isKindOfClass:[CDVReachability class]]) { + BOOL isOffline = (reachability.currentReachabilityStatus == NotReachable); + NSLog (@"Received a network connectivity change notification. The device is currently %@.", isOffline ? @"offLine" : @"online"); + if (self.enableOfflineSupport) { + if (isOffline) { + [self.offlineView setHidden:NO]; + } + else { + if (self.failedURL) { + [(UIWebView*)self.webView loadRequest:[NSURLRequest requestWithURL:self.failedURL]]; } else { - if (self.failedURL) { - [(UIWebView*)self.webView loadRequest: [NSURLRequest requestWithURL: self.failedURL]]; - } - else { - [self.offlineView setHidden:YES]; - } + [self.offlineView setHidden:YES]; } } } @@ -423,18 +444,18 @@ - (void)webViewDidFinishLoad:(NSNotification*)notification NSMutableArray* scripts = [[NSMutableArray alloc] init]; if ([pluginMode isEqualToString:@"client"]) { - [scripts addObject: @"cordova.js"]; + [scripts addObject:@"cordova.js"]; } - [scripts addObject: @"hostedapp-bridge.js"]; - [self injectScripts: scripts]; + [scripts addObject:@"hostedapp-bridge.js"]; + [self injectScripts:scripts]; } // inject custom scripts NSObject* setting = [self.manifest objectForKey:@"mjs_import_scripts"]; if (setting != nil && [setting isKindOfClass:[NSArray class]]) { - NSArray* customScripts = (NSArray*) setting; + NSArray* customScripts = (NSArray*)setting; if (customScripts != nil && customScripts.count > 0) { for (NSDictionary* item in customScripts) @@ -442,7 +463,7 @@ - (void)webViewDidFinishLoad:(NSNotification*)notification if ([self isMatchingRuleForPage:item withPlatformCheck:NO]) { NSString* source = [item valueForKey:@"src"]; - [self injectScripts: @[source]]; + [self injectScripts:@[source]]; } } } @@ -475,7 +496,7 @@ - (void)didWebViewFailLoadWithError:(NSNotification*)notification } #ifndef __CORDOVA_4_0_0 -- (BOOL) shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType +- (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType { NSURL* url = [request URL]; @@ -490,9 +511,8 @@ - (BOOL) shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UI return NO; } -#endif --(BOOL) shouldAllowNavigation:(NSURL*) url +- (BOOL)shouldAllowNavigation:(NSURL*)url { NSMutableArray* scopeList = [[NSMutableArray alloc] initWithCapacity:0]; @@ -523,12 +543,12 @@ -(BOOL) shouldAllowNavigation:(NSURL*) url NSObject* setting = [self.manifest objectForKey:@"mjs_access_whitelist"]; if (setting != nil && [setting isKindOfClass:[NSArray class]]) { - NSArray* accessRules = (NSArray*) setting; + NSArray* accessRules = (NSArray*)setting; if (accessRules != nil) { for (NSDictionary* rule in accessRules) { - NSString *accessUrl = [rule objectForKey:@"url"]; + NSString* accessUrl = [rule objectForKey:@"url"]; if (accessUrl != nil) { [scopeList addObject:accessUrl]; @@ -541,7 +561,7 @@ -(BOOL) shouldAllowNavigation:(NSURL*) url setting = [self.manifest objectForKey:@"mjs_extended_scope"]; if (setting != nil && [setting isKindOfClass:[NSArray class]]) { - NSArray* scopeRules = (NSArray*) setting; + NSArray* scopeRules = (NSArray*)setting; if (scopeRules != nil) { for (NSString* rule in scopeRules) @@ -553,5 +573,14 @@ -(BOOL) shouldAllowNavigation:(NSURL*) url return [[[CDVWhitelist alloc] initWithArray:scopeList] URLIsAllowed:url]; } +#endif + +// Updates the network connectivity status when the app is paused or resumes +// NOTE: for onPause and onResume, calls into JavaScript must not call or trigger any blocking UI, like alerts +- (void)appStateChange +{ + CDVConnection* connection = [self.commandDelegate getCommandInstance:@"NetworkStatus"]; + [self updateConnectivityStatus:connection.internetReach]; +} @end