欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

WKWebView的使用(一)

程序员文章站 2022-03-20 17:55:52
...

随着iOS10的出现,大部分应用都已经抛弃了iOS7的支持,那么将UIWebView替换为WKWebView的工作也就提上了日程。毕竟UIWebView的占用内存大,而且存在泄漏问题,包括对js的支持也是不如WKWebView的,所以大部分的UIWebView都应该替换为WKWebView

由于我们的工程对js只进行了简单的支持和调用,并没有太多复杂的交互,这里就不对WKUIDelegate进行说明了,毕竟我也不是很清楚。这里简单说一下我在替换过程中遇到的一些问题吧:

  1. 弹出的链接替换
    在UIWebViewDelegate中,shouldStartLoadWithRequest方法里可以获取到对应的NSURLRequest,进行处理,然后返回YES/NO;而在WKNavigationDelegate中,对应的方法应该是decidePolicyForNavigationAction,可以在navigationAction中获取到对应的request,然后进行处理,不过没有返回值,而是使用回调方法进行处理。

  2. 初始键盘弹出
    UIWebView中,有一个属性keyboardDisplayRequiresUserAction,设置为NO时就可以在页面刚加载时直接弹出键盘;
    WKWebView中,是没有这个属性的,如果要实现类似的功能,就必须替换WKWebView中相应的方法,代码如下:

    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,才可以实现该功能;需要特别注意的是,该函数只能调用一次,否则会导致循环调用,程序崩溃。上述代码引用自*的答案

  3. JavaScript的调用
    看起来和UIWebView的调用差不多,一个方法是stringByEvaluatingJavaScriptFromString,另一个是evaluateJavaScript,但其实是完全不同的,主要就在于一个是同步调用,另一个是异步调用。
    如果原来的代码已经使用了UIWebView,那么在修改WKWebView时一定要注意,因为异步调用是不可以同时调用多个js方法的,否则执行顺序将无法保证。
    下面写出我把异步调用修改为同步调用的方法,是实现在了WKWebViewcategory里面:

    - (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之后,性能上确实提高了,比以前流畅多了。