测试应用程序是否从UILocalNotification变为活动状态

wh1*_*t1k 43 iphone background objective-c uilocalnotification

有没有办法知道应用程序是否通过本地通知变为活动状态?

我知道有一种方法来测试,如果应用程序被启动从本地通知提醒; 但如果只是坐在那里的背景,并收到通知?

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

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

有办法吗?

Mic*_*ord 63

我从@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.
    }
}
Run Code Online (Sandbox Code Playgroud)

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 {
}
Run Code Online (Sandbox Code Playgroud)

如果在应用程序位于前台时收到通知,请使用以下方法:

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

- (void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
}
Run Code Online (Sandbox Code Playgroud)

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

  • 答对了!!!!!!!!!!(需要感叹号才能达到最小评论长度......) (4认同)
  • 哦! 但是,我正在实现新的iOS 8可操作通知,我注意到应用程序:handleActionWithIdentifier:forLocalNotification:completionHandler:被调用.(不仅仅是一个动作被点击,但是如果通知本身被点击.)希望这可以帮助其他人在将来阅读这个. (3认同)

jar*_*air 29

我担心赛尔特不正确.当应用程序从后台进入前台时,无论是通过直接用户操作还是用户对a的响应UILocalNotification,都不会触发applicationDidFinishLaunchingWithOptions.然而,它确实打电话applicationWillEnterForegroundapplicationDidBecomeActive.这可以用几个来验证NSLogs.

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

应用程序进入前台后,它将收到以下方法application:DidReceiveLocalNotification:如果应用程序进入前台以响应a UILocalNotification.

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

有没有人找到解决方案?


小智 10

您可以通过以下方式检查应用程序运行与否的情况.

- (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);
}
Run Code Online (Sandbox Code Playgroud)


小智 7

我做的是,我测试了两个场景,一个是通过点击图标将应用程序放回到前台,另一个是通过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;
Run Code Online (Sandbox Code Playgroud)

这可能包含程序员希望他们在应用程序返回到前台时可以访问的所有信息,特别是,我想访问标记"isHandlingURL",如果应用程序被系统放入前台,则表示为1如果应用程序被用户置于前台,则调用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);
}
Run Code Online (Sandbox Code Playgroud)

如果我用完整的长字格式写,则打印出测试:4a400120x04a40012.这给了我二进制0000 0100 1010 0100 0000 0000 0001 0010.回首成_applicationFlags,这将给我们从第6位"isHandlingURL" LSB,这是0.现在,如果我尝试将应用到后台,并用URL SYS电话把它带回来,我得到一个打印出来的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
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以继续编写一个完整的函数来解析所有_applicationFlag,但是此时不确定模拟器和目标上的地址增量是否固定为15,我的下一个目标是用魔法替换一些宏定义的数字'15'或来自系统的值,所以我可以确定它总是按需要移位0x3C,我需要查看UIApplication头以确保_applicationFlag总是移位0x3C.

目前为止就这样了!