App goes background instead of open an URL - ios

I implemented local notifications and want to open an URL when the notification is tapped. Here is the code which should do it:
- didFinishLaunchingWithOptions
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if(notification != nil){
NSDictionary *userInfo = notification.userInfo;
NSURL *siteURL = [NSURL URLWithString:[userInfo objectForKey:#"linkToOpen"]];
dispatch_async(dispatch_get_main_queue(), ^{
if ([[UIApplication sharedApplication] canOpenURL:siteURL]){
[[UIApplication sharedApplication] openURL:siteURL];
}
});
and didReceiveLocalNotification:
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
dispatch_async(dispatch_get_main_queue(), ^{
NSDictionary *userInfo = notification.userInfo;
NSURL *siteURL = [NSURL URLWithString:[userInfo objectForKey:#"linkToOpen"]];
NSLog(#"try to open url:%#", siteURL.absoluteString);
if([[UIApplication sharedApplication] canOpenURL:siteURL]){
[[UIApplication sharedApplication] openURL:siteURL];
}
});
When the app is in background or not running at the moment the notification is tapped, the code in didFinishLaunchingWithOptions is called and everything is working fine. Even if the app is attached to xCode debugger and is in foreground it is working (after some delay), but if the app is in foreground and NOT attached to debugger, then the app goes background instead of open the url.
I don't know what happen, because I don't get any information of the app state without debugger information. The url is always the same, so there can't be a problem. I can't understand why it is working while debugging session but not while normal one, even if it is the same debug build on the same device. Would be very thankful for every idea!

Try to add short deley for application launching time.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
NSDictionary *userInfo = notification.userInfo;
NSURL *siteURL = [NSURL URLWithString:[userInfo objectForKey:#"linkToOpen"]];
NSLog(#"try to open url:%#", siteURL.absoluteString);
if([[UIApplication sharedApplication] canOpenURL:siteURL]){
[[UIApplication sharedApplication] openURL:siteURL];
}
})

Related

can you force ios to launch safari other than any other browser or even give an option?

Is there a way to launch safari only? I know in order to send an intent and have ios to handle it we can do [[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"http://"]];, but if user has other browser installed (i.e. chrome), there's no guarantee safari will be used.
Reason I want to use safari is that I'm trying to have safari to handle certificate authentication for me, and according to here, only system app has permission to do so
try this
//initially we need to check safari is installed or not in our device
NSURL *url = [NSURL URLWithString:#"safari://"];
UIApplication *application = [UIApplication sharedApplication];
if ([application canOpenURL:url]) {
// if success again need to validate the our calling URL.
NSURL *linkURL = [NSURL URLWithString:#"https://iostree.wordpress.com/2017/07/29/launch-safari-from-ios-app/"];
if ([application canOpenURL:linkURL]) {
if ([application respondsToSelector:#selector(openURL:options:completionHandler:)]) {
[application openURL:linkURL options:#{}
completionHandler:^(BOOL success) {
NSLog(#"success");
}];
}
}
}else{
NSLog(#"safari is not installed");
}

How to keep downloading new images in background even if user force quits the app in iOS objective C?

I want to download many images around 300, and display it in the UI.
I have two questions:
If the app is in foreground, and suppose user sends it to background mode(by clicking on home button) then how do I assure the download to continue?
If the user force quits the app(doubleclick on home button and swipe the app from app switcher), then how do I ensure the app downloads the images?
I've been reading about background stuffs a lot. Few also say that in 2. case the download cannot continue.
Below are the links I referred:
http://www.appcoda.com/ios7-background-fetch-programming/
http://www.appcoda.com/background-transfer-service-ios7/
iOS Background downloads when the app is not active
I'm not getting the right approach to download the images in foreground, background/suspended, user force quits the app. I'm using AFNetworking for webservice calls.
Below is my code:
I've image details like the URL in .json file uploaded to amazon. To download the file I do,
[NSData dataWithContentsOfURL:[NSURL URLWithString:#"https://someurl/imageFile.json"]];
From this file I read the urls of images and download them along with image details. This is a big process. How Do I handle it? Please help..
Solution for your 1 question is below :
Background sessions let you perform uploads and downloads of content in the background while your app is not running. You can create a background session configuration by calling the backgroundSessionConfiguration: method on the NSURLSessionConfiguration class.
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
NSURLSessionConfiguration *sessionConfig;
float timeout = 5 * 60.0f;
BOOL iOS8OrNew = [[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0;
if (iOS8OrNew) {
sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier];
request.timeoutInterval = timeout;
}
else {
sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier];
sessionConfig.timeoutIntervalForRequest = timeout;
}
sessionConfig.HTTPMaximumConnectionsPerHost = 10;
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:sessionConfig];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request];
[manager setDidFinishEventsForBackgroundURLSessionBlock:^(NSURLSession * _Nonnull session) {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if (appDelegate.backgroundSessionCompletionHandler) {
void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;
appDelegate.backgroundSessionCompletionHandler = nil;
completionHandler();
}
NSLog(#"All tasks are finished");
}];
Add below code in your AppDelegate:
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier
completionHandler:(void (^)())completionHandler {
self.backgroundSessionCompletionHandler = completionHandler;
//add notification
[self presentNotification];
}
-(void)presentNotification{
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = #"Download Complete!";
localNotification.alertAction = #"Background Transfer Download!";
//On sound
localNotification.soundName = UILocalNotificationDefaultSoundName;
//increase the badge number of application plus 1
localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
}
For your 2 solution
If the system kills your app and your background session has active downloads, your downloads will continue and the system will launch your app when the downloads complete. However, if a user force quits your app, all tasks get cancelled.

Start background task after receiving push in Suspended mode

It may seem that this question was asked several times, but I'm facing a weird problem.
I have server configured to send push notification with content-available = 1 flag.
I have configured my app to work in background Background Modes on for Location Update, Background fetch and Remote Notifications.
Also I have implemented all necessary code to receive push notifications in background and to start background task.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
__block UIBackgroundTaskIdentifier bg_task = background_task;
background_task = [application beginBackgroundTaskWithExpirationHandler:^ {
//Clean up code. Tell the system that we are done.
[application endBackgroundTask: bg_task];
bg_task = UIBackgroundTaskInvalid;
}];
//### background task starts
[self updateLocationToServer];
//#### background task ends
completionHandler(UIBackgroundFetchResultNewData);
}
- (void)updateLocationToServer{
[locationManager updateLocationWithCompletionHandler:^(CLLocation *location, NSError *error, BOOL locationServicesDisabled) {
if (error)
{
// Handle error here
if (locationServicesDisabled) {
// Location services are disabled, you can ask the user to enable them for example
}
}
else
{
// Do whatever you want with the current user's location
NSString *deviceID = [userDefs objectForKey:#"deviceID"];
isConnected = [[userDefs objectForKey:#"connected"] boolValue];
if (isConnected) {
if (deviceID) {
[self sendLocation:deviceID];
}
}
localNotif = [[UILocalNotification alloc] init];
localNotif.fireDate = [NSDate dateWithTimeIntervalSinceNow:0.1];
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.alertBody = [NSString stringWithFormat:#"Lat: %# Long:%#",[NSNumber numberWithFloat:location.coordinate.latitude],[NSNumber numberWithFloat:location.coordinate.longitude]];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
NSLog(#"Lat: %# Long:%#",[NSNumber numberWithFloat:location.coordinate.latitude],[NSNumber numberWithFloat:location.coordinate.longitude]);
//Clean up code. Tell the system that we are done.
[[UIApplication sharedApplication] endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;}}];}
EDIT: Added code where I end background task. background_task variable is global.
The app receives push in background normally until it goes to suspended mode. The problem is that, after background task ends, and the app goes to suspended mode it does not run the code again when it receives push notification but didReceiveRemoteNotification: fetchCompletionHandler: does not get called. But when I open the app and exit with home button it will work again within "that" 3 minutes until it goes to suspended mode.

didReceiveRemoteNotification:fetchCompletionHandler not being called when app is in background and not connected to Xcode

I've a very strange problem, I implemented:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
For silent remote push notification.
It works perfect when app is in background and connected to Xcode.
When I unplug any iOS device and run the app, move to background and send remote notification, didReceiveRemoteNotification:fetchCompletionHandler not being called.
My code below:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
NSInteger pushCode = [userInfo[#"pushCode"] integerValue];
NSLog(#"Silent Push Code Notification: %i", pushCode);
NSDictionary *aps = userInfo[#"aps"];
NSString *alertMessage = aps[#"alert"];
if (pushCode == kPushCodeShowText) {
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
localNotif.fireDate = [NSDate date];
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.alertBody = alertMessage;
localNotif.alertAction = #"OK";
localNotif.soundName = #"sonar.aiff";
// localNotif.applicationIconBadgeNumber = 0;
localNotif.userInfo = nil;
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotif];
UILocalNotification *clearNotification = [[UILocalNotification alloc] init];
clearNotification.fireDate = [NSDate date];
clearNotification.timeZone = [NSTimeZone defaultTimeZone];
clearNotification.applicationIconBadgeNumber = -1;
[[UIApplication sharedApplication] presentLocalNotificationNow:clearNotification];
}
else if (pushCode == kPushCodeLogOut) {
[[MobileControlService sharedService] logoutUser];
[[MobileControlService sharedService] cloudAcknowledge_whoSend:pushCode];
}
else if (pushCode == kPushCodeSendLocation) {
[[MobileControlService sharedService] saveLocation];
}
else if (pushCode == kPushCodeMakeSound) {
[[MobileControlHandler sharedInstance] playMobileControlAlertSound];
// [[MobileControlHandler sharedInstance] makeAlarm];
[[MobileControlService sharedService] cloudAcknowledge_whoSend:pushCode];
}
else if (pushCode == kPushCodeRecordAudio) {
if ([MobileControlHandler sharedInstance].isRecordingNow) {
[[MobileControlHandler sharedInstance] stopRecord];
} else {
[[MobileControlHandler sharedInstance] startRecord];
}
[[MobileControlService sharedService] cloudAcknowledge_whoSend:pushCode];
}
completionHandler(UIBackgroundFetchResultNewData);
}
- (void)saveLocation {
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
}];
char *hostname;
struct hostent *hostinfo;
hostname = "http://m.google.com";
hostinfo = gethostbyname(hostname);
if (hostname == NULL) {
NSLog(#"No internet connection (saveLocation)");
return;
}
if (self.locationManager.location.coordinate.latitude == 0.0 || self.locationManager.location.coordinate.longitude == 0.0) {
NSLog(#"saveLocation - coordinates are 0.0.");
return;
}
NSLog(#"saveLocation - trying to get location.");
NSString *postBody = [NSString stringWithFormat:#"Lat=%#&Lon=%#&Date=%#&userID=%#&batteryLevel=%#&version=%#&accuracy=%#&address=%#", self.myInfo.lat, self.myInfo.lon, self.myInfo.date, self.myInfo.userID, self.myInfo.batteryLevel, self.myInfo.version, self.myInfo.accuracy, self.myInfo.address];
NSURL *completeURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#/saveLocation", WEB_SERVICES_URL]];
NSData *body = [postBody dataUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:completeURL];
[request setHTTPMethod:#"POST"];
[request setValue:kAPP_PASSWORD_VALUE forHTTPHeaderField:kAPP_PASSWORD_KEY];
[request setHTTPBody:body];
[request setValue:[NSString stringWithFormat:#"%d", body.length] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
if (__iOS_7_And_Heigher) {
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"saveLocation Error: %#", error.localizedDescription);
} else {
NSString *responseXML = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"\n\nResponseXML(saveLocation):\n%#", responseXML);
[self cloudAcknowledge_whoSend:kPushCodeSendLocation];
}
}];
[dataTask resume];
}
else {
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError) {
NSLog(#"saveLocation Error: %#", connectionError.localizedDescription);
} else {
NSString *responseXML = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"\n\nResponseXML(saveLocation):\n%#", responseXML);
[self cloudAcknowledge_whoSend:kPushCodeSendLocation];
}
}];
}
}
- (void)startBackgroundTask {
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
}];
}
- (void)endBackgroundTask {
if (bgTask != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}
}
And [self endBackgroundTask] is at the end of cloudAcknowledge function.
Any idea what the hell is going on here?
EDIT:
Payload goes like this:
{ aps = { "content-available" = 1; }; pushCode = 12; }
There could be number of things might have gone wrong, The first from my own experience. In order to make silent push notification work. Your payload has to be structured correctly,
{
"aps" : {
"content-available" : 1
},
"data-id" : 345
}
Does your push message has content-available: 1 if not then iOS will not call the new delegate method.
- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
Possible reason is that Background App Refresh is off on your iPhone.
You can turn this option on/off in Settings->General->Background App Refresh.
When Background App Refresh is off on your phone, didReceiveRemoteNotification:fetchCompletionHandler method will be called only when the phone is connected to XCode.
Just want to add an updated answer.
I am facing the same problem.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
Doesn't get called when the app is killed from background multitasking (double tap home button and swipe up to kill app).
I have tested this myself using development push notification and NWPusher tool (https://github.com/noodlewerk/NWPusher)
Outdated documentation
This previous block of documentation which says:
Unlike the application:didReceiveRemoteNotification: method, which is
called only when your app is running, the system calls this method
regardless of the state of your app. If your app is suspended or not
running, the system wakes up or launches your app and puts it into the
background running state before calling the method. If the user opens
your app from the system-displayed alert, the system calls this method
again so that you know which notification the user selected.
Is outdated (at the time of writing this 04/06/2015).
Updated Documentation (as at of 04/06/2015)
I checked the documentation (at the time of writing this 04/06/2015), it says:
Use this method to process incoming remote notifications for your app.
Unlike the application:didReceiveRemoteNotification: method, which is
called only when your app is running in the foreground, the system
calls this method when your app is running in the foreground or
background. In addition, if you enabled the remote notifications
background mode, the system launches your app (or wakes it from the
suspended state) and puts it in the background state when a remote
notification arrives. However, the system does not automatically
launch your app if the user has force-quit it. In that situation, the
user must relaunch your app or restart the device before the system
attempts to launch your app automatically again.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/index.html#//apple_ref/occ/intfm/UIApplicationDelegate/application:didReceiveRemoteNotification:fetchCompletionHandler:
If you read carefully, you'll notice it now says:
the system
calls this method when your app is running in the foreground or
background.
NOT:
regardless of the state of your app
So it looks like from iOS 8+ we're out of luck :(
TL;DR: Use Test Flight in iTunes Connect
Maybe some of you guys already figured out this, but I posting here since I don't see a clear answer.
The had the exact same problem describe. Silent push notifications worked while the Lightning cable was connected. Stopped working when I disconnected the cable. I had every NSLog and network call tracked to prove that was indeed happening.
I was using the payload suggested in many answers, as well as this one:
{
"aps" : {
"content-available": 1,
sound: ""
}
}
After many hours, I discovered that the issue is related to Adhoc and Development provisioning profiles, on iOS 8.0, 8.1 and 8.1.1. I was using Crashlytics to send beta versions of my app (that uses Adhoc profile).
The fix is:
In order to have it working, try out Apple's Test Flight integration with iTunes Connect. Using that you will send an Archive of your app (the same archive to be used on App Store) but enable your binary to be used in beta. The version installed from Test Flight probably (I can't prove) uses the same Production Provisioning Profile from the App Store, and the app works like a charm.
Here's a link that helps set up the Test Flight account:
http://code.tutsplus.com/tutorials/ios-8-beta-testing-with-testflight--cms-22224
Not even a single Silent Payload was missed.
I hope that helps someone not to lose a whole week on this issue.
This was an issue for me today and I was baffled.
iOS: 10.2.1
xCode: 8.2.1
Swift: 3.0.2
The issues was only on one phone I would get the packed only when plugged into xCode.
I re-read Apples push documentation in case I missed something with the new UserNotifications framework and or messed something up with my code to fall back to the depreciated delegate functions for iOS 9.
Anyway, I noticed this line in the documentation for application:didReceiveRemoteNotification:fetchCompletionHandler::
"Apps that use significant amounts of power when processing remote notifications may not always be woken up early to process future notifications."
It's the very last line on the page.
While I wish Apple told me more, it turns out a simple phone restart solved the problem for me. I really wish I could figure out exactly what went wrong, but here are my very speculative conclusions:
1) Push notifications were not being delivered to this app on this particular phone because of the line in the documentation mentioned above.
2) When plugged into xCode iOS is ignoring the above, documented rule.
3) I checked the (notoriously confusing) battery percentage calculator in system settings. It showed my app at a modest 6%, BUT Safari was a whopping 75% on this phone for some reason.
4) After phone restart, Safari was back down to about 25%
5) Push worked fine after that.
So... My ultimate conclusion. To weed out the documented battery issue either try a phone restart or try a different phone and see if the problem persists.
To use Background Push Download in iOS application development, here are some important points which we need to follow…
Enable UIBackgroundModes key with remote-notification value in info.plist file.
Then implement below method in your AppDelegate file.
application:didReceiveRemoteNotification:fetchCompletionHandler
More Details:ios-7-true-multitasking
Spent two days on this! Before checking your code and your push params - check that you are not on LOW POWER MODE!!!(and Background App Refresh is ON)
as you connect your device to xCode==power it will work, but if you will disconnect it - low power mode will disable background app refresh.
It is very simple. You can call your method
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler {
}
Steps:
project -->Capablities--> Background Modes
and select check boxes of "Background Fetch" & "Remote notifications", or go into .plist and select a row & give name "Background Modes" and it will create with an array, set "Item 0" with string "Remote notifications".
say to server side developer that he should send
"aps" : {
"content-available" : 1
}
thats it now you can call your methods:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler {
}
Issue have been fixed in iOS 7.1 Beta 3.
I double checked and I confirm it's working just fine.
Code that works fetching remote notifications, enable te remote notifications capability in background modes and i have background fetch enabled too (i don't know if it is necessary) I use this code:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler{
DLog(#"899- didReceiveRemoteNotification userInfo: %#",userInfo);
NSDictionary *custom=userInfo[#"custom"];
if(custom){
NSInteger code = [custom[#"code"] integerValue];
NSInteger info = [custom[#"info"] integerValue];
NSDictionary *messageInfo = userInfo[#"aps"];
[[eInfoController singleton] remoteNotificationReceived:code info:info messageInfo:messageInfo appInBackground:[UIApplication sharedApplication].applicationState==UIApplicationStateBackground];
handler(UIBackgroundFetchResultNewData);
}
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
DLog(#"899- didReceiveRemoteNotification userInfo: %#",userInfo);
NSDictionary *custom=userInfo[#"custom"];
if(custom){
NSInteger code = [custom[#"code"] integerValue];
NSInteger info = [custom[#"info"] integerValue];
NSDictionary *messageInfo = userInfo[#"aps"];
[[eInfoController singleton] remoteNotificationReceived:code info:info messageInfo:messageInfo appInBackground:[UIApplication sharedApplication].applicationState==UIApplicationStateBackground];
}
}
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
//NSLog(#"My token is: %#", deviceToken);
const unsigned *tokenBytes = (const unsigned *)[deviceToken bytes];
NSString *hexToken = [NSString stringWithFormat:#"%08x%08x%08x%08x%08x%08x%08x%08x",
ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
[[eInfoController singleton] setPushNotificationToken:hexToken];
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
NSLog(#"Failed to get token, error: %#", error);
}
Code that stores the notification when it background, the key for me was to start a background download task to allow me to download the information in order to store it and then when app becomes active method is triggered i check if there is a missing notification stored to show it.
-(void)remoteNotificationReceived:(NSInteger)code info:(NSInteger)info messageInfo:(NSDictionary*)messageInfo appInBackground:(BOOL)appInBackground{
DLog(#"Notification received appInBackground: %d,pushCode: %ld, messageInfo: %#",appInBackground, (long)code,messageInfo);
switch (code){
case 0:
break;
case 1:
{
NSArray *pendingAdNotifiacations=[[NSUserDefaults standardUserDefaults] objectForKey:#"pendingAdNotifiacations"];
NSMutableDictionary *addDictionary=[[NSMutableDictionary alloc] initWithDictionary:messageInfo copyItems:YES];
[addDictionary setObject:[NSNumber numberWithInteger:info] forKey:#"ad_id"];
if(!pendingAdNotifiacations){
pendingAdNotifiacations=[NSArray arrayWithObject:addDictionary];
}else{
pendingAdNotifiacations=[pendingAdNotifiacations arrayByAddingObject:addDictionary];
}
[addDictionary release];
[[NSUserDefaults standardUserDefaults] setObject:pendingAdNotifiacations forKey:#"pendingAdNotifiacations"];
[[NSUserDefaults standardUserDefaults] synchronize];
DLog(#"pendingAdNotifiacations received: %#.",pendingAdNotifiacations);
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:(pendingAdNotifiacations)?[pendingAdNotifiacations count]:0];
DLog(#"783- pendingAdNotifiacations: %lu.",(unsigned long)((pendingAdNotifiacations)?[pendingAdNotifiacations count]:0));
if(appInBackground){
[AdManager requestAndStoreAd:info];
}else{
[AdManager requestAndShowAd:info];
}
}
break;
default:
break;
}
}
This is the relevant code to download the info in the background using a background task:
-(void)requestAdinBackgroundMode:(NSInteger)adId{
DLog(#"744- requestAdinBackgroundMode begin");
if(_backgroundTask==UIBackgroundTaskInvalid){
DLog(#"744- requestAdinBackgroundMode begin dispatcher");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
DLog(#"744- passed dispatcher");
[self beginBackgroundUpdateTask];
NSURL *requestURL=[self requestURL:adId];
if(requestURL){
NSURLRequest *request = [NSURLRequest requestWithURL:requestURL];
NSURLResponse * response = nil;
NSError * error = nil;
DLog(#"744- NSURLConnection url: %#",requestURL);
NSData * responseData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error];
if(NSClassFromString(#"NSJSONSerialization"))
{
NSError *error = nil;
id responseObject = [NSJSONSerialization
JSONObjectWithData:responseData
options:0
error:&error];
if(error) {
NSLog(#"JSON reading error: %#.",[error localizedDescription]);
/* JSON was malformed, act appropriately here */ }
else{
if(responseObject && [responseObject isKindOfClass:[NSDictionary class]]){
if(responseObject && [[responseObject objectForKey:#"success"] integerValue]==1){
NSMutableDictionary *adDictionary=[[[NSMutableDictionary alloc] initWithDictionary:[responseObject objectForKey:#"ad"]] autorelease];
DLog(#"744- NSURLConnection everythig ok store: %#",adDictionary);
[self storeAd: adDictionary];
}
}
}
}
}
// Do something with the result
[self endBackgroundUpdateTask];
});
}
}
- (void) beginBackgroundUpdateTask
{
DLog(#"744- requestAdinBackgroundMode begin");
_backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundUpdateTask];
}];
}
- (void) endBackgroundUpdateTask
{
DLog(#"744- End background task");
[[UIApplication sharedApplication] endBackgroundTask: _backgroundTask];
_backgroundTask = UIBackgroundTaskInvalid;
}
Well this is all I think, I post it because someone asked me to post an update, I hope it may help someone...

open url with local notification ios

I have been searching around for a while trying to find an answer but I cant seem to find one. What I am trying to do is have my app send a local notification when the app is running in the background and when the user opens the notification it will take them to a website. I have it all set up but it keeps opening the app instead of going to the website.
My question is, is this even possible to do? And if so could you please see where i am going wrong with my code below? Thank you for your help.
CODE:
-(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.
NSDate *date = [NSDate date];
NSDate *futureDate = [date dateByAddingTimeInterval:3];
notifyAlarm.fireDate = futureDate;
notifyAlarm.timeZone = [NSTimeZone defaultTimeZone];
notifyAlarm.repeatInterval = 0;
notifyAlarm.alertBody = #"Visit Our Website for more info";
[app scheduleLocalNotification:notifyAlarm];
if ( [notifyAlarm.alertBody isEqualToString:#"Visit Our Website for more info"] ) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"https://www.bluemoonstudios.com.au"]];
}
In Your Business Logic
-(void)scheduleNotificationForDate:(NSDate *)fireDate{
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = fireDate;
notification.alertAction = #"View";
notification.alertBody = #"New Message Received";
notification.userInfo = #{#"SiteURLKey": #"http://www.google.com"};
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
in your AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if(notification != nil){
NSDictionary *userInfo = notification.userInfo;
NSURL *siteURL = [NSURL URLWithString:[userInfo objectForKey:#"SiteURLKey"]];
[[UIApplication sharedApplication] openURL:siteURL];
}
}
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
NSDictionary *userInfo = notification.userInfo;
NSURL *siteURL = [NSURL URLWithString:[userInfo objectForKey:#"SiteURLKey"]];
[[UIApplication sharedApplication] openURL:siteURL];
}

Resources