iOS WebView與JS交互

最近在做的項目重點就是原生app與js的交互,以前也做過但是并沒有深入的了解和研究過,因為這個項目我嘗試了三種方式的交互方法,經過實踐也更了解每種方法的利弊,再次分享一下希望大家可以批評指正:

首先分析一下app目前的樣式分類原生app和webapp的定義以及優(yōu)缺點Web App

WebApp

即是一種框架型APP開發(fā)模式(HTML5 APP框架開發(fā)模式),該開發(fā)具有跨平臺的優(yōu)勢,該模式通常由“HTML5云網(wǎng)站+APP應用客戶端”兩部份構成,APP應用客戶端只需安裝應用的框架部份,而應用的數(shù)據(jù)則是每次打開APP的時候,去云端取數(shù)據(jù)呈現(xiàn)給手機用戶。

原生App

原生APP又稱Native

App,該開發(fā)針對IOS、Android、Windows等不同的手機操作系統(tǒng)要采用不同的語言和框架進行開發(fā),該模式通常是由“云服務器數(shù)據(jù)+APP應用客戶端”兩部份構成,APP應用所有的UI元素、數(shù)據(jù)內容、邏輯框架均安裝在手機終端上。

Hybrid App(混合模式移動應用)

是指介于web-app、native-app這兩者之間的app,兼具“Native App良好用戶交互體驗的優(yōu)勢”和“Web App跨平臺開發(fā)的優(yōu)勢”。

這篇文章作者總結的不錯

WebAPP與原生APP的交互設計區(qū)別 - 簡書

http://www.oschina.net/question/585173_2141646

這篇文章講述了目前移動開發(fā)的趨勢:

為什么移動開發(fā)開始用混合app開發(fā)(Hybrid App)

知道了各種形式app的定義卻別,也更了解Hybrid App的優(yōu)勢那怎樣更好的實現(xiàn)原生與web 的交互呢?

首先我認為最好的方式

1. 運用JavaScriptCore框架進行交互

在iOS 7之后,apple添加了一個新的庫JavaScriptCore,用來做JS交互,因此JS與原生OC交互也變得簡單了許多。這是我做的一個例子

1.首先創(chuàng)建JSContext 對象(此處通過當前webView的鍵獲取到jscontext)

_mJSContext=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

2.異常處理

_mJSContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {

context.exception = exceptionValue;

DLog(@"%@", exceptionValue);

};

3.在JS中添加了方法指針提供給JS調用

@WeakObj(self);

_mJSContext[@"jSInvokerGetMid"] = ^(void){

DLog(@"JS獲取UUID");

@StrongObj(self);

return ?self.devie.mac;

};

_mJSContext[@"jSInvokerGetLocation"] = ^(void){

DLog(@"JS獲取坐標");

@StrongObj(self);

id devicePoint = @{

@"latitude": [NSString stringWithFormat:@"%f", self.location.coordinate.latitude],

@"longitude": [NSString stringWithFormat:@"%f", self.location.coordinate.longitude]

};

return devicePoint;

};

_mJSContext[@"jSInvokerGetUserSgid"] = ^(void){

DLog(@"JS用戶的ID");

return @"UserId";

};

_mJSContext[@"jSInvokerSpeechSubView"] = ^(void){

DLog(@"將要進行界面跳轉由h5界面跳轉到原生界面");

@StrongObj(self);

NSArray *args = [JSContext currentArguments];

JSValue * value = args[0];

NSString * str = value.toString;

//必須放入主線程中更新UI否則會出錯

dispatch_async(dispatch_get_main_queue(), ^{

SGHomeSeachDetailController * detailViewCon = [[SGHomeSeachDetailController alloc]init];

detailViewCon.baseUrl = str;

[self.navigationController pushViewController: detailViewCon animated:YES];

});

};

4.iOS調用JS進行初始化

NSString *textJS = @"window.ios_callback('這里是JS中alert彈出的message')";

[_mJSContext evaluateScript:textJS];

也可以參考:IOS中 使用JavaScriptCore 實現(xiàn)OC與JS的交互 - 簡書

以及我的博客:JS和Native交互之 - 運用JavaScriptCore框架進行交互 - lxm_780337的博客? ? ? ? ?- 博客頻道 - CSDN.NET

WebViewJavascriptBridge

Obj-C和JavaScript原理:

Obj-C調用JavaScript很簡單,可以通過webview的stringByEvaluatingJavaScriptFromString:方法調用JavaScript代碼;JavaScript調用Obj-C,則是通過web

view的代理方法shouldStartLoadWithRequest:來接收JavaScript的網(wǎng)絡請求從而實現(xiàn)調用。

利弊:

需要把響應的方法放到橋梁內,這樣對安卓端可能會中影響

不錯的例子:

1.按照本地的CSS文件展示一串網(wǎng)絡獲取的帶HTML格式的只有body部分的文本,需要自己拼寫完整的HTML。除此之外,還需要禁用獲取的HTML文本中自帶的

《 img 》

標簽自動加載,并把下載圖片的操作放在native端來處理,并通過JS將圖片在Cache中的地址返回給UIWebview。http://www.cocoachina.com/ios/20150814/12985.html

過程:

一開始,我們在Native端和JS端都分別進行初始化:

OC端:

@property WebViewJavascriptBridge* bridge;

對應的初始化代碼如下,在初始化中直接包含了一個用于接收JS的回調:

_bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) {

NSLog(@"ObjC received message from JS: %@", data);

responseCallback(@"Response for message from ObjC");

}];

JS端:(以下是固定寫法,你自己的JS文件中必須包含如下代碼)

function connectWebViewJavascriptBridge(callback) {

if (window.WebViewJavascriptBridge) {

callback(WebViewJavascriptBridge)

} else {

document.addEventListener('WebViewJavascriptBridgeReady', function() {

callback(WebViewJavascriptBridge)

}, false)

}

connectWebViewJavascriptBridge(function(bridge) {

//注意,你的bridge函數(shù)都應寫在這里面

}

//例如

function doSomething(){

connectWebViewJavascriptBridge(function(bridge) {

bridge.init(function(message, yourCallback) {

log('ObjC called testJavascriptHandler with', message)

var responseData = { 'Javascript Says':'Right back atcha!' }

log('JS responding with', responseData)

responseCallback(responseData)

})

}

}

然后,我們要知道,在WebViewJavascriptBridge中,交互的方式只有兩種:send 和 callHandle,JS和OC都有這兩個方法,所以對應的四種關系是:

blob.png

OC調用JS方法

1.調用JS中bridge.init的方法

//OC

[_bridge send:@"The message sent from ObjC to JS" responseCallback:^(id response) {

NSLog(@"sendMessage got response: %@", response);//這里的response是js方法中的data

}];

//對應調用js中的方法

bridge.init(function(message, yourCallback) {

log('ObjC called testJavascriptHandler with', message)

var responseData = { 'Javascript Says':'Right back atcha!' }

log('JS responding with', responseData)

responseCallback(responseData)

})

2.調用JS中bridge.registerHandler方法,該方法可以注冊方法名,通過注冊名確認調用方法

//OC

[_bridge callHandler:@"注冊名" data:data responseCallback:^(id response) {

NSLog(@"testJavascriptHandler responded: %@", response);

}];

//對應調用的js中的方法

bridge.registerHandler('注冊名', function(data, responseCallback) {

log('ObjC called testJavascriptHandler with', data)

var responseData = { 'Javascript Says':'Right back atcha!' }

log('JS responding with', responseData)

responseCallback(responseData)

})

JS端調用OC端方法

1.調用OC中創(chuàng)建bridge對象時定義時的方法

//JS中

bridge.send(data,function(response){

log('這里是回調方法',response) //回調方法

})

//對應調用的OC中bridge初始化中設置的block方法

_bridge

= [WebViewJavascriptBridge bridgeForWebView:webView

webViewDelegate:self handler:^(id data, WVJBResponseCallback

responseCallback) {

//do something...

NSLog(@"ObjC received message from JS: %@", data);//從js獲得的參數(shù)

responseCallback(@"Response");//Response to js

}];

2.通過方法名調用OC中bridge的注冊方法

//JS中

bridge.callHandler('注冊名', {'foo': 'bar'}, function(response) {

log('JS got response', response)

})

//對應調用的OC中的bridge注冊的方法

[_bridge registerHandler:@"注冊名" handler:^(id data, WVJBResponseCallback responseCallback) {

NSLog(@"testObjcCallback called: %@", data);//從js獲取的參數(shù)

responseCallback(@"Response");//

}];

這篇文章講了交互原理非常不錯:JS和Native交互之 -WebViewJavascriptBridge源碼分析 - lxm_780337的博客? ? ? ? ?- 博客頻道 - CSDN.NET

UIWebView的代理方法

原理:- (BOOL)webView:(UIWebView *)webView

shouldStartLoadWithRequest:(NSURLRequest *)request

navigationType:(UIWebViewNavigationType)navigationType;在WebView中的wap頁將要載入內容時得到通知觸發(fā),返回NO則阻止加載內容,優(yōu)點:簡單易用,在頁面跳轉請求時進行iOS端的頁面跳轉,并返回NO阻止wap內的頁面跳轉缺點:無法識別不加載新內容的JS動作(點擊按鈕彈出對話框和提交等)例子:HTML網(wǎng)頁和一個btn點擊事件用來與原生OC交互(用JS發(fā)起一個假的URL請求,然后利用UIWebView的代理方法攔截這次請求,然后再做相應的處理)JS調用IOSHTML代碼如下:

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容