WebKit內(nèi)核的研究與應(yīng)用

概述

本篇文章將闡述,WebKit核新的類和協(xié)議宗苍、MessageHandler消息處理器钻弄、JS->OC佃却,OC->JS 交互流程WKNavagationDelegate協(xié)議窘俺、WKUIDelegate協(xié)議等類或方法分析WebKit內(nèi)核的原理及應(yīng)用說明饲帅。

重點注意

WebKit 的函數(shù)和方法只能在App的主線程或者主隊列中調(diào)用。

WebKit核新的類和協(xié)議

WKWebView:網(wǎng)頁的渲染與展示瘤泪,通過WKWebViewConfiguration可以進行配置灶泵。

WKWebViewConfiguration:這個類專門用來配置WKWebView。

WKPreference:這個類用來進行M相關(guān)設(shè)置对途。

WKProcessPool:這個類用來配置進程池赦邻,與網(wǎng)頁視圖的資源共享有關(guān)。

WKUserContentController:這個類主要用來做native與JavaScript的交互管理实檀。

WKUserScript:用于進行JavaScript注入惶洲。

WKScriptMessageHandler:這個類專門用來處理JavaScript調(diào)用native的方法。

WKNavigationDelegate:網(wǎng)頁跳轉(zhuǎn)間的導(dǎo)航管理協(xié)議膳犹,這個協(xié)議可以監(jiān)聽網(wǎng)頁的活動恬吕。

WKNavigationAction:網(wǎng)頁某個活動的示例化對象。

WKUIDelegate:用于交互處理JavaScript中的一些彈出框镣奋。

WKBackForwardList:堆棧管理的網(wǎng)頁列表币呵。

WKBackForwardListItem:每個網(wǎng)頁節(jié)點對象怀愧。

使用WKWebViewConfiguration對WebView進行配置

WebbView初始化

初始化函數(shù)

- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration;

加載方式侨颈,建議使用蘋果推薦使用的函數(shù)

// 加載HTML文件,推薦使用
- (WKNavigation *)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL;
// 加載一個請求芯义,推薦使用
- (WKNavigation *)loadRequest:(NSURLRequest *)request;

// 加載本地文件哈垢,如Html文件等,不推薦使用
- (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL API_AVAILABLE(macosx(10.11), ios(9.0));
// // 加載本地文件,如Html文件等,不推薦使用
- (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL API_AVAILABLE(macosx(10.11), ios(9.0));

WKWebViewConfiguration內(nèi)容配置

  • WKPerference偏好設(shè)置
//進行偏好設(shè)置
WKPreferences * preference = [[WKPreferences alloc]init];    
//最小字體大小 當(dāng)將javaScriptEnabled屬性設(shè)置為NO時扛拨,可以看到明顯的效果
preference.minimumFontSize = 0;    
//設(shè)置是否支持javaScript 默認(rèn)是支持的
preference.javaScriptEnabled = YES;    
//設(shè)置是否允許不經(jīng)過用戶交互由javaScript自動打開窗口
preference.javaScriptCanOpenWindowsAutomatically = YES;
config.preferences = preference;
  • WKUserContentControllernativeJavaScript的交互管理
    WKUserContentController 最重要的對象方法就是addScriptMessageHandler:name:耘分,我把這個功能簡稱為MessageHandler(消息處理器)。- addScriptMessageHandler:name:有兩個參數(shù),第一個參數(shù)是userContentController的代理對象(通常是self)求泰,第二個參數(shù)是JS里發(fā)送postMessage的對象(相當(dāng)于一個nativejs相互識別的一個標(biāo)識)央渣。使用MessageHandler功能,就必須要實現(xiàn)WKScriptMessageHandler協(xié)議渴频。
//設(shè)置內(nèi)容交互控制器 用于處理JavaScript與native交互
WKUserContentController * userController = [[WKUserContentController alloc]init];    
//設(shè)置處理代理并且注冊要被js調(diào)用的方法名稱
[userController addScriptMessageHandler:self name:@"name"];    
//js注入芽丹,注入一個測試方法。
NSString *javaScriptSource = @"function userFunc(){window.webkit.messageHandlers.name.postMessage( {\"name\":\"HS\"})}";    
WKUserScript *userScript = [[WKUserScript alloc] initWithSource:javaScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
// forMainFrameOnly:NO(全局窗口)卜朗,yes(只限主窗口)[userController addUserScript:userScript];
config.userContentController = userController;
  • 在native代理的回調(diào)方法中拔第,會獲取到JavaScript傳遞進來的消息
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{    
//這里可以獲取到JavaScript傳遞進來的消息
}
  • WKScriptMessage類是JavaScript傳遞的對象實例
//傳遞的消息主體
@property (nonatomic, readonly, copy) id body;
//傳遞消息的WebView
@property (nullable, nonatomic, readonly, weak) WKWebView *webView;
//傳遞消息的WebView當(dāng)前頁面對象
@property (nonatomic, readonly, copy) WKFrameInfo *frameInfo;
//消息名稱,也就是我們注冊回調(diào)的“name”
@property (nonatomic, readonly, copy) NSString *name;
  • 注入JS腳本
- (void)addUserScript:(WKUserScript *)userScript;
  • WKWebsiteDataStore:WebKit框架采用其本身的緩存框架

@interface WKWebsiteDataStore : NSObject
//獲取默認(rèn)的存儲器 此存儲器為持久性的會被寫入磁盤
+ (WKWebsiteDataStore *)defaultDataStore;
//獲取一個臨時的存儲器
+ (WKWebsiteDataStore *)nonPersistentDataStore;
//存儲器是否是臨時的
@property (nonatomic, readonly, getter=isPersistent) BOOL persistent;
//所有可以存儲的類型
+ (NSSet<NSString *> *)allWebsiteDataTypes;
@end

//設(shè)置數(shù)據(jù)存儲store
config.websiteDataStore = [WKWebsiteDataStore defaultDataStore];

//設(shè)置是否將網(wǎng)頁內(nèi)容全部加載到內(nèi)存后再渲染
    config.suppressesIncrementalRendering = NO;    //設(shè)置HTML5視頻是否允許網(wǎng)頁播放 設(shè)置為NO則會使用本地播放器
    config.allowsInlineMediaPlayback =  YES;    //設(shè)置是否允許ariPlay播放
    config.allowsAirPlayForMediaPlayback = YES;    //設(shè)置視頻是否需要用戶手動播放  設(shè)置為NO則會允許自動播放
    config.requiresUserActionForMediaPlayback = NO;    //設(shè)置是否允許畫中畫技術(shù) 在特定設(shè)備上有效
    config.allowsPictureInPictureMediaPlayback = YES;    //設(shè)置選擇模式 是按字符選擇 還是按模塊選擇/*
    typedef NS_ENUM(NSInteger, WKSelectionGranularity) {
        //按模塊選擇
        WKSelectionGranularityDynamic,
        //按字符選擇
        WKSelectionGranularityCharacter,
    } NS_ENUM_AVAILABLE_IOS(8_0);
    */
    config.selectionGranularity = WKSelectionGranularityCharacter;    //設(shè)置請求的User-Agent信息中應(yīng)用程序名稱 iOS9后可用
    config.applicationNameForUserAgent = @"HS";

JS->OC,OC->JS 交互流程

Native 實現(xiàn)方式

    //防止頻繁IO操作场钉,造成性能影響
    static NSString *nativejsSource;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        nativejsSource = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"NativeApi" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil];
    });
    //添加自定義的腳本
    WKUserScript *js = [[WKUserScript alloc] initWithSource:nativejsSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
    [self.webView.configuration.userContentController addUserScript:js];

    //注冊分享回調(diào)
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"nativeShare"];
    
    // 注冊添加聯(lián)系人的回調(diào)
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"nativeChoosePhoneContact"];

JS端實現(xiàn)方式

/**
 * Native為H5提供的Api接口
 *
 * @type {js對象}
 */
var DANativeApi = (function() {

    var NativeApi = {
        /**
         * 分享
         * @param  {js對象} shareInfo 分享信息和回調(diào)
         * @return {void}           無同步返回值蚊俺,異步返回分享結(jié)果 true or false
         */
        share: function(shareInfo) {
            if (shareInfo == undefined || shareInfo == null || typeof(shareInfo) !== "object") {
                alert("參數(shù)" + JSON.stringify(shareInfo) + "不合法");
            } else {
                alert("分享的參數(shù)為" + JSON.stringify(shareInfo));
            }
            //調(diào)用native端
            _nativeShare(shareInfo);
        },
        /**
         * 從通訊錄選擇聯(lián)系人
         * @return {void} 無同步返回值,異步返回選擇的結(jié)果
         */
        choosePhoneContact: function(param) {
            //具體是否需要判斷
            //調(diào)用native端
            _nativeChoosePhoneContact(param);
        }
    }

    //下面是一些私有函數(shù)
    /**
     * Native端實現(xiàn)逛万,適用于WKWebView泳猬,UIWebView如何實現(xiàn),小伙伴自己動腦筋吧~
     * @param  {js對象} shareInfo 分享的信息和回調(diào)
     * @return {void}           無同步返回值宇植,異步返回
     */
    function _nativeShare(shareInfo) {
        //用于WKWebView暂殖,因為WKWebView并沒有辦法把js function傳遞過去,因此需要特殊處理一下
        //把js function轉(zhuǎn)換為字符串当纱,oc端調(diào)用時 (<js function string>)(true); 即可
        //如果有回調(diào)函數(shù)呛每,且為function
        var callbackFunction = shareInfo.result;
        if (callbackFunction != undefined && callbackFunction != null && typeof(callbackFunction) === "function") {
            shareInfo.result = callbackFunction.toString();
        }
        //js -> oc 
        // 至于Android端,也可以坡氯,比如 window.jsInterface.nativeShare(JSON.stringify(shareInfo));
        window.webkit.messageHandlers.nativeShare.postMessage(shareInfo);
    }
    /**
     * Native端實現(xiàn)選擇聯(lián)系人晨横,并異步返回結(jié)果
     * @param  {[type]} param [description]
     * @return {[type]}       [description]
     */
    function _nativeChoosePhoneContact(param) {
        var callbackFunction = param.completion;
        if (callbackFunction != undefined && callbackFunction != null && typeof(callbackFunction) === "function") {
            param.completion = callbackFunction.toString();
        }
        //js -> oc 
        window.webkit.messageHandlers.nativeChoosePhoneContact.postMessage(param);
    }

    //閉包,把Api對象返回
    return NativeApi;
})();

/*

//調(diào)用時箫柳,分享
DANativeApi.share({
    title: document.title,
    desc: "",
    url: location.href,
    imgUrl: "",
    result: function(res) {
        // body...
        alert("分享結(jié)果為:" + JSON.stringify(res));
    }
});

//選擇聯(lián)系人
DANativeApi.choosePhoneContact({
    completion: function(res) {
        alert("選擇聯(lián)系人的結(jié)果為:" + JSON.stringify(res));
    }
});
 */

釋放回調(diào)

- (void)dealloc
{
// 注冊的回調(diào)要及時釋放手形,防止強引用,循環(huán)引用
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"nativeShare"];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"nativeChoosePhoneContact"];
}

OC調(diào)用JS

// 將分享結(jié)果返回給js
    NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url];
    [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        NSLog(@"%@----%@",result, error);
    }];

實現(xiàn)WKScriptMessageHandler協(xié)議方法(JS調(diào)用OC)

#pragma mark - WKScriptMessageHandler 
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
// 分享
 if ( [message.name isEqualToString:@"nativeShare"]) {

        // JS ->OC
        // 第一步悯恍,處理分享數(shù)據(jù)
        NSDictionary *shareData = message.body;
        NSLog(@"%@分享的數(shù)據(jù)為: %@", message.name, shareData);

        // 第二步库糠,彈出分享的圖層,執(zhí)行分享操作
        
        // 第三部涮毫,模擬異步回調(diào)瞬欧,將分享狀態(tài)反饋給JS端
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

            //讀取js function的字符串
            NSString *jsFunctionString = shareData[@"result"];

            //拼接調(diào)用該方法的js字符串
            NSString *callbackJs = [NSString stringWithFormat:@"(%@)(%d);", jsFunctionString, NO];    //后面的參數(shù)NO為模擬分享失敗

            //執(zhí)行回調(diào)OC->JS,調(diào)用JS端的方法罢防,將分享狀態(tài)告知js,然后evaluateJavaScript:completionHandler的回調(diào)處理JS對于分享狀態(tài)反饋的回應(yīng)艘虎。
            [self.webView evaluateJavaScript:callbackJs completionHandler:^(id _Nullable result, NSError * _Nullable error) {
                if (!error) {
                    NSLog(@"模擬回調(diào),分享失敗");
                }
            }];
        });
    }
   
    //選擇聯(lián)系人
    else if ([message.name isEqualToString:@"nativeChoosePhoneContact"]) {
     
        [self selectContactCompletion:^(NSString *name, NSString *phone) {
            NSLog(@"選擇完成");
            //讀取js function的字符串
            NSString *jsFunctionString = message.body[@"completion"];
            //拼接調(diào)用該方法的js字符串
            NSString *callbackJs = [NSString stringWithFormat:@"(%@)({name: '%@', mobile: '%@'});", jsFunctionString, name, phone];
            //執(zhí)行回調(diào)
            [self.webView evaluateJavaScript:callbackJs completionHandler:^(id _Nullable result, NSError * _Nullable error) {
                
            }];
        }];
    
    }
}

WKWebView中的屬性和方法解析

常用的屬性和方法

//設(shè)置導(dǎo)航代理
@property (nullable, nonatomic, weak) id <WKNavigationDelegate> navigationDelegate;
//設(shè)置UI代理
@property (nullable, nonatomic, weak) id <WKUIDelegate> UIDelegate;
//導(dǎo)航列表
@property (nonatomic, readonly, strong) WKBackForwardList *backForwardList;
//通過url加載網(wǎng)頁視圖
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
//通過文件加載網(wǎng)頁視圖
- (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL NS_AVAILABLE(10_11, 9_0);
//通過HTML字符串加載網(wǎng)頁視圖
- (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
//通過data數(shù)據(jù)加載網(wǎng)頁視圖
- (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL NS_AVAILABLE(10_11, 9_0);
//渲染導(dǎo)航列表中的某個網(wǎng)頁節(jié)點
- (nullable WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item;
//網(wǎng)頁標(biāo)題
@property (nullable, nonatomic, readonly, copy) NSString *title;
//網(wǎng)頁的url
@property (nullable, nonatomic, readonly, copy) NSURL *URL;
//網(wǎng)頁是否正在加載中
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
//加載進度 可以監(jiān)聽這個屬性的值配合UIProgressView來設(shè)計進度條
@property (nonatomic, readonly) double estimatedProgress;
//是否全部是安全連接
@property (nonatomic, readonly) BOOL hasOnlySecureContent;
//證書列表
@property (nonatomic, readonly, copy) NSArray *certificateChain;
//是否可以回退
@property (nonatomic, readonly) BOOL canGoBack;
//是否可以前進
@property (nonatomic, readonly) BOOL canGoForward;
//回退網(wǎng)頁
- (nullable WKNavigation *)goBack;
//前進網(wǎng)頁
- (nullable WKNavigation *)goForward;
//刷新網(wǎng)頁
- (nullable WKNavigation *)reload;
//忽略緩存的刷新
- (nullable WKNavigation *)reloadFromOrigin;
//停止加載
- (void)stopLoading;
//執(zhí)行JavaScript代碼
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ __nullable)(__nullable id, NSError * __nullable error))completionHandler;
//是否允許右滑返回手勢
@property (nonatomic) BOOL allowsBackForwardNavigationGestures;

WKBackForwardList類為導(dǎo)航管理的網(wǎng)頁列表類

@interface WKBackForwardList : NSObject
//當(dāng)前所在的網(wǎng)頁節(jié)點
@property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *currentItem;
//前進的一個網(wǎng)頁節(jié)
@property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *forwardItem;
//回退的一個網(wǎng)頁節(jié)點
@property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *backItem;
//獲取某個index的網(wǎng)頁節(jié)點
- (nullable WKBackForwardListItem *)itemAtIndex:(NSInteger)index;
//獲取回退的節(jié)點數(shù)組
@property (nonatomic, readonly, copy) NSArray<WKBackForwardListItem *> *backList;
//獲取前進的節(jié)點數(shù)組
@property (nonatomic, readonly, copy) NSArray<WKBackForwardListItem *> *forwardList;
@end

WKBackForwardListItem 網(wǎng)頁節(jié)點

@interface WKBackForwardListItem : NSObject
//當(dāng)前節(jié)點的URL
@property (readonly, copy) NSURL *URL;
//當(dāng)前節(jié)點的標(biāo)題
@property (nullable, readonly, copy) NSString *title;
//創(chuàng)建此WebView的初始URL
@property (readonly, copy) NSURL *initialURL;

WKUserScript

//注入的js代碼的腳本
    WKUserScript *js = [[WKUserScript alloc] initWithSource:jsSource injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:NO];
    [self.webView.configuration.userContentController addUserScript:js];

/*source為要注入的js代碼
WKUserScriptInjectionTime設(shè)置注入的時機forMainFrameOnly參數(shù)設(shè)置是否只在主頁面注入
typedef NS_ENUM(NSInteger, WKUserScriptInjectionTime) {
    //原js代碼運行前注入
    WKUserScriptInjectionTimeAtDocumentStart,
    //原js代碼運行后注入
    WKUserScriptInjectionTimeAtDocumentEnd
} NS_ENUM_AVAILABLE(10_10, 8_0);

*/

- (instancetype)initWithSource:(NSString *)source injectionTime:(WKUserScriptInjectionTime)injectionTime forMainFrameOnly:(BOOL)forMainFrameOnly;

WKNavagationDelegate協(xié)議

該代理提供的方法咒吐,可以用來追蹤加載過程(頁面開始加載野建、加載完成属划、加載失敗)候生、決定是否執(zhí)行跳轉(zhuǎn)同眯。

//追蹤加載過程
// 頁面開始加載時調(diào)用
-(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;

// 當(dāng)內(nèi)容開始返回時調(diào)用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;

// 頁面加載完成之后調(diào)用
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;

// 頁面加載失敗時調(diào)用
 -(void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;

// 頁面跳轉(zhuǎn)的代理方法有三種,分為(收到跳轉(zhuǎn)與決定是否跳轉(zhuǎn)兩種):
// 接收到服務(wù)器跳轉(zhuǎn)請求之后調(diào)用
 -(void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;

 // 在收到響應(yīng)后唯鸭,決定是否跳轉(zhuǎn)
 -(void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;


/*
在發(fā)送請求之前嗽测,決定是否跳轉(zhuǎn),決定是否響應(yīng)網(wǎng)頁的某個動作,例如加載肿孵,回退唠粥,前進,刷新等停做,在這個方法中晤愧,必須執(zhí)行decisionHandler()代碼塊,并將是否允許這個活動執(zhí)行在block中進行傳入
*//*
WKNavigationAction是網(wǎng)頁動作的抽象化蛉腌,其中封裝了許多行為信息官份,后面會介紹
WKNavigationActionPolicy為開發(fā)者回執(zhí),枚舉如下:
typedef NS_ENUM(NSInteger, WKNavigationActionPolicy) {
    //取消此次行為
    WKNavigationActionPolicyCancel,
    //允許此次行為
    WKNavigationActionPolicyAllow,
} NS_ENUM_AVAILABLE(10_10, 8_0);
*/
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    decisionHandler(WKNavigationActionPolicyAllow);
}

WKUIDelegate協(xié)議


//創(chuàng)建新的webView時調(diào)用的方法
-(WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{    return webView;
}
//關(guān)閉webView時調(diào)用的方法
-(void)webViewDidClose:(WKWebView *)webView{

}
//下面這些方法是交互JavaScript的方法
//JavaScript調(diào)用alert方法后回調(diào)的方法 message中為alert提示的信息 必須要在其中調(diào)用completionHandler()
-(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{    NSLog(@"%@",message);
    completionHandler();
}
//JavaScript調(diào)用confirm方法后回調(diào)的方法 confirm是js中的確定框烙丛,需要在block中把用戶選擇的情況傳遞進去
-(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{    NSLog(@"%@",message);
    completionHandler(YES);
}
//JavaScript調(diào)用prompt方法后回調(diào)的方法 prompt是js中的輸入框 需要在block中把用戶輸入的信息傳入
-(void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{    NSLog(@"%@",prompt);
    completionHandler(@"123");
}

WKNavagationAction類

@interface WKNavigationAction : NSObject
//原頁面
@property (nonatomic, readonly, copy) WKFrameInfo *sourceFrame;
//目標(biāo)頁面
@property (nullable, nonatomic, readonly, copy) WKFrameInfo *targetFrame;
//請求URL
@property (nonatomic, readonly, copy) NSURLRequest *request;

//活動類型/*typedef NS_ENUM(NSInteger, WKNavigationType) {
    //鏈接激活    WKNavigationTypeLinkActivated,
    //提交操作    WKNavigationTypeFormSubmitted,
    //前進操作    WKNavigationTypeBackForward,
    //刷新操作    WKNavigationTypeReload,
    //重提交操作 例如前進 后退 刷新    WKNavigationTypeFormResubmitted,
    //其他類型
    WKNavigationTypeOther = -1,
} NS_ENUM_AVAILABLE(10_10, 8_0);
*/

@property (nonatomic, readonly) WKNavigationType navigationType;
@end

參考鏈接

https://www.cnblogs.com/XYQ-208910/p/5876419.html
http://www.reibang.com/p/ab58df0bd1a1
http://www.reibang.com/p/ab58df0bd1a1

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末舅巷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子河咽,更是在濱河造成了極大的恐慌钠右,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忘蟹,死亡現(xiàn)場離奇詭異飒房,居然都是意外死亡,警方通過查閱死者的電腦和手機媚值,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門狠毯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人褥芒,你說我怎么就攤上這事嚼松。” “怎么了锰扶?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵献酗,是天一觀的道長。 經(jīng)常有香客問我少辣,道長凌摄,這世上最難降的妖魔是什么羡蛾? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任漓帅,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘忙干。我一直安慰自己器予,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布捐迫。 她就那樣靜靜地躺著乾翔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪施戴。 梳的紋絲不亂的頭發(fā)上反浓,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機與錄音赞哗,去河邊找鬼雷则。 笑死,一個胖子當(dāng)著我的面吹牛肪笋,可吹牛的內(nèi)容都是我干的月劈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼藤乙,長吁一口氣:“原來是場噩夢啊……” “哼猜揪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起坛梁,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤而姐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后划咐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體毅人,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年尖殃,在試婚紗的時候發(fā)現(xiàn)自己被綠了丈莺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡送丰,死狀恐怖缔俄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情器躏,我是刑警寧澤俐载,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站登失,受9級特大地震影響遏佣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜揽浙,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一状婶、第九天 我趴在偏房一處隱蔽的房頂上張望意敛。 院中可真熱鬧,春花似錦膛虫、人聲如沸草姻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽撩独。三九已至,卻和暖如春账月,著一層夾襖步出監(jiān)牢的瞬間综膀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工局齿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留僧须,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓项炼,卻偏偏與公主長得像担平,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锭部,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容