帶你走進WKWebView的世界

通過學(xué)習(xí),你將會學(xué)習(xí)以下幾個方面的內(nèi)容:

  • **什么是WKWebView以及它和UIWebView的區(qū)別是什么 **
  • **認識SafariServices.framework框架,捎帶認識UIActivity **
  • 回顧UIWebView在公司工程中的使用
  • WKKit 和 WKWebView簡介,特性認識API
  • UIWebView 和WKWebview 以及JSCore JS和OC的相互調(diào)用
  • NSURLProtocal的使用
  • WKWebView的一些坑

文章結(jié)構(gòu)目錄

1.背景
2.移動端展示web方案

--- 2.1 Safari
--- 2.2 SFSafariViewController
--- 2.3 UIWebView,回顧在公司工程中的使用
--- 2.3 UIWebView 接口說明

3.WKKit& WKWebView

--- 3.1WKKit框架介紹,WKWebView API介紹
--- 3.2OC如何給JS注入對象及JS如何給IOS發(fā)送數(shù)據(jù)
--- 3.3JS調(diào)用alert、confirm、prompt時,不采用JS原生提示,而是使用iOS原生來實現(xiàn)
--- 3.4如何監(jiān)聽web內(nèi)容加載進度、是否加載完成
--- 3.5如何處理去跨域問題
--- 3.6JS和OC的相互調(diào)用
--- 3.7WKWebview API問題

1.背景

自iOS問世以來,iOS 和web總是形影相隨。畢竟,當iOS誕生的時候,網(wǎng)站已經(jīng)有15年的歷史了(第一個網(wǎng)站的創(chuàng)建甚至可以追溯到1991年,而iOS在2007年才出現(xiàn),而那時候還沒有AppStore,沒有應(yīng)用分發(fā)市場)iPhone出現(xiàn)的時候就已經(jīng)有很多的web內(nèi)容了,這樣iOS必須提供一種方法來顯示web內(nèi)容。
----翻譯一位蘋果工程師的一段話

2.移動端展示web方案

在iOS 9中,我們有不同的渲染網(wǎng)頁內(nèi)容的選擇,根據(jù)具體需求,開發(fā)人員可以評估不同的選擇,選擇一個適合他們更好。讓我們看看一個開發(fā)人員可以采用的不同的解決方案。

讓我們看看目前在移動端都有哪些方案:

  • Safari
  • SFSafariViewController
  • UIWebView
  • WKWebview

對于前兩種我們都已了解或者掌握,我們先簡單的說明一下,我們的重心還是WKWebview上。

2.1Safari

我們通常用

 NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];
 [[UIApplication sharedApplication] openURL:url];

這種簡單的方式用蘋果自帶的safari瀏覽器打開一個網(wǎng)頁,從iOS9開始從一個app打開另一個app就像內(nèi)嵌app一樣,可以返回原來的app. 雖然這是一個小小的方案,但是對于跳轉(zhuǎn)到其他app,大家還是不怎么情愿的,因為,我們只想讓用戶停留在我們的app里。

2.2SFSafariViewController

我們不得不說safari確實很強大,在iOS9,蘋果公司給我們提供了一個SafariServices.framework ,這個框架很簡單,就幾個文件
1.SFSafariViewController(瀏覽控制器)
2.SSReadingList(用戶safari閱讀列表)
3.SFContentBlockerState(safari內(nèi)容攔擊)不用了解

這里只是簡單了解下SFSafariViewController,這個控制器的API,很簡單。
用SFSafariViewController 這種方式可以加載web內(nèi)容,而且是內(nèi)置在我們app里的瀏覽器,但是這個控制器有個致命的弱點就是不能自定義,蘋果公司并沒有開放出很多API,有一些私有的API可以獲得進行自定義,但是我們不能使用,略顯尷尬,我想之所以蘋果公司不開放很多api的理由,應(yīng)該主要還是以原生app和safari為主流的原因吧。

2.3UIWebView

廢話不多說,我們把重點放在最后WkWebview上,再認識WKWebview之前,我們有必要再簡單回顧下UIwebView的使用,以及我們工程里對UIwebview的使用.
UIWebview是UIKit框架里的一個視圖類, 繼承UIView, 整個接口文件也只有100行,里面有一個scrollview的屬性,這些都是我們簡單的認識。大家感興趣可以了解下UIwebView的內(nèi)部實現(xiàn),后面稍微提一下。

1.公司對UIWebview的簡單使用
1.1用webView打電話
代碼如下



   NSString *phoneNum = nil;
   if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0){
            phoneNum = [NSString stringWithFormat:@"telprompt://%@",self.phoneNumber];
        } else {
            phoneNum = [NSString stringWithFormat:@"tel://%@",self.phoneNumber];// 電話號碼
    }
 

  if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0) {
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneNum]];            
    } else {
    UIWebView *callPhoneWebVw = [[UIWebView alloc] initWithFrame:CGRectZero];
   self.callwebView = callPhoneWebVw;
     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:phoneNum]];
     [_callwebView loadRequest:request];
 }

1.2 封裝了 PZLWJSBridgeView ,控件繼承UIWebview
在家居和知識詳情模塊,都有用到這個類
1.3LLLwebviewcontroller大家都知道,我們最多的是使用這個類,加載wap頁面,我們在這里簡單看下這個控制器是怎么使用的。
其實使用也是蠻簡單的,具體步驟如下:
1.3.1創(chuàng)建UIwebview(此處省略代碼)
1.3.2創(chuàng)建假的進度條,之所以是假的,是因為webview不支持加載進度
1.3.3然后就是一些分享業(yè)務(wù)上的邏輯了(簡單調(diào)用js代碼獲取js數(shù)據(jù))
1.3.4 每次請求的時候有添加cookie的操作,然后dealloc的時候刪除 cookie(UIwebview并不支持cookie操作)
1.3.5 加載URL過濾,PZLWURLRequestFilter: NSURLProtocol,咱公司對于這個繼承自NSURLProtocol的文件也打成了靜態(tài)庫,感興趣的同學(xué)可以去github上找一下, github有實現(xiàn)Demo。但是這個URL過濾,在WKWebView上不支持。
我們簡單學(xué)習(xí)一下這個在我們公司封裝成靜態(tài)庫的實現(xiàn)過程吧

我們用UIWebview無非就是三個代理和調(diào)用javascript代碼,而且只是獲得html的內(nèi)容。像這樣 :

[self.webView stringByEvaluatingJavaScriptFromString:@"document.getElementById('soufunclient').innerHTML"];

總的來說,UIwebview的使用很簡單,這里對UIWebview頭文件做了說明

//  Copyright (c) 2007-2015 Apple Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIView.h>
#import <UIKit/UIKitDefines.h>
#import <UIKit/UIDataDetectors.h>
#import <UIKit/UIScrollView.h>

NS_ASSUME_NONNULL_BEGIN

typedef NS_ENUM(NSInteger, UIWebViewNavigationType) {
    UIWebViewNavigationTypeLinkClicked,//用戶觸發(fā)了一個鏈接
    UIWebViewNavigationTypeFormSubmitted,//用戶提交了一個表單
    UIWebViewNavigationTypeBackForward,//用戶觸擊前進前進或返回按鈕
    UIWebViewNavigationTypeReload,//用戶觸擊重新加載的按鈕
    UIWebViewNavigationTypeFormResubmitted,//用戶重復(fù)提交表單
    UIWebViewNavigationTypeOther//發(fā)生了其他行為
} __TVOS_PROHIBITED;

//2. 加載內(nèi)容關(guān)于分頁顯示幾種不同類型
typedef NS_ENUM(NSInteger, UIWebPaginationMode) {
    UIWebPaginationModeUnpaginated,
    UIWebPaginationModeLeftToRight,
    UIWebPaginationModeTopToBottom,
    UIWebPaginationModeBottomToTop,
    UIWebPaginationModeRightToLeft
} __TVOS_PROHIBITED;

typedef NS_ENUM(NSInteger, UIWebPaginationBreakingMode) {
    UIWebPaginationBreakingModePage,//默認設(shè)置是這個屬性,CSS屬性以頁樣式。
    UIWebPaginationBreakingModeColumn//當UIWebPaginationBreakingMode設(shè)置這個屬性的時候,這個頁面內(nèi)容CSS屬性以column-break 代替page-breaking樣式。
} __TVOS_PROHIBITED;

@class UIWebViewInternal;
@protocol UIWebViewDelegate;

NS_CLASS_AVAILABLE_IOS(2_0) __TVOS_PROHIBITED @interface UIWebView : UIView <NSCoding, UIScrollViewDelegate> 

@property (nullable, nonatomic, assign) id <UIWebViewDelegate> delegate;

@property (nonatomic, readonly, strong) UIScrollView *scrollView NS_AVAILABLE_IOS(5_0);

- (void)loadRequest:(NSURLRequest *)request;
- (void)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
- (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName baseURL:(NSURL *)baseURL;

@property (nullable, nonatomic, readonly, strong) NSURLRequest *request;

- (void)reload;
- (void)stopLoading;

- (void)goBack;
- (void)goForward;

@property (nonatomic, readonly, getter=canGoBack) BOOL canGoBack;
@property (nonatomic, readonly, getter=canGoForward) BOOL canGoForward;
@property (nonatomic, readonly, getter=isLoading) BOOL loading;

- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;

//是否讓內(nèi)容伸縮至適應(yīng)屏幕當前尺寸
@property (nonatomic) BOOL scalesPageToFit;

//這個屬性如果設(shè)置為YES,當進入到頁面視圖可以自動檢測電話號碼,讓用戶可以單機號碼進行撥打,不過現(xiàn)已棄用。
@property (nonatomic) BOOL detectsPhoneNumbers NS_DEPRECATED_IOS(2_0, 3_0);

//這個屬性可以設(shè)定使電話號碼,網(wǎng)址,電子郵件和符合格式的日期等文字變?yōu)檫B接文字。
@property (nonatomic) UIDataDetectorTypes dataDetectorTypes NS_AVAILABLE_IOS(3_0);

//這個屬性決定了頁面用內(nèi)嵌HTML5播放視頻還是用本地的全屏控制。為了內(nèi)嵌視頻播放,不僅僅需要在這個頁面上設(shè)置這個屬性,還需要在HTML的viedeo元素必須包含webkit-playsinline屬性。默認iPhone為NO,iPad為YES。
@property (nonatomic) BOOL allowsInlineMediaPlayback NS_AVAILABLE_IOS(4_0); // iPhone Safari defaults to NO. iPad Safari defaults to YES

//這個屬性決定了HTML5視頻可以自動播放還是需要用戶啟動播放。iPhone和iPad默認都是YES。
@property (nonatomic) BOOL mediaPlaybackRequiresUserAction NS_AVAILABLE_IOS(4_0); // iPhone and iPad Safari both default to YES

//這個屬性決定了從這個頁面是否可以Air Play。iPhone和iPad上都是默認YES。
@property (nonatomic) BOOL mediaPlaybackAllowsAirPlay NS_AVAILABLE_IOS(5_0); // iPhone and iPad Safari both default to YES

//這個值決定了網(wǎng)頁內(nèi)容的渲染是否在把內(nèi)容全部加到內(nèi)存中再去處理。如果設(shè)置為YES,只有網(wǎng)頁內(nèi)容加載到內(nèi)存里了才會去渲染。默認為NO
@property (nonatomic) BOOL suppressesIncrementalRendering NS_AVAILABLE_IOS(6_0); // iPhone and iPad Safari both default to NO

//這個屬性如果設(shè)置為YES,用戶必須明確的點擊頁面上的元素或者相關(guān)聯(lián)的輸入頁面來顯示鍵盤。如果設(shè)置為NO,一個元素的焦點事件就會導(dǎo)致輸入視圖的顯示和自動關(guān)聯(lián)這個元素。
@property (nonatomic) BOOL keyboardDisplayRequiresUserAction NS_AVAILABLE_IOS(6_0); // default is YES
//設(shè)置頁面分頁模型選擇。
@property (nonatomic) UIWebPaginationMode paginationMode NS_AVAILABLE_IOS(7_0);
//這個屬性決定了CSS屬性是采用column-break 還是page-breaking樣式。
@property (nonatomic) UIWebPaginationBreakingMode paginationBreakingMode NS_AVAILABLE_IOS(7_0);

//分頁的長度
@property (nonatomic) CGFloat pageLength NS_AVAILABLE_IOS(7_0);
//分頁之間間距
@property (nonatomic) CGFloat gapBetweenPages NS_AVAILABLE_IOS(7_0);
//分頁的個數(shù)
@property (nonatomic, readonly) NSUInteger pageCount NS_AVAILABLE_IOS(7_0);

//是否允許畫中畫播放The default value is YES on devices that support Picture in Picture (PiP) mode and NO on all other devices.
@property (nonatomic) BOOL allowsPictureInPictureMediaPlayback NS_AVAILABLE_IOS(9_0);

//3DTouch的預(yù)覽功能,默認為NO
@property (nonatomic) BOOL allowsLinkPreview NS_AVAILABLE_IOS(9_0); // default is NO
@end

__TVOS_PROHIBITED @protocol UIWebViewDelegate <NSObject>

@optional
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
- (void)webViewDidStartLoad:(UIWebView *)webView;
- (void)webViewDidFinishLoad:(UIWebView *)webView;
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;

@end

NS_ASSUME_NONNULL_END

現(xiàn)在小編告訴你, 終于進行我們要講的主題了,不好意思,現(xiàn)在才開始,不過也會很快結(jié)束的。

3 WKKit && WKWebview
3.1WKKit框架介紹,WKWebView API介紹

WKWebview在WKKit這個框架里, 蘋果將UIWebViewDelegate和UIWebView重構(gòu)成了14個類與3個協(xié)議官方鏈接

WebKit provides a set of classes to display web content in windows, and implements browser features such as following links when clicked by the user, managing a back-forward list, and managing a history of pages recently visited. WebKit greatly simplifies the complicated process of loading webpages—that is, asynchronously requesting web content from an HTTP server where the response may arrive incrementally, in random order, or partially due to network errors. WebKit also simplifies the process of displaying that content which can contain various MIME types, and compound frame elements each with their own set of scroll bars.

在Overview的時候,蘋果官方文檔有這樣的一段描述。
并且還有一個提示

Concurrency Note
The WebKit framework is not thread-safe. If you call functions or methods in this framework, you must do so exclusively on the main program thread.

不是線程安全的。
同樣的WebKit框架在MAC app和 iOS APP里是不一樣的, 我們可以看到在macAPP里,這個框架是很大的, 里面還包含了子框架, 而且這個框架暴露的頭文件也很多,有CSS,DOM等操作的API.

說了這么多,我們稍等一會就只來看看iOS上webkit框架,如果大家剛興趣可以學(xué)習(xí)或者了解一下MAC上的webkit框架

WWDC2014-206session:
The modern Webkit APi
1.Same on iOS and OS X
2.Modern
3.Streamlined(精簡的)
4.Multi-process architecture

Multi-process architecture

我們首先了解下WKWebView的一些優(yōu)勢:
1WKWebview在性能、穩(wěn)定性上和UIwebview相比
2WKWebView更多的支持HTML5的特性
3WKWebView更快,占用內(nèi)存可能只有UIWebView的1/3 ~ 1/4
4WKWebView高達60fps的滾動刷新率和豐富的內(nèi)置手勢(Built-in gestures)
5WKWebView具有Safari相同的JavaScript引擎Nitro(JJT四個進程解釋執(zhí)行優(yōu)化js代碼)(Fast JavaScript)
6WKWebView增加了加載進度屬性
7Easy app-webpage communication
8Responsive scrolling
9更省電量 battery
以上信息可以在WWDC2014-206節(jié)-介紹 WebKit modern API 的時候提到。

**(lldb) po [self.webView  recursiveDescription]
<UIWebView: 0x14d14130; frame = (0 0; 320 504); layer = <CALayer: 0x12cca690>>
   | <_UIWebViewScrollView: 0x6c55400; frame = (0 0; 320 504); clipsToBounds = YES; autoresize = H; gestureRecognizers = <NSArray: 0x12c7adf0>; layer = <CALayer: 0x10a4f9c0>; contentOffset: {0, 0}; contentSize: {320, 504}>
   |    | <UIWebBrowserView: 0x69fac00; frame = (0 0; 320 504); text = ''; gestureRecognizers = <NSArray: 0x10ac37f0>; layer = <UIWebLayer: 0x12c9f580>>
   |    |    | <LegacyTileHostLayer: 0x14d04c30> (layer)
   |    |    |    | <LegacyTileLayer: 0x10a99700> (layer)
   |    | <UIImageView: 0x14d0ffd0; frame = (3 498.5; 314 2.5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x14d100b0>>
   |    | <UIImageView: 0x14c4e3a0; frame = (314.5 3; 2.5 498); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x14ceb340>>
**(lldb) po [self.webView recursiveDescription]**
<WKWebView: 0x1612c8720; frame = (0 0; 320 504); layer = <CALayer: 0x16127b9b0>>
   | <WKScrollView: 0x160977600; baseClass = UIWebScrollView; frame = (0 0; 320 504); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x16488d250>; layer = <CALayer: 0x16488a970>; contentOffset: {0, 0}; contentSize: {0, 0}>
   |    | <WKContentView: 0x160a56000; frame = (0 0; 320 504); gestureRecognizers = <NSArray: 0x164887d20>; layer = <CALayer: 0x16127b650>>
   |    |    | <UIView: 0x16129d960; frame = (0 0; 320 504); clipsToBounds = YES; layer = <CALayer: 0x1612c3150>>
   |    |    |    | <UIView: 0x1612c2fe0; frame = (0 0; 320 504); autoresize = W+H; layer = <CALayer: 0x16128a9f0>>
   |    | <UIView: 0x164887750; frame = (0 0; 0 0); opaque = NO; layer = <CALayer: 0x16127a070>>
   |    | <UIImageView: 0x16102fa70; frame = (310 498.5; 7 2.5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x161227960>>
   |    | <UIImageView: 0x163647e60; frame = (314.5 494; 2.5 7); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x1610ac060>>


UIWebView.png 引用自CocoaChina

UIWebView屬于UIKit,封裝了WebKit.framework的WebView.WebView組合管理了WebCore.framework的Page,并提供了各種Clients.Page管理了Main Frame,Main Frame管理了sub Frame(FrameTree)
我們看一下po出來的視圖層級完全不一樣,可以說兩者關(guān)系并不大,
WebView繼承自WAKView,WAKView類似于NSView,可以做較少的改動使得Mac和iOS共用一套。由UIWebDocumentView對WebView進行操作并接收回調(diào)事件,當數(shù)據(jù)發(fā)生變化的時候,就會通知UIWebTiledView重新繪制。
UIWebTiledView和WAKWindow這兩個類主要負責(zé)頁面的繪制,包括布局繪圖排版,交互等,WAKWindow還會做一些用戶操作事件的分派。UIWebBrowserView主要負責(zé): form的自動填充 fixed元素的位置調(diào)整JavaScript的手勢識別, 鍵盤彈出時的視圖滾動處理,防止遮擋,提供接口讓UIWebView獲取信息,為顯示PDF時添加頁號標簽 - -- 引在cocoachina一篇文章

但是我在實際測試的時候, 在真機上出現(xiàn)過收到內(nèi)存警告。
下面兩張圖片對比下加載www.fang.com的wap頁的時候,以及點擊wap的時候內(nèi)存變化的情況。

UIWebView內(nèi)存變化情況
WKWebview內(nèi)存變化情況

從上面一個圖片可以看出,剛開始加載網(wǎng)頁的時候內(nèi)存使用是差不多的, 但是
當我和wap頁面交互的時候,內(nèi)存變化對于UIWebview來說是巨大的, 對于WkWebView來說相對是較小的。

Class:

WKBackForwardList: 之前訪問過的 web 頁面的列表,可以通過后退和前進動作來訪問到。
WKBackForwardListItem: webview 中后退列表里的某一個網(wǎng)頁。
WKFrameInfo: 包含一個網(wǎng)頁的布局信息。
WKNavigation: 包含一個網(wǎng)頁的加載進度信息。
WKNavigationAction: 包含可能讓網(wǎng)頁導(dǎo)航變化的信息,用于判斷是否做出導(dǎo)航變化。
WKNavigationResponse: 包含可能讓網(wǎng)頁導(dǎo)航變化的返回內(nèi)容信息,用于判斷是否做出導(dǎo)航變化。
WKPreferences: 概括一個 webview 的偏好設(shè)置。
WKProcessPool: 表示一個 web 內(nèi)容加載池。
WKUserContentController: 提供使用 JavaScript post 信息和注射 script 的方法。
WKScriptMessage: 包含網(wǎng)頁發(fā)出的信息。
WKUserScript: 表示可以被網(wǎng)頁接受的用戶腳本。
WKWebViewConfiguration: 初始化 webview 的設(shè)置。
WKWindowFeatures: 指定加載新網(wǎng)頁時的窗口屬性。

WKUserScript:

What Can User Scripts Do?
Incredibly powerful
? Modify the document
? Listen for events
? Load resources
? Communicate back to your application

Protocal:

WKNavigationDelegate: 提供了追蹤主窗口網(wǎng)頁加載過程和判斷主窗口和子窗口是否進行頁面加載新頁面的相關(guān)方法。
WKScriptMessageHandler: 提供從網(wǎng)頁中收消息的回調(diào)方法。
WKUIDelegate: 提供用原生控件顯示網(wǎng)頁的方法回調(diào)。

現(xiàn)在讓我們跳到Xcode



/*
說明:
 1.WKProcessPool
@abstract The process pool from which to obtain the view's web content
 process.
 @discussion When a web view is initialized, a new web content process
 will be created for it from the specified pool, or an existing process in
 that pool will be used.
 ! A WKProcessPool object represents a pool of web content processes.
 The process pool associated with a web view is specified by its web view
 configuration. Each web view is given its own web content process until an
 implementation-defined process limit is reached; after that, web views
 with the same process pool end up sharing web content processes.
 這個東西好像與cookie有關(guān),一個例子。

 2WKUserContentController
 A WKUserContentController object provides a way for JavaScript to post
 messages to a web view.
 The user content controller associated with a web view is specified by its
 web view configuration.
 
 3
 它是用于webview內(nèi)容交互時選擇內(nèi)容的粒度類型設(shè)置。比如說,當使用WKSelectionGranularityDynamic時,而所選擇的內(nèi)容是單個塊,這時候granularity可能會是單個字符;當所選擇的web內(nèi)容不限制于某個塊時,granularity可能會是單個塊。

*/

#import "LLLWKwebViewViewController.h"
//1.第一步導(dǎo)入框架
#import <WebKit/WebKit.h>
//大家可以看一下,這個Webkit包含了27個文件,我們不能講的很詳細, 只能盡力去說一下

@interface LLLWKwebViewViewController ()<WKNavigationDelegate,WKUIDelegate>

@property(nonatomic,strong)WKWebView *wkwebview;

@end

@implementation LLLWKwebViewViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    
//    WKWebView *wkView = [[WKWebView alloc]initWithFrame:self.view.bounds];
    
    //3.初始化WKPreferences
    WKPreferences *preference = [[WKPreferences alloc]init];
    preference.minimumFontSize = 0;
    preference.javaScriptEnabled = YES;
    preference.javaScriptCanOpenWindowsAutomatically=NO;
    
    //4初始化WKUserContentController
    WKUserContentController *wkuserCVC = [[WKUserContentController alloc]init];
   // [wkuserCVC addUserScript:nil];
   // [wkuserCVC addScriptMessageHandler:<#(nonnull id<WKScriptMessageHandler>)#> name:<#(nonnull NSString *)#>]
    
    //5.WKWebsiteDataStore
    WKWebsiteDataStore *dataStore = [WKWebsiteDataStore defaultDataStore];
    dataStore = [WKWebsiteDataStore nonPersistentDataStore];//適合隱私瀏覽
    NSSet *set = [WKWebsiteDataStore allWebsiteDataTypes];
    NSArray *arr = [set allObjects];
   // [dataStore fetchDataRecordsOfTypes:(nonnull NSSet<NSString *> *) completionHandler:^(NSArray<WKWebsiteDataRecord *> * _Nonnull) {
        
  //  }];
   // [dataStore removeDataOfTypes:(nonnull NSSet<NSString *> *) forDataRecords:(nonnull NSArray<WKWebsiteDataRecord *> *) completionHandler:^{
        
    //}];
    //6WKWebsiteDataRecord
   // WKWebsiteDataRecord *dataRecord = [[WKWebsiteDataRecord alloc]init];
   // dataRecord.dataTypes
    
    //2.初始化設(shè)置
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc]init];
    config.processPool = [[WKProcessPool alloc]init];
    config.preferences = preference;
    config.userContentController = wkuserCVC;
    config.websiteDataStore = dataStore;
    config.suppressesIncrementalRendering = NO;//ioS9
    config.applicationNameForUserAgent = @"USer-agent";//ios9
    config.allowsAirPlayForMediaPlayback =YES;//airplay isallowed
    config.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeAll;//ios10
    config.allowsInlineMediaPlayback = NO;
    config.selectionGranularity = WKSelectionGranularityDynamic;
    config.allowsPictureInPictureMediaPlayback = NO;
    config.dataDetectorTypes = UIDataDetectorTypePhoneNumber;
    config.ignoresViewportScaleLimits = NO;
    
    WKWebView*wkView = [[WKWebView alloc]initWithFrame:self.view.bounds configuration:config];
    self.wkwebview = wkView;
    WKBackForwardList *list = wkView.backForwardList;
    WKBackForwardListItem *backlistItem =  list.backItem;
    WKBackForwardListItem *forwardlistItem =  list.forwardItem;
    WKBackForwardListItem *currentlistItem = list.currentItem;
    WKBackForwardListItem *nextlistItem =  [list itemAtIndex:1];
    NSArray *backList =  list.backList;
    NSArray *forwardList =  list.forwardList;
    
    WKNavigation *navigation = [wkView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.fang.com"]]];
    wkView.UIDelegate = self;
    wkView.navigationDelegate = self;
    [self.view addSubview:wkView];
    

    
    
}

#pragma mark---WKNavigationDelegate

/*! @abstract Decides whether to allow or cancel a navigation.
 @param webView The web view invoking the delegate method.
 @param navigationAction Descriptive information about the action
 triggering the navigation request.
 @param decisionHandler The decision handler to call to allow or cancel the
 navigation. The argument is one of the constants of the enumerated type WKNavigationActionPolicy.
 @discussion If you do not implement this method, the web view will load the request or, if appropriate, forward it to another application.
 */

//1.The number 1 called
//3.The number 3 called
//7.The number 7 called

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{

    NSLog(@"%s--navigationAction is %@",__FUNCTION__,navigationAction);

    decisionHandler(WKNavigationActionPolicyAllow);

}

/*! @abstract Decides whether to allow or cancel a navigation after its
 response is known.
 @param webView The web view invoking the delegate method.
 @param navigationResponse Descriptive information about the navigation
 response.
 @param decisionHandler The decision handler to call to allow or cancel the
 navigation. The argument is one of the constants of the enumerated type WKNavigationResponsePolicy.
 @discussion If you do not implement this method, the web view will allow the response, if the web view can show it.
 */
//5.The number 5 called

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    
    NSLog(@"%s--navigationAction is %@",__FUNCTION__,navigationResponse);

    decisionHandler(WKNavigationResponsePolicyAllow);
    

}

/*! @abstract Invoked when a main frame navigation starts.
 @param webView The web view invoking the delegate method.
 @param navigation The navigation.
 #########Called when web content begins to load in a web view.
 */
//2.the number 2 called
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation{

    NSLog(@"%s--navigation is %@",__FUNCTION__,navigation);

}

/*! @abstract Invoked when a server redirect is received for the main
 frame.
 @param webView The web view invoking the delegate method.
 @param navigation The navigation.
 */
//4.The number 4 called

- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation{

    NSLog(@"%s--navigation is %@",__FUNCTION__,navigation);

}

/*! @abstract Invoked when an error occurs while starting to load data for
 the main frame.
 @param webView The web view invoking the delegate method.
 @param navigation The navigation.
 @param error The error that occurred.
 */
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error{

    NSLog(@"%s--navigation is %@ and error is %@",__FUNCTION__,navigation,error);

}

/*! @abstract Invoked when content starts arriving for the main frame.
 @param webView The web view invoking the delegate method.
 @param navigation The navigation.
 ################Called when the web view begins to receive web content.

 */
//6.The number 6 called

- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation{

    NSLog(@"%s--navigation is %@",__FUNCTION__,navigation);

}

/*! @abstract Invoked when a main frame navigation completes.
 @param webView The web view invoking the delegate method.
 @param navigation The navigation.
 */
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{

    NSLog(@"%s--navigation is %@",__FUNCTION__,navigation);

}

/*! @abstract Invoked when an error occurs during a committed main frame
 navigation.
 @param webView The web view invoking the delegate method.
 @param navigation The navigation.
 @param error The error that occurred.
 */
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error{

    NSLog(@"%s--navigation is %@",__FUNCTION__,navigation);

}

/*! @abstract Invoked when the web view needs to respond to an authentication challenge.
 @param webView The web view that received the authentication challenge.
 @param challenge The authentication challenge.
 @param completionHandler The completion handler you must invoke to respond to the challenge. The
 disposition argument is one of the constants of the enumerated type
 NSURLSessionAuthChallengeDisposition. When disposition is NSURLSessionAuthChallengeUseCredential,
 the credential argument is the credential to use, or nil to indicate continuing without a
 credential.
 @discussion If you do not implement this method, the web view will respond to the authentication challenge with the NSURLSessionAuthChallengeRejectProtectionSpace disposition.
 */
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{

    NSLog(@"%s--challenge is %@",__FUNCTION__,challenge);

    completionHandler(NSURLSessionAuthChallengeUseCredential,nil);
}

/*! @abstract Invoked when the web view's web content process is terminated.
 @param webView The web view whose underlying web content process was terminated.
 */
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0)){
    NSLog(@"%s-",__FUNCTION__);

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

#pragma mark---WKUIDelegate
/*! @abstract Creates a new web view.
 @param webView The web view invoking the delegate method.
 @param configuration The configuration to use when creating the new web
 view.
 @param navigationAction The navigation action causing the new web view to
 be created.
 @param windowFeatures Window features requested by the webpage.
 @result A new web view or nil.
 @discussion The web view returned must be created with the specified configuration. WebKit will load the request in the returned web view.
 
 If you do not implement this method, the web view will cancel the navigation.
 */
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{

    NSLog(@"%s--configuration is %@ \n and navigationAction is %@\n and windowFeatures is %@",__FUNCTION__,configuration,navigationAction,windowFeatures);
    return webView;
}

/*! @abstract Notifies your app that the DOM window object's close() method completed successfully.
 @param webView The web view invoking the delegate method.
 @discussion Your app should remove the web view from the view hierarchy and update
 the UI as needed, such as by closing the containing browser tab or window.
 */
- (void)webViewDidClose:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0)){

    NSLog(@"%s-",__FUNCTION__);

}

/*! @abstract Displays a JavaScript alert panel.
 @param webView The web view invoking the delegate method.
 @param message The message to display.
 @param frame Information about the frame whose JavaScript initiated this
 call.
 @param completionHandler The completion handler to call after the alert
 panel has been dismissed.
 @discussion For user security, your app should call attention to the fact
 that a specific website controls the content in this panel. A simple forumla
 for identifying the controlling website is frame.request.URL.host.
 The panel should have a single OK button.
 
 If you do not implement this method, the web view will behave as if the user selected the OK button.
 */
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{

    NSLog(@"%s and message is %@ and frame is %@",__FUNCTION__,message,frame);

}

/*! @abstract Displays a JavaScript confirm panel.
 @param webView The web view invoking the delegate method.
 @param message The message to display.
 @param frame Information about the frame whose JavaScript initiated this call.
 @param completionHandler The completion handler to call after the confirm
 panel has been dismissed. Pass YES if the user chose OK, NO if the user
 chose Cancel.
 @discussion For user security, your app should call attention to the fact
 that a specific website controls the content in this panel. A simple forumla
 for identifying the controlling website is frame.request.URL.host.
 The panel should have two buttons, such as OK and Cancel.
 
 If you do not implement this method, the web view will behave as if the user selected the Cancel button.
 */
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler{

    NSLog(@"%s and message is %@ and frame is %@",__FUNCTION__,message,frame);

}

/*! @abstract Displays a JavaScript text input panel.
 @param webView The web view invoking the delegate method.
 @param message The message to display.
 @param defaultText The initial text to display in the text entry field.
 @param frame Information about the frame whose JavaScript initiated this call.
 @param completionHandler The completion handler to call after the text
 input panel has been dismissed. Pass the entered text if the user chose
 OK, otherwise nil.
 @discussion For user security, your app should call attention to the fact
 that a specific website controls the content in this panel. A simple forumla
 for identifying the controlling website is frame.request.URL.host.
 The panel should have two buttons, such as OK and Cancel, and a field in
 which to enter text.
 
 If you do not implement this method, the web view will behave as if the user selected the Cancel button.
 */
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler{

    NSLog(@"%s and prompt is %@ and defaulttext is %@ and frame is %@",__FUNCTION__,prompt,defaultText,frame);

}

/*! @abstract Allows your app to determine whether or not the given element should show a preview.
 @param webView The web view invoking the delegate method.
 @param elementInfo The elementInfo for the element the user has started touching.
 @discussion To disable previews entirely for the given element, return NO. Returning NO will prevent
 webView:previewingViewControllerForElement:defaultActions: and webView:commitPreviewingViewController:
 from being invoked.
 
 This method will only be invoked for elements that have default preview in WebKit, which is
 limited to links. In the future, it could be invoked for additional elements.
 */
- (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo API_AVAILABLE(ios(10.0)){

    NSLog(@"%s-%@",__FUNCTION__, elementInfo);
    return YES;

}

/*! @abstract Allows your app to provide a custom view controller to show when the given element is peeked.
 @param webView The web view invoking the delegate method.
 @param elementInfo The elementInfo for the element the user is peeking.
 @param defaultActions An array of the actions that WebKit would use as previewActionItems for this element by
 default. These actions would be used if allowsLinkPreview is YES but these delegate methods have not been
 implemented, or if this delegate method returns nil.
 @discussion Returning a view controller will result in that view controller being displayed as a peek preview.
 To use the defaultActions, your app is responsible for returning whichever of those actions it wants in your
 view controller's implementation of -previewActionItems.
 
 Returning nil will result in WebKit's default preview behavior. webView:commitPreviewingViewController: will only be invoked
 if a non-nil view controller was returned.
 */
- (nullable UIViewController *)webView:(WKWebView *)webView previewingViewControllerForElement:(WKPreviewElementInfo *)elementInfo defaultActions:(NSArray<id <WKPreviewActionItem>> *)previewActions API_AVAILABLE(ios(10.0)){

    NSLog(@"%s",__FUNCTION__);
    return nil;
}

/*! @abstract Allows your app to pop to the view controller it created.
 @param webView The web view invoking the delegate method.
 @param previewingViewController The view controller that is being popped.
 */
- (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController API_AVAILABLE(ios(10.0)){

    NSLog(@"%s",__FUNCTION__);

}
@end

3.2 OC如何給JS注入對象及JS如何給IOS發(fā)送數(shù)據(jù)

1.通過直接注入js代碼, 我們可以做很多事情,上面已經(jīng)提到
1 .1Modify the document1.2 Listen for events1.3 Load resources1.4Communicate back to your application

    WKUserContentController *wkuserCVC = [[WKUserContentController alloc]init];
    WKUserScript *script = [[WKUserScript alloc]initWithSource:@"js code" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
    [wkuserCVC addUserScript:script];

2.WKUserContentController是用于給JS注入對象的,注入對象后,JS端就可以使用:

window.webkit.messageHandlers.<name>.postMessage(<messageBody>) 

來調(diào)用發(fā)送數(shù)據(jù)給iOS端,比如:

window.webkit.messageHandlers.AppModel.postMessage({body: '傳數(shù)據(jù)'});

OC則是注入對象是,設(shè)置了一個代理

#pragma mark @protocol WKScriptMessageHandler <NSObject>

/*! @abstract Invoked when a script message is received from a webpage.
 @param userContentController The user content controller invoking the
 delegate method.
 @param message The script message received.
 */
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{

    NSLog(@"%s and messgae is %@\n\n\n",__FUNCTION__,message);

}

現(xiàn)在我們通過上述代碼的學(xué)習(xí),基本大體了解了WKwebview 的API的使用,
這里面大約總共有27多個類, 還有很多的協(xié)議。常用的我們首先掌握了, 然后
不常用的大家也可以多研究一下。

3.3 JS調(diào)用alert、confirm、prompt時,不采用JS原生提示,而是使用iOS原生來實現(xiàn)

OC代碼咋是收到代理以后,展示原生的控件,代碼如下,這里我們

- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler{

    NSLog(@"%s\n\n\n prompt:%@  defaultText:%@ frame:%@",__FUNCTION__,prompt,defaultText,frame);
    
    UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:@"prompt" message:[NSString stringWithFormat:@"prompt:%@\ndefaultText:%@\nframe:%@",prompt,defaultText,frame] preferredStyle:UIAlertControllerStyleAlert];
    [alertVc addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.textColor = [UIColor blueColor];
    }];
    [alertVc addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler([[alertVc.textFields lastObject] text]);
    }]];
    [self presentViewController:alertVc animated:YES completion:^{
        
    }];

}

3.4 如何監(jiān)聽web內(nèi)容加載進度、是否加載完成

WKWebView 有一個屬性estimatedProgress,這個就是加載進度。我們利用KVO監(jiān)聽這個屬性值的變化,就可以顯示加載進度了。

    [self.webview addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];

3.5如何處理去跨域問題

#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
  NSString *hostname = navigationAction.request.URL.host.lowercaseString;
  if (navigationAction.navigationType == WKNavigationTypeLinkActivated
      && ![hostname containsString:@".baidu.com"]) {
// 對于跨域,需要手動跳轉(zhuǎn)
    [[UIApplication sharedApplication] openURL:navigationAction.request.URL];
    
    // 不允許web內(nèi)跳轉(zhuǎn)
    decisionHandler(WKNavigationActionPolicyCancel);
  } else {
    self.progressView.alpha = 1.0;
    decisionHandler(WKNavigationActionPolicyAllow);
  }
  
    NSLog(@"%s", __FUNCTION__);
}

3.6 WKWebView關(guān)于緩存

因為現(xiàn)在WKWebView會忽視默認的網(wǎng)絡(luò)存儲, NSURLCache, NSHTTPCookieStorage, NSCredentialStorage。 目前是這樣的,WKWebView有自己的進程,同樣也有自己的存儲空間用來存儲cookie和cache, 其他的網(wǎng)絡(luò)類如NSURLConnection是無法訪問到的。 同時WKWebView發(fā)起的資源請求也是不經(jīng)過NSURLProtocol的,導(dǎo)致無法自定義請求
不可否認的,WKWebView確實要好用,APP內(nèi)的表現(xiàn)也很好,但吐槽的地方也是蠻多的。

    WKWebsiteDataStore *dataStore = [WKWebsiteDataStore defaultDataStore];
//    dataStore = [WKWebsiteDataStore nonPersistentDataStore];//適合隱私瀏覽
    NSSet *set = [WKWebsiteDataStore allWebsiteDataTypes];
    NSArray *arr = [set allObjects];
   // [dataStore fetchDataRecordsOfTypes:(nonnull NSSet<NSString *> *) completionHandler:^(NSArray<WKWebsiteDataRecord *> * _Nonnull) {
        
  //  }];
    [dataStore removeDataOfTypes:set forDataRecords:arr completionHandler:^{
        
    }];
    [dataStore removeDataOfTypes:set modifiedSince:[NSDate dateWithTimeIntervalSinceNow:-100] completionHandler:^{
        
    }];
    

3.7JS和OC的相互調(diào)用

第一種:有很多的app直接使用在webview的代理中通過攔截的方式與native進行交互,通常是通過攔截url scheme判斷是否是我們需要攔截處理的url及其所對應(yīng)的要處理的功能是什么。任意版本都支持。
第二種:iOS7之后出了JavaScriptCore.framework用于與JS交互,但是不支持iOS6,對于還需要支持iOS6的app,就不能考慮這個了。若需要了解,看最后的推薦閱讀。
第三種:WebViewJavascriptBridge開源庫使用,本質(zhì)上,它也是通過webview的代理攔截scheme,然后注入相應(yīng)的JS。
第四種:react-native

對于第一種,其實在上文的講解中可能穿插了, 這里簡單總結(jié)下:
1.OC調(diào)用JS代碼

UIWebview:
[webView stringByEvaluatingJavaScriptFromString:@"helloWithName('jack')"];
WKWebview:
 [self.webView evaluateJavaScript:@"document.getElementById('soufunclient').innerHTML" completionHandler:^(id _Nullable string, NSError * _Nullable error) {
        shareContent = [NSString stringWithFormat:@"%@",string];
  }];
//在這里說明一下,上面的方法是同步的,而WKwebView的方法是異步的。

2JS調(diào)用OC代碼
UIWebView:

//具體讓js通知native進行方法調(diào)用,我們可以讓js產(chǎn)生一個特殊的請求。可以讓Native代碼可以攔截到,而且不然用戶察覺。業(yè)界一般的實現(xiàn)方案是在網(wǎng)頁中加載一個隱藏的iframe來實現(xiàn)該功能。通過將iframe的src指定為一個特殊的URL,實現(xiàn)在- (BOOL)webView:(UIWebView )webView shouldStartLoadWithRequest:(NSURLRequest )request navigationType:(UIWebViewNavigationType)navigationType;方案中進行攔截處理。對應(yīng)的js調(diào)用代碼如下:



 function loadURL(url) {
        var iFrame;
        iFrame = document.createElement("iframe");
        iFrame.setAttribute("src", url);
        iFrame.setAttribute("style", "display:none;");
        iFrame.setAttribute("height", "0px");
        iFrame.setAttribute("width", "0px");
        iFrame.setAttribute("frameborder", "0");
        document.body.appendChild(iFrame);
        // 發(fā)起請求后這個iFrame就沒用了,所以把它從dom上移除掉
        iFrame.parentNode.removeChild(iFrame);
        iFrame = null;
    }

WKWebView:
對于WkwebView我們上面3.2 OC如何給JS注入對象及JS如何給IOS發(fā)送數(shù)據(jù)
已經(jīng)講到了。

當然這里的總結(jié)是最簡單的。
大家有沒有想過,我們怎么才能知道js里的哪些方法OC可以調(diào)用,同樣OC里哪些模塊,JS也知道可以調(diào)用呢,React Native 是FaceBook開源的, 大家可以自行百度學(xué)習(xí),很牛啊。

對于第二種:javascriptcore.framework
我們之前分享JSPatch的時候簡單講過,這里我們再從這篇文章簡單講一下js和OC是通過這個框架相互調(diào)用的方法。
http://nshipster.com/javascriptcore/
不知道大家最近有沒有關(guān)注微信小程序,微信小程序的代碼就是允許在微信宿主程序的JavaScriptcore環(huán)境中的。大家可以下載微信官方給的開發(fā)工具進行開發(fā)微信小程序,具體學(xué)習(xí)參考微信的官方文檔說明。

對于第三種WebViewJavascriptBridge,第三方框架,挺出名的, 具體的實現(xiàn)是通過webview攔截的方式。我沒有細致的去看,就不講了,感興趣的同學(xué)可以研究。
http://www.cocoachina.com/ios/20150811/12985.html

對于React Native ,這個實現(xiàn)原理很牛掰,大家自己可以搜一下原理看看,這個采用JSX編寫,就js和html……,這個東西沒有學(xué)過,我也不多說了,有時間還是需要學(xué)習(xí)一下的,有些公司早就應(yīng)用生產(chǎn)了,解決了想熱修復(fù)一樣的功能。

現(xiàn)在JS和OC交互我們大體就講完了。
1UIWebview攔截 ,執(zhí)行js代碼
2WkWebview注入js對象,OC回調(diào),當然我個人認為在服務(wù)器發(fā)送響應(yīng)頭也是可以做攔截的,和UIwebview一樣,不過沒有發(fā)現(xiàn)網(wǎng)上有這樣說的。
3就是WebViewJavascriptBridge第三方攔截框架,根本上是對上面的封裝
4ReacNative 這個就不說了,基本就是用的 JSBridge ,運行時

3.8WKWebview API問題

最后我們來學(xué)習(xí)這兩篇文章
1.https://github.com/ShingoFukuyama/WKWebViewTips/blob/master/README.md
2.http://nshipster.cn/wkwebkit/
3.http://blog.csdn.net/j_av_a/article/details/52160413
這篇文章是WkWebview的一些坑, 文章是一個日本人整理的,是一篇非常不錯的文章。

進階

1.使用safari對webview進行調(diào)試

http://www.brighttj.com/ios/ios-user-safari-debug-webview.html
當然這是對于web開發(fā)的, 感興趣的同學(xué)也可以學(xué)習(xí)一下

2.WebView加載HTML圖片大小自適應(yīng)與文章自動換行

http://www.brighttj.com/ios/ios-webview-load-html-image-adaptive.html
這是CSS一個簡單小例子,有的同學(xué)大學(xué)都學(xué)過css,html5,javascript
大家感興趣可以學(xué)習(xí)js的DOM 編程,Ajax,jquery框架,當然如果你對前端感興趣可以修行一下

3.WKWebViewでJavaScript(Alert,Confirm,Prompt)の処理

http://qiita.com/ShingoFukuyama/items/5d97e6c62e3813d1ae98

4WBWebViewConsole

https://github.com/Naituw/WBWebViewConsole

5 iOS10ATS問題

https://onevcat.com/2016/06/ios-10-ats/

6Cookie問題http://stackoverflow.com/questions/26573137/can-i-set-the-cookies-to-be-used-by-a-wkwebview
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,196評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,456評論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,955評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,195評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,725評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,608評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,802評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,048評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,424評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,762評論 2 372

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

  • 前言 關(guān)于UIWebView的介紹,相信看過上文的小伙伴們,已經(jīng)大概清楚了吧,如果有問題,歡迎提問。 本文是本系列...
    CoderLF閱讀 9,000評論 2 12
  • 雖然WKWebView是在Apple的WWDC 2014隨iOS 8和OS X 10.10出來的,是為了解決UIW...
    winann閱讀 136,002評論 195 641
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,151評論 4 61
  • 我們本是敵對,卻偏要固執(zhí)的在一起,也許,天堂,是我們最好的歸宿。 01. 大火在不遠處以勢不可擋的姿態(tài)向我們襲來,...
    龜小慢閱讀 909評論 4 3
  • 博文《像墨一樣的陽光》中有一段話讀起來總覺得別扭,但又說不上來哪里不對,原文如下: “也許,導(dǎo)演三池崇史一開始就用...
    關(guān)中人閱讀 391評論 0 1