执行一段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啊这个人
https://www.jianshu.com/p/cd0d819b9851
iOS UIWebView 和 WKWebView 的 cookie 获取,设置,删除
这里讨论了 H5 页面首屏启动时间的优化,上述优化过后,基本上耗时只剩 webview 本身的启动/渲染机制问题了,这个问题跟后续的响应流畅度的问题一起属于另一个优化范围,就是类 RN / Weex 这样的方案,有机会再探讨。
网友评论