WKWebView應(yīng)用,重置UA,動(dòng)態(tài)更新注入

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)大家指正

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,674評(píng)論 1 32
  • 基本應(yīng)用 首先使用WKWebView.你需要導(dǎo)入WebKit。關(guān)于WKWebView其他基礎(chǔ)使用不在本篇研究范圍。...
    XueYongWei閱讀 14,709評(píng)論 12 42
  • 人的一生都會(huì)面臨著無(wú)數(shù)的選擇,決定改變了一生。不管最后結(jié)果如何,對(duì)與錯(cuò),我們都需要對(duì)自己所做的決定來(lái)買單。 兩年前...
    角落里的薔薇7V閱讀 342評(píng)論 0 1

友情鏈接更多精彩內(nèi)容