1. 开发应用程序时, 如果要在接受到本地通知或者远程通知里进行事件处理, 则可以直接在didReceiveLocalNotification和didReceivedRemoteNotification方法中直接进行调用。
应用程序启动时的main.m文件, 直接指定appDelegate
int main(int argc,
char * argv[])
{
@autoreleasepool {
return
UIApplicationMain(argc, argv, nil,
NSStringFromClass([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 UIApplicationBackgroundRefreshStatusDidChangeNotification
NS_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 (nonatomic,
strong)
NSObject<UIApplicationDelegate> *naAppDelegate;
@property (nonatomic,
strong) NSObject<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
class] instancesRespondToSelector:selector];
}
@end
使用时, 只需要在SDK的初始化时, 调用下面代码,前提,SDK的单例类中有一个proxy变量
- (void)addAppDelegateProxy
{
_proxy = [[NABAppDelegateProxy
alloc] init];
@synchronized ([UIApplication
sharedApplication]) {
_proxy.naAppDelegate = [[NABAppDelegate
alloc] init];
_proxy.originalAppDelegate = [UIApplication
sharedApplication].delegate;
[UIApplication
sharedApplication].delegate =
_proxy;
// 这句最为重要
}
}
就这样,在SDK中就可以获取到所有原来appDelegate的所有回调用方法了。
- (BOOL)naDelegateRespondsToSelector:(SEL)selector
{
return [self.naAppDelegate respondsToSelector:selector]
&& ![[NSObject class]instancesRespondToSelector:selector];
}
- (void)setCustomAppDelegateProxy:(id<UIApplicationDelegate>)delegate
{
if (delegate) {
self.proxy.naAppDelegate = delegate;
}
}
调用示例:
NABAppDelegateDemo *demoAppDelegate = [[NABAppDelegateDemo alloc]
init];
[[XXXSDK
shared] setCustomAppDelegateProxy:demoAppDelegate];
@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