You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cordova插件扩展CDVAppDelegate:未实现协议方法swizzling后无法调用问题

解决Cordova中CDVAppDelegate扩展可选协议方法不触发的问题

嘿,我之前做Cordova推送插件的时候也踩过一模一样的坑!你遇到的问题根源其实是Objective-C运行时对可选协议方法的调用逻辑——方法混写(swizzling)只能替换已经存在的方法,没法凭空给类新增一个它原本没实现的协议方法。

iOS系统调用可选协议方法时,会先通过respondsToSelector:检查目标类有没有实现这个方法,如果CDVAppDelegate本身没写这个方法,哪怕你用swizzling“假装”加了,系统还是会判定它没实现,自然不会触发调用。而你改CDVAppDelegate源码加了空实现后,方法存在了,swizzling才能替换它的实现,所以就生效了。

下面给你两个不用改Cordova源码的靠谱方案:

方案一:用Runtime动态给CDVAppDelegate加方法

直接用Objective-C的Runtime API给CDVAppDelegate新增协议方法的实现,步骤很简单:

  1. 新建一个CDVAppDelegate的分类,比如叫CDVAppDelegate+PushHook
  2. 在分类的+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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:23:21