测试应用程序是否确实通过 UILocalNotification 变为活动状态

发布于 2024-10-01 13:33:41 字数 199 浏览 5 评论 0原文

有没有办法通过本地通知知道应用程序是否已激活?

我知道有一种方法可以测试应用程序是否是从本地通知警报启动的;但如果它只是坐在后台并收到通知呢?

当应用程序处于活动状态时,我需要运行不同的代码:

  1. 来自本地通知。
  2. 刚刚变得活跃:)

有办法做到吗?

Is there a way to know if the application did become active from a local notification?

I know there is a way to test if the application was launched from a local notification alert; but if it just was sitting out there the background, and received a notification?

I need to run different code, when the app has become active:

  1. From a local notification.
  2. Just has become active :)

Is there a way to do it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

Hello爱情风 2024-10-08 13:33:41

我从@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 {
}

请注意,除非您想在应用程序中支持旧版本的操作系统,否则无需检查应用程序状态。

I got the clue to the solution for this from @naveed's tip on checking the state of the application when the didReceiveNotification method is called.
No need to check variables etc when the app resumes from the background.

On iOS7 and lower you handle the notifications like this:

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

Update for iOS 8: The following methods are now invoked when the app is opened from the background via a 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 {
}

If the notifications are received while the app is in the foreground, use the methods:

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

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

Note that there is no need to check application state unless you want to support older versions of the OS in your app.

恐怕西尔特是不正确的。当应用从后台进入前台时,无论是通过直接用户操作还是通过用户对 UILocalNotification 的响应,它都不会触发 applicationDidFinishLaunchingWithOptions。但是,它确实会调用 applicationWillEnterForegroundapplicationDidBecomeActive。这可以通过几个 NSLogs 进行验证。

因此,问题仍然存在:如果应用程序从后台进入前台,则无法发现该应用程序进入前台是否是为了响应用户对 UILocalNotification 的响应,或者是否是只是进入前台。除非...

一旦应用程序进入前台,它将接收方法application:DidReceiveLocalNotification:如果应用程序进入前台是为了响应UILocalNotification

问题在于,在 application:DidReceiveLocalNotification: 方法中为响应接收 UILocalNotification 而进行的任何 UI 更改都发生在应用程序已经进入前台之后,从而给应用程序带来令人不安的体验用户。

有人找到解决办法了吗?

I'm afraid Sylter is incorrect. When an app enters the foreground from the background, either by a direct user action or by a user response to a UILocalNotification, it does not trigger applicationDidFinishLaunchingWithOptions. It does, however, call applicationWillEnterForeground and applicationDidBecomeActive. This can be verified with a couple of NSLogs.

So, the problem remains: if an app is entering the foreground from the background, there is no way to discover if the app is entering the foreground in response to a user's response to a UILocalNotification, or if it is merely entering the foreground. Except...

Once the app has entered the foreground, it will receive the method application:DidReceiveLocalNotification: if the app entered the foreground in response to a UILocalNotification.

The problem is that any UI changes made within the application:DidReceiveLocalNotification: method in response to receiving the UILocalNotification occur after the app has already entered the foreground, creating a disturbing experience for the user.

Has anyone found a solution?

娇纵 2024-10-08 13:33:41

当收到应用程序时,您可以通过以下方式检查任一应用程序是否正在运行的场景。

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

You can check the scenarios of either application is running or not when application received by following.

- (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);
}
半城柳色半声笛 2024-10-08 13:33:41

我所做的是,我测试了两种场景,一种是通过单击图标将应用程序放回前台,另一种是通过 URL sys 调用,并比较 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”,如果应用程序被放入由系统调用前台,如果用户将应用程序置于前台,则为 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,这将为我们提供从 LSB 算起的第 6 位的“isHandlingURL”,即 0。现在,如果我尝试将应用程序置于后台并通过 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。

现在就这些了!

What I did was, I tested two scenarios, one is to put the app back to the foreground by clicking on the icon, another by URL sys call, and compared all the variables inside UIApplication, and surprisingly I finally found what I was looking for in 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;

This contains possibly all the information a programmer wish they have access to when the application returns to the foreground, to be in particular, I would like to access the flag "isHandlingURL" which says 1 if the app is put into foreground by a sys-call, 0 if the app is put into foreground by the user.

Next, I looked at the address of "application" and "_applicationFlags", noticed that they are offset by 0x3C, which is 60, so I decided to use address operations to get my needed bit:

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

which prints out test:4a40012, or 0x04a40012 if I write in a complete long word format.
This gives me in binary 0000 0100 1010 0100 0000 0000 0001 0010.
Looking back into _applicationFlags, this will give us "isHandlingURL" on 6th bit from LSB, which is 0. Now if I try to put the app into background and bring it back with a URL sys call, I get a print out of 4a40032 which in binary is 0000 0100 1010 0100 0000 0000 0011 0010 and I have my isHandlingURL bit turned on! So all that there is left to do is to complete the statement by bit-shift operations, and the final code will look like:

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

I can go on and write a complete function to parse out all the _applicationFlag, but then it is at this point uncertain if the address increment is fixed to be 15 on both the simulator and the target, my next goal will be to replace with magic number '15' by some macro defines or values from the system so I can be sure that it will always shift 0x3C as required, and I need to look into UIApplication header to make sure that the _applicationFlag will always shift by 0x3C.

That's all for now!

苯莒 2024-10-08 13:33:41

在您的 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:.
     */
}

In your 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;
}

Or, if you want to know when the application is in foreground or in background you can use this method:

- (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:.
     */
}
但可醉心 2024-10-08 13:33:41

好的,这是我最终的优雅的解决方案,让您能够访问在 UIApplication 中声明为私有结构的 _applicationFlags 。首先创建一个标头“ApplicationFlag.h”:

//
//  ApplicationFlag.h
//  PHPConnectDemo
//
//  Created by Paul on 5/18/11.
//  Copyright 2011 [email protected]. 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 [email protected]. 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

然后在应用程序委托中进行常规初始化以及属性、合成、包含...无论如何:

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

Ok here is my final and elegant solution for you to be able to access the _applicationFlags declared as a private struct within UIApplication. First create a header "ApplicationFlag.h":

//
//  ApplicationFlag.h
//  PHPConnectDemo
//
//  Created by Paul on 5/18/11.
//  Copyright 2011 [email protected]. 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

Then create an implimentation "ApplicationFlag.m":

//
//  ApplicationFlag.m
//  PHPConnectDemo
//
//  Created by Paul on 5/18/11.
//  Copyright 2011 [email protected]. 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

Then do the usual initialization in your Application delegate along with the property, synthesize, includes... whatever:

applicationFlags = [[ApplicationFlag alloc] init];

Then you can start referring to the flags:

- (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
    }
}
尾戒 2024-10-08 13:33:41

为了更深入地了解该问题,我刚刚测试了从本地通知启动我的应用程序,并监视了应用程序委托方法的调用顺序。我的测试设备是运行 iOS 7.1.1 的第五代 iPod Touch 和运行 iOS 7.1.1 的 iPhone 4S。两种设备的方法调用顺序相同。

如果应用程序只是进入后台,则点击 UILocalNotification 启动应用程序会调用 applicationWillEnterForeground:,然后调用 application:didReceiveLocalNotification:,以及最后,applicationDidBecomeActive:。请注意,方法调用的顺序与 @jaredsinclair 的答案不同,该答案是几年前编写的,可能在不同版本的 iOS 上进行了测试。

但是,如果应用程序被终止(通过 iOS 或用户从多任务侧滚动器中滑出应用程序),则点击 UILocalNotification 再次启动应用程序只会调用 applicationDidBecomeActive:。方法 application:didReceiveLocalNotification: IS NOT CALLED.

我如何测试应用程序委托方法回调序列:在应用程序委托中,我创建了一个 NSMutableArray并在调用 applicationWillEnterForeground:application:didReceiveLocalNotification:applicationDidBecomeActive: 时用字符串填充它。然后,我显示了最后两个方法的数组内容,因为我不确定它们的调用顺序。当应用程序来自后台时,只有当我得到两个 UIAlertView 时,但这只是因为这两个方法被一个接一个地调用。

无论如何,我还想得出这样的结论:如果应用程序来自终止状态,则无法跟踪应用程序是否是从 UILocalNotification 启动的。< /strong> 有人想通过重现测试来帮助确认吗?

To shed more light into the problem, I just tested launching my app from a local notification and monitored the order at which app delegate methods were called. My test devices were an iPod Touch 5th generation running iOS 7.1.1, and an iPhone 4S running iOS 7.1.1. The order of method calls were the same for both devices.

If the app has merely gone to the background, tapping on a UILocalNotification to launch the app calls applicationWillEnterForeground:, then application:didReceiveLocalNotification:, and finally, applicationDidBecomeActive:. Note that the sequence of method calls is different from @jaredsinclair's answer, which was written a few years ago and was probably tested on a different version of iOS.

If the app, however, is terminated (by iOS or by the user swiping out the app from the multitasking side-scroller), tapping on a UILocalNotification to launch the app again only calls applicationDidBecomeActive:. The method application:didReceiveLocalNotification: IS NOT CALLED.

How I tested the app delegate method callback sequence: In the app delegate, I created an NSMutableArray and populated it with a string whenever applicationWillEnterForeground:, application:didReceiveLocalNotification:, and applicationDidBecomeActive: were called. Then, I displayed the contents of the array from the last two methods since I wasn't sure in what order they would be called. When the app comes from the background, that's only when I get two UIAlertViews, but only because the two said methods are called one after the other.

In any case, I'd also like to push forward the conclusion that there is no way to track whether the app was launched from a UILocalNotification if the app is coming from a terminated state. Someone wants to help confirm by reproducing the test?

流绪微梦 2024-10-08 13:33:41
- (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

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

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文