美文网首页
14-3 iOS 与H5

14-3 iOS 与H5

作者: Rumbles | 来源:发表于2020-11-19 18:30 被阅读0次

    执行一段js代码

    #pragma mark --  收集JS页面传来的图片及添加图片点击事件
    -(void)getImagesFromJSAndClickImgEvent:(WKWebView *)webView{
        //这里是JS,主要目的: - 获取H5图片的url
        static  NSString * const jsGetImages =
        @"function getImages(){\
        var objs = document.getElementsByTagName(\"img\");\
        var imgScr = '';\
        for(var i=0;i<objs.length;i++){\
        imgScr = imgScr + objs[i].src + '+';\
        };\
        return imgScr;\
        };";
        WS(weakSelf);
        [self.webView evaluateJavaScript:jsGetImages completionHandler:^(id _Nullable result, NSError * _Nullable error) {
            
        }];
        
        [self.webView evaluateJavaScript:@"getImages()" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
            SS(strongSelf);
            strongSelf.mUrlArray = [NSMutableArray arrayWithArray:[result componentsSeparatedByString:@"+"]];
            if (strongSelf.mUrlArray.count >= 2) {
                [strongSelf.mUrlArray removeLastObject];
            }
        }];
        
        [self.webView evaluateJavaScript:@"function registerImageClickAction(){\
         var imgs=document.getElementsByTagName('img');\
         var length=imgs.length;\
         for(var i=0;i<length;i++){\
         img=imgs[i];\
         img.onclick=function(){\
         window.location.href='image-preview:'+this.src}\
         }\
         }" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
            
        }];
        
        [self.webView evaluateJavaScript:@"registerImageClickAction();" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
            
        }];
        
    }
    
    计算高度:
        //加载web页面数据
        NSString *fullContent = @"<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1,maximum-scale=1, user-scalable=no\" /><link href=\"http://apps.bdimg.com/libs/bootstrap/3.3.4/css/bootstrap.css\" rel=\"stylesheet\"></head><body><div style=\"font-size:14px;width:100%;line-height:1.6;word-break;break-all;word-wrap:break-word;padding-bottom:20px;color: #999999;\">'+temp+'</div><div id=\"testDiv\" style = \"height:0; width:100px\"></div></body></html>";
        //防止/n不换行,替换标签
        NSString *changeContent = [model.content stringByReplacingOccurrencesOfString:@"\n" withString:@"<br>"];
        fullContent = [fullContent stringByReplacingOccurrencesOfString:@"'+temp+'" withString:STRING_NIL(changeContent)];
        fullContent = [fullContent stringByReplacingOccurrencesOfString:@"<b>" withString:@"<b style=\"color: #333333; font-size: 16px;\">"];
        fullContent = [fullContent stringByReplacingOccurrencesOfString:@"display:block;width:100%" withString:[NSString stringWithFormat:@"display:block;width:%fpx",Screen_W - 40]];
        
        [self.webView loadHTMLString:fullContent baseURL:nil];
       
        
        WS(weakSelf);
        [self.webView evaluateJavaScript:@"document.getElementById(\"testDiv\").offsetTop" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
            SS(strongSelf);
            //获取页面高度,并重置webview的frame
            strongSelf.model.height = [result doubleValue] + 84;
        }];
    

    2.注入监听方法不是方法

        // WKWebView的配置
        WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
        [configuration.userContentController addScriptMessageHandler:self name:@"userSelectionString"];
        // js 方法注入
        NSString *printContent = @"document.addEventListener('selectionchange', function () {window.webkit.messageHandlers.userSelectionString.postMessage(window.getSelection().toString());})";
        WKUserScript *userScript = [[WKUserScript alloc] initWithSource:printContent injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
        [configuration.userContentController addUserScript:userScript];
    
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
        NSLog(@"userContentController %@",message.body);
        NSLog(@"userContentController %@",message.name);
    }
    

    3.获取文字

        NSString *lJs2 = @"document.documentElement.innerText"; //根据标识符获取不同内容
    

    4.获取WebView加载的HTML

    [webView evaluateJavaScript:@"document.getElementsByTagName('html')[0].innerHTML" completionHandler:^(id result, NSError * _Nullable error) {
        NSString *html = result;
        NSLog(@"%@", html);
    }];
    

    5.JS调用iOS的代码

        WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
        [configuration.userContentController addScriptMessageHandler:self name:@"userSelectionString"];
    
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    
        NSString *body = message.body;
        if ([NSString isBlankString:body]) {
            
        } else {
            
        }
    }
    
    js方法:window.webkit.messageHandlers.userSelectionString.postMessage(window.getSelection().toString())
    最好是传json
    

    5.wkwebview 去掉剪切板

    #import "HDPlayBackMuluWebView.h"
    
    BOOL wel_canPerformAction(id self,  SEL _cmd, SEL arg1, id arg2) {
        return NO;
    }
    
    
    @implementation HDPlayBackMuluWebView
    
    
    /// iOS 10.0 调用
    + (void)load {
        
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            Method  m = class_getInstanceMethod(NSClassFromString(@"WKContentView"), NSSelectorFromString(@"canPerformAction:withSender:"));
            
            class_addMethod(NSClassFromString(@"WKContentView"), NSSelectorFromString(@"wel_canPerformAction:withSender:"), (IMP)wel_canPerformAction, method_getTypeEncoding(m));
            
            Method m1 = class_getInstanceMethod(NSClassFromString(@"WKContentView"), NSSelectorFromString(@"canPerformAction:withSender:"));
            Method m2 = class_getInstanceMethod(NSClassFromString(@"WKContentView"), NSSelectorFromString(@"wel_canPerformAction:withSender:"));
            method_exchangeImplementations(m1,m2);
        });
    }
    
    - (BOOL)wel_canPerformAction:(SEL)arg1 withSender:(id)arg2 {
        return NO;
    }
    
    
    /// iOS 10.0 的系统不可以用
    - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
        return NO;
    }
    @end
    

    6优化工作

    1.白屏
    2.cookie
    3.秒开:缓存和预加载
    

    1.使用本地资源 文件

    1.这边实现了一个 webview 缓冲池的方案,在 App 启动的时候就初始化了,在需要打开网页的时候直接从缓冲池里面去取 webview 就行
    2.自定义拦截请求 setURLSchemeHandler 把能缓存的都缓存[html 拦截/js || css 文件/]下来 并且可以设置缓存的策略 内存缓存 和 硬盘缓存. 使用请求头获取到请求的资源:Accept
    3.在 webview 初始化的同时并行去请求数据?这个怎么做 使用js和H5的交互
    

    2.使用缓存

    1.页面即将白屏的时候WKNavigationDelegate会回调一个方法 我们在这里执行reload方法
    2.在跳转其他页面占有大量内存的时候。在viewwillapple执行reload方法
    

    3.cookie问题 服务器返回给iOS iOS请求在带给服务器 或者H5 Cookie最常用的也就是维持登录状态了

    cookie 我们登陆成功后获取到cookie。然后首次打开 webview的时候携带上
    存储的时候我们需要区分iOS11 和 iOS 11 之前
    
    iOS11之前
    1.iOS和js交互 通过 document.cookie 设置 Cookie 解决后续页面(同域)Ajax、iframe 请求的 Cookie 问题
    2.拼接在header里面 设置请求头  不能被js读取到
    通过key-Value构造一个cookie,WKWebView loadRequest 前,在 request header 中设置 Cookie, 解决首个请求 Cookie 带不上的问题,
    
    iOS11之后 将cookie存入到WKHTTPCookieStore里面
        /// 发送请求之前
        if (@available(iOS 11.0, *)) {
            WKHTTPCookieStore *httpCookieStore = webView.configuration.websiteDataStore.httpCookieStore;
            for (NSHTTPCookie *cookie in cookies) {
                [httpCookieStore setCookie:cookie completionHandler:^{
                                
                }];
            }
        } else {
            // Fallback on earlier versions
        }
    
    获取cookie是从登陆成功的接口中获取的,这个时候的cookie是被同步到了[[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]中,其实整个app的生命周期里,所有的通过网络请求用到的cookie都会被同步到这个单例中,由它进行管理。
    然后保存起来 
    
    
    获取cookie 存起来:1)从网站返回的 response headerfields 中获取。(2)通过调用js的方法获取 cookie。
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
        NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
        NSArray *cookies =[NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
        NSLog(@"\n====================================\n");
        //读取wkwebview中的cookie 方法1
        for (NSHTTPCookie *cookie in cookies) {
            //        [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
            NSLog(@"wkwebview中的cookie:%@", cookie);
        }
        NSLog(@"\n====================================\n");
        //读取wkwebview中的cookie 方法2 读取Set-Cookie字段
        NSString *cookieString = [[response allHeaderFields] valueForKey:@"Set-Cookie"];
        NSLog(@"wkwebview中的cookie:%@", cookieString);
        NSLog(@"\n====================================\n");
        //看看存入到了NSHTTPCookieStorage了没有
        NSHTTPCookieStorage *cookieJar2 = [NSHTTPCookieStorage sharedHTTPCookieStorage];
        for (NSHTTPCookie *cookie in cookieJar2.cookies) {
            NSLog(@"NSHTTPCookieStorage中的cookie%@", cookie);
        }
        NSLog(@"\n====================================\n");
    
        decisionHandler(WKNavigationResponsePolicyAllow);
    }
    
    通过 JS 获取 cookie
    - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
    {
        
        [webView evaluateJavaScript:[NSString stringWithFormat:@"document.cookie"] completionHandler:^(id _Nullable response, NSError * _Nullable error) {
            if (response != 0) {
                NSLog(@"\n\n\n\n\n\n document.cookie%@,%@",response,error);
            }
        }];
    }
    
    
    document.cookie 的方法获取 cookie并不支持跨越获取
    1.加载一个本地为空的html,域名指向你的第一次加载的url的域名。
    
        if ([response.URL.scheme.lowercaseString containsString:@"http"]) {
            NSArray *cookies =[NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
            if (@available(iOS 11.0, *)) {
                //浏览器自动存储cookie
            }else
            {
                //存储cookies
                dispatch_sync(dispatch_get_global_queue(0, 0), ^{
                    
                    @try{
                        //存储cookies
                        for (NSHTTPCookie *cookie in cookies) {
                            [weakSelf.webView insertCookie:cookie];
                        }
                    }@catch (NSException *e) {
                        NSLog(@"failed: %@", e);
                    } @finally {
                        
                    }
                });
            }
            
        }
    

    性能优化 我们本地加载数据 + 加载web页面。然后数据展示:
    NB啊这个人

    iOS 端 h5 页面秒开优化实践

    https://www.jianshu.com/p/cd0d819b9851

    iOS UIWebView 和 WKWebView 的 cookie 获取,设置,删除
    这里讨论了 H5 页面首屏启动时间的优化,上述优化过后,基本上耗时只剩 webview 本身的启动/渲染机制问题了,这个问题跟后续的响应流畅度的问题一起属于另一个优化范围,就是类 RN / Weex 这样的方案,有机会再探讨。

    相关文章

      网友评论

          本文标题:14-3 iOS 与H5

          本文链接:https://www.haomeiwen.com/subject/wqtfqktx.html