要是 IOS 開發的哥們告訴大家說webview 和 本地交互只能通過 “攔截Url” 的方式。。。你可以告訴他們還可以 像android 一樣注入 JavaScriptInterface.
原文如下:
http://dukeland.hk/2013/01/28/adding-javascript-interface-to-uiwebview-like-android/
JANUARY 28, 2013
輕鬆加入 Javascript Interface 到 UIWebView 中(跟 Android 一樣方便)
最近在開發一個 iOS app,需要使用混合模式(native + WebView),當中有些部份需要 Javascript 和 Objective-C 雙向溝通,要在 Objective-C中使用 Javascript function 並不難,使用 UIWebView 中的 “stringByEvaluatingJavaScriptFromString” 就可以了,要在 Javascript 中使用 Objective-C 比較難一點點,需要 implement UIWebViewDelegate的 “shouldStartLoadWithRequest”。
Android 在這一方面做得很簡單,在 WebView 裏有一個 method 叫做 “addJavascriptInterface”,可以讓開發者自由加入 Javascript 的 Interface,在 Javascript 中就可以直接使用 Java 的 function,在 Objective-C 中我們可以複制一下這個模式嗎?
當然可以,不然我為什麼要寫這篇文章?
市面上已經有一個挺方便的 class 可以用,就是這個 Native Bridge,然而用了之後你會發現有些問題;第一它要 return 數值到 Javascript 的話要用 async-style,這樣你的程式碼看起來會過份臃腫。第二讓 Javascript 使用的 function 要全部寫到 UIWebView 的 handleCall 中,用起上來不夠簡潔。讓我們來解決這個問題吧!
首先我們要繼承一下 UIWebView,並加入以下 method。
1
2
3
|
-( void )
addJavascriptInterfaces:( NSObject *)interfaceWithName:( NSString *)
name{ [ self .proxyDelegate
addJavascriptInterfaces:interfaceWithName:name]; } |
method signature 就跟 Android 裏的一樣,裏面會使用 proxy delegate 的 addJavascriptInterfaces,為什麼要用 proxy delegate 呢?因為要避免佔據了 UIWebView 的 delegate property 呀,不然其他用家怎樣使用它來 intercept 其他 request 呢!
Proxy Delegate 就是這個 library 的主角,它主要 implement 了兩個 method 來加入我們想要的功能,一是 webViewDidStartLoad,一是 shouldStartLoadWithRequest。
在 webViewDidStartLoad 時我們要把我們的 Javascript 注入到 UIWebView 中,這包括兩個部份。第一部份是我們的 Javascript 基本代碼,這包括了兩個 function,call() 用來 call Objective-C Interface 的 method,inject() 用來注入 Interface 內所有 method signature 到 Javascript 去。第二部份是我們 runtime 生成的 method signature,會使用 inject() 注入到 Javascript 中。
在 shouldStartLoadWithRequest 時我們要 intercept 一下,看看這個 request 是不是 easy-js: protocol,是的話我們就用 reflection 的方法去呼叫我們的 Objective-C Interface,並且把 return value 用 Javascript 再注入到 UIWebView 中,這樣我們便不用等到 request 完才用 async 的方法把 return value 傳到 UIWebView 去。
用文字解釋這個 library 實在不容易,大家還是看代碼更簡單。
GitHub: EasyJSWebView
Sample project: EasyJSWebViewSample
使用方法:
1. 建立一個 Javascript Interface Class
1
2
3
4
5
6
7
8
9
|
@interface MyJSInterface: NSObject -( void )
test; -( void )
testWithParam:( NSString *)
param; -( void )
testWithTwoParam:( NSString *)
param AndParam2:( NSString *)
param2; -( NSString *)
testWithRet; @end |
2. 把它加入到 WebView 裏
1
2
3
|
MyJSInterface*interface=[MyJSInterface new ]; [ self .myWebView
addJavascriptInterfaces:interfaceWithName:@ "MyJSTest" ]; [interface
release]; |
3. 在 Javascript 中可以直接使用了
1
2
3
4
5
|
MyJSTest.test(); MyJSTest.testWithParam( "ha:ha" ); MyJSTest.testWithTwoParamAndParam2( "haha1" , "haha2" ); var str
=MyJSTest.testWithRet(); |
更多其他例子請到 github 的 sample project 裏閱讀吧。