2013-03-19 13 views
20

Ho appena aggiunto notifiche push alla mia app. Mi piacerebbe avere così che quando un utente apre l'app da una notifica, aprirà uno specifico controller di visualizzazione e non il mio rootViewController. Ecco la mia AppDelegate:Apri visualizzazione specifica all'apertura dell'app da notifica

#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 

E qui è il controller della vista voglio aprire quando si apre una notifica:

#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 

Ecco il pezzo di codice che ho aggiunto ai miei didFinishLaunchingWithOptions metodo. Ho quasi funzionato tutto. Le viste Web funzionano ora quando si seleziona una riga e la barra di navigazione è lì e apparentemente funziona come dovrebbe. L'unico problema che sto avendo ora è far apparire la barra delle schede. Ecco il pezzo di codice che sto usando attualmente.

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]; 
    } 

risposta

40

Si potrebbe inviare una notifica se stessi quando si riceve una notifica remota e registrando il viewcontroller a questa notifica, si potrebbe aprire una particolare viewController una volta ricevuto la notifica.

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{ 

    [[NSNotificationCenter defaultCenter] postNotificationName:@"pushNotification" object:nil userInfo:userInfo]; 

} 

Nel vostro registro FirstViewController.m per l'ascolto di questa notifica.

-(void)viewDidLoad{ 

     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pushNotificationReceived) name:@"pushNotification" object:nil]; 

} 

All'interno del metodo si potrebbe aprire particolare viewController

-(void)pushNotificationReceived{ 

[self presentViewController:self.secondViewController animated:YES completion:nil]; 
} 

Infine annullare la registrazione viewController corrente dalla notifica metodo dealloc

-(void)dealloc{ 
[[NSNotificationCenter defaultCenter] removeObserver:self]; 

} 
+7

Non sarebbe questo solo il lavoro se l'utente era ultima a guardare il tuo FirstView? Non penso che funzioni se visualizzassero una vista diversa, andassero alla schermata iniziale, ricevessimo una notifica e poi cliccassimo su di essa. Non aprirebbe semplicemente la tua app sulla pagina da cui erano stati interrotti e il tuo osservatore non avrebbe mai visto la notifica? – dmarsi

+0

@nsgulliver, un'ulteriore domanda, se l'app viene uccisa, l'iphone riceve le informazioni di push, fa clic sulle informazioni di push, si apre l'app e quindi può passare alla vc speciale? – aircraft

9

Se l'applicazione viene aperta da una notifica, sia dei due metodi dalla tua delegata dell'app si chiamerà

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo 

O

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 

Nel caso di questi ultimi, i launchOptions ti consente di sapere se l'applicazione è stata lanciata a causa di una notifica remota o per altre ragioni (vedi Keys opzione di avvio here)

messo in un controllo di questi metodi in modo che lo specifico controllore di vista venga aperto se l'app viene avviata da una notifica.

2

Si può fare qualche cosa di simile

- (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]; 
} 
+0

Si sta utilizzando una notifica locale. Sto cercando di farlo con le notifiche push remote. Ho provato il tuo codice e quando ho ricevuto una notifica remota e l'ho toccata, la mia app ha iniziato ad aprirsi e poi si è bloccata. – raginggoat

+1

Funziona ma è necessario includere la barra di navigazione e la barra delle schede. – raginggoat

Problemi correlati