今天碰到一个问题,web那边在script完成时候注册了oc调用的handler,oc这边却调用不到,通知handler没有找到(大致这意思),调试后发现
WebViewJavascriptBridge的对象创建时间有点过晚导致,WebViewJavascriptBridge的创建时机是web加载完成,然后发起一个“wvjbscheme://BRIDGE_LOADED”链接请求,本地拦截后进行代码注入。具体可以查看 injectJavascriptFile 这个方法的执行时机。
这边的做法是采用分类覆盖方式来实现代码如下:
#import "WKWebViewJavascriptBridge+Fix.h"
#import <WebKit/WebKit.h>
#import <WebViewJavascriptBridge/WebViewJavascriptBridge_JS.h>
#import <WebViewJavascriptBridge/WKWebViewJavascriptBridge.h>
@interface WKWebViewJavascriptBridge ()
- (void) _setupInstance:(WKWebView*)webView;
@end
@implementation WKWebViewJavascriptBridge (Fix)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
+ (instancetype)bridgeForWebView:(WKWebView*)webView
{
WKWebViewJavascriptBridge* bridge = [[self alloc] init];
[bridge _setupInstance:webView];
injectJavascriptFile(webView);
[bridge reset];
return bridge;
}
#pragma clang diagnostic pop
void injectJavascriptFile(WKWebView* webView)
{
WKUserScript *javascriptBridge_js = [[WKUserScript alloc] initWithSource:WebViewJavascriptBridge_js() injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
[webView.configuration.userContentController addUserScript:javascriptBridge_js];
NSString* bridge_loaded_command = [NSString stringWithFormat:@"\
var bridgeLoadedIframe = document.createElement('iframe');\
bridgeLoadedIframe.style.display = 'none';\
bridgeLoadedIframe.src = '%@://%@';\
document.documentElement.appendChild(bridgeLoadedIframe);\
", kOldProtocolScheme, kBridgeLoaded];
WKUserScript *javascriptBridge_loaded_js = [[WKUserScript alloc] initWithSource:bridge_loaded_command injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
[webView.configuration.userContentController addUserScript:javascriptBridge_loaded_js];
}
@end
简单阐述一下:
往web注入个WebViewJavascriptBridge的创建js代码,在页面加载之前执行,这样就能保证web那边注册handler时候一定存在对象。
由于这是在加载前进行注册,所以oc这边收不到原本的“wvjbscheme://BRIDGE_LOADED”命令,在injectJavascriptFile 内的self.startupMessageQueue无法触发,新的调用也就执行不到了,所以这边补一个命令。