執(zhí)行一段js代碼
#pragma mark -- 收集JS頁面?zhèn)鱽淼膱D片及添加圖片點擊事件
-(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.注入監(jiān)聽方法不是方法
// 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 的系統(tǒng)不可以用
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
return NO;
}
@end
6優(yōu)化工作
1.白屏
2.cookie
3.秒開:緩存和預加載
1.使用本地資源 文件
1.這邊實現(xiàn)了一個 webview 緩沖池的方案穿稳,在 App 啟動的時候就初始化了,在需要打開網頁的時候直接從緩沖池里面去取 webview 就行
2.自定義攔截請求 setURLSchemeHandler 把能緩存的都緩存[html 攔截/js || css 文件/]下來 并且可以設置緩存的策略 內存緩存 和 硬盤緩存. 使用請求頭獲取到請求的資源:Accept
3.在 webview 初始化的同時并行去請求數據?這個怎么做 使用js和H5的交互
2.使用緩存
1.頁面即將白屏的時候WKNavigationDelegate會回調一個方法 我們在這里執(zhí)行reload方法
2.在跳轉其他頁面占有大量內存的時候卷玉。在viewwillapple執(zhí)行reload方法
3.cookie問題 服務器返回給iOS iOS請求在帶給服務器 或者H5 Cookie最常用的也就是維持登錄狀態(tài)了
cookie 我們登陸成功后獲取到cookie。然后首次打開 webview的時候攜帶上
存儲的時候我們需要區(qū)分iOS11 和 iOS 11 之前
iOS11之前
1.iOS和js交互 通過 document.cookie 設置 Cookie 解決后續(xù)頁面(同域)Ajax喷市、iframe 請求的 Cookie 問題
2.拼接在header里面 設置請求頭 不能被js讀取到
通過key-Value構造一個cookie相种,WKWebView loadRequest 前,在 request header 中設置 Cookie, 解決首個請求 Cookie 帶不上的問題品姓,
iOS11之后 將cookie存入到WKHTTPCookieStore里面
/// 發(fā)送請求之前
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 {
}
});
}
}
性能優(yōu)化 我們本地加載數據 + 加載web頁面哎媚。然后數據展示:
NB啊這個人
http://www.reibang.com/p/cd0d819b9851
iOS UIWebView 和 WKWebView 的 cookie 獲取,設置,刪除
這里討論了 H5 頁面首屏啟動時間的優(yōu)化,上述優(yōu)化過后喊儡,基本上耗時只剩 webview 本身的啟動/渲染機制問題了拨与,這個問題跟后續(xù)的響應流暢度的問題一起屬于另一個優(yōu)化范圍,就是類 RN / Weex 這樣的方案艾猜,有機會再探討买喧。