Проверьте, стало ли приложение активным из UILocalNotification - PullRequest
43 голосов
/ 09 ноября 2010

Есть ли способ узнать, стало ли приложение активным из локального уведомления?

Я знаю, что есть способ проверить, было ли приложение запущено из локального уведомления;но если он просто сидел на заднем плане и получил уведомление?

Мне нужно запустить другой код, когда приложение станет активным:

  1. Из локального уведомления.
  2. Только что стал активным:)

Есть ли способ сделать это?

Ответы [ 8 ]

63 голосов
/ 19 мая 2011

Я получил ключ к решению этой проблемы из подсказки @ naveed о проверке состояния приложения при вызове метода didReceiveNotification.Нет необходимости проверять переменные и т. Д., Когда приложение возобновляет работу из фона.

На iOS7 и ниже вы обрабатываете такие уведомления:

- (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.
    }
}

Обновитьдля iOS 8: Следующие методы теперь вызываются, когда приложение открывается из фона через уведомление.

- (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 {
}

Если уведомления получены, когда приложение находится на переднем плане, используйте методы:

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

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

Обратите внимание, что нет необходимости проверять состояние приложения, если вы не хотите поддерживать более старые версии ОС в своем приложении.

29 голосов
/ 01 февраля 2011

Боюсь, Сильтер не прав. Когда приложение выходит на передний план из фона либо прямым действием пользователя, либо ответом пользователя на UILocalNotification, оно не запускает applicationDidFinishLaunchingWithOptions. Однако он вызывает applicationWillEnterForeground и applicationDidBecomeActive. Это можно проверить с парой NSLogs.

Таким образом, проблема остается: если приложение выходит на передний план из фона, невозможно определить, выходит ли приложение на передний план в ответ на ответ пользователя на UILocalNotification или это просто выход на передний план За исключением ...

Как только приложение вышло на передний план, оно получит метод application:DidReceiveLocalNotification: если приложение вышло на передний план в ответ на UILocalNotification.

Проблема заключается в том, что любые изменения пользовательского интерфейса, сделанные в методе application:DidReceiveLocalNotification: в ответ на получение UILocalNotification, происходят после , когда приложение уже вышло на передний план, создавая беспокойство пользователя.

Кто-нибудь нашел решение?

10 голосов
/ 19 апреля 2011

Вы можете проверить, запущено приложение или нет, когда приложение получено, следуя.

- (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);
}
7 голосов
/ 18 мая 2011

То, что я сделал, я протестировал два сценария, один - вернуть приложение на передний план, нажав на значок, другой - по вызову sys URL, и сравнил все переменные внутри UIApplication, и, к удивлению, я наконец нашел то, чтоискал в 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;

Это, возможно, содержит всю информацию, к которой программист хотел бы иметь доступ, когда приложение возвращается на передний план, в частности, я хотел бы получить доступ к флагуisHandlingURL, который говорит 1, если приложение выводится на передний план с помощью sys-вызова, 0, если приложение выводится на передний план пользователем.

Далее я посмотрел адрес "application" и "_applicationFlags ", заметил, что они смещены на 0x3C, что составляет 60, поэтому я решил использовать адресные операции, чтобы получить мой необходимый бит:

- (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);
}

, который печатает test: 4a40012 ,или 0x04a40012 , если я напишу полный формат длинного слова.Это дает мне в двоичном виде 0000 0100 1010 0100 0000 0000 0001 0010 .Возвращаясь к _applicationFlags, это даст нам «isHandlingURL» на 6-м бите от LSB, который равен 0. Теперь, если я попытаюсь перевести приложение в фоновый режим и вернуть его с помощью вызова sys URL, я получу отпечаток 4a40032 который в двоичном виде равен 0000 0100 1010 0100 0000 0000 0011 0010 , и у меня включен бит isHandlingURL!Итак, все, что осталось сделать, это завершить оператор с помощью операций сдвига битов, и окончательный код будет выглядеть следующим образом:

- (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
    }
}

Я могу продолжить и написать полную функцию, чтобы разобрать все_applicationFlag, но в этой точке неясно, будет ли фиксированный приращение адреса равным 15 как на симуляторе, так и на цели, моей следующей целью будет замена на магическое число '15' каким-либо макроопределением или значениями из системы, поэтомуЯ могу быть уверен, что он всегда будет сдвигаться на 0x3C по мере необходимости, и мне нужно заглянуть в заголовок UIApplication, чтобы убедиться, что _applicationFlag всегда будет сдвигаться на 0x3C.

На этом пока все!

4 голосов
/ 09 ноября 2010

В вашем 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;
}

Или, если вы хотите знать, когда приложение находится на переднем или на заднем плане, вы можете использовать этот метод:

- (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:.
     */
}
0 голосов
/ 11 сентября 2015
- (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

}
0 голосов
/ 01 июля 2014

Чтобы пролить больше света на проблему, я просто протестировал запуск своего приложения из локального уведомления и отслеживал порядок вызова методов делегирования приложения. Моими тестовыми устройствами были iPod Touch 5-го поколения с iOS 7.1.1 и iPhone 4S с iOS 7.1.1. Порядок вызовов методов был одинаковым для обоих устройств.

Если приложение просто ушло в фоновый режим, нажав UILocalNotification, чтобы запустить приложение, вызовет applicationWillEnterForeground:, затем application:didReceiveLocalNotification: и, наконец, applicationDidBecomeActive:. Обратите внимание, что последовательность вызовов методов отличается от ответа @ jaredsinclair, который был написан несколько лет назад и, вероятно, был протестирован на другой версии iOS.

Если приложение, однако, завершает работу (iOS или пользователь, удаляющий приложение из боковой скроллера многозадачности), нажав UILocalNotification, чтобы запустить приложение снова, только вызовет applicationDidBecomeActive:. Метод application:didReceiveLocalNotification: НЕ ВЫЗЫВАЕТСЯ.

Как я проверял последовательность обратного вызова метода делегата приложения: в делегате приложения я создал NSMutableArray и заполнял его строкой всякий раз, когда вызывались applicationWillEnterForeground:, application:didReceiveLocalNotification: и applicationDidBecomeActive:. Затем я отобразил содержимое массива из двух последних методов, так как не был уверен, в каком порядке они будут вызваны. Когда приложение приходит из фона, это происходит только тогда, когда я получаю два UIAlertView с, но только потому, что два указанных метода вызываются один за другим.

В любом случае, я бы также хотел сделать вывод, что нет способа отследить, было ли приложение запущено с UILocalNotification , если приложение выходит из завершенного состояния. Кто-то хочет помочь подтвердить, воспроизведя тест?

0 голосов
/ 18 мая 2011

Хорошо, вот мое окончательное и элегантное решение, позволяющее вам получить доступ к _applicationFlags, объявленным как частная структура в UIApplication.Сначала создайте заголовок «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

Затем создайте имплиментацию «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

Затем выполните обычную инициализацию в вашем делегате Application вместе ссвойство, синтезировать, включает в себя ... что угодно:

applicationFlags = [[ApplicationFlag alloc] init];

Тогда вы можете начать ссылаться на флаги:

- (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
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...