• 记录使用WKWebView进行OC与JS交互所踩过的坑


    目录:
    1.页面cookie缓存
    2.允许弹出JS的弹框
    3.在webview页面加载的时候,添加加载进度条
    4.禁止掉webview页面的长按复制粘贴功能
    5.设置webview的userAgent
    正文:
    1.1  cookie、localStorage、sessionStorage
    相同点:都是浏览器端存储数据,且同源。
    区别:cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器之间来回传递。而localStorage和sessionStorage不会自动把数据发送给服务器,仅在本地保存。cookie限制存储大小为4k,localStorage和sessionStorage存储大小为5M。数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭前有效, 自然也就不可能持久保持;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期 时间之前一直有效,即使窗口或浏览器关闭。作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页 面;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。
    1.2  如何保存cookie?
    如果只在loadRequest的时候保存cookie,那么在这个url页面上点击可点击的链接,进入其他页面可能cookie就消失了,所以要使用一个贯穿全局的东西来保存cookie。
    所以保存cookie需要从两步做起:1.在【WKWebView loadRequest:NSUrlRequest】时,往request里注入HTTPHeaderField
    此时cookie的形式是:
    具体代码如下:
    NSMutableDictionary *cookieDic = [NSMutableDictionary dictionary];
        NSMutableString *cookieValue = [NSMutableString stringWithFormat:@""];
        NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
        for (NSHTTPCookie *cookie in [cookieJar cookies]) {
            [cookieDic setObject:cookie.value forKey:cookie.name];
        }
        
        // cookie重复,先放到字典进行去重,再进行拼接
        for (NSString *key in cookieDic) {
            NSString *appendString = [NSString stringWithFormat:@"%@=%@;", key, [cookieDic valueForKey:key]];
            [cookieValue appendString:appendString];
        }
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
        [request addValue:cookieValue forHTTPHeaderField:@"Cookie"];
        
        [_webView loadRequest:request];
     
    2.在webview初始化的时候,手动设置全局保存cookie。
    这里的cookie的格式是:NSString *cookieValue = @"document.cookie = 'fromapp=ios';document.cookie = 'channel=appstore';"
    首先使用WKUserScript注入cookie,再把WKUserScript放入WKUserContentController里,再把WKUserContentController作为WKWebViewConfiguration的一个属性,具体实现代码如下:
            WKWebViewConfiguration *config = [WKWebViewConfiguration new];
         // 将所有cookie以document.cookie = 'key=value';形式进行拼接
            NSString *cookieValue = [self getCookieSets];
            WKUserContentController* userContentController = WKUserContentController.new;
            WKUserScript * cookieScript = [[WKUserScript alloc]
                                           initWithSource: cookieValue
                                           injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
            [userContentController addUserScript:cookieScript];
            config.userContentController = userContentController;
            _webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 64, Screen_Width, Screen_Height - 64) configuration:config];
    
    - (NSString *)getCookieSets
    {
        NSMutableDictionary *cookieDic = [NSMutableDictionary dictionary];
        NSMutableString *cookieValue = [NSMutableString stringWithFormat:@""];
        NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
        for (NSHTTPCookie *cookie in [cookieJar cookies]) {
            [cookieDic setObject:cookie.value forKey:cookie.name];
        }
        
        /* 
        cookie重复,先放到字典进行去重,再进行拼接,拼接格式为
        NSString *cookieValue = @"document.cookie = 'fromapp=ios';document.cookie = 'channel=appstore';";
      */
    for (NSString *key in cookieDic) { NSString *appendString = [NSString stringWithFormat:@"document.cookie = '%@=%@';", key, [cookieDic valueForKey:key]]; [cookieValue appendString:appendString]; } return cookieValue; }

    2.允许弹出js的弹窗

    当js调用alert弹窗时,是不能直接在APP页面上弹出来的,必须由APP实现以下三个代理方法,才能弹出他们的弹窗

    在JS端调用alert函数时,会触发此代理方法。JS端调用alert时所传的数据可以通过message拿到 在原生得到结果后,需要回调JS,是通过completionHandler回调 

    - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message

    initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;

     

    JS端调用confirm函数时,会触发此方法。

    - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message

    initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;

     

    JS端调用confirm函数时,会触发此方法

    - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message

    initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;

    3.加载不安全的Https链接

    当加载的H5页面链接是不安全的https链接时,页面会表现为进度条在走,但是过一会进度条消失,页面空白,无内容显示。

    这时候必须做一些兼容操作,才能正常加载页面。在认证的代理方法里进行信任。

    4.WkWebview无法播放wav格式音频

    在H5页面播放语音,没有声音,但是能确保的是音频文件是正确的,因为在iOS端发送的语音在安卓端是可以播放的;后来经测试发现在微信端发送的语音在iOS上也能播放,而微信端发送的语音格式是MP3,iOS端发送的是WAV格式的;于是就怀疑是语音文件格式的问题,于是用苹果自带的浏览器进行测试发现并不支持WAV格式的音频播放。刚开始一直以为是权限未开放的问题,并没有怀疑是格式的问题,因为WAV是苹果录音的原生音频格式

    5.H5页面图片横竖屏显示错乱

    H5页面图片浏览器在安卓端显示的图片是竖屏的,但是在iOS端显示的图片确实横屏的,本来以为是iOS端的图片是自动根据屏幕适应,后来才发现是因为:

    图片有自己的存储信息,苹果手机在拍摄的时候会给图片加上横评或者竖屏的信息的,拍摄的时候是横屏的自然显示的就是横屏的,服务器传的图片之所以是竖屏的是因为服务器那边旋转了图片的位置,但是图片自身的那个横评或者竖屏的信息没有修改,所以在浏览器加载时图片仍然显示自身记录的横屏

     6.WkWebView中window.open方法不起作用

     具体情景是:在一个加载H5页面的App页面上,当用户点击App页面上的导航栏按钮时,会调用H5提供的方法,在当前App页面重新打开一个H5窗口,H5那边使用的是window.open来开辟新窗口,但是iOS这边调用无效,而Android调用后执行效果正常。查了资料才知道原来iOS的WkWebview对window.open方法进行了安全限制,即调用该方法,不会起到作用。网上给出的大部分解决方法都是在window.open调用的时候,在代理方法
    webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
    

      里面进行拦截url,然后使用【UIApplication openURL】方法进行跳转,但是这种方法对于我的需求来说并不适用,因为我是需要在App当前页面打开新窗口,不离开当前页面。所以后来询问了H5那边的开发人员除了window.open有没有其他打开新窗口页面的方法,然后H5那边跟App一起尝试了用window.location,成功解决问题。

     

     7.WkWebView加载PDF乱码

     使用WKWebView加载部分PDF文件时显示乱码,
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void(^)(WKNavigationActionPolicy))decisionHandler {
        
        NSString *strRequest = [navigationAction.request.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        WKNavigationActionPolicy policy = WKNavigationActionPolicyAllow;
        
        
        if ([strRequest rangeOfString:@"?sign="].location != NSNotFound)
        {
            NSString *headStr = [[strRequest componentsSeparatedByString:@"?sign="] firstObject]; //加载PDF文件需要设置编码
            if ([headStr rangeOfString:@".pdf"].location != NSNotFound) {
                NSData *data = [NSData dataWithContentsOfURL:navigationAction.request.URL];
                if (@available(iOS 9.0, *)) {
                    [self.webView loadData:data MIMEType:@"application/pdf" characterEncodingName:@"GBK" baseURL:nil];
                } else {
                    // Fallback on earlier versions
                }
            }
        }
    }
    

      

     
     
     
     
     
  • 相关阅读:
    Android Jetpack之WorkManager: 观察结果
    解决'androidx.arch.core:core-runtime' has different version for the compile (2.0.0) and runtime (2.0.1)
    我要研究一下minio,管理大量的照片
    分发消息的写法
    百度地图坐标转换
    HighChart 实现从后台取数据来实时更新柱状和折线组图
    导出Excel
    Java 8新特性之集合
    java中的Switch case语句
    提问:"~"运算符
  • 原文地址:https://www.cnblogs.com/i-am-lvjiazhen/p/7115968.html
Copyright © 2020-2023  润新知