随着iOS10的出现,大部分应用都已经抛弃了iOS7的支持,那么将UIWebView
替换为WKWebView
的工作也就提上了日程。毕竟UIWebView
的占用内存大,而且存在泄漏问题,包括对js的支持也是不如WKWebView
的,所以大部分的UIWebView
都应该替换为WKWebView
。
由于我们的工程对js只进行了简单的支持和调用,并没有太多复杂的交互,这里就不对WKUIDelegate
进行说明了,毕竟我也不是很清楚。这里简单说一下我在替换过程中遇到的一些问题吧:
- 弹出的链接替换
在UIWebViewDelegate中,
shouldStartLoadWithRequest
方法里可以获取到对应的NSURLRequest,进行处理,然后返回YES
/NO
;而在WKNavigationDelegate
中,对应的方法应该是decidePolicyForNavigationAction
,可以在navigationAction中获取到对应的request,然后进行处理,不过没有返回值,而是使用回调方法进行处理。 - 初始键盘弹出
在
UIWebView
中,有一个属性keyboardDisplayRequiresUserAction
,设置为NO
时就可以在页面刚加载时直接弹出键盘;
在WKWebView
中,是没有这个属性的,如果要实现类似的功能,就必须替换WKWebView
中相应的方法,代码如下:
```objective-c
static void (originalIMP)(id self, SEL _cmd, void arg0, BOOL arg1, BOOL arg2, id arg3) = NULL;
void interceptIMP (id self, SEL _cmd, void* arg0, BOOL arg1, BOOL arg2, id arg3) {
originalIMP(self, _cmd, arg0, TRUE, arg2, arg3);
}
void setWkWebViewShowKeybord() {
Class cls = NSClassFromString(@"WKContentView");
SEL originalSelector = NSSelectorFromString(@"_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:");
Method originalMethod = class_getInstanceMethod(cls, originalSelector);
IMP impOvverride = (IMP) interceptIMP;
originalIMP = (void *)method_getImplementation(originalMethod);
method_setImplementation(originalMethod, impOvverride);
}
> 需要调用�函数`setWkWebViewShowKeybord`,才可以实现该功能;需要特别注意的是,该函数只能调用一次,否则会导致循环调用,程序崩溃。上述代码引用自[stackoverflow的答案](http://stackoverflow.com/questions/32407185/wkwebview-cant-open-keyboard-for-input-field)
3. `JavaScript`的调用
> 看起来和`UIWebView`的调用差不多,一个方法是`stringByEvaluatingJavaScriptFromString`,另一个是`evaluateJavaScript`,但其实是完全不同的,主要就在于一个是同步调用,另一个是异步调用。
如果原来的代码已经使用了`UIWebView`,那么在修改`WKWebView`时一定要注意,因为异步调用是不可以同时调用多个`js`方法的,否则执行顺序将无法保证。
下面写出我把异步调用修改为同步调用的方法,是实现在了`WKWebView`的`category`里面:
```objective-c
- (id)syncEvalJavascriptString:(NSString *)jsCode {
__block id returnValue = nil;
__block BOOL finished = NO;
[self evaluateJavaScript:jsCode completionHandler:^(id _Nullable result, NSError * _Nullable error) {
returnValue = result;
finished = YES;
}];
while (!finished) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
return returnValue;
}
需要注意的就是
NSRunLoop
那里不可以使用dispatch_semaphore_t
信号量代替,会导致永久等待的,已经实测过了。
目前我使用到的也就这些了,后续如果有对于WKWebView
的更多了解的话,在增加吧。不过替换成了WKWebView
之后,性能上确实提高了,比以前流畅多了。