Open notification even application inactive or terminate - xcode

From my apps, it can receive the notification even the apps is inactive or terminate. But,when i click on the notification to open it, it will open the main page instead of going "Journal Page" as i wish.
This will work only if the apps are active or in background. Can anyone tell me something about this problem? I have try to put the UIApplicationState for all three(Active, Inactive, Background) in didReceiveRemoteNotification method, but every notification will go through the in background state even i open the notification during the apps is active or in background.
Can anyone give me any idea to solve this problem?
This is method for remote notification:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
if([userInfo valueForKey:#"app"]) {
NSString *action_app = [userInfo valueForKey:#"app"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:action_app forKey:#"app"];
NSLog(#"detect app value from UA ====> %#",action_app);
SampleViewController *sample=[[SampleViewController alloc]init];
[sample viewDidAppear:YES];
}else if([userInfo valueForKey:#"url"]){
NSString *action_url = [userInfo valueForKey:#"url"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:action_url forKey:#"url"];
NSLog(#"detect url value from UA ====> %#",action_url);
SampleViewController *sample=[[SampleViewController alloc]init];
[sample viewDidAppear:YES];
}else{
NSLog(#"---nothing to read---");
}
// 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];
// Reset the badge after a push received (optional)
[[UAPush shared] resetBadge];
// Open inboxData when receive notification
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.blankviewController = [[SampleViewController alloc] initWithNibName:#"SampleViewController" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.blankviewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
}

didReceiveRemoteNotification: is only called if the notification is tapped when the app is in the background, or if the app is already running.
If the app is not running when the notification arrives, then when you tap on the notification the application:didFinishLaunchingWithOptions: method is called and the notification payload is passed to it.

Related

Receiving Apple Push Notifications when app is in background

I have implemented push notifications in my iOS8 app. I am trying to play an audio file once the notification is received.
The code is playing the audio when the app is in the foreground, but when the app is in the background, nothing happens.
I have tried regenerating the certificates and provisioning profiles. And I have made sure that the app is running in the background, i.e. the user has not swiped up to remove it. In Background modes, I have enabled Remote Notifications, Background Fetch and Audio & Airplay.
I have added code snippets from my AppDelegate.m file:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// More code here ---------------------------------------------------
if (launchOptions) {
NSDictionary *userInfo = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
if (apsInfo) { //apsInfo is not nil
[self performSelector:#selector(playCarAlarmAudio)
withObject:nil
afterDelay:1];
}
}
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
[[UIApplication sharedApplication] registerForRemoteNotifications];
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge
|UIUserNotificationTypeSound
|UIUserNotificationTypeAlert) categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
}
// More code here ---------------------------------------------------
}
The delegate methods to handle push notifications:
-(void) application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(#"Failed to register for push");
}
-(void) application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
}
-(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[self respondToEventNotification:userInfo];
}
-(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// [self respondToEventNotification:userInfo];
[self playAlarmAudio];
}
-(void) respondToEventNotification : (NSDictionary *) userInfo {
if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) {
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
[localNotification setSoundName:#"alarm.mp3"];
[localNotification setFireDate:[NSDate date]];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}
else if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) {
[self playAlarmAudio];
}
}
And to play the Alarm:
-(void) playAlarmAudio {
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"alarm" ofType:#"mp3"];
NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileUrl error:nil];
self.audioPlayer.numberOfLoops = 1;
[self.audioPlayer play];
}
According to the following Apple documentation, the notification sound to be played is specified inside the notification payload dictionary (https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html):
The Notification Payload
Each remote notification includes a payload. The payload contains information about how the system should alert the user as well as any custom data you provide. In iOS 8 and later, the maximum size allowed for a notification payload is 2 kilobytes; Apple Push Notification service refuses any notification that exceeds this limit. (Prior to iOS 8 and in OS X, the maximum payload size is 256 bytes.)
For each notification, compose a JSON dictionary object (as defined by RFC 4627). This dictionary must contain another dictionary identified by the key aps. The aps dictionary can contain one or more properties that specify the following user notification types:
An alert message to display to the user
A number to badge the app icon with
A sound to play

Create notification with reply field

How do i get input from a notification with a reply field. I have not found anything in the documentation
Here is my current code, what do I need to get a response from the user?
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize nTitle;
#synthesize nMessage;
- (IBAction)showNotification:(id)sender{
NSUserNotification *notification = [[NSUserNotification alloc] init];
notification.title = [nTitle stringValue];
notification.informativeText = [nMessage stringValue];
notification.soundName = NSUserNotificationDefaultSoundName;
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
}
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification{
return YES;
}
#end
Where can i find more recent information and documentation for the notification center?
You can find the latest documentation in headers as usual. First of all, make sure you are using OSX SDK 10.9. There are few new fields with description.
NSUserNotification.h:
// Set to YES if the notification has a reply button. The default value is NO.
// If both this and hasActionButton are YES, the reply button will be shown.
#property BOOL hasReplyButton NS_AVAILABLE(10_9, NA);
// Optional placeholder for inline reply field.
#property (copy) NSString *responsePlaceholder NS_AVAILABLE(10_9, NA);
// When a notification has been responded to, the NSUserNotificationCenter delegate
// didActivateNotification: will be called with the notification with the activationType
// set to NSUserNotificationActivationTypeReplied and the response set on the response property
#property (readonly) NSAttributedString *response NS_AVAILABLE(10_9, NA);
Let's do it:
- (IBAction)showNotification:(id)sender{
NSUserNotification *notification = [[NSUserNotification alloc] init];
...
notification.responsePlaceholder = #"Reply";
notification.hasReplyButton = true;
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
}
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
{
if (notification.activationType == NSUserNotificationActivationTypeReplied){
NSString* userResponse = notification.response.string;
}
}
Notice that the reply button is hidden until mouse is outside a notification window and the reply field will be shown after button click.
You can find all the documentation you need in the inline documentation of Xcode 5 if you search "NSUserNotificationCenter", "NSUserNotification" and "NSUserNotificationCenterDelegate Protocol Reference".
There's no reply field in a user notification but you can add an action button and test if the user clicked this button or the default button to dismiss the notification. However, if in the Notification Center preferences, the user choose to receive banners instead of alerts, you'll never be informed of the response because there are no buttons in banners.

Compling Xcode Project Application Windows are expected to have a root view controller

How do i fix this error? iphone simulator works but when I use ipad i get this in console.. 2013-05-25 20:59:17.556 YourRSS[2717:c07] Application windows are expected to have a root view controller at the end of application launch
//
// AppDelegate.m
// YourRSS
//
// Created by Mohammad Komeili on 5/17/13.
// Copyright (c) 2013 MOMEKS. All rights reserved.
//
#import "AppDelegate.h"
#import "ViewController.h"
#import "ViewController_iPad2.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] ;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPhone" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
}
/* }else{
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPad2" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
}
*/
self.navigationController.navigationBarHidden = YES;
self.window.rootViewController = self.navigationController;
[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 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:.
}
#end
The part of the code that is commented out was what would have executed if you were not on an iPhone (see: UIUserInterfaceIdiomPhone). Since you're skipping over the creation of the navigation controller when you're on an iPad, it stays nil...which gives you the obvious error.

Local Notification is displayed without didFinishLaunchingWithOptions:

I have quite an understanding issue with displaying local notifications.
As far as I was reading in other threads, one has first create and schedule the local notification with the application.
For displaying that notification, one has to use the delegates didFinishLaunchingWithOptions: (if app is in background operation) and didReceiveLocalNotification: (if app is in foreground).
Now even though I did NOT change the didFinishLaunchingWithOptions: method, the notification is already getting viewed when my app is in the background.
It wouldn't be that big of a problem if the didFinishLaunchingWithOptions: would at least be used when I specify it at all. But it doesn't.
So my problem is, that even though I haven't used the didFinishLaunchingWithOptions: method, the notification is getting displayed. When the user clicks on the notification, the app gets to foreground and the didReceiveLocalNotification: method is triggered and the notification is displayed again.
What I originally wanted to do is to cancelAllLocalNotifications on execution of didFinishLaunchingWithOptions:, but since it is not getting executed, I'm kinda stuck here.
Ok, there might be a workaround with applicationWillEnterForeground: but honestly, I'd like to understand, why the notification is getting displayed even without having specified that in didFinishLaunchingWithOptions:.
All of your help is really appreaciated!! Thanks!!
//
// myNotificationsClass.m
//
#import "myNotificationsClass.h"
#implementation myNotificationsClass
//Sets up a Local Notification with Message, TimeFromNow, BadgeNumber and UserInfo
//no Class Instance for calling this method needed!!
+ (void)setupLocalNotificationsWithMessage: (NSString *) message andTimeFromNow: (NSTimeInterval) seconds andAlertAction: (NSString *) alertAction andBadgeNumber: (NSInteger) badgeNumber andUserInfo: (NSDictionary *) infoDict {
//[[UIApplication sharedApplication] cancelAllLocalNotifications];
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
// create date/time information
localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:seconds];
localNotification.timeZone = [NSTimeZone defaultTimeZone];
//setup Appearence and Message
localNotification.alertBody = message; //#"Time to get up!";
localNotification.alertAction = alertAction;
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.applicationIconBadgeNumber = badgeNumber;
localNotification.userInfo = infoDict;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}
#end
//overwrites the viewWillAppear: Method from the primary Class to display a Test Notification
#implementation UIViewController (localNotification)
- (void)viewWillAppear:(BOOL)animated {
[myNotificationsClass setupLocalNotificationsWithMessage:#"First Test after 2 Seconds" andTimeFromNow:2 andAlertAction:#"GoTo iSnah" andBadgeNumber:7 andUserInfo:nil];
}
#end
//receive Local Notifications even if the App is in Foreground
//overwrites the primery method
#implementation UIResponder (localNotificationForeground)
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleName"]
message:notification.alertBody
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
//reset Badge
application.applicationIconBadgeNumber = 0;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Because I don't want the Notification to be displayed twice
[[UIApplication sharedApplication] cancelAllLocalNotifications];
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (notification) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleName"]
message:notification.alertBody
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
//reset Badge
application.applicationIconBadgeNumber = 0;
}
return YES;
}
#end
You are very close. If the app is running in the background, the user responding to the notification will not cause the app to "launch". "Launch" means the app is not running at all (foreground or background). So only put code in there that you want to execute when the app launches or starts as a result of the user responding to your local notification.
So what you need for your didReceiveLocalNotification method is something to check the application state to see if it was in the foreground or in the background when the user responded to the local notification.
You might do something like the following to differentiate your logic between foreground and background:
- (void)application:(UIApplication *)application didReceiveLocalNotification: (UILocalNotification *)notification
if ( application.applicationState == UIApplicationStateActive ){
NSLog(#"Was already in the foreground");
}
else{
NSLog(#"Was in the background");
}
}
Minor point, however. Documentation states that the didReceiveLocalNotification method is invoked after application:didFinishLaunchingWithOptions: (if that method is implemented). So if you have both methods implemented you'll need to make sure the combination of the 2 work correctly in a "launch" situation.

How to mute and unmute audio in iPad by tapping a button?

I'd like to know how to make the mute and unmute the audio on my iPad application by tapping a button. I already have a working code in my viewDidLoad method that plays a music when the app is launched. All I need to do is to create a button that will stop the music from playing and also resume it when tapped again.
Here's my code in my viewDidLoad:
- (void)viewDidLoad
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"Bored" ofType:#"mp3"];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
[theAudio play];
[super viewDidLoad];
}
Just look at the AVAudioPlayer API - it's all there: play, pause, volume, etc.

Resources