###一、UIWebView的幾種加載方式html
加載本地的HTML文件前端
//建立URL NSURL *url = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"html"]; //建立NSURLRequest NSURLRequest *request = [NSURLRequest requestWithURL:url]; //加載 [_webView loadRequest:request];
UIWebView 還支持將一個NSString對象做爲源來加載。你能夠爲其提供一個基礎URL,來指導UIWebView對象如何跟隨連接和加載遠程資源:java
NSString *path = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"]; NSString *htmlString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; [webView loadHTMLString:htmlString baseURL:[NSURL URLWithString:path]];
###二、UIWebView代理方法git
設置代理github
self.webView.delegate = self;
代理方法web
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { //返回YES,進行加載。經過UIWebViewNavigationType能夠獲得請求發起的緣由 return YES; }
開始加載json
- (void)webViewDidStartLoad:(UIWebView *)webView { }
完成加載數組
- (void)webViewDidFinishLoad:(UIWebView *)webView { }
加載出錯瀏覽器
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { }
###三、導航框架
UIWebView 類內部會管理瀏覽器的導航動做
[webView goBack]; //後退 [webView goForward]; //前進 [webView reload];//重載 [webView stopLoading];//取消載入內容
###四、UIWebView和JavaScript交互
UIWebView的方法
- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
相關應用:
// 獲取當前頁面的title NSString *title = [webview stringByEvaluatingJavaScriptFromString:@"document.title"]; // 獲取當前頁面的url NSString *url = [webview stringByEvaluatingJavaScriptFromString:@"document.location.href"];
iOS原生應用和web頁面的交互大體上有這幾種方法iOS7以後的JavaScriptCore
、攔截協議、第三方框架WebViewJavaScriptBridge
、iOS8以後的WKWebView
在這裏只介紹JavaScriptCore
和'攔截協議'
iOS7以後蘋果推出了JavaScriptCore這個框架,從而讓web頁面和本地原生應用交互起來很是方便,並且使用此框架能夠作到Android那邊和iOS相對統一,web前端寫一套代碼就能夠適配客戶端的兩個平臺,從而減小了web前端的工做量。
####4.1 JavaScriptCore
JavaScriptCore中類及協議:
JSContext
:給JavaScript提供運行的上下文環境 JSValue
:JavaScript和Objective-C數據和方法的橋樑 JSManagedValue
:管理數據和方法的類 JSVirtualMachine
:處理線程相關,使用較少 JSExport
:這是一個協議,若是採用協議的方法交互,本身定義的協議必須遵照此協議
web前端
在三端交互中,web前端要強勢一些,一切傳值、方法命名都按web前端開發人員來定義,讓另外兩端去作適配。在這裏以調用NSLog和保存圖片爲例來詳細講解,測試網頁代碼取名爲test.html,其代碼內容以下:
test.html代碼內容
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> </head> <body> <div style="text-align: center;"> <h1>Objective-C和JavaScript交互的那些事</h1> <div><img src="http://chuantu.biz/t5/34/1474337388x3063167327.jpg" /></div> <div><input type="button" value="點擊我能夠看到Xcode的NSLog" onclick="Toyun.callCamera()" /></div> <div><input type="button" value="點擊我能夠保持圖片到手機相冊" onclick="callShare()" /></div> </div> <script> var callShare = function() { var shareInfo = JSON.stringify({"title": "標題", "desc": "內容", "shareUrl": "http://chuantu.biz/t5/34/1474337388x3063167327.jpg"}); Toyun.share(shareInfo); } var picCallback = function(photos) { alert(photos); } var shareCallback = function(NSString){ alert(NSString); } </script> </body> </html>
test.html代碼解釋:
可能有些同窗對web前端的一些知識不太熟悉,稍微對這段代碼作下解釋,先說Toyun是iOS和Android這兩邊在本地要注入的一個對象【參考下面iOS的代碼更容易明白】,充當原生應用和web頁面之間的一個橋樑。頁面上定義了兩個按鈕名字分別爲點擊我能夠看到Xcode的NSLog
和點擊我能夠保持圖片到手機相冊
。點擊第一個按鈕會經過Toyun這個橋樑調用本地應用的方法- (void)callCamera,沒有傳參;而點擊第二個按鈕會先調用本文件中的JavaScript方法callShare,這裏將要保存的內容格式轉成JSON字符串格式(這樣作是爲了適配Android,iOS能夠直接接受JSON對象)而後再經過Toyun這個橋樑去調用原生應用的- (void)share:(NSString *)shareInfo方法這個是有傳參的,參數爲shareInfo。而下面的兩個方法爲原生方法調用後的回調方法,其中picCallback爲獲取圖片成功的回調方法,而且傳回拿到的參數photos;shareCallback爲分享成功的回調方法。
IOS代碼
經過JSContext,在ObjC中經過JSContext注入模型,而後調用模型的方法:
首先,咱們須要先定義一個協議,並且這個協議必需要遵照JSExport協議
@protocol JavaScriptObjectiveCDelegate <JSExport> //協議方法 - (void)callCamera ; - (void)share:(id)shareString ; @end
接下來,咱們還須要定義一個模型,這個模型遵循咱們定義的協議
// 此模型用於注入JS的模型,這樣就能夠經過模型來調用方法. @interface Model : NSObject<JavaScriptObjectiveCDelegate>
實現協議方法:
- (void)callCamera { NSLog(@"點擊了網頁按鈕"); JSValue *picCallback = self.jsContext[@"picCallback"]; //參數傳遞 [picCallback callWithArguments:@[@"請看Xcode!"]]; } - (void)share:(id)shareString { NSLog(@"share:%@", shareString); NSData *json = [shareString dataUsingEncoding:NSUTF8StringEncoding]; // 將json格式數據解析爲對應的數據類型(數組、字典、字符串、數字) NSError *error = nil; // NSJSONReadingMutableContainers: 轉爲對應的可變容器(可變數組、可變字典) NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:json options:NSJSONReadingMutableContainers error:&error]; NSLog(@"%@",jsonData[@"shareUrl"]); NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:jsonData[@"shareUrl"]]]; UIImage *image = [UIImage imageWithData:data]; // 將圖片保存到相冊中 UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL); }
接下來,咱們在controller中在webview加載完成的代理中,給JS注入模型
- (void)webViewDidFinishLoad:(UIWebView *)webView { self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; // 經過模型調用方法,這種方式更好些。 Model *model = [[Model alloc] init]; self.jsContext[@"Toyun"] = model; model.jsContext = self.jsContext; model.webView = self.webView; self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) { context.exception = exceptionValue; NSLog(@"異常信息:%@", exceptionValue); }; }
####4.2 攔截協議
攔截協議這個適合一些比較簡單的一些狀況,不須要引入什麼框架,只須要web前端配合一下就好。可是在具體調用哪個方法上,以及在傳值的時候可能會有些不方便,並且調用完後沒法在回調JavaScript的方法。
test.html中的代碼
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> </head> <body> <div> <input type="button" value="CallCamera" onclick="callCamera()"> </div> <script> function callCamera() { window.location.href = 'toyun://callCamera'; } </script> </body> </html>
test.html中的代碼解釋:
這段代碼相比上面的那段測試代碼是很簡單的,一樣有一個按鈕,名字爲CallCamera點擊以後調用本身的callCamera方法,window.location.href這裏是改變主窗口的指向從而立刻發出一個連接爲toyun://callCamera請求,而想要傳給原生應用的參數也可已包含到此請求中,而在iOS方法中咱們要攔截這個請求,根據請求內容去判斷JavaScript想要作的事情,從而實現web頁面和本地應用之間的交互。
iOS對應的代碼
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString *url = request.URL.absoluteString; if ([url rangeOfString:@"toyun://"].location != NSNotFound) { // url的協議頭是toyun NSLog(@"callCamera"); return NO; } return YES; }
iOS對應的代碼的解釋:
在webView的代理方法中去攔截自定義的協議Toyun://若是是此協議則據此判斷JavaScript想要作的事情,調用原生應用的方法,這些都是提早約定好的,同時阻止此連接的跳轉。
Demo地址: