IOS——UIWebView基本使用與JS交互

###一、UIWebView的幾種加載方式html

加載本地的HTML文件前端

  • 經過NSURLRequest加載:
//建立URL
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"html"];
    //建立NSURLRequest
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    //加載
    [_webView loadRequest:request];
  • 經過NSString加載:

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地址:

https://github.com/fuxinto/HfxDemo

相關文章
相關標籤/搜索