UIWebView
自iOS2就有,WKWebView
從iOS8纔有,毫無疑問WKWebView
將逐步取代笨重的UIWebView
。經過簡單的測試便可發現UIWebView
佔用過多內存,且內存峯值更是誇張。WKWebView
網頁加載速度也有提高,可是並不像內存那樣提高那麼多。下面列舉一些其它的優點: javascript
estimatedProgress
UIWebView
使用很是簡單,能夠分爲三步,也是最簡單的用法,顯示網頁html
- (void)simpleExampleTest { // 1.建立webview,並設置大小,"20"爲狀態欄高度 UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.height - 20)]; // 2.建立請求 NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.cnblogs.com/mddblog/"]]; // 3.加載網頁 [webView loadRequest:request]; // 最後將webView添加到界面 [self.view addSubview:webView]; }
- (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;
UIWebView
不只能夠加載HTML頁面,還支持pdf、word、txt、各類圖片等等的顯示。下面以加載mac桌面上的png圖片:/Users/coohua/Desktop/bigIcon.png
爲例 java
// 1.獲取url NSURL *url = [NSURL fileURLWithPath:@"/Users/coohua/Desktop/bigIcon.png"]; // 2.建立請求 NSURLRequest *request=[NSURLRequest requestWithURL:url]; // 3.加載請求 [self.webView loadRequest: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;
一共有四個方法ios
/// 是否容許加載網頁,也可獲取js要打開的url,經過截取此url可與js交互 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString *urlString = [[request URL] absoluteString]; urlString = [urlString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSArray *urlComps = [urlString componentsSeparatedByString:@"://"]; NSLog(@"urlString=%@---urlComps=%@",urlString,urlComps); return YES; } /// 開始加載網頁 - (void)webViewDidStartLoad:(UIWebView *)webView { NSURLRequest *request = webView.request; NSLog(@"webViewDidStartLoad-url=%@--%@",[request URL],[request HTTPBody]); } /// 網頁加載完成 - (void)webViewDidFinishLoad:(UIWebView *)webView { NSURLRequest *request = webView.request; NSURL *url = [request URL]; if ([url.path isEqualToString:@"/normal.html"]) { NSLog(@"isEqualToString"); } NSLog(@"webViewDidFinishLoad-url=%@--%@",[request URL],[request HTTPBody]); NSLog(@"%@",[self.webView stringByEvaluatingJavaScriptFromString:@"document.title"]); } /// 網頁加載錯誤 - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { NSURLRequest *request = webView.request; NSLog(@"didFailLoadWithError-url=%@--%@",[request URL],[request HTTPBody]); }
主要有兩方面:js執行OC代碼、oc調取寫好的js代碼 git
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
函數。// 實現自動定位js代碼, htmlLocationID爲定位的位置(由js開發人員給出),實現自動定位代碼,應該在網頁加載完成以後再調用 NSString *javascriptStr = [NSString stringWithFormat:@"window.location.href = '#%@'",htmlLocationID]; // webview執行代碼 [self.webView stringByEvaluatingJavaScriptFromString:javascriptStr]; // 獲取網頁的title NSString *title = [self.webView stringByEvaluatingJavaScriptFromString:@"document.title"];
不少時候,咱們要對網頁作一些編輯,好比加載一個網頁後,個別緣由,咱們不想顯示新聞的來源,以下圖的新聞來源「新華網」,網頁的連接以下:http://op.inews.qq.com/mcms/h5/default/detail?id=NEW2016103101306200&refer=100000050
(可能已經失效)github
那咱們就可使用js代碼將這個標籤去掉,且只留下時間。js代碼的編寫,根據火狐瀏覽器查看它的標籤名稱,而後作處理,如上圖,具體代碼以下:web
- (void)deleteNewsSource { // 1.去掉頁面標題 NSMutableString *str = [NSMutableString string]; // 去掉導航頁,若是想把「騰訊新聞」導航欄一併去掉,就打開註釋 // [str appendString:@"document.getElementsByClassName('g-header')[0].style.display = 'none';"]; // 來源 [str appendString:@"if(document.getElementsByClassName('g-wrapper-author')[0].innerHTML.indexOf(' ') == -1){document.getElementsByClassName('g-wrapper-author')[0].innerHTML = document.getElementsByClassName('g-wrapper-author')[0].innerHTML}else{document.getElementsByClassName('g-wrapper-author')[0].innerHTML = document.getElementsByClassName('g-wrapper-author')[0].innerHTML.split(' ')[1];}"]; // 執行js代碼 [_webView stringByEvaluatingJavaScriptFromString:str]; }
代碼執行的時機,通常狀況下是等待網頁加載完成- (void)webViewDidFinishLoad:(UIWebView *)webView
裏面執行,比較合理,可是有延遲,咱們會發現剛開始有來源,而後忽然又沒有了,即js代碼執行有延遲。瀏覽器
這樣的話,咱們能夠在- (void)webViewDidStartLoad:(UIWebView *)webView
網頁開始加載裏面開啓一個定時器,好比定時0.2秒(根據須要本身設定),在定時器裏面不停的調用- (void)deleteNewsSource
方法便可解決。而後在- (void)webViewDidFinishLoad:(UIWebView *)webView
裏面關掉定時器。另外定時器容易引發循環引用,必定要注意釋放。好比能夠在viewDidDisappear方法裏釋放定時器。。。緩存
- (void)webViewDidStartLoad:(UIWebView *)webView { // 1.去掉頁面來源標籤,時間根據須要本身設置,定時器在這裏開啓具備必定危險性 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(deleteNewsSource) userInfo:nil repeats:YES]; [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; self.timer = timer; }
與UIWebview同樣,僅需三步:服務器
- (void)simpleExampleTest { // 1.建立webview,並設置大小,"20"爲狀態欄高度 WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.height - 20)]; // 2.建立請求 NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.cnblogs.com/mddblog/"]]; // 3.加載網頁 [webView loadRequest:request]; // 最後將webView添加到界面 [self.view addSubview:webView]; }
loadFileURL
函數,顧名思義加載本地文件,不要用loadRequest來加載本地HTML,另外,加載網頁顯示屬於UI,因此應在主線程裏面執行加載網頁函數,不過即便在其它線程執行了加載網頁函數,也不要緊,蘋果已作了處理,保證UI在主線程更新。/// 模擬器調試加載mac本地文件 - (void)loadLocalFile { // 1.建立webview,並設置大小,"20"爲狀態欄高度 WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.height - 20)]; // 2.建立url userName:電腦用戶名 NSURL *url = [NSURL fileURLWithPath:@"/Users/userName/Desktop/bigIcon.png"]; // 3.加載文件 [webView loadFileURL:url allowingReadAccessToURL:url]; // 最後將webView添加到界面 [self.view addSubview:webView]; } /// 其它三個加載函數 - (WKNavigation *)loadRequest:(NSURLRequest *)request; - (WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL; - (WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL;
reloadFromOrigin
和goToBackForwardListItem
。@property (nonatomic, readonly) BOOL canGoBack; @property (nonatomic, readonly) BOOL canGoForward; - (WKNavigation *)goBack; - (WKNavigation *)goForward; - (WKNavigation *)reload; - (WKNavigation *)reloadFromOrigin; // 增長的函數 - (WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item; // 增長的函數 - (void)stopLoading;
執行js代碼
/// jsStr爲要執行的js代碼,字符串形式 [webView evaluateJavaScript:jsStr completionHandler:^(id item, NSError * _Nullable error) { // 執行結果回調 }];
一共有三個代理協議:
三個是否容許加載函數:
/// 接收到服務器跳轉請求以後調用 (服務器端redirect),不必定調用 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation; /// 3 在收到服務器的響應頭,根據response相關信息,決定是否跳轉。decisionHandler必須調用,來決定是否跳轉,參數WKNavigationActionPolicyCancel取消跳轉,WKNavigationActionPolicyAllow容許跳轉 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler; /// 1 在發送請求以前,決定是否跳轉 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
追蹤加載過程函數:
/// 2 頁面開始加載 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation; /// 4 開始獲取到網頁內容時返回 - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation; /// 5 頁面加載完成以後調用 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation; /// 頁面加載失敗時調用 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;
固然須要對webview作一些特殊處理,建立的時候調用initWithFrame:configuration:
作一些配置,configuration
爲WKWebViewConfiguration
類型,具體再也不詳述,代理方法以下:
/// message: 收到的腳本信息. - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
固然,app也能夠執行js代碼,以下:
/// jsStr爲要執行的js代碼,字符串形式 [webView evaluateJavaScript:jsStr completionHandler:^(id item, NSError * _Nullable error) { // 執行結果回調 }];
/// 建立一個新的WebView - (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures; /// 輸入框 - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler; /// 確認框 - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler; /// 警告框 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
file://
則加載本地文件,http://
則加載網絡內容,若是二者都不是則搜索輸入的關鍵字。/// 控件高度 #define kSearchBarH 44 #define kBottomViewH 44 /// 屏幕大小尺寸 #define kScreenWidth [UIScreen mainScreen].bounds.size.width #define kScreenHeight [UIScreen mainScreen].bounds.size.height #import "ViewController.h" #import <WebKit/WebKit.h> @interface ViewController () <UISearchBarDelegate, WKNavigationDelegate> @property (nonatomic, strong) UISearchBar *searchBar; /// 網頁控制導航欄 @property (weak, nonatomic) UIView *bottomView; @property (nonatomic, strong) WKWebView *wkWebView; @property (weak, nonatomic) UIButton *backBtn; @property (weak, nonatomic) UIButton *forwardBtn; @property (weak, nonatomic) UIButton *reloadBtn; @property (weak, nonatomic) UIButton *browserBtn; @property (weak, nonatomic) NSString *baseURLString; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // [self simpleExampleTest]; [self addSubViews]; [self refreshBottomButtonState]; [self.wkWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.cnblogs.com/mddblog/"]]]; } - (void)simpleExampleTest { // 1.建立webview,並設置大小,"20"爲狀態欄高度 WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.height - 20)]; // 2.建立請求 NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.cnblogs.com/mddblog/"]]; // // 3.加載網頁 [webView loadRequest:request]; // [webView loadFileURL:[NSURL fileURLWithPath:@"/Users/userName/Desktop/bigIcon.png"] allowingReadAccessToURL:[NSURL fileURLWithPath:@"/Users/userName/Desktop/bigIcon.png"]]; // 最後將webView添加到界面 [self.view addSubview:webView]; } /// 模擬器加載mac本地文件 - (void)loadLocalFile { // 1.建立webview,並設置大小,"20"爲狀態欄高度 WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.height - 20)]; // 2.建立url userName:電腦用戶名 NSURL *url = [NSURL fileURLWithPath:@"/Users/userName/Desktop/bigIcon.png"]; // 3.加載文件 [webView loadFileURL:url allowingReadAccessToURL:url]; // 最後將webView添加到界面 [self.view addSubview:webView]; } - (void)addSubViews { [self addBottomViewButtons]; [self.view addSubview:self.searchBar]; [self.view addSubview:self.wkWebView]; } - (void)addBottomViewButtons { // 記錄按鈕個數 int count = 0; // 添加按鈕 UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button setTitle:@"後退" forState:UIControlStateNormal]; [button setTitleColor:[UIColor colorWithRed:249 / 255.0 green:102 / 255.0 blue:129 / 255.0 alpha:1.0] forState:UIControlStateNormal]; [button setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted]; [button setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled]; [button.titleLabel setFont:[UIFont systemFontOfSize:15]]; button.tag = ++count; // 標記按鈕 [button addTarget:self action:@selector(onBottomButtonsClicled:) forControlEvents:UIControlEventTouchUpInside]; [self.bottomView addSubview:button]; self.backBtn = button; button = [UIButton buttonWithType:UIButtonTypeCustom]; [button setTitle:@"前進" forState:UIControlStateNormal]; [button setTitleColor:[UIColor colorWithRed:249 / 255.0 green:102 / 255.0 blue:129 / 255.0 alpha:1.0] forState:UIControlStateNormal]; [button setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted]; [button setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled]; [button.titleLabel setFont:[UIFont systemFontOfSize:15]]; button.tag = ++count; [button addTarget:self action:@selector(onBottomButtonsClicled:) forControlEvents:UIControlEventTouchUpInside]; [self.bottomView addSubview:button]; self.forwardBtn = button; button = [UIButton buttonWithType:UIButtonTypeCustom]; [button setTitle:@"從新加載" forState:UIControlStateNormal]; [button setTitleColor:[UIColor colorWithRed:249 / 255.0 green:102 / 255.0 blue:129 / 255.0 alpha:1.0] forState:UIControlStateNormal]; [button setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted]; [button setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled]; [button.titleLabel setFont:[UIFont systemFontOfSize:15]]; button.tag = ++count; [button addTarget:self action:@selector(onBottomButtonsClicled:) forControlEvents:UIControlEventTouchUpInside]; [self.bottomView addSubview:button]; self.reloadBtn = button; button = [UIButton buttonWithType:UIButtonTypeCustom]; [button setTitle:@"Safari" forState:UIControlStateNormal]; [button setTitleColor:[UIColor colorWithRed:249 / 255.0 green:102 / 255.0 blue:129 / 255.0 alpha:1.0] forState:UIControlStateNormal]; [button setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted]; [button setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled]; [button.titleLabel setFont:[UIFont systemFontOfSize:15]]; button.tag = ++count; [button addTarget:self action:@selector(onBottomButtonsClicled:) forControlEvents:UIControlEventTouchUpInside]; [self.bottomView addSubview:button]; self.browserBtn = button; // 統一設置frame [self setupBottomViewLayout]; } - (void)setupBottomViewLayout { int count = 4; CGFloat btnW = 80; CGFloat btnH = 30; CGFloat btnY = (self.bottomView.bounds.size.height - btnH) / 2; // 按鈕間間隙 CGFloat margin = (self.bottomView.bounds.size.width - btnW * count) / count; CGFloat btnX = margin * 0.5; self.backBtn.frame = CGRectMake(btnX, btnY, btnW, btnH); btnX = self.backBtn.frame.origin.x + btnW + margin; self.forwardBtn.frame = CGRectMake(btnX, btnY, btnW, btnH); btnX = self.forwardBtn.frame.origin.x + btnW + margin; self.reloadBtn.frame = CGRectMake(btnX, btnY, btnW, btnH); btnX = self.reloadBtn.frame.origin.x + btnW + margin; self.browserBtn.frame = CGRectMake(btnX, btnY, btnW, btnH); } /// 刷新按鈕是否容許點擊 - (void)refreshBottomButtonState { if ([self.wkWebView canGoBack]) { self.backBtn.enabled = YES; } else { self.backBtn.enabled = NO; } if ([self.wkWebView canGoForward]) { self.forwardBtn.enabled = YES; } else { self.forwardBtn.enabled = NO; } } /// 按鈕點擊事件 - (void)onBottomButtonsClicled:(UIButton *)sender { switch (sender.tag) { case 1: { [self.wkWebView goBack]; [self refreshBottomButtonState]; } break; case 2: { [self.wkWebView goForward]; [self refreshBottomButtonState]; } break; case 3: [self.wkWebView reload]; break; case 4: [[UIApplication sharedApplication] openURL:self.wkWebView.URL]; break; default: break; } } #pragma mark - WKWebView WKNavigationDelegate 相關 /// 是否容許加載網頁 在發送請求以前,決定是否跳轉 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { NSString *urlString = [[navigationAction.request URL] absoluteString]; urlString = [urlString stringByRemovingPercentEncoding]; // NSLog(@"urlString=%@",urlString); // 用://截取字符串 NSArray *urlComps = [urlString componentsSeparatedByString:@"://"]; if ([urlComps count]) { // 獲取協議頭 NSString *protocolHead = [urlComps objectAtIndex:0]; NSLog(@"protocolHead=%@",protocolHead); } decisionHandler(WKNavigationActionPolicyAllow); } #pragma mark - searchBar代理方法 /// 點擊搜索按鈕 - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { // 建立url NSURL *url = nil; NSString *urlStr = searchBar.text; // 若是file://則爲打開bundle本地文件,http則爲網站,不然只是通常搜索關鍵字 if([urlStr hasPrefix:@"file://"]){ NSRange range = [urlStr rangeOfString:@"file://"]; NSString *fileName = [urlStr substringFromIndex:range.length]; url = [[NSBundle mainBundle] URLForResource:fileName withExtension:nil]; // 若是是模擬器加載電腦上的文件,則用下面的代碼 // url = [NSURL fileURLWithPath:fileName]; }else if(urlStr.length>0){ if ([urlStr hasPrefix:@"http://"]) { url=[NSURL URLWithString:urlStr]; } else { urlStr=[NSString stringWithFormat:@"http://www.baidu.com/s?wd=%@",urlStr]; } urlStr = [urlStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; url=[NSURL URLWithString:urlStr]; } NSURLRequest *request=[NSURLRequest requestWithURL:url]; // 加載請求頁面 [self.wkWebView loadRequest:request]; } #pragma mark - 懶加載 - (UIView *)bottomView { if (_bottomView == nil) { UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, kScreenHeight - kBottomViewH, kScreenWidth, kBottomViewH)]; view.backgroundColor = [UIColor colorWithRed:230/255.0 green:230/255.0 blue:230/255.0 alpha:1]; [self.view addSubview:view]; _bottomView = view; } return _bottomView; } - (UISearchBar *)searchBar { if (_searchBar == nil) { UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 20, kScreenWidth, kSearchBarH)]; searchBar.delegate = self; searchBar.text = @"http://www.cnblogs.com/mddblog/"; _searchBar = searchBar; } return _searchBar; } - (WKWebView *)wkWebView { if (_wkWebView == nil) { WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 20 + kSearchBarH, kScreenWidth, kScreenHeight - 20 - kSearchBarH - kBottomViewH)]; webView.navigationDelegate = self; // webView.scrollView.scrollEnabled = NO; // webView.backgroundColor = [UIColor colorWithPatternImage:self.image]; // 容許左右劃手勢導航,默認容許 webView.allowsBackForwardNavigationGestures = YES; _wkWebView = webView; } return _wkWebView; } @end