1. 程式人生 > >IOS應用通過UIWEBVIEW實現與JS互動

IOS應用通過UIWEBVIEW實現與JS互動

眾所周知,蘋果商店的稽核是不允許應用載入外部可執行檔案的。即如果你想要給APP增加功能就需要修改程式碼增加新功能的程式碼後重新上傳至蘋果商店,經過漫長的稽核之後再上線。那麼有沒有辦法繞過這個步驟去動態的新增新功能呢?答案是有的。我們可以通過擁有歷史悠久的javascript來實現這個。是的,你沒看錯。就是javascript!具體怎麼實現呢?彆著急,接著往下看。
在iOS裡開啟網頁是用UIWebView實現的。查一下它的API文件,發現有個方法叫stringByEvaluatingJavaScriptFromString。從字面意思就可以看出這個方法正是我們所要的。文件裡對它的描述是這樣的。

stringByEvaluatingJavaScriptFromString:
Returns the result of running a script.
- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
Parameters
script
The script to run.
Return Value
The result of running script or nil if it fails.
Discussion
JavaScript execution time is limited to 10 seconds for each top-level entry point. If your script executes for more than 10 seconds, the web view stops executing the script. This is likely to occur at a random place in your code, so unintended consequences may result. This limit is imposed because JavaScript execution may cause the main thread to block, so when scripts are running, the user is not able to interact with the webpage.
JavaScript allocations are also limited to 10 MB. The web view raises an exception if you exceed this limit on the total memory allocation for JavaScript.

看起來很容易使用嘛。先建立一個UIWebView的例項。

//建立要開啟的html檔案的完整路徑
NSBundle *bundle = [NSBundle mainBundle];
NSString *resPath = [bundle resourcePath];
NSString *filePath = [resPath stringByAppendingPathComponent:@"hello.html"];
//初始化一個UIWebView例項
myWebView = [[UIWebView alloc] initWithFrame:self.view.frame];
//載入指定的html檔案
[myWebView loadRequest:[[NSURLRequest alloc] initWithURL:[[NSURL alloc] initFileURLWithPath:filePath]]];


下面就是我們的主角登場了。注意,這個方法得在WebView載入完成後執行。如下所示:

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *jsCode = [NSString stringWithFormat:@"alert(1);"];
[myWebView stringByEvaluatingJavaScriptFromString:jsCode];
}

執行程式就可以看到一個由js彈出的彈窗了。
但是這僅僅是Objc呼叫js而已,怎樣才能用js去調Objc的方法呢?如果能實現這一步,那麼我們就可以實現提供一些系統層面的api去供js呼叫,從而去讓js實現更多功能。檢視一下UIWebViewDelegate的文件,會發現有如下介面

webView:shouldStartLoadWithRequest:navigationType:
Sent before a web view begins loading a frame.
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

當一個web檢視開始載入一個frame的時候會觸發它。看起來很符合我們的需求。我們可以在頁面裡建立一個iframe,使用js程式碼去改變它的src來觸發這個呼叫,從而實現js對Objc的呼叫。具體的實現方式就不在此贅述,有興趣的可以看一下我寫的這個簡單測試。
github地址:https://github.com/feeyar/ObjcCallJS

後記:這篇文章只是提出了實現的一種思路,但實現起來不太優雅。其實還有很多思路,比如封裝一個js委託類,把js對oc的呼叫快取起來,在oc中定時的去檢測快取的呼叫佇列做相應處理。推薦看看apache的Cordova專案原始碼 https://github.com/apache/incubator-cordova-ios

看到一篇很不錯的文章,也順道記錄下來: