sdk開發中如何去捕獲系統的didReceiveLocalNotification以及didReceiveRemoteNotification通知

1. 開發應用程序時, 如果要在接受到本地通知或者遠程通知裏進行事件處理, 則可以直接在didReceiveLocalNotification和didReceivedRemoteNotification方法中直接進行調用。

應用程序啓動時的main.m文件, 直接指定appDelegate

int main(int argc, char * argv[])

{

    @autoreleasepool {

        return UIApplicationMain(argc, argv, nilNSStringFromClass([DemoAppDelegate class]));

    }

}


2. 如果是捕獲的是

applicationWillResignActive, 

applicationWillEnterForeground, 

applicationDidBecomeActive, 

didFinishLaunchingWithOptions

根據UIApplication.h中的通知列表中, 表示上述的事件都可以通過通知獲取, 通知事件列表如下:

// These notifications are sent out after the equivalent delegate message is called

UIKIT_EXTERN NSString *const UIApplicationDidEnterBackgroundNotification      NS_AVAILABLE_IOS(4_0);

UIKIT_EXTERN NSString *const UIApplicationWillEnterForegroundNotification     NS_AVAILABLE_IOS(4_0);

UIKIT_EXTERN NSString *const UIApplicationDidFinishLaunchingNotification;

UIKIT_EXTERN NSString *const UIApplicationDidBecomeActiveNotification;

UIKIT_EXTERN NSString *const UIApplicationWillResignActiveNotification;

UIKIT_EXTERN NSString *const UIApplicationDidReceiveMemoryWarningNotification;

UIKIT_EXTERN NSString *const UIApplicationWillTerminateNotification;

UIKIT_EXTERN NSString *const UIApplicationSignificantTimeChangeNotification;

UIKIT_EXTERN NSString *const UIApplicationWillChangeStatusBarOrientationNotification; // userInfo contains NSNumber with new orientation

UIKIT_EXTERN NSString *const UIApplicationDidChangeStatusBarOrientationNotification;  // userInfo contains NSNumber with old orientation

UIKIT_EXTERN NSString *const UIApplicationStatusBarOrientationUserInfoKey;            // userInfo dictionary key for status bar orientation

UIKIT_EXTERN NSString *const UIApplicationWillChangeStatusBarFrameNotification;       // userInfo contains NSValue with new frame

UIKIT_EXTERN NSString *const UIApplicationDidChangeStatusBarFrameNotification;        // userInfo contains NSValue with old frame

UIKIT_EXTERN NSString *const UIApplicationStatusBarFrameUserInfoKey;                  // userInfo dictionary key for status bar frame

UIKIT_EXTERN NSString *const UIApplicationBackgroundRefreshStatusDidChangeNotificationNS_AVAILABLE_IOS(7_0);

UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsURLKey                  NS_AVAILABLE_IOS(3_0); // userInfo contains NSURL with launch URL

UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsSourceApplicationKey    NS_AVAILABLE_IOS(3_0); // userInfo contains NSString with launch app bundle ID

UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsRemoteNotificationKey   NS_AVAILABLE_IOS(3_0); // userInfo contains NSDictionary with payload

UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsLocalNotificationKey    NS_AVAILABLE_IOS(4_0); // userInfo contains a UILocalNotification

UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsAnnotationKey           NS_AVAILABLE_IOS(3_2); // userInfo contains object with annotation property list

UIKIT_EXTERN NSString *const UIApplicationProtectedDataWillBecomeUnavailable   NS_AVAILABLE_IOS(4_0);

UIKIT_EXTERN NSString *const UIApplicationProtectedDataDidBecomeAvailable      NS_AVAILABLE_IOS(4_0);

UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsLocationKey             NS_AVAILABLE_IOS(4_0); // app was launched in response to a CoreLocation event.

UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsNewsstandDownloadsKey   NS_AVAILABLE_IOS(5_0); // userInfo contains an NSArray of NKAssetDownload identifiers

UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsBluetoothCentralsKey    NS_AVAILABLE_IOS(7_0); // userInfo contains an NSArray of CBCentralManager restore identifiers

UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsBluetoothPeripheralsKey NS_AVAILABLE_IOS(7_0); // userInfo contains an NSArray of CBPeripheralManager restore identifiers


3. 對於本地通知調起事件,以及遠程通知事件上,你可能會想通過註冊上述的通知來進行捕獲。 但是, 你在查詢了上面這個列表後發現, 沒有這兩個通知事件。所以你抓狂了, 別急。 下面就是解決這個問題的方法。 開發SDK時,不能像上面第一部分代碼中main.m中那樣在應用程序啓動時能掛上AppDelegate, 所以不能通過appDelgate獲取到本地通知和遠程通知的調用時機。


3.1分析發現我們可以在程序中獲取到

[UIApplication sharedApplication].delegate, 這個delegate默認是指向DemoAppDelegate, 現在我們可以把[UIApplication sharedApplication].delegate指向一個變量proxy, 那麼這個變量將會獲取到所有原來應用AppDelegate的回調方法, 其中包括appDidFinishLaunchedWithOption, appWillResignActive, appWillEnterForeground等回調用, 同樣也包括本地通知以及遠程通知調用時的回調。 


等等, 你似乎想到什麼。。。


沒錯, 你這樣寫會有問題, 會導致原始的appDelegate將會再也獲取不到這些回調了, 這是有潛在問題的。 比如你在appDelegate中實現的appWillTerminate中可能會做一些保存數據的操作,上面這樣做的話,你的這個appDelegate中的回調就再也調用不了啦, 自然你的數據保存操作也不會被執行。


3.2 緊接着, 你就會想到,有沒有什麼辦法能捕獲appDelegate的回調, 但又不影響appDelegate自身的調用呢?


有! 上面這個方法是把這個[UIApplication sharedApplication].delegate指向一個變量proxy, 我們只需要在proxy這個變量中同時把appDelegate也進行調用就可以了。 也即在proxy中,我們可以先處理一下我們想處理的回調方法, 然後繼續讓這些回調方法繼續流轉, 如流轉到appDelegate即可。也即讓自己先處理完成後, 再進行消息的轉發。


所以,我們需要如下幾個類。

1. 

.h

@interface NABAppDelegate : NSObject <UIApplicationDelegate>

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;

@end


.m

#import "NABAppDelegate.h"

@implementation NABAppDelegate

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

{

    NBLog(@"%@, %@", application, notification);

// SDK在這裏,可以做自己想做的事

}

@end


2. 

.h

@interface NABAppDelegateProxy : NSProxy <UIApplicationDelegate>

- (id)init;

@property (nonatomicstrongNSObject<UIApplicationDelegate> *naAppDelegate;

@property (nonatomicstrongNSObject<UIApplicationDelegate> *originalAppDelegate;

@end


.m

#import "NABAppDelegateProxy.h"

@implementation NABAppDelegateProxy

- (id)init

{

    return self;

}


- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector

{

    NSMethodSignature *sig;

    sig = [self.originalAppDelegate methodSignatureForSelector:aSelector];

    if (sig) {

        return sig;

    } else {

        sig = [self.naAppDelegate methodSignatureForSelector:aSelector];

        return sig;

    }

    return nil;

}


// Invoke the invocation on whichever real object had a signature for it.

- (void)forwardInvocation:(NSInvocation *)invocation

{    

    if ([self naDelegateRespondsToSelector:[invocation selector]]) {

        [invocation invokeWithTarget:self.naAppDelegate];

    }

    

    if ([self.originalAppDelegate methodSignatureForSelector:[invocation selector]]) {

        [invocation invokeWithTarget:self.originalAppDelegate];

    }

}


// Override some of NSProxy's implementations to forward them...

- (BOOL)respondsToSelector:(SEL)aSelector

{    

    if ([self.naAppDelegate respondsToSelector:aSelector])

        return YES;

    if ([self.originalAppDelegate respondsToSelector:aSelector])

        return YES;

    

    return NO;

}


- (BOOL)naDelegateRespondsToSelector:(SEL)selector

{

    return [self.naAppDelegate respondsToSelector:selector] && ![[NSObject classinstancesRespondToSelector:selector];

}

@end



使用時, 只需要在SDK的初始化時, 調用下面代碼,前提,SDK的單例類中有一個proxy變量

- (void)addAppDelegateProxy

{

    _proxy = [[NABAppDelegateProxy allocinit];

  

    @synchronized ([UIApplication sharedApplication]) {

        _proxy.naAppDelegate = [[NABAppDelegate allocinit];

        _proxy.originalAppDelegate = [UIApplication sharedApplication].delegate;

        [UIApplication sharedApplication].delegate = _proxy;// 這句最爲重要

    }

}


就這樣,在SDK中就可以獲取到所有原來appDelegate的所有回調用方法了。
接着再分析一下, 

- (BOOL)naDelegateRespondsToSelector:(SEL)selector

{

    return [self.naAppDelegate respondsToSelector:selector] && ![[NSObject class]instancesRespondToSelector:selector];

}

注意一下這個方法中, 最後一句, 有加入[NSObject class]的處理。
這是因爲這個方法, 我們是爲了取僅僅naDelegate這個變量能處理哪些方法, 排除NSObject能處理的方法外。 因爲self.naAppDelegate這個變量是一個NSObject類型, 會有很多NSObject能響應的方法,如isKindOfClass, isEqual等。 這些isKindOfClass, isEqual的方法可以由originalAppDelegate變量去進行響應。 所以用到上述的排除方法。

3.3最後,如果你的代碼中需要指定其它的回調對象來接收appDelegate的回調方法, 使用下面方法即可。只要不修改proxy.originalAppDelegate,修改proxy.naAppDelegate即可。

- (void)setCustomAppDelegateProxy:(id<UIApplicationDelegate>)delegate

{

    if (delegate) {

        self.proxy.naAppDelegate = delegate;

    }

}


調用示例:


        NABAppDelegateDemo *demoAppDelegate = [[NABAppDelegateDemo allocinit];

        [[XXXSDK sharedsetCustomAppDelegateProxy:demoAppDelegate];

(注:這裏的NABAppDelegateDemo可以是直接繼承NABAppDelegate)

@interface NABAppDelegateDemo : NABAppDelegate

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;

@end


@implementation NABAppDelegateDemo

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

{

    NSLog(@"did receive local notification, notification=%@", notification);

    [application cancelLocalNotification:notification]; //(這裏可以根據需要決定是否進行cancelNotification)

}


@end


原文:http://blog.csdn.net/smking/article/details/39010067

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章