Cordova插件扩展CDVAppDelegate:未实现协议方法swizzling后无法调用问题
解决Cordova中CDVAppDelegate扩展可选协议方法不触发的问题
嘿,我之前做Cordova推送插件的时候也踩过一模一样的坑!你遇到的问题根源其实是Objective-C运行时对可选协议方法的调用逻辑——方法混写(swizzling)只能替换已经存在的方法,没法凭空给类新增一个它原本没实现的协议方法。
iOS系统调用可选协议方法时,会先通过respondsToSelector:检查目标类有没有实现这个方法,如果CDVAppDelegate本身没写这个方法,哪怕你用swizzling“假装”加了,系统还是会判定它没实现,自然不会触发调用。而你改CDVAppDelegate源码加了空实现后,方法存在了,swizzling才能替换它的实现,所以就生效了。
下面给你两个不用改Cordova源码的靠谱方案:
方案一:用Runtime动态给CDVAppDelegate加方法
直接用Objective-C的Runtime API给CDVAppDelegate新增协议方法的实现,步骤很简单:
- 新建一个CDVAppDelegate的分类,比如叫
CDVAppDelegate+PushHook - 在分类的
+load方法里,用class_addMethod把你的自定义方法加进去:
#import <objc/runtime.h> #import <Cordova/CDVAppDelegate.h> #import <UserNotifications/UserNotifications.h> @implementation CDVAppDelegate (PushHook) + (void)load { SEL targetSel = @selector(userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:); // 获取我们自定义的方法实现 Method customMethod = class_getInstanceMethod(self, targetSel); // 如果CDVAppDelegate本身没实现这个方法,就动态添加 if (!class_getInstanceMethod([CDVAppDelegate class], targetSel)) { class_addMethod([CDVAppDelegate class], targetSel, method_getImplementation(customMethod), method_getTypeEncoding(customMethod)); } } // 你的自定义推送处理方法 - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { // 这里写你的推送逻辑,比如解析推送内容 NSLog(@"收到推送:%@", response.notification.request.content.userInfo); // 务必调用completionHandler,不然会有运行时警告 completionHandler(); } @end
这个方法的核心是class_addMethod,它能真正把方法添加到CDVAppDelegate的方法列表里,这样系统就能检测到这个方法存在,从而正常触发调用。
方案二:遵循Cordova插件规范,在插件类里处理推送
其实Cordova本身就支持插件监听App生命周期和推送事件,完全没必要直接碰CDVAppDelegate。你可以在自己的插件类里实现推送相关的协议,然后通过插件的初始化流程注册代理:
#import <Cordova/CDVPlugin.h> #import <UserNotifications/UserNotifications.h> @interface MyPushPlugin : CDVPlugin <UNUserNotificationCenterDelegate> @end @implementation MyPushPlugin - (void)pluginInitialize { [super pluginInitialize]; // 把当前插件实例设为通知中心的代理 UNUserNotificationCenter *notificationCenter = [UNUserNotificationCenter currentNotificationCenter]; notificationCenter.delegate = self; } // 实现推送响应的协议方法 - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { // 这里可以把推送事件传递给JS层,比如用CDVPluginResult NSDictionary *pushData = response.notification.request.content.userInfo; CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:pushData]; [self.commandDelegate sendPluginResult:result callbackId:nil]; completionHandler(); } @end
这种方式更符合Cordova的插件开发规范,不用修改或混写框架的核心类,还能直接和JS层交互,是更推荐的做法。
内容的提问来源于stack exchange,提问作者Crag
相关产品推荐
相关产品推荐

