I have a phonegap/cordova app and when I call the ChildBrowser from the app, exit the childbrowser, and go back to app, the webview goes under status bar.
There are a million answers as to how to prevent webview (in iOS7 and later) from going under status bar. That is not the issue here because initially the app is fine and its webview is not overlapping with the status bar.
The issue happens only after exiting the childbrowser.
Basic flow:
Launch app (all is fine) -> call ChildBrowser (from app) -> Exit ChildBrowser -> back to app (PROBLEM: webview under status bar).
Please ask for clarifications and please advise.
AppDelegate.m
/*
Licensed to the Apache Software Foundation (ASF) under one
...
*/
//
// AppDelegate.m
#import "AppDelegate.h"
#import "MainViewController.h"
#ifdef CORDOVA_FRAMEWORK
#import <Cordova/CDVPlugin.h>
#import <Cordova/CDVURLProtocol.h>
#else
#import "CDVPlugin.h"
#import "CDVURLProtocol.h"
#endif
#implementation AppDelegate
#synthesize window, viewController;
- (id) init
{
/** If you need to do any extra app-specific initialization, you can do it here
* -jm
**/
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
[cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
[CDVURLProtocol registerURLProtocol];
return [super init];
}
#pragma UIApplicationDelegate implementation
/**
* This is main kick off after the app inits, the views and Settings are setup here. (preferred - iOS4 and up)
*/
- (BOOL) application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
NSURL* url = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey];
NSString* invokeString = nil;
if (url && [url isKindOfClass:[NSURL class]]) {
invokeString = [url absoluteString];
NSLog(#"ios-cordova-childbrowser launchOptions = %#", url);
}
CGRect screenBounds = [[UIScreen mainScreen] bounds];
self.window = [[[UIWindow alloc] initWithFrame:screenBounds] autorelease];
self.window.autoresizesSubviews = YES;
CGRect viewBounds = [[UIScreen mainScreen] applicationFrame];
self.viewController = [[[MainViewController alloc] init] autorelease];
self.viewController.useSplashScreen = YES;
self.viewController.wwwFolderName = #"www";
self.viewController.startPage = #"index.html";
self.viewController.invokeString = invokeString;
self.viewController.view.frame = viewBounds;
// check whether the current orientation is supported: if it is, keep it, rather than forcing a rotation
BOOL forceStartupRotation = YES;
UIDeviceOrientation curDevOrientation = [[UIDevice currentDevice] orientation];
if (UIDeviceOrientationUnknown == curDevOrientation) {
// UIDevice isn't firing orientation notifications yet… go look at the status bar
curDevOrientation = (UIDeviceOrientation)[[UIApplication sharedApplication] statusBarOrientation];
}
if (UIDeviceOrientationIsValidInterfaceOrientation(curDevOrientation)) {
for (NSNumber *orient in self.viewController.supportedOrientations) {
if ([orient intValue] == curDevOrientation) {
forceStartupRotation = NO;
break;
}
}
}
if (forceStartupRotation) {
NSLog(#"supportedOrientations: %#", self.viewController.supportedOrientations);
// The first item in the supportedOrientations array is the start orientation (guaranteed to be at least Portrait)
UIInterfaceOrientation newOrient = [[self.viewController.supportedOrientations objectAtIndex:0] intValue];
NSLog(#"AppDelegate forcing status bar to: %d from: %d", newOrient, curDevOrientation);
[[UIApplication sharedApplication] setStatusBarOrientation:newOrient];
}
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];
[sharedCache release];
[self.window addSubview:self.viewController.view];
[self.window makeKeyAndVisible];
[[UIApplication sharedApplication]setStatusBarStyle:UIStatusBarStyleBlackTranslucent];
return YES;
}
// this happens while we are running ( in the background, or from within our own app )
// only valid if ios-cordova-childbrowser-Info.plist specifies a protocol to handle
- (BOOL) application:(UIApplication*)application handleOpenURL:(NSURL*)url
{
if (!url) {
return NO;
}
// calls into javascript global function 'handleOpenURL'
NSString* jsString = [NSString stringWithFormat:#"handleOpenURL(\"%#\");", url];
[self.viewController.webView stringByEvaluatingJavaScriptFromString:jsString];
// all plugins will get the notification, and their handlers will be called
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]];
return YES;
}
- (void) dealloc
{
[super dealloc];
}
- (void)setOrientation:(NSMutableArray *)arguments
{
NSLog(#"setting orientation");
MainViewController *vc = self.viewController;
[vc setDevideDirection:2];
//self.viewController.supportedOrientations = arguments;
//self.viewController.supportedOrientations = arguments;
}
#end
Related
After searching on Stackoverflow, I was unable to find a duplicate question with the solution I needed and at one point this code was working fine until recently, here is the stack trace from the debug console:
2016-10-10 17:01:27.873567 Eboticon[1628:411719] [DYMTLInitPlatform] platform initialization successful
2016-10-10 17:01:28.042711 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.ratchpack3
2016-10-10 17:01:28.042838 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.greetingspack1
2016-10-10 17:01:28.042902 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.baepack1
2016-10-10 17:01:28.042959 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.ratchpack1
2016-10-10 17:01:28.043014 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.churchpack1
2016-10-10 17:01:28.043068 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.greekpack2
2016-10-10 17:01:28.043122 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.ratchpack2
2016-10-10 17:01:28.043176 Eboticon[1628:411555] Not purchased: com.eboticon.Eboticon.churchpack2
warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available.
2016-10-10 17:06:16.186456 Eboticon[1628:411555] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
*** First throw call stack:
(0x18f5b41c0 0x18dfec55c 0x18f493ad4 0x1000ec6d8 0x1000eb7ec 0x19546e61c 0x19567ed60 0x195684ad0 0x195699270 0x195681ab4 0x191155904 0x191155770 0x191155b18 0x18f562278 0x18f561bc0 0x18f55f7c0 0x18f48e048 0x1954677cc 0x195462550 0x100118f9c 0x18e4705b8)
libc++abi.dylib: terminating with uncaught exception of type NSException
When adding an Exception breakpoint, it points to this line of code being the problem:
[arrImagePagerImages addObject:[UIImage imageWithData:data]];
Here is the full code base with the problematic code towards the end:
#import "AppDelegate.h"
#import "JMCategoriesData.h"
#import "MasterViewController.h"
#import "GAI.h"
#import "GAIFields.h"
#import "iRate.h"
#import "DDLog.h"
#import "DDTTYLogger.h"
#import "Harpy.h"
#import "Constants.h"
#import <Fabric/Fabric.h>
#import <Crashlytics/Crashlytics.h>
#import <Parse/Parse.h>
#import "SWRevealViewController.h"
#import "RightViewController.h"
#import "XOSplashVideoController.h"
#define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
#interface AppDelegate()<SWRevealViewControllerDelegate>
#end
#implementation AppDelegate
#pragma mark -
#pragma mark AppDelegate Methods
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Register for Push Notitications
UIUserNotificationType userNotificationTypes = (UIUserNotificationTypeAlert |
UIUserNotificationTypeBadge |
UIUserNotificationTypeSound);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:userNotificationTypes
categories:nil];
[application registerUserNotificationSettings:settings];
[application registerForRemoteNotifications];
//[self showSplashVideo];
//PARSE
//[Parse setApplicationId:#"gBcNi8fexXd1Uiggm6e2hRFuOPkoEefsbxLDNzO7"
//clientKey:#"dKZXWc9CXdksCA7HPVSCp0Yz0tTBQuqnQEvXKwL6"];
[PFAnalytics trackAppOpenedWithLaunchOptions:launchOptions];
[self initialize];
// Override point for customization after application launch.
return YES;
}
/**
* Setup iRate rating scheme
*/
- (void) configureiRate
{
#try {
[iRate sharedInstance].appStoreID = appStoreID;
[iRate sharedInstance].daysUntilPrompt = 10;
[iRate sharedInstance].usesUntilPrompt = 5;
//[iRate sharedInstance].verboseLogging = YES;
[iRate sharedInstance].promptAtLaunch = YES;
[iRate sharedInstance].eventsUntilPrompt = 5;
[iRate sharedInstance].promptForNewVersionIfUserRated = YES;
[iRate sharedInstance].remindPeriod = 7;
//TODO: Set below to no before deploying!
[iRate sharedInstance].previewMode = NO;
DDLogInfo(#"%#: Number of events until iRate launch %lu", NSStringFromClass(self.class), (unsigned long)[iRate sharedInstance].eventCount);
DDLogInfo(#"%#: Number of iRate uses %lu", NSStringFromClass(self.class), (unsigned long)[iRate sharedInstance].usesCount);
DDLogInfo(#"%#: Prompt for rating criteria met: %lu", NSStringFromClass(self.class), (unsigned long)[iRate sharedInstance].shouldPromptForRating);
}
#catch (NSException *exception) {
DDLogError(#"[ERROR] in enabling iRate: %#", exception.description);
}
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// Store the deviceToken in the current installation and save it to Parse.
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:deviceToken];
currentInstallation.channels = #[ #"global" ];
[currentInstallation saveInBackground];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[PFPush handlePush:userInfo];
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
#pragma mark -
#pragma mark Initialize
- (void) showSplashVideo {
CGRect frame = [[UIScreen mainScreen] bounds];
self.window = [[UIWindow alloc] initWithFrame:frame];
NSLog(#"Screen Height %f", self.window.frame.size.height);
NSString *portraitVideoName = #"EboticonIntroNEW640x960";
NSString *portraitImageName = #"iphone640x960.png";
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && self.window.frame.size.height > 480) {
portraitImageName = #"iphone640x1136.png";
portraitVideoName = #"EboticonIntroNEW640x1136";
}
NSString *landscapeVideoName = nil; // n/a
NSString *landscapeImageName = nil; // n/a
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
portraitVideoName = #"EboticonIntroNEW768x1024";
portraitImageName = #"ipad768x1024.png";
landscapeVideoName = #"EboticonIntroNEW768x1024.mp4";
landscapeImageName = #"ipad768x1024.png";
}
// our video
NSURL *portraitUrl = [[NSBundle mainBundle] URLForResource:portraitVideoName withExtension:#"mp4"];
NSURL *landscapeUrl = [[NSBundle mainBundle] URLForResource:landscapeVideoName withExtension:#"mp4"];
// our splash controller
XOSplashVideoController *splashVideoController =
[[XOSplashVideoController alloc] initWithVideoPortraitUrl:portraitUrl
portraitImageName:portraitImageName
landscapeUrl:landscapeUrl
landscapeImageName:landscapeImageName
delegate:self];
// we'll start out with the spash view controller in the window
self.window.rootViewController = splashVideoController;
[self.window makeKeyAndVisible];
}
- (void) initialize {
_products = nil;
[[EboticonIAPHelper sharedInstance] requestProductsWithCompletionHandler:^(BOOL success, NSArray *products) {
if (success) {
_products = products;
NSLog(#"--------DONE-------");
}
}];
arrImagePagerImages = [[NSMutableArray alloc]init];
for (NSInteger i = 1 ; i <= 4 ; i ++){
NSString *sUrl = [NSString stringWithFormat:#"http://www.inclingconsulting.com/eboticon/store/banner%i.png", (int)i];
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: sUrl]];
if (data == nil)continue;
[arrImagePagerImages addObject:[UIImage imageWithData:data]];
}
//Setting up Navigation Bar
[[UINavigationBar appearance] setBarTintColor:UIColorFromRGB(0x380063)];
NSShadow *shadow = [[NSShadow alloc] init];
shadow.shadowColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8];
shadow.shadowOffset = CGSizeMake(0, 1);
[[UINavigationBar appearance] setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys:
[UIColor colorWithRed:245.0/255.0 green:245.0/255.0 blue:245.0/255.0 alpha:1.0], NSForegroundColorAttributeName,
shadow, NSShadowAttributeName,
[UIFont fontWithName:#"Avenir-Black" size:21.0], NSFontAttributeName, nil]];
[[UINavigationBar appearance] setTintColor:UIColorFromRGB(0xFf6c00)]; //Color of back button
//Tabbar With sidebar Items
NSNumber *caption = #(1); //initialize caption to on
self.tabBarController = [[TabViewController alloc] initWithCaption:caption];
RightViewController *rightViewController = [[RightViewController alloc] init];
SWRevealViewController *mainRevealController = [[SWRevealViewController alloc]
initWithRearViewController:rightViewController frontViewController:self.tabBarController];
mainRevealController.rightViewController = rightViewController;
mainRevealController.delegate = self;
self.viewController = mainRevealController;
//Add Tab Bar
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
//self.window.rootViewController = self.tabBarController;
self.window.rootViewController = self.viewController;
UIImageView *splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Default.png"]];
[self.window addSubview:splashScreen];
[self.window makeKeyAndVisible];
[UIView animateWithDuration:0.3 animations:^{splashScreen.alpha = 0.0;}
completion:(void (^)(BOOL)) ^{
[splashScreen removeFromSuperview];
}
];
// Present Window before calling Harpy
//[self.window makeKeyAndVisible];
//GOOGLE ANALYTICS INITIALIZER
// Optional: automatically send uncaught exceptions to Google Analytics.
[GAI sharedInstance].trackUncaughtExceptions = YES;
// Optional: set Google Analytics dispatch interval to e.g. 20 seconds.
[GAI sharedInstance].dispatchInterval = 20;
// Optional: set Logger to VERBOSE for debug information.
[[[GAI sharedInstance] logger] setLogLevel:kGAILogLevelError];
// Initialize tracker. Replace with your tracking ID.
#ifdef FREE
[[GAI sharedInstance] trackerWithTrackingId:#"UA-48552713-3"];
DDLogInfo(#"Google Analytics Enabled for Lite Version");
#else
[[GAI sharedInstance] trackerWithTrackingId:#"UA-48552713-4"];
DDLogInfo(#"Google Analytics Enabled for Paid Version");
#endif
//Set dry run to yes for testing purposes
[[GAI sharedInstance] setDryRun:NO];
//Set version for app tracking
NSString *version = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
[[GAI sharedInstance].defaultTracker set:kGAIAppVersion value:version];
[[GAI sharedInstance].defaultTracker set:kGAISampleRate value:#"50.0"];
//Cocoalumberjack init files
[DDLog addLogger:[DDTTYLogger sharedInstance]];
[[DDTTYLogger sharedInstance] setColorsEnabled:YES];
//configure iRate
[self configureiRate];
//Harpy
//TODO: turn on Harpy
[self configureHarpy];
//FABRIC
[Fabric with:#[CrashlyticsKit]];
}
/**
* Setup Harpy update reminder
*/
- (void) configureHarpy
{
#try {
// Set the App ID for your app
#ifdef FREE
[[Harpy sharedInstance] setAppID:#"977505283"];
#else
[[Harpy sharedInstance] setAppID:#"899011953"];
#endif
// Set the UIViewController that will present an instance of UIAlertController
[[Harpy sharedInstance] setPresentingViewController:_window.rootViewController];
// (Optional) The tintColor for the alertController
//[[Harpy sharedInstance] setAlertControllerTintColor:#"<#alert_controller_tint_color#>"];
// (Optional) Set the App Name for your app
#ifdef FREE
[[Harpy sharedInstance] setAppName:#"Eboticon Lite"];
#else
[[Harpy sharedInstance] setAppName:#"Eboticon"];
#endif
// Perform check for new version of your app
[[Harpy sharedInstance] checkVersion];
}
#catch (NSException *exception) {
DDLogError(#"[ERROR] in enabling Harpy: %#", exception.description);
}
}
#pragma mark -
#pragma mark Reveal Controller Delegate
- (NSString*)stringFromFrontViewPosition:(FrontViewPosition)position
{
NSString *str = nil;
if ( position == FrontViewPositionLeft ) str = #"FrontViewPositionLeft";
if ( position == FrontViewPositionRight ) str = #"FrontViewPositionRight";
if ( position == FrontViewPositionRightMost ) str = #"FrontViewPositionRightMost";
if ( position == FrontViewPositionRightMostRemoved ) str = #"FrontViewPositionRightMostRemoved";
return str;
}
- (void)revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position
{
NSLog( #"%#: %#", NSStringFromSelector(_cmd), [self stringFromFrontViewPosition:position]);
}
- (void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position
{
NSLog( #"%#: %#", NSStringFromSelector(_cmd), [self stringFromFrontViewPosition:position]);
}
- (void)revealController:(SWRevealViewController *)revealController willRevealRearViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
- (void)revealController:(SWRevealViewController *)revealController didRevealRearViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
- (void)revealController:(SWRevealViewController *)revealController willHideRearViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
- (void)revealController:(SWRevealViewController *)revealController didHideRearViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
- (void)revealController:(SWRevealViewController *)revealController willShowFrontViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
- (void)revealController:(SWRevealViewController *)revealController didShowFrontViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
- (void)revealController:(SWRevealViewController *)revealController willHideFrontViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
- (void)revealController:(SWRevealViewController *)revealController didHideFrontViewController:(UIViewController *)rearViewController
{
NSLog( #"%#", NSStringFromSelector(_cmd));
}
#pragma mark Splash Video
- (void)splashVideoLoaded:(XOSplashVideoController *)splashVideo
{
// load up our real view controller, but don't put it in to the window until the video is done
// if there's anything expensive to do it should happen in the background now
//
// self.viewController = [[XOViewController alloc] initWithNibName:#"XOViewController" bundle:nil];
}
- (void)splashVideoComplete:(XOSplashVideoController *)splashVideo
{
// swap out the splash controller for our app's
//self.window.rootViewController = self.viewController;
[self initialize];
}
#end
When we comment out the problematic line, the app runs fine but won't display the needed array. When I do an NSLog of the array, it displays the addresses of objects. Any suggestions on why it won't display the objects and the system thinks its nil?
[UIImage imageWithData:] may return nil if the data supplied cannot be converted to an image. If this happens then you will get the exception because you are adding the result to an array without checking, and NSMutableArray cannot contain nil.
You should convert the image separately and only add it to the array if it is non-nil:
UIImage *image = [UIImage imageWithData:data];
if (image != nil) {
[arrImagePagerImages addObject:image];
} else {
NSLog(#"Unable to convert data to image");
}
acctually the problem is with your nsdata assignment
for (NSInteger i = 1 ; i <= 4 ; i ++){
NSString *sUrl = [NSString stringWithFormat:#"http://www.inclingconsulting.com/eboticon/store/banner%i.png", (int)i];
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: sUrl]];
if (data == nil)continue;
[arrImagePagerImages addObject:[UIImage imageWithData:data]];
}
as you are initiating new nsdata with url so it could be nil so for achieving this you have to check the length as well also you have to check check that data should not be null.
please try this
for (NSInteger i = 1 ; i <= 4 ; i ++){
NSString *sUrl = [NSString stringWithFormat:#"http://www.inclingconsulting.com/eboticon/store/banner%i.png", (int)i];
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: sUrl]];
if ([data isKindOfClass:[NSData class]] && data.length == 0){
NSLog(#"no data");
}else{
[arrImagePagerImages addObject:[UIImage imageWithData:data]]}
}
I am working on a web application that uses html5, css3, and jquery as the app. We run the web files through XCODE and use XCODE to upload the "apps" to iPads.
Recently we have been getting a memory warning and a crash after the splash screen spins for a few seconds.
The apps work fine in the XCODE simulator, and we have noticed that it seems to happen when the app has video files (even small ones like 800KB).
Here is the console from running the app on the iPad.
How do we prevent this crash?
Aug 15 11:50:12 BD-Graphics-Lab-6-iPad3 BD Push Button[4020]
: Multi-tasking -> Device: YES, App: YES
Aug 15 11:50:12
BD-Graphics-Lab-6-iPad3 kernel[0] : launchd[4020] Builtin
profile: container (sandbox)
Aug 15 11:50:12 BD-Graphics-Lab-6-iPad3
kernel[0] : launchd[4020] Container:
/private/var/mobile/Applications/997C5F22-C5A6-4A05-96C8-8ABEA9DAAC8A
(sandbox)
Aug 15 11:50:12 BD-Graphics-Lab-6-iPad3 BD Push
Button[4020] : Resetting plugins due to page load.
Aug 15
11:50:15 BD-Graphics-Lab-6-iPad3 BD Push Button[4020] :
Received memory warning.
Aug 15 11:50:17 BD-Graphics-Lab-6-iPad3
UserEventAgent[13] : jetsam: kernel termination snapshot being
created
Aug 15 11:50:17 BD-Graphics-Lab-6-iPad3 com.apple.launchd1
(UIKitApplication:com.bd.Push.us.y[0x4721][4020]) :
(UIKitApplication:com.bd.Push.us.y[0x4721]) Exited: Killed: 9
Aug 15
11:50:17 BD-Graphics-Lab-6-iPad3 backboardd[26] : Application
'UIKitApplication:com.bd.Push.us.y[0x4721]' exited abnormally with
signal 9: Killed: 9
Aug 15 11:50:17 BD-Graphics-Lab-6-iPad3
ReportCrash[4021] : libMobileGestalt
copySystemVersionDictionaryValue: Could not lookup ReleaseType from
system version dictionary
Aug 15 11:50:17 BD-Graphics-Lab-6-iPad3
ReportCrash[4021] : Saved crashreport to
/Library/Logs/CrashReporter/LowMemory-2013-08-15-115017.plist using
uid: 0 gid: 0, synthetic_euid: 0 egid: 0
AppDelegate.m
#implementation AppDelegate
#synthesize window, viewController;
- (id)init
{
/** If you need to do any extra app-specific initialization, you can do it here
* -jm
**/
NSHTTPCookieStorage* cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
[cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
int cacheSizeMemory = 8 * 1024 * 1024; // 8MB
int cacheSizeDisk = 32 * 1024 * 1024; // 32MB
#if __has_feature(objc_arc)
NSURLCache* sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:#"nsurlcache"];
#else
NSURLCache* sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:#"nsurlcache"] autorelease];
#endif
[NSURLCache setSharedURLCache:sharedCache];
self = [super init];
return self;
}
#pragma mark UIApplicationDelegate implementation
/**
* This is main kick off after the app inits, the views and Settings are setup here. (preferred - iOS4 and up)
*/
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
int cacheSizeMemory = 16*1024*1024; // 16MB
int cacheSizeDisk = 32*1024*1024; // 32MB
NSURLCache *sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:#"nsurlcache"] autorelease];
[NSURLCache setSharedURLCache:sharedCache];
CGRect screenBounds = [[UIScreen mainScreen] bounds];
#if __has_feature(objc_arc)
self.window = [[UIWindow alloc] initWithFrame:screenBounds];
#else
self.window = [[[UIWindow alloc] initWithFrame:screenBounds] autorelease];
#endif
self.window.autoresizesSubviews = YES;
#if __has_feature(objc_arc)
self.viewController = [[MainViewController alloc] init];
#else
self.viewController = [[[MainViewController alloc] init] autorelease];
#endif
self.viewController.useSplashScreen = YES;
// Set your app's start page by setting the <content src='foo.html' /> tag in config.xml.
// If necessary, uncomment the line below to override it.
// self.viewController.startPage = #"index.html";
// NOTE: To customize the view's frame size (which defaults to full screen), override
// [self.viewController viewWillAppear:] in your view controller.
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
// this happens while we are running ( in the background, or from within our own app )
// only valid if flush.ca.mbp-Info.plist specifies a protocol to handle
- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url
{
if (!url) {
return NO;
}
// calls into javascript global function 'handleOpenURL'
NSString* jsString = [NSString stringWithFormat:#"handleOpenURL(\"%#\");", url];
[self.viewController.webView stringByEvaluatingJavaScriptFromString:jsString];
// all plugins will get the notification, and their handlers will be called
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]];
return YES;
}
// repost the localnotification using the default NSNotificationCenter so multiple plugins may respond
- (void) application:(UIApplication*)application
didReceiveLocalNotification:(UILocalNotification*)notification
{
// re-post ( broadcast )
[[NSNotificationCenter defaultCenter] postNotificationName:CDVLocalNotification object:notification];
}
- (NSUInteger)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window
{
// iPhone doesn't support upside down by default, while the iPad does. Override to allow all orientations always, and let the root view controller decide what's allowed (the supported orientations mask gets intersected).
NSUInteger supportedInterfaceOrientations = (1 << UIInterfaceOrientationPortrait) | (1 << UIInterfaceOrientationLandscapeLeft) | (1 << UIInterfaceOrientationLandscapeRight) | (1 << UIInterfaceOrientationPortraitUpsideDown);
return supportedInterfaceOrientations;
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication*)application
{
[[NSURLCache sharedURLCache] removeAllCachedResponses];
NSLog(#"Cache Cleared");
}
CDVViewController.m
- (void)didReceiveMemoryWarning
{
// iterate through all the plugin objects, and call hasPendingOperation
// if at least one has a pending operation, we don't call [super didReceiveMemoryWarning]
NSEnumerator* enumerator = [self.pluginObjects objectEnumerator];
CDVPlugin* plugin;
BOOL doPurge = YES;
while ((plugin = [enumerator nextObject])) {
if (plugin.hasPendingOperation) {
NSLog(#"Plugin '%#' has a pending operation, memory purge is delayed for didReceiveMemoryWarning.", NSStringFromClass([plugin class]));
doPurge = NO;
}
}
if (doPurge) {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
}
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload
{
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.webView.delegate = nil;
self.webView = nil;
[CDVUserAgentUtil releaseLock:&_userAgentLockToken];
}
#pragma mark UIWebViewDelegate
/**
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.");
[_commandQueue resetRequestId];
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginResetNotification object:self.webView]];
}
/**
Called when the webview finishes loading. This stops the activity view.
*/
- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{
NSLog(#"Finished load of: %#", theWebView.request.URL);
// It's safe to release the lock even if this is just a sub-frame that's finished loading.
[CDVUserAgentUtil releaseLock:&_userAgentLockToken];
/*
* Hide the Top Activity THROBBER in the Battery Bar
*/
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[self processOpenUrl];
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:self.webView]];
}
I had an issue with my app as well using phonegap, but once we implemented this fix in the app delegate all was working perfectly. In your case since you said emptying the cache was not working, maybe you just need to specify the cache size in which case just use the (BOOL)application code below.
In the appdelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
int cacheSizeMemory = 16*1024*1024; // 16MB
int cacheSizeDisk = 32*1024*1024; // 32MB
NSURLCache *sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:#"nsurlcache"] autorelease];
[NSURLCache setSharedURLCache:sharedCache];
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
[[NSURLCache sharedURLCache] removeAllCachedResponses];
NSLog(#"Cache Cleared");
}
Additionally we used this in the CDVViewController.m to clear it every 1 second,
- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{ //...
[[NSURLCache sharedURLCache] removeAllCachedResponses];
NSLog(#"Cache Cleared");
[NSTimer scheduledTimerWithTimeInterval: 1.0
target: self
selector:#selector(onTick:)
userInfo: nil repeats: YES];
}
-(void)onTick:(NSTimer *)timer {
[[NSURLCache sharedURLCache] removeAllCachedResponses];
NSLog(#"Cache Cleared");
}
I have just added push notifications to my app. I'm wanting to have so that when a user opens the app from a notification, it will open a specific view controller and not my rootViewController. Here is my AppDelegate:
#import "KFBAppDelegate.h"
#import "KFBViewController.h"
#import "AboutUs.h"
#import "ContactUs.h"
#import "KYFB.h"
#import "KFBNavControllerViewController.h"
#import "KFBTabBarViewController.h"
#import "RSFM.h"
#import "LegislatorInfo.h"
#import "Events.h"
#import "ActionAlertsViewController.h"
#import "UAirship.h"
#import "UAPush.h"
#import "UAAnalytics.h"
#implementation KFBAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// This prevents the UA Library from registering with UIApplcation by default when
// registerForRemoteNotifications is called. This will allow you to prompt your
// users at a later time. This gives your app the opportunity to explain the benefits
// of push or allows users to turn it on explicitly in a settings screen.
// If you just want everyone to immediately be prompted for push, you can
// leave this line out.
// [UAPush setDefaultPushEnabledValue:NO];
//Create Airship options dictionary and add the required UIApplication launchOptions
NSMutableDictionary *takeOffOptions = [NSMutableDictionary dictionary];
[takeOffOptions setValue:launchOptions forKey:UAirshipTakeOffOptionsLaunchOptionsKey];
// Call takeOff (which creates the UAirship singleton), passing in the launch options so the
// library can properly record when the app is launched from a push notification. This call is
// required.
//
// Populate AirshipConfig.plist with your app's info from https://go.urbanairship.com
[UAirship takeOff:takeOffOptions];
// Set the icon badge to zero on startup (optional)
[[UAPush shared] resetBadge];
// Register for remote notfications with the UA Library. This call is required.
[[UAPush shared] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound |
UIRemoteNotificationTypeAlert)];
// Handle any incoming incoming push notifications.
// This will invoke `handleBackgroundNotification` on your UAPushNotificationDelegate.
[[UAPush shared] handleNotification:[launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey]
applicationState:application.applicationState];
// self.tabBarController = [[UITabBarController alloc] initWithNibName:#"KFBViewController" bundle:nil];
KFBViewController *rootView = [[KFBViewController alloc] initWithNibName:#"KFBViewController" bundle:nil];
KFBNavControllerViewController *navController = [[KFBNavControllerViewController alloc] initWithRootViewController:rootView];
navController.delegate = rootView;
UIViewController *aboutUs = [[AboutUs alloc] initWithNibName:#"AboutUs" bundle:nil];
KFBNavControllerViewController *navController1 = [[KFBNavControllerViewController alloc] initWithRootViewController:aboutUs];
UIViewController *contactUs = [[ContactUs alloc] initWithNibName:#"ContactUs" bundle:nil];
KFBNavControllerViewController *navController2 = [[KFBNavControllerViewController alloc] initWithRootViewController:contactUs];
UIViewController *kyfb = [[KYFB alloc] initWithNibName:#"KYFB" bundle:nil];
KFBNavControllerViewController *navController3 = [[KFBNavControllerViewController alloc] initWithRootViewController:kyfb];
// UIViewController *rsfm = [[RSFM alloc] initWithNibName:#"RSFM" bundle:nil];
// KFBNavControllerViewController *navController4 = [[KFBNavControllerViewController alloc] initWithRootViewController:rsfm];
// UIViewController *li = [[LegislatorInfo alloc] initWithNibName:#"LegislatorInfo" bundle:nil];
// KFBNavControllerViewController *navController5 = [[KFBNavControllerViewController alloc] initWithRootViewController:li];
// UIViewController *events = [[Events alloc] initWithNibName:#"Events" bundle:nil];
// KFBNavControllerViewController *navController6 = [[KFBNavControllerViewController alloc] initWithRootViewController:events];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
//self.viewController = [[KFBViewController alloc] initWithNibName:#"KFBViewController" bundle:nil];
//self.window.rootViewController = self.viewController;
self.tabBarController = [[KFBTabBarViewController alloc] init];
self.tabBarController.viewControllers = #[navController, navController1, navController2, navController3];
// self.tabBarController.customizableViewControllers = nil;
self.window.rootViewController = self.tabBarController;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
UA_LDEBUG(#"Application did become active.");
// Set the icon badge to zero on resume (optional)
[[UAPush shared] resetBadge];
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
[UAirship land];
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// Updates the device token and registers the token with UA.
[[UAPush shared] registerDeviceToken:deviceToken];
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *) error
{
UA_LERR(#"Failed To Register For Remote Notifications With Error: %#", error);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
UA_LINFO(#"Received remote notification: %#", userInfo);
// Send the alert to UA so that it can be handled and tracked as a direct response. This call
// is required.
[[UAPush shared] handleNotification:userInfo applicationState:application.applicationState];
// Optionally provide a delegate that will be used to handle notifications received while the app is running
// [UAPush shared].delegate = your custom push delegate class conforming to the UAPushNotificationDelegate protocol
// Reset the badge after a push received (optional)
[[UAPush shared] resetBadge];
}
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
#end
And here is the view controller I want to open when opening a notification:
#import "ActionAlertsViewController.h"
#import "RSSChannel.h"
#import "RSSItem.h"
#import "WebViewController.h"
#import "CustomCellBackground.h"
#implementation ActionAlertsViewController
{
UIActivityIndicatorView *loadingIndicator;
}
#synthesize webViewController;
- (void)viewDidLoad
{
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
self.title = #"Action Alerts";
loadingIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
loadingIndicator.center = CGPointMake(160, 160);
loadingIndicator.hidesWhenStopped = YES;
[self.view addSubview:loadingIndicator];
[loadingIndicator startAnimating];
// UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
// refresh.attributedTitle = [[NSAttributedString alloc] initWithString:#"Pull to Refresh"];
// [refresh addTarget:self action:#selector(refreshView:)forControlEvents:UIControlEventValueChanged];
// self.refreshControl = refresh;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSLog(#"%# found a %# element", self, elementName);
if ([elementName isEqual:#"channel"])
{
// If the parser saw a channel, create new instance, store in our ivar
channel = [[RSSChannel alloc]init];
// Give the channel object a pointer back to ourselves for later
[channel setParentParserDelegate:self];
// Set the parser's delegate to the channel object
[parser setDelegate:channel];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// return 0;
NSLog(#"channel items %d", [[channel items]count]);
return [[channel items]count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// return nil;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell"];
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"UITableViewCell"];
cell.textLabel.font=[UIFont systemFontOfSize:16.0];
}
RSSItem *item = [[channel items]objectAtIndex:[indexPath row]];
[[cell textLabel]setText:[item title]];
cell.backgroundView = [[CustomCellBackground alloc] init];
cell.selectedBackgroundView = [[CustomCellBackground alloc] init];
cell.textLabel.backgroundColor = [UIColor clearColor];
cell.textLabel.highlightedTextColor = [UIColor darkGrayColor];
return cell;
}
- (void)fetchEntries
{
// Create a new data container for the stuff that comes back from the service
xmlData = [[NSMutableData alloc]init];
// Construct a URL that will ask the service for what you want -
// note we can concatenate literal strings together on multiple lines in this way - this results in a single NSString instance
NSURL *url = [NSURL URLWithString:#"http://kyfbnewsroom.com/category/public-affairs/notifications/feed/"];
// Put that URL into an NSURLRequest
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// Create a connection that will exchange this request for data from the URL
connection = [[NSURLConnection alloc]initWithRequest:req delegate:self startImmediately:YES];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self)
{
[self fetchEntries];
}
return self;
}
// This method will be called several times as the data arrives
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
// Add the incoming chunk of data to the container we are keeping
// The data always comes in the correct order
[xmlData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)conn
{
/* We are just checking to make sure we are getting the XML
NSString *xmlCheck = [[NSString alloc]initWithData:xmlData encoding:NSUTF8StringEncoding];
NSLog(#"xmlCheck = %#", xmlCheck);*/
[loadingIndicator stopAnimating];
// Create the parser object with the data received from the web service
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:xmlData];
// Give it a delegate - ignore the warning here for now
[parser setDelegate:self];
//Tell it to start parsing - the document will be parsed and the delegate of NSXMLParser will get all of its delegate messages sent to it before this line finishes execution - it is blocking
[parser parse];
// Get rid of the XML data as we no longer need it
xmlData = nil;
// Reload the table.. for now, the table will be empty
NSMutableArray *notActionAlerts = [NSMutableArray array];
for (RSSItem *object in channel.items) {
if (!object.isActionAlert) {
[notActionAlerts addObject:object];
}
}
for (RSSItem *object in notActionAlerts) {
[channel.items removeObject:object];
}
[[self tableView]reloadData];
NSLog(#"%#\n %#\n %#\n", channel, [channel title], [channel infoString]);
}
- (void)connection:(NSURLConnection *)conn didFailWithError:(NSError *)error
{
// Release the connection object, we're done with it
connection = nil;
// Release the xmlData object, we're done with it
xmlData = nil;
// Grab the description of the error object passed to us
NSString *errorString = [NSString stringWithFormat:#"Fetch failed: %#", [error localizedDescription]];
// Create and show an alert view with this error displayed
UIAlertView *av = [[UIAlertView alloc]initWithTitle:#"Error" message:errorString delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Push the web view controller onto the navigation stack - this implicitly creates the web view controller's view the first time through
// [[self navigationController]pushViewController:webViewController animated:YES];
[self.navigationController pushViewController:webViewController animated:NO];
// Grab the selected item
RSSItem *entry = [[channel items]objectAtIndex:[indexPath row]];
// Construct a URL with the link string of the item
NSURL *url = [NSURL URLWithString:[entry link]];
// Construct a request object with that URL
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// Load the request into the web view
[[webViewController webView]loadRequest:req];
webViewController.hackyURL = url;
// Set the title of the web view controller's navigation item
// [[webViewController navigationItem]setTitle:[entry title]];
}
/*
-(void)refreshView:(UIRefreshControl *)refresh
{
refresh.attributedTitle = [[NSAttributedString alloc] initWithString:#"Refreshing data..."];
// custom refresh logic would be placed here...
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MMM d, h:mm a"];
NSString *lastUpdated = [NSString stringWithFormat:#"Last updated on %#",[formatter stringFromDate:[NSDate date]]];
refresh.attributedTitle = [[NSAttributedString alloc] initWithString:lastUpdated];
[refresh endRefreshing];
}
*/
#end
Here is the chunk of code I've added to my didFinishLaunchingWithOptions method. I've gotten almost everything working. The web views work now when selecting a row and the navigation bar is there and seemingly works as it should. The only trouble I'm having now is getting the tab bar to show up. Here is the chunk of code I'm currently using.
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification)
{
ActionAlertsViewController *actionAlerts = [[ActionAlertsViewController alloc] initWithStyle:UITableViewStylePlain];
WebViewController *wvc = [[WebViewController alloc]init];
[actionAlerts setWebViewController:wvc];
KFBNavControllerViewController *navController7 = [[KFBNavControllerViewController alloc] initWithRootViewController:actionAlerts];
[self.window.rootViewController presentViewController:navController7 animated:NO completion:nil];
}
You could post a notification yourself when you receive a remote notification and by registering the viewcontroller to this notification, you could open a particular viewController once notification is received.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
[[NSNotificationCenter defaultCenter] postNotificationName:#"pushNotification" object:nil userInfo:userInfo];
}
In your FirstViewController.m register for listening to this notification.
-(void)viewDidLoad{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pushNotificationReceived) name:#"pushNotification" object:nil];
}
Inside the method you could open particular viewController
-(void)pushNotificationReceived{
[self presentViewController:self.secondViewController animated:YES completion:nil];
}
Finally un-register current viewController from notification in dealloc method
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
If the app is opened from a notification, either of the two methods from your app delegate will be called
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
OR
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
In case of the latter, the launchOptions will let you know if the app was launched due to a remote notification or some other reason (see Launch Option Keys here)
Put in a check in these methods so that the specific viewcontroller will be opened if the app is launched from a notification.
You can do some thing like this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
// If application is launched due to notification,present another view controller.
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification)
{
NotificationViewController *viewController = [[NotificationViewController alloc]initWithNibName:NSStringFromClass([NotificationViewController class]) bundle:nil];
[self.window.rootViewController presentModalViewController:viewController animated:NO];
[viewController release];
}
return YES;
}
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NotificationViewController *viewController = [[NotificationViewController alloc]initWithNibName:NSStringFromClass([NotificationViewController class]) bundle:nil];
[self.window.rootViewController presentModalViewController:viewController animated:NO];
[viewController release];
}
EDITED
still not sure whats wrong please help
hi there I'm creating and iOS application and trying to make it play a sound when running I've type up my code in the app delegate .h , .m and it plays the sound fine but the thing is it goes to a black screen when my ViewController.xib has a blue background heres heres the code i have
AppDelegate.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#class ViewController;
#interface AppDelegate : NSObject <UIApplicationDelegate, AVAudioPlayerDelegate> {
UIWindow *window;
ViewController *viewController;
AVAudioPlayer *_backgroundMusicPlayer;
BOOL _backgroundMusicPlaying;
BOOL _backgroundMusicInterrupted;
UInt32 _otherMusicIsPlaying;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet ViewController *viewController;
- (void)tryPlayMusic;
AppDelegate.m
#import "AppDelegate.h"
#import "ViewController.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize viewController = _viewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Set up the audio session
// See handy chart on pg. 55 of the Audio Session Programming Guide for what the categories mean
// Not absolutely required in this example, but good to get into the habit of doing
// See pg. 11 of Audio Session Programming Guide for "Why a Default Session Usually Isn't What You Want"
NSError *setCategoryError = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError];
// Create audio player with background music
NSString *ticktockPath = [[NSBundle mainBundle] pathForResource:#"ticktock" ofType:#"wav"];
NSURL *ticktockURL = [NSURL fileURLWithPath:ticktockPath];
NSError *error;
_backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:ticktockURL error:&error];
[_backgroundMusicPlayer setDelegate:self]; // We need this so we can restart after interruptions
[_backgroundMusicPlayer setNumberOfLoops:-1]; // Negative number means loop forever
// Override point for customization after app launch
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
- (void) audioPlayerBeginInterruption: (AVAudioPlayer *) player {
_backgroundMusicInterrupted = YES;
_backgroundMusicPlaying = NO;
}
- (void) audioPlayerEndInterruption: (AVAudioPlayer *) player {
if (_backgroundMusicInterrupted) {
[self tryPlayMusic];
_backgroundMusicInterrupted = NO;
}
}
- (void)applicationDidBecomeActive:(NSNotification *)notification {
[self tryPlayMusic];
}
- (void)tryPlayMusic {
// Play the music if no other music is playing and we aren't playing already
if (_otherMusicIsPlaying != 1 && !_backgroundMusicPlaying) {
[_backgroundMusicPlayer prepareToPlay];
[_backgroundMusicPlayer play];
_backgroundMusicPlaying = YES;
}
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
#end
ok so thats all the code
and heres what i get when app loads and the sound works fine
and this is what i want to get (ViewController.xib)
Thank in advanced
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSError *setCategoryError = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError];
self.viewController = [[ViewController alloc] init];
// Create audio player with background music
NSString *ticktockPath = [[NSBundle mainBundle] pathForResource:#"ticktock" ofType:#"wav"];
NSURL *ticktockURL = [NSURL fileURLWithPath:ticktockPath];
NSError *error;
_backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:ticktockURL error:&error];
[_backgroundMusicPlayer setDelegate:self]; // We need this so we can restart after interruptions
[_backgroundMusicPlayer setNumberOfLoops:-1]; // Negative number means loop forever
// Override point for customization after app launch
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
new code
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
You never initialized your view controller.
Somewhere before you do
[window addSubview:viewController.view];
You need to do
self.viewController = [[ViewController alloc] init];
I see that you declared the property as an IBOutlet.. is it actually hooked up to something in Interface Builder?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
NSError *setCategoryError = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError];
// Create audio player with background music
NSString *ticktockPath = [[NSBundle mainBundle] pathForResource:#"ticktock" ofType:#"wav"];
NSURL *ticktockURL = [NSURL fileURLWithPath:ticktockPath];
NSError *error;
_backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:ticktockURL error:&error];
[_backgroundMusicPlayer setDelegate:self]; // We need this so we can restart after interruptions
[_backgroundMusicPlayer setNumberOfLoops:-1]; // Negative number means loop forever
self.viewController = [[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
Copy that function and just delete this one - (void)applicationDidFinishLaunching:(UIApplication *)application completely.
You should also consider converting your project to use ARC. It will remove the need to retain/release/autorelease statements.
You have two targets - are all your resources included in the target that you're building?
I'ld love to use this combination of Software for some simple push notifications.
Sending and Receiving isn't the problem - did it!
But how can I tell the jQueryMobile Application out of iOS that it is launched by PushNotification and shouldn't show the home screen but an other - notification related - screen instead?
Notification object has a property applicationLaunchNotification which has value 1 if the application is launched via the notifictaion.
This below method queries the pending notification on the start of the application:
window.plugins.pushNotification.getPendingNotifications(function(notifications) {
if(notifications.length > 0){
var note = notifications[0];
if(note.applicationLaunchNotification == "1"){
// do the processing
}
}
});
For detail - https://github.com/phonegap/phonegap-plugins/tree/master/iOS/PushNotification
use can change you app deligate code and enable push in application pro-vising profile
#import "AppDelegate.h"
#import "MainViewController.h"
#import <Cordova/CDVPlugin.h>
#implementation AppDelegate
#synthesize window, viewController;
- (id)init
{
/** If you need to do any extra app-specific initialization, you can do it here
* -jm
**/
NSHTTPCookieStorage* cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
[cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
self = [super init];
return self;
}
#pragma mark UIApplicationDelegate implementation
/**
* This is main kick off after the app inits, the views and Settings are setup here. (preferred - iOS4 and up)
*/
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
CGRect screenBounds = [[UIScreen mainScreen] bounds];
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
self.window = [[[UIWindow alloc] initWithFrame:screenBounds] autorelease];
self.window.autoresizesSubviews = YES;
self.viewController = [[[MainViewController alloc] init] autorelease];
self.viewController.useSplashScreen = YES;
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
// this happens while we are running ( in the background, or from within our own app )
// only valid if __TESTING__-Info.plist specifies a protocol to handle
- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url
{
if (!url) {
return NO;
}
// calls into javascript global function 'handleOpenURL'
NSString* jsString = [NSString stringWithFormat:#"handleOpenURL(\"%#\");", url];
[self.viewController.webView stringByEvaluatingJavaScriptFromString:jsString];
// all plugins will get the notification, and their handlers will be called
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]];
return YES;
}
// repost the localnotification using the default NSNotificationCenter so multiple plugins may respond
// ADD OUR NOTIFICATION CODE
#pragma mark - Push notification Delegate Methods
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:#"<>"]];
token = [token stringByReplacingOccurrencesOfString:#" " withString:#""];
//NSLog(#"content---%#", token);
}
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
//flagPushConfirmation=[NSString stringWithFormat:#"startPush"];
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Device not Register for notification"
delegate:self cancelButtonTitle:#"OK"otherButtonTitles:nil];
[message show];
}
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Notification"
message:#"Recieve Notification" delegate:self cancelButtonTitle:#"cancel"otherButtonTitles:#"ok",nil];
[message show];
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive) {
// WAS RUNNING
NSLog(#"I was currently active");
NSString *notCB = [notification.userInfo objectForKey:#"foreground"];
NSString *notID = [notification.userInfo objectForKey:#"notificationId"];
NSString * jsCallBack = [NSString
stringWithFormat:#"%#(%#)", notCB,notID];
[self.viewController.webView stringByEvaluatingJavaScriptFromString:jsCallBack];
application.applicationIconBadgeNumber = 0;
}
else {
// WAS IN BG
NSLog(#"I was in the background");
NSString *notCB = [notification.userInfo objectForKey:#"background"];
NSString *notID = [notification.userInfo objectForKey:#"notificationId"];
NSString * jsCallBack = [NSString
stringWithFormat:#"%#(%#)", notCB,notID];
[self.viewController.webView stringByEvaluatingJavaScriptFromString:jsCallBack];
application.applicationIconBadgeNumber = 0;
}
}
- (NSUInteger)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window
{
// iPhone doesn't support upside down by default, while the iPad does. Override to allow all orientations always, and let the root view controller decide what's allowed (the supported orientations mask gets intersected).
NSUInteger supportedInterfaceOrientations = (1 << UIInterfaceOrientationPortrait) | (1 << UIInterfaceOrientationLandscapeLeft) | (1 << UIInterfaceOrientationLandscapeRight) | (1 << UIInterfaceOrientationPortraitUpsideDown);
return supportedInterfaceOrientations;
}