WKWebView的應(yīng)用
在ios12.2后UIWebView系統(tǒng)不在給予支持了,要求更新wkwebview,12.2后
image.png
而且在12.0后一些網(wǎng)頁(yè)視頻不能播放了,找了很久原因也沒有找到,最終的解決方法就是把UIwebView換成WkwebView解決視頻播放問(wèn)題,今天就將自己在集成的時(shí)候遇到的問(wèn)題和遷移方法進(jìn)行提供,供大家參考.
對(duì)于系統(tǒng)在11.0到11.3之間,網(wǎng)頁(yè)打開地圖閃退,在viewDidLoad添加以下代碼解決
//解決在11.0到11.3之間的系統(tǒng)打開地圖閃退問(wèn)題
if (iOS_SYSTEM >= 11.0 && iOS_SYSTEM <= 11.3) {
setenv("JSC_useJIT", "false", 0);
}
1.初始化wkweb
初始化
#import <WebKit/WebKit.h>
WKWebView *cq_newWkWeb (void) {
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
configuration.allowsAirPlayForMediaPlayback = YES;//是否運(yùn)行airplay自動(dòng)播放媒體功能
configuration.allowsInlineMediaPlayback = YES;// 是使用h5的視頻播放器在線播放, 還是使用原生播放器全屏播放
configuration.selectionGranularity = WKSelectionGranularityCharacter;//解決WKWebView的內(nèi)存泄露
configuration.dataDetectorTypes = UIDataDetectorTypePhoneNumber;
configuration.suppressesIncrementalRendering = YES;
configuration.processPool = [[WKProcessPool alloc] init];
NSString *version= [UIDevice currentDevice].systemVersion;
if(version.doubleValue >= 10.0) {
// 該屬性只支持10+系統(tǒng)
configuration.dataDetectorTypes = WKDataDetectorTypePhoneNumber;
configuration.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;//允許網(wǎng)頁(yè)自動(dòng)播放視頻和自動(dòng)播放音頻
}else if (version.doubleValue <= 10.0 && version.doubleValue >=9.0){
configuration.requiresUserActionForMediaPlayback = YES;//允許網(wǎng)頁(yè)自動(dòng)播放視頻和自動(dòng)播放音頻
}
// 創(chuàng)建設(shè)置對(duì)象
WKPreferences *preference = [[WKPreferences alloc]init];
//最小字體大小 當(dāng)將javaScriptEnabled屬性設(shè)置為NO時(shí),可以看到明顯的效果
preference.minimumFontSize = 0;
//設(shè)置是否支持javaScript 默認(rèn)是支持的
preference.javaScriptEnabled = YES;
// 在iOS上默認(rèn)為NO,表示是否允許不經(jīng)過(guò)用戶交互由javaScript自動(dòng)打開窗口
preference.javaScriptCanOpenWindowsAutomatically = YES;
configuration.preferences = preference;
//設(shè)置是否允許畫中畫技術(shù) 在特定設(shè)備上有效
configuration.allowsPictureInPictureMediaPlayback = YES;
WKUserContentController *userContentController = [[WKUserContentController alloc] init];
configuration.userContentController = userContentController;
WKWebView *web = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
web.userInteractionEnabled = YES;
web.multipleTouchEnabled = true;
web.backgroundColor = [UIColor whiteColor];
web.opaque = NO;
// web.scalesPageToFit = true;
return web;
}
- (WKWebView *)baseWebView {
if (!_baseWebView) {
_baseWebView = cq_newWkWeb();
_baseWebView.UIDelegate = self;
_baseWebView.navigationDelegate = self;
[_baseWebView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil];
[_baseWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
[self.view addSubview:_baseWebView];
}
return _baseWebView;
}
協(xié)議遵守
WKNavigationDelegate, WKUIDelegate,
#pragma mark - WKNavigationDelegate
/* 頁(yè)面開始加載 */
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
}
/* 開始返回內(nèi)容 */
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
}
/* 頁(yè)面加載完成 */
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
}
/* 頁(yè)面加載失敗 */
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation{
}
/* 在發(fā)送請(qǐng)求之前,決定是否跳轉(zhuǎn) */
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
//允許跳轉(zhuǎn)
decisionHandler(WKNavigationActionPolicyAllow);
//不允許跳轉(zhuǎn)
//decisionHandler(WKNavigationActionPolicyCancel);
}
/* 在收到響應(yīng)后,決定是否跳轉(zhuǎn) */
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
NSLog(@"%@",navigationResponse.response.URL.absoluteString);
//允許跳轉(zhuǎn)
decisionHandler(WKNavigationResponsePolicyAllow);
//不允許跳轉(zhuǎn)
//decisionHandler(WKNavigationResponsePolicyCancel);
}
2.設(shè)置監(jiān)聽
監(jiān)聽標(biāo)題
[_baseWebView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil];
監(jiān)聽進(jìn)度條
[_baseWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
監(jiān)聽處理
#pragma mark kov
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if([keyPath isEqualToString:@"title"]) {
NSString *n_new = [change dicStringForKey:@"new"];
[self setJs_Title:n_new];
} else if ([keyPath isEqualToString:@"estimatedProgress"]) {
self.webProgress.progress = self.baseWebView.estimatedProgress;
if (self.webProgress.progress == 1) {
__weak typeof (self)weakSelf = self;
[UIView animateWithDuration:0.25f delay:0.1f options:UIViewAnimationOptionCurveEaseOut animations:^{
weakSelf.webProgress.transform = CGAffineTransformMakeScale(1.0f, 1.2f);
} completion:^(BOOL finished) {
weakSelf.webProgress.hidden = YES;
}];
}
}
}
3.wkweb調(diào)用原生彈框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
UIAlertAction *alertActionCancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
// 返回用戶選擇的信息
completionHandler();
}];
UIAlertAction *alertActionOK = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}];
// alert彈出框
UIAlertController *alterVC =[UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert];
[alterVC addAction:alertActionCancel];
[alterVC addAction:alertActionOK];
[self presentViewController:alterVC animated:YES completion:nil];
}
4.js注入
對(duì)于交互的js注入
//注冊(cè)所有js
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"AppJsObj" ofType:@"js"];
NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
WKUserScript *jsFile = [[WKUserScript alloc] initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:true];
[self.configuration.userContentController addUserScript:jsFile];
對(duì)于需要改變值的js,例如登陸的js需要在登陸后改變js的值的注入方法
//注冊(cè)用戶信息js方法
NSString *jsFunc = [NSString stringWithFormat:@"var New_AppJsObj = {function() {var userinfo;}, getUserInfo: function(){return userinfo},setUserInfo: function(user){userinfo = user},getNetworkType: function(){return '%@'}}",@([CQNetworkManager status])];
WKUserScript *jsFileUserInfo = [[WKUserScript alloc] initWithSource:jsFunc injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:true];
[self.configuration.userContentController addUserScript:jsFileUserInfo];
更新注入
NSString *par = [[CQUser getUserInfo] getSessionToken];
NSString *js = [NSString stringWithFormat:@"New_AppJsObj.setUserInfo('%@')",par];
[self evaluateJavaScript:js completionHandler:^(id _Nullable data, NSError * _Nullable error) {
if (!error) {
NSLog(@"更新用戶信息成功");
}
}];
[self evaluateJavaScript:@"New_AppJsObj.getUserInfo()" completionHandler:^(id _Nullable data, NSError * _Nullable error) {
NSLog(@"用戶信息:。。%@",data);
}];
使用下面這個(gè)代理進(jìn)行js攔截處理
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSString *absoluteString = navigationAction.request.URL.absoluteString;
NSLog(@"%@",absoluteString);
NSString *hostString = navigationAction.request.URL.host;
if ([hostString containsString:@"itunes.apple.com"]) {//跳轉(zhuǎn)appstore
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:absoluteString]]) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:absoluteString]];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
}
NSString *scheme = navigationAction.request.URL.scheme;
if ([scheme isEqualToString:@"tel"]) {
NSString *absoluteString = navigationAction.request.URL.absoluteString;
NSString *telNo = [absoluteString componentsSeparatedByString:@":"].lastObject;
if (!CQ_stringIsEmpty(telNo)) {
[Utils callPhone:telNo];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
}
if (![webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler]) {
decisionHandler(WKNavigationActionPolicyCancel);
return ;
}
if (![self decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler]) {
decisionHandler(WKNavigationActionPolicyCancel);
return ;
}
//如果是跳轉(zhuǎn)一個(gè)新頁(yè)面
if (navigationAction.targetFrame == nil) {
[webView loadRequest:navigationAction.request];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
5自定義userAgent
首先在AppDelegate文件中獲取系統(tǒng)UA并進(jìn)行記錄
// 獲取 userAgent
self.wkWeb = [[WKWebView alloc] init];
__weak typeof(self) weakSelf = self;
[self.wkWeb evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id _Nullable data, NSError * _Nullable error) {
NSUserDefaults *userD = [NSUserDefaults standardUserDefaults];
NSString *dataString = String_nil(data);
[userD registerDefaults:@{kUserAgentKey : dataString}];
[userD synchronize];
weakSelf.wkWeb = nil;
}];
重寫UA,并將原來(lái)的拼在后面進(jìn)行更新
/**
重置UA
*/
+ (NSString *)cq_resetUA {
NSString *oldAgent = String_nil([kCQUserDefaults objectForKey:kUserAgentKey]);
if ([oldAgent containsString:prefixString]) {
// 截取之前的UA
oldAgent = [oldAgent componentsSeparatedByString:prefixString].firstObject;
}
CQUser *u = [CQUser getUserInfo];
//loginType(0:未登錄 1:第三方登錄 2:手機(jī)號(hào)登錄)
NSString *loginType = @"0";
if (u.isLogged) {
loginType = CQ_stringIsEmpty(u.phone) ? @"1" : @"2";
}
NSString *newAgent = [NSString stringWithFormat:@"%@(%@;iOS;%@;%@;%@;%@)",prefixString,[Utils getAppBuild],kCQAPPID,u.sessionId,u.token,loginType];
newAgent = [oldAgent stringByAppendingString:newAgent];
[[NSUserDefaults standardUserDefaults] cq_registerUserAgent:newAgent];
return newAgent;
}
在需要更新的地方調(diào)用進(jìn)行UA更新
self.baseweb.customUserAgent = [WKWebView cq_resetUA];
在這里整個(gè)WkWebView就算遷移或者集成完畢了,希望大家bug少一點(diǎn),工資多一點(diǎn),寫的不好,請(qǐng)大家指正