在iOS開發中,咱們常常會碰到這樣的需求:在UIWebView中的一個連接,點了以後不是進下一個網頁,而是進下一個UIViewController,或者讓ObjC代碼作點事情。這在資訊類的應用中很常見,好比網易新聞、騰訊新聞,以及咱們公司的東方財富通中的資訊。git
而在舊的iOS版本中,系統不提供在Javascript直接調用ObjC的方法。只能經過變換location等發起網絡請求的方式,使得UIWebViewDelegate
中的- (BOOL)webView:shouldStartLoadWithRequest:navigationType:
感知到,進而作ObjC的處理。github
然而這樣作比較不優雅,全部的事情都圍繞在URL請求上面,而不是方法調用上面,看上去不優雅。MHGJavascriptBridge的用意即是將URL請求等等封裝起來,讓Javascript和ObjC代碼注重於方法調用自己上來。web
Github地址:https://github.com/hikui/MHGJavascriptBridge數組
MHGJavascriptBridge由3個文件組成,MHGJavascriptBridge.h
, MHGJavascriptBridge.m
, MHGJavascriptBridge.js
。將這三個文件加入Xcode工程中。注意,MHGJavascriptBridge.js
必須加入到資源文件中(在"Building phases" -> "Copy bundle resources"中出現),Xcode默認會將.js文件加入到Compile Sources裏面去,這是錯誤的。網絡
首先,咱們須要初始化一個bridge,這一般是在一個UIViewController中進行的。這裏假設在UIViewController中對bridge進行初始化。在初始化中,須要設定bridge的webView
屬性:異步
@interface MHGWebViewController ()<UIWebViewDelegate> @property (nonatomic, strong) MHGJavascriptBridge *bridge; @property (nonatomic, strong) UIWebView *webView; @end ... - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { _bridge = [[MHGJavascriptBridge alloc]init]; _bridge.webView = self.webView; } return self; }
在MHGJavascriptBridge中,全部能被Javascript調用的Objective C方法將以block的形式呈現。首先咱們須要定義一些blocks,而後對每個block起名。函數
- (void)viewDidLoad { [super viewDidLoad]; [self.bridge setBlockName:@"button1OnClick" block:^(NSDictionary *dict) { // do stuff NSLog(@"button1 on click with params:%@", dict); }]; [self.bridge setBlockName:@"beginSomeTasks" block:^(NSDictionary *dict) { // do stuff NSLog(@"begin some tasks with params:%@", dict); }]; ... }
MHGJavascriptBridge的原理是構造特定的URL,而且用UIWebViewDelegate
中的- (BOOL)webView:shouldStartLoadWithRequest:navigationType:
攔截這個URL。因此在這個delegate方法中,咱們須要加入攔截語句:ui
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { BOOL intercepted = [self.bridge interceptRequest:request]; //必須有 // Do other things ... return YES; }
其中,interceptRequest:
方法會返回一個BOOL
,若是攔截成功,則返回YES
。atom
這樣,Objective C部分就設置完成了。其中須要注意的是,block被調用時,會傳入一個dict
,這是Javascript部分代碼調Objective C代碼時所傳的參數。url
Javascript部分設置比較簡單,最基本的設置是要保證UIWebView中的HTML引入了MHGJavascriptBridge.js
:
<script src="MHGJavascriptBridge.js"></script>
一旦設置完成以後,Javascript和Objective C就能互相調用了。代碼以下:
var button1ClickEventHandler = function (){ // Do stuff ... MHGJavascriptBridge.callNativeBlock('button1OnClick',{'url':imageURL}); }; <button onClick="button1ClickEventHandler()">button 1</button>
這時,點擊button1時,就能觸發Objective C的代碼了。MHGJavascriptBridge.callNativeBlock
有兩個參數,第一個參數是在Objective C中註冊的block名字,第二個參數是傳給block裏面的dict
的額外信息。其中第二個參數必須是一個字典(或者說是一個Javascript Object),或者什麼都不傳。
方法和上述相似:
... [self.bridge callJavascriptFunction:@"setImageWithURL" withParams:@[fileURL.absoluteString]]; ...
其中第一個參數是Javascript函數名。若是你在HTML中定義了function xxx(){}
或者var xxx = function(){}
的話,就能被調用。第二個參數是一個數組,傳的是Javascript函數要用的參數列。