Question

Yat-il un moyen de savoir si l'application ne deviennent actifs d'une notification locale?

Je sais qu'il ya un moyen de tester si l'application était lancé d'une alerte de notification locale; mais s'il était assis juste là-bas l'arrière-plan, et a reçu une notification?

J'ai besoin d'exécuter du code différent, lorsque l'application est devenu actif:

  1. une notification locale.
  2. Tout est devenu actif:)

Est-il possible de le faire?

Était-ce utile?

La solution

Je crains Sylter est incorrect. Quand une application entre l'avant-plan de l'arrière-plan , que ce soit par une action directe de l'utilisateur ou par une réponse utilisateur à un UILocalNotification, il ne justifie pas la applicationDidFinishLaunchingWithOptions. Il ne remet toutefois applicationWillEnterForeground et applicationDidBecomeActive. Cela peut être vérifié avec quelques NSLogs.

Alors, le problème reste: si une application est entrée au premier plan de l'arrière-plan, il n'y a pas moyen de découvrir si l'application est entrée au premier plan en réponse à la réponse à une UILocalNotification d'un utilisateur, ou si elle est simplement entrer dans la premier plan. Sauf que ...

Une fois que l'application est entré au premier plan, il recevra la méthode application:DidReceiveLocalNotification:. Si l'application est entrée au premier plan en réponse à une UILocalNotification

Le problème est que toute l'interface utilisateur Les modifications apportées dans la méthode de application:DidReceiveLocalNotification: en réponse à la réception du UILocalNotification se produisent après l'application est déjà entré au premier plan, créant ainsi une expérience déroutante pour l'utilisateur.

Quelqu'un at-il trouvé une solution?

Autres conseils

Je suis la clé de la solution pour cela de la pointe de @ Naveed sur la vérification de l'état de l'application lorsque la méthode didReceiveNotification est appelée. Pas besoin de vérifier les variables etc lorsque l'application reprend à partir de l'arrière-plan.

et baissez iOS 7 vous gérez les notifications comme ceci:

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
    if (application.applicationState == UIApplicationStateInactive ) {
         //The application received the notification from an inactive state, i.e. the user tapped the "View" button for the alert.
         //If the visible view controller in your view controller stack isn't the one you need then show the right one.
    }

    if(application.applicationState == UIApplicationStateActive ) { 
        //The application received a notification in the active state, so you can display an alert view or do something appropriate.
    }
}

Mise à jour pour iOS 8:. Les méthodes suivantes sont maintenant invoquées lorsque l'application est ouverte de l'arrière-plan via une notification

- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void(^)())completionHandler {
}

- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler {
}

Si les notifications sont reçues lorsque l'application est au premier plan, utilisez les méthodes suivantes:

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

- (void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
}

Notez qu'il n'y a pas besoin de vérifier l'état d'application sauf si vous voulez soutenir les anciennes versions du système d'exploitation dans votre application.

Vous pouvez vérifier les scénarios de deux applications en cours d'exécution est ou non lorsque l'application reçue en suivant.

- (void)application:(UIApplication *)app didReceiveLocalNotification:(UILocalNotification *)notif {
    if (app.applicationState == UIApplicationStateInactive ) {
        NSLog(@"app not running");
    }else if(app.applicationState == UIApplicationStateActive )  {
        NSLog(@"app running");      
    }

    // Handle the notificaton when the app is running
    NSLog(@"Recieved Notification %@",notif);
}

Ce que j'ai fait, je l'ai testé deux scénarios, l'un est de mettre à l'arrière de l'application au premier plan en cliquant sur l'icône, une autre par l'appel URL, et comparé toutes les variables à l'intérieur UIApplication, et étonnamment j'ai finalement trouvé ce que je était à la recherche dans UIApplication.h:

struct {
    unsigned int isActive:1;
    unsigned int isSuspended:1;
    unsigned int isSuspendedEventsOnly:1;
    unsigned int isLaunchedSuspended:1;
    unsigned int calledNonSuspendedLaunchDelegate:1;
    unsigned int isHandlingURL:1;
    unsigned int isHandlingRemoteNotification:1;
    unsigned int isHandlingLocalNotification:1;
    unsigned int statusBarShowsProgress:1;
    unsigned int statusBarRequestedStyle:4;
    unsigned int statusBarHidden:1;
    unsigned int blockInteractionEvents:4;
    unsigned int receivesMemoryWarnings:1;
    unsigned int showingProgress:1;
    unsigned int receivesPowerMessages:1;
    unsigned int launchEventReceived:1;
    unsigned int isAnimatingSuspensionOrResumption:1;
    unsigned int isResuming:1;
    unsigned int isSuspendedUnderLock:1;
    unsigned int isRunningInTaskSwitcher:1;
    unsigned int shouldExitAfterSendSuspend:1;
    unsigned int shouldExitAfterTaskCompletion:1;
    unsigned int terminating:1;
    unsigned int isHandlingShortCutURL:1;
    unsigned int idleTimerDisabled:1;
    unsigned int deviceOrientation:3;
    unsigned int delegateShouldBeReleasedUponSet:1;
    unsigned int delegateHandleOpenURL:1;
    unsigned int delegateOpenURL:1;
    unsigned int delegateDidReceiveMemoryWarning:1;
    unsigned int delegateWillTerminate:1;
    unsigned int delegateSignificantTimeChange:1;
    unsigned int delegateWillChangeInterfaceOrientation:1;
    unsigned int delegateDidChangeInterfaceOrientation:1;
    unsigned int delegateWillChangeStatusBarFrame:1;
    unsigned int delegateDidChangeStatusBarFrame:1;
    unsigned int delegateDeviceAccelerated:1;
    unsigned int delegateDeviceChangedOrientation:1;
    unsigned int delegateDidBecomeActive:1;
    unsigned int delegateWillResignActive:1;
    unsigned int delegateDidEnterBackground:1;
    unsigned int delegateWillEnterForeground:1;
    unsigned int delegateWillSuspend:1;
    unsigned int delegateDidResume:1;
    unsigned int userDefaultsSyncDisabled:1;
    unsigned int headsetButtonClickCount:4;
    unsigned int isHeadsetButtonDown:1;
    unsigned int isFastForwardActive:1;
    unsigned int isRewindActive:1;
    unsigned int disableViewGroupOpacity:1;
    unsigned int disableViewEdgeAntialiasing:1;
    unsigned int shakeToEdit:1;
    unsigned int isClassic:1;
    unsigned int zoomInClassicMode:1;
    unsigned int ignoreHeadsetClicks:1;
    unsigned int touchRotationDisabled:1;
    unsigned int taskSuspendingUnsupported:1;
    unsigned int isUnitTests:1;
    unsigned int requiresHighResolution:1;
    unsigned int disableViewContentScaling:1;
    unsigned int singleUseLaunchOrientation:3;
    unsigned int defaultInterfaceOrientation:3;
} _applicationFlags;

Il contient peut-être toutes les informations d'un souhait de programmeur qu'ils ont accès à quand l'application retourne au premier plan, pour être en particulier, je voudrais accéder au drapeau « isHandlingURL » qui dit 1 si l'application est mis en avant-plan par un sys appel, 0 si l'application est mis en avant-plan par l'utilisateur.

Ensuite, je regardais à l'adresse de « demande » et « _applicationFlags », a remarqué qu'ils sont compensés par 0x3C, qui est de 60, alors j'ai décidé d'utiliser des opérations d'adresse pour obtenir mon bit nécessaire:

- (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.
     */
    id* app = [UIApplication sharedApplication];
    app = app+15; //address increments by long words, don't know if it will be the same on device
    NSLog(@"Test:%x",*app);
}

qui imprime Test: 4a40012 , ou 0x04a40012 si j'écris dans un format long mot complet. Cela me donne en binaire 0100 1010 0100 0000 0000 0000 0001 0010 . En regardant en arrière dans _applicationFlags, cela nous donnera « isHandlingURL » le 6 bit de bit de poids faible, ce qui est égal à 0. Maintenant, si j'essaie de mettre l'application en arrière-plan et le ramener à l'appel d'une URL, je reçois une impression de 4a40032 qui en binaire est 0100 1010 0100 0000 0000 0000 0011 0010 et j'ai mon isHandlingURL peu allumé! Donc, tout ce qu'il reste à faire est de compléter la déclaration des opérations de décalage de bits, et le code final ressemblera à ceci:

- (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.
     */
    id* app = (id*)[UIApplication sharedApplication]+15;
    BOOL isHandlingURL = ((Byte)*app>>5&0x1);
    if (isHandlingURL) {
        //do whatever I wanna do here
    }
}

Je peux continuer et écrire une fonction complète pour analyser toutes les _applicationFlag, mais il est à ce point incertain si l'incrément d'adresse est fixée à être 15 fois sur le simulateur et l'objectif, mon prochain objectif sera de remplacer par le numéro magique « 15 » par certains définit macro ou les valeurs du système pour que je puisse être sûr qu'il se déplacera toujours 0x3C au besoin, et je dois regarder en-tête UIApplication pour vous assurer que le _applicationFlag toujours passer par 0x3C.

C'est tout pour le moment!

Dans votre AppDelegate:

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

    // Override point for customization after application launch.

    UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];

    if (localNotif) {
        NSLog(@"Recieved Notification %@",localNotif);
    //Do Something
    } else {
    //Do Something else if I didn't recieve any notification, i.e. The app has become active
    }

    return YES;
}

Ou, si vous voulez savoir quand l'application est au premier plan ou en arrière-plan, vous pouvez utiliser cette méthode:

- (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, called instead of applicationWillTerminate: when the user quits.
     */
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
    /*
     Called as part of  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.
     */
}


- (void)applicationWillTerminate:(UIApplication *)application {
    /*
     Called when the application is about to terminate.
     See also applicationDidEnterBackground:.
     */
}

Ok, voici ma solution finale et élégante pour vous d'être en mesure d'accéder aux _applicationFlags déclarés comme struct privé au sein UIApplication. Tout d'abord créer un en-tête "ApplicationFlag.h":

//
//  ApplicationFlag.h
//  PHPConnectDemo
//
//  Created by Paul on 5/18/11.
//  Copyright 2011 Paul.Poyu.Lu@gmail.com. All rights reserved.
//

#import <Foundation/Foundation.h>
#ifndef APP_FLAG
#define APP_FLAG
#define APP_FLAG_OFFSET 15
#endif

struct appFlag {
    unsigned int isActive:1;
    unsigned int isSuspended:1;
    unsigned int isSuspendedEventsOnly:1;
    unsigned int isLaunchedSuspended:1;
    unsigned int calledNonSuspendedLaunchDelegate:1;
    unsigned int isHandlingURL:1;
    unsigned int isHandlingRemoteNotification:1;
    unsigned int isHandlingLocalNotification:1;
    unsigned int statusBarShowsProgress:1;
    unsigned int statusBarRequestedStyle:4;
    unsigned int statusBarHidden:1;
    unsigned int blockInteractionEvents:4;
    unsigned int receivesMemoryWarnings:1;
    unsigned int showingProgress:1;
    unsigned int receivesPowerMessages:1;
    unsigned int launchEventReceived:1;
    unsigned int isAnimatingSuspensionOrResumption:1;
    unsigned int isResuming:1;
    unsigned int isSuspendedUnderLock:1;
    unsigned int isRunningInTaskSwitcher:1;
    unsigned int shouldExitAfterSendSuspend:1;
    unsigned int shouldExitAfterTaskCompletion:1;
    unsigned int terminating:1;
    unsigned int isHandlingShortCutURL:1;
    unsigned int idleTimerDisabled:1;
    unsigned int deviceOrientation:3;
    unsigned int delegateShouldBeReleasedUponSet:1;
    unsigned int delegateHandleOpenURL:1;
    unsigned int delegateOpenURL:1;
    unsigned int delegateDidReceiveMemoryWarning:1;
    unsigned int delegateWillTerminate:1;
    unsigned int delegateSignificantTimeChange:1;
    unsigned int delegateWillChangeInterfaceOrientation:1;
    unsigned int delegateDidChangeInterfaceOrientation:1;
    unsigned int delegateWillChangeStatusBarFrame:1;
    unsigned int delegateDidChangeStatusBarFrame:1;
    unsigned int delegateDeviceAccelerated:1;
    unsigned int delegateDeviceChangedOrientation:1;
    unsigned int delegateDidBecomeActive:1;
    unsigned int delegateWillResignActive:1;
    unsigned int delegateDidEnterBackground:1;
    unsigned int delegateWillEnterForeground:1;
    unsigned int delegateWillSuspend:1;
    unsigned int delegateDidResume:1;
    unsigned int userDefaultsSyncDisabled:1;
    unsigned int headsetButtonClickCount:4;
    unsigned int isHeadsetButtonDown:1;
    unsigned int isFastForwardActive:1;
    unsigned int isRewindActive:1;
    unsigned int disableViewGroupOpacity:1;
    unsigned int disableViewEdgeAntialiasing:1;
    unsigned int shakeToEdit:1;
    unsigned int isClassic:1;
    unsigned int zoomInClassicMode:1;
    unsigned int ignoreHeadsetClicks:1;
    unsigned int touchRotationDisabled:1;
    unsigned int taskSuspendingUnsupported:1;
    unsigned int isUnitTests:1;
    unsigned int requiresHighResolution:1;
    unsigned int disableViewContentScaling:1;
    unsigned int singleUseLaunchOrientation:3;
    unsigned int defaultInterfaceOrientation:3;
};

@interface ApplicationFlag : NSObject {
    struct appFlag* _flags;
}

@property (nonatomic,assign) struct appFlag* _flags;

@end

Ensuite, créer un implimentation "ApplicationFlag.m":

//
//  ApplicationFlag.m
//  PHPConnectDemo
//
//  Created by Paul on 5/18/11.
//  Copyright 2011 Paul.Poyu.Lu@gmail.com. All rights reserved.
//

#import "ApplicationFlag.h"

@implementation ApplicationFlag

@synthesize _flags;

- (id)init
{
    self = [super init];
    if (self) {
        // Custom initialization
        _flags = (id*)[UIApplication sharedApplication]+APP_FLAG_OFFSET;
    }
    return self;
}

@end

Ensuite, faites l'initialisation habituelle dans votre délégué de demande ainsi que la propriété Synthétiser comprend ... peu importe:

applicationFlags = [[ApplicationFlag alloc] init];

Ensuite, vous pouvez commencer à se référant aux drapeaux:

- (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.
     */
    if (!applicationFlags._flags->isHandlingURL) {
        //Do whatever you want here
    }
}

Pour jeter plus de lumière sur le problème, je viens de tester le lancement de mon application à partir d'une notification locale et contrôlé l'ordre auquel les méthodes de délégués d'application ont été appelés. Mes appareils d'essai ont été un iPod Touch 5e génération fonctionnant sous iOS 7.1.1, et un iPhone 4S iOS 7.1.1. L'ordre des appels de méthode étaient les mêmes pour les deux appareils.

Si l'application est simplement allé à l'arrière-plan, en tapant sur un UILocalNotification pour lancer l'appel d'applications applicationWillEnterForeground:, puis application:didReceiveLocalNotification:, et enfin, applicationDidBecomeActive:. Notez que la séquence d'appels de méthode est autre de @ jaredsinclair de la réponse qui a été écrit il y a quelques années et a probablement été testé sur une autre version de iOS.

Si l'application, cependant, est terminée (par iOS ou par l'utilisateur sur l'application glisser du multi-tâches à défilement horizontal), en tapant sur un UILocalNotification pour lancer l'application à nouveau les appels que applicationDidBecomeActive:. La méthode application:didReceiveLocalNotification: N'EST PAS APPELLE.

Comment je l'ai testé la méthode délégué app séquence de rappel: Dans le délégué de l'application, j'ai créé un NSMutableArray et peuplé avec une chaîne à chaque fois applicationWillEnterForeground:, application:didReceiveLocalNotification: et applicationDidBecomeActive: ont été appelés. Ensuite, je le contenu de affiché le tableau des deux dernières méthodes depuis je ne savais pas dans quel ordre ils seraient appelés. Lorsque l'application vient de l'arrière-plan, qui est seulement quand je reçois deux UIAlertViews, mais seulement parce que les deux dites méthodes sont appelées un après l'autre.

Dans tous les cas, je tiens aussi à faire avancer la conclusion qu'il n'y a pas moyen de suivre si l'application a été lancée à partir d'une UILocalNotification si l'application provient d'un état terminé. Quelqu'un veut pour aider à confirmer en reproduisant le test?

- (void)application:(UIApplication *)application didReceiveLocalNotification:(NSDictionary *)userInfo
{
    if ( application.applicationState == UIApplicationStateActive )
        // app was already in the foreground
    else
        // app was just brought from background to foreground

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top