アプリケーションがローカル通知からアクティブになったかどうかを知る方法はありますか?
アプリケーションがローカル通知アラートから起動されたかどうかをテストする方法があることを私は知っています。しかし、それが背景に座っていて、通知を受け取った場合はどうでしょうか。
アプリがアクティブになったら、別のコードを実行する必要があります。
- ローカル通知から。
- ちょうどアクティブになりました:)
それを行う方法はありますか?
アプリケーションがローカル通知からアクティブになったかどうかを知る方法はありますか?
アプリケーションがローカル通知アラートから起動されたかどうかをテストする方法があることを私は知っています。しかし、それが背景に座っていて、通知を受け取った場合はどうでしょうか。
アプリがアクティブになったら、別のコードを実行する必要があります。
それを行う方法はありますか?
didReceiveNotificationメソッドが呼び出されたときにアプリケーションの状態をチェックする@naveedのヒントから、この解決策の手がかりを得ました。アプリがバックグラウンドから再開するときに変数などをチェックする必要はありません。
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 {
}
アプリで古いバージョンのOSをサポートする場合を除いて、アプリケーションの状態を確認する必要はありません。
シルターが間違っているのではないかと思います。アプリがバックグラウンドからフォアグラウンドに入るとき、直接のユーザーアクションまたはユーザーの応答によって、アプリUILocalNotification
はトリガーされませんapplicationDidFinishLaunchingWithOptions
。ただし、とを呼び出しapplicationWillEnterForeground
ますapplicationDidBecomeActive
。これは、いくつかので確認できますNSLogs
。
したがって、問題は残ります。アプリがバックグラウンドからフォアグラウンドに入っている場合、アプリがユーザーの応答に応答してフォアグラウンドに入っているのUILocalNotification
か、それとも単にフォアグラウンドに入っているだけなのかを検出する方法はありません。それ外...
アプリがフォアグラウンドに入ると、メソッドを受け取りますapplication:DidReceiveLocalNotification
:アプリがに応答してフォアグラウンドに入った場合UILocalNotification
。
application:DidReceiveLocalNotification:
問題は、UILocalNotificationの受信に応じてメソッド内で行われたUIの変更は、アプリがすでにフォアグラウンドに入った後に発生し、ユーザーに不快な体験をもたらすことです。
誰かが解決策を見つけましたか?
以下の方法で、アプリケーションを受信したときに、いずれかのアプリケーションが実行されているかどうかのシナリオを確認できます。
- (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);
}
私が行ったのは、2つのシナリオをテストしたことです。1つはアイコンをクリックしてアプリをフォアグラウンドに戻すこと、もう1つは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;
これには、アプリケーションがフォアグラウンドに戻ったときにプログラマーがアクセスしたいすべての情報が含まれている可能性があります。特に、アプリケーションがシステムによってフォアグラウンドに置かれた場合に1を示すフラグ「isHandlingURL」にアクセスしたいと思います。ユーザーがアプリをフォアグラウンドにした場合は0を呼び出します。
次に、「application」と「_applicationFlags」のアドレスを調べたところ、60である0x3Cによってオフセットされていることに気付いたので、アドレス操作を使用して必要なビットを取得することにしました。
- (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 000000010010が得られます。_applicationFlagsを振り返ると、LSBから6番目のビットに「isHandlingURL」が表示されます。これは0です。アプリをバックグラウンドに戻し、URL sys呼び出しで戻すと、4a40032が出力されます。バイナリでは000001001010 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シフトすることを確認する必要があります。
それは今のところすべてです!
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:.
*/
}
これが、UIApplication内でプライベート構造体として宣言された_applicationFlagsにアクセスできるようにするための私の最後のエレガントなソリューションです。まず、ヘッダー「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
次に、アプリケーションデリゲートで、プロパティ、合成、インクルードなどとともに通常の初期化を実行します。
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
}
}
問題をさらに明らかにするために、ローカル通知からアプリを起動することをテストし、アプリデリゲートメソッドが呼び出される順序を監視しました。私のテストデバイスは、iOS7.1.1を実行しているiPodTouch第5世代と、iOS7.1.1を実行しているiPhone4Sでした。メソッド呼び出しの順序は、両方のデバイスで同じでした。
アプリがバックグラウンドに移動しただけの場合は、をタップしUILocalNotification
てアプリを起動しapplicationWillEnterForeground:
、次に、、application:didReceiveLocalNotification:
最後に。を呼び出しますapplicationDidBecomeActive:
。メソッド呼び出しのシーケンスは、数年前に作成され、おそらく別のバージョンのiOSでテストされた@jaredsinclairの回答とは異なることに注意してください。
ただし、アプリが終了した場合(iOSによって、またはユーザーがマルチタスクサイドスクローラーからアプリをスワイプして)、をタップしUILocalNotification
てアプリを再度起動すると、が呼び出されるだけapplicationDidBecomeActive:
です。メソッドapplication:didReceiveLocalNotification:
は呼び出されません。
アプリデリゲートメソッドのコールバックシーケンスをテストした方法:アプリデリゲートで、、、が呼び出されるNSMutableArray
たびapplicationWillEnterForeground:
にapplication:didReceiveLocalNotification:
、を作成し、文字列を入力しました。applicationDidBecomeActive:
次に、最後の2つのメソッドの配列の内容を表示しました。これは、それらがどの順序で呼び出されるかわからなかったためです。アプリがバックグラウンドから来る場合、それは私が2つを取得したときUIAlertView
だけですが、それは2つの前述のメソッドが次々に呼び出されるためです。
UILocalNotification
いずれにせよ、アプリが終了状態から来ている場合、アプリがから起動されたかどうかを追跡する方法はないという結論を推し進めたいと思います。誰かがテストを再現することで確認を手伝いたいですか?
- (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
}