14-3 iOS 与H5

执行一段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= 2) {
            [strongSelf.mUrlArray removeLastObject];
        }
    }];
    
    [self.webView evaluateJavaScript:@"function registerImageClickAction(){\
     var imgs=document.getElementsByTagName('img');\
     var length=imgs.length;\
     for(var i=0;i
'+temp+'
"; //防止/n不换行,替换标签 NSString *changeContent = [model.content stringByReplacingOccurrencesOfString:@"\n" withString:@"
"]; fullContent = [fullContent stringByReplacingOccurrencesOfString:@"'+temp+'" withString:STRING_NIL(changeContent)]; fullContent = [fullContent stringByReplacingOccurrencesOfString:@"" withString:@""]; 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)