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

如何在Cordova iOS插件中实现UIWebViewDelegate?插件设置失效排查

解决Cordova插件中设置UIWebViewDelegate无效的问题

我之前也踩过这个坑!Cordova的CDVViewController本身就是UIWebViewDelegate的实现者,它会在初始化WebView时自动把自己设为代理,而且后续还会维护这个代理关系——直接给webView.delegate赋值的话,很快就会被Cordova的内部逻辑覆盖,导致你的自定义代理方法根本不会被调用。下面给你两种靠谱的解决方案:

方法一:代理转发(完整覆盖所有Delegate方法)

这种方式通过创建一个自定义代理类,把原有的CDVViewController代理“包裹”起来,既实现你的自定义逻辑,又不破坏Cordova原本的代理流程。

步骤1:在插件的.m文件中定义自定义代理类

// 自定义代理类,用于转发WebView代理方法
@interface CustomWebViewDelegate : NSObject <UIWebViewDelegate>
@property (nonatomic, weak) id<UIWebViewDelegate> originalDelegate; // 持有原代理(弱引用避免循环引用)
@end

@implementation CustomWebViewDelegate

// 重写你需要自定义的代理方法,比如拦截请求
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    // 这里写你的自定义逻辑,比如判断请求URL做拦截
    NSLog(@"自定义代理拦截请求:%@", request.URL.absoluteString);
    
    // 必须调用原代理的对应方法,保证Cordova的原有逻辑正常运行
    if ([self.originalDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) {
        return [self.originalDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
    }
    return YES;
}

// 重写其他你需要的代理方法,比如页面开始加载、加载完成等
- (void)webViewDidStartLoad:(UIWebView *)webView {
    NSLog(@"自定义代理:页面开始加载");
    if ([self.originalDelegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
        [self.originalDelegate webViewDidStartLoad:webView];
    }
}

// 实现转发逻辑,把未重写的代理方法交给原代理处理
- (id)forwardingTargetForSelector:(SEL)aSelector {
    if ([self.originalDelegate respondsToSelector:aSelector]) {
        return self.originalDelegate;
    }
    return [super forwardingTargetForSelector:aSelector];
}

- (BOOL)respondsToSelector:(SEL)aSelector {
    if ([self.originalDelegate respondsToSelector:aSelector]) {
        return YES;
    }
    return [super respondsToSelector:aSelector];
}

@end

步骤2:在插件初始化时替换代理

首先在插件类的接口部分声明一个属性来持有自定义代理(避免被ARC自动释放):

@interface YourPluginName : CDVPlugin
@property (nonatomic, strong) CustomWebViewDelegate* customDelegate;
@end

然后在插件的pluginInitialize方法中完成代理替换:

- (void)pluginInitialize {
    // 获取当前的CDVViewController和它的WebView
    CDVViewController* viewController = (CDVViewController*)self.viewController;
    UIWebView* webView = viewController.webView;
    
    // 创建自定义代理实例,保存原代理
    self.customDelegate = [[CustomWebViewDelegate alloc] init];
    self.customDelegate.originalDelegate = webView.delegate;
    
    // 将WebView的代理替换为自定义代理
    webView.delegate = self.customDelegate;
}

方法二:监听Cordova原生通知(简单安全,适合常见场景)

如果你的需求只是监听页面加载开始、完成、失败这类事件,不需要拦截请求,那么可以直接监听Cordova内置的通知,完全不需要碰代理。

- (void)pluginInitialize {
    // 监听WebView开始加载的通知
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleWebViewStartLoad:)
                                                 name:CDVWebViewDidStartLoadNotification
                                               object:nil];
    
    // 监听WebView加载完成的通知
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleWebViewFinishLoad:)
                                                 name:CDVWebViewDidFinishLoadNotification
                                               object:nil];
    
    // 监听WebView加载失败的通知
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleWebViewLoadError:)
                                                 name:CDVWebViewDidFailLoadWithErrorNotification
                                               object:nil];
}

// 处理开始加载事件
- (void)handleWebViewStartLoad:(NSNotification*)notification {
    UIWebView* webView = notification.object;
    NSURLRequest* request = notification.userInfo[@"request"];
    NSLog(@"页面开始加载:%@", request.URL);
    // 你的自定义逻辑
}

// 处理加载完成事件
- (void)handleWebViewFinishLoad:(NSNotification*)notification {
    NSLog(@"页面加载完成");
    // 你的自定义逻辑
}

// 处理加载失败事件
- (void)handleWebViewLoadError:(NSNotification*)notification {
    NSError* error = notification.userInfo[@"error"];
    NSLog(@"页面加载失败:%@", error.localizedDescription);
    // 你的自定义逻辑
}

// 插件销毁时移除通知监听,避免内存泄漏
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

选择建议

  • 如果需要处理所有UIWebViewDelegate方法(比如拦截请求、处理JS交互等),优先用方法一的代理转发;
  • 如果只是监听页面加载状态,方法二更简单安全,不会干扰Cordova的内部逻辑。

内容的提问来源于stack exchange,提问作者Dan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:53:22