http://www.cocoachina.com/ios/20160127/15105.html
WKWebView
WKWebView用于ios8+
JavaScriptCore
iOS7之后蘋果推出了JavaScriptCore這個框架涩盾,從而讓web頁面和本地原生應(yīng)用交互起來非常方便叶眉,而且使用此框架可以做到Android那邊和iOS相對統(tǒng)一莲趣,web前端寫一套代碼就可以適配客戶端的兩個平臺走芋,從而減少了web前端的工作量。
web前端去定義方法名,iOS和Android根據(jù)web前端定義好的去寫代碼怨喘。JavaScriptCore中web頁面調(diào)用原生應(yīng)用的方法可以用Delegate或Block兩種方法吩案,此文以按Delegate講解靠益。
ViewController中的代碼
#import "ViewController.h"
#import [JavaScriptCore/JavaScriptCore.h](此處為尖括號)
@protocol JSObjcDelegate [JSExport](此處為尖括號)
- (void)callCamera;
- (void)share:(NSString *)shareString;
@end
@interface ViewController () [UIWebViewDelegate, JSObjcDelegate](此處為尖括號)
@property (nonatomic, strong) JSContext *jsContext;
@property (weak, nonatomic) IBOutlet UIWebView *webView;
@end
@implementation ViewController
#pragma mark - Life Circle
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"html"];
[self.webView loadRequest:[[NSURLRequest alloc] initWithURL:url]];
}
#pragma mark - UIWebViewDelegate
- (void)webViewDidFinishLoad:(UIWebView *)webView {
self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
self.jsContext[@"Toyun"] = self;
self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
context.exception = exceptionValue;
NSLog(@"異常信息:%@", exceptionValue);
};
}
#pragma mark - JSObjcDelegate
- (void)callCamera {
NSLog(@"callCamera");
// 獲取到照片之后在回調(diào)js的方法picCallback把圖片傳出去
JSValue *picCallback = self.jsContext[@"picCallback"];
[picCallback callWithArguments:@[@"photos"]];
}
- (void)share:(NSString *)shareString {
NSLog(@"share:%@", shareString);
// 分享成功回調(diào)js的方法shareCallback
JSValue *shareCallback = self.jsContext[@"shareCallback"];
[shareCallback callWithArguments:nil];
}
@end
ViewController中的代碼解釋
自定義JSObjcDelegate協(xié)議胧后,而且此協(xié)議必須遵守JSExport這個協(xié)議,自定義協(xié)議中的方法就是暴露給web頁面的方法抱环。在webView加載完畢的時候獲取JavaScript運行的上下文環(huán)境镇草,然后再注入橋梁對象名為Toyun,承載的對象為self即為此控制器,控制器遵守此自定義協(xié)議實現(xiàn)協(xié)議中對應(yīng)的方法祟偷。在JavaStript調(diào)用完本地應(yīng)用的方法做完相對應(yīng)的事情之后,又回調(diào)了JavaStript中對應(yīng)的方法,從而實現(xiàn)了web頁面和本地應(yīng)用之間的通訊。
JavaScriptCore使用注意
JavaStript調(diào)用本地方法是在子線程中執(zhí)行的撩笆,這里要根據(jù)實際情況考慮線程之間的切換捺球,而在回調(diào)JavaScript方法的時候最好是在剛開始調(diào)用此方法的線程中去執(zhí)行那段JavaStript方法的代碼,我在實際運用中開始沒注意歹鱼,就被坑慘了啊泣栈。什么,說的太繞弥姻,看下面的代碼解釋:
// 假設(shè)此方法是在子線程中執(zhí)行的南片,線程名sub-thread
- (void)callCamera {
// 這句假設(shè)要在主線程中執(zhí)行,線程名main-thread
NSLog(@"callCamera");
// 下面這兩句代碼最好還是要在子線程sub-thread中執(zhí)行啊
JSValue *picCallback = self.jsContext[@"picCallback"];
[picCallback callWithArguments:@[@"photos"]];
}
攔截協(xié)議
攔截協(xié)議這個適合一些比較簡單的一些情況庭敦,不需要引入什么框架疼进,只需要web前端配合一下就好。但是在具體調(diào)用哪一個方法上秧廉,以及在傳值的時候可能會有些不方便伞广,而且調(diào)用完后無法在回調(diào)JavaScript的方法
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *url = request.URL.absoluteString;
if ([url rangeOfString:@"toyun://"].location != NSNotFound) {
// url的協(xié)議頭是Toyun
NSLog(@"callCamera");
return NO;
}
return YES;
}
iOS對應(yīng)的代碼的解釋
在webView的代理方法中去攔截自定義的協(xié)議Toyun://如果是此協(xié)議則據(jù)此判斷JavaStript想要做的事情,調(diào)用原生應(yīng)用的方法疼电,這些都是提前約定好的嚼锄,同時阻止此鏈接的跳轉(zhuǎn)。
理解
h5會在點擊某按鈕是發(fā)起url請求蔽豺,而我們可以在代理方法中對該方法進(jìn)行攔截区丑。當(dāng)此功能是開放給native的,web會自定義特定的url開頭茫虽,所以native就可以通過過濾是否是特定的url來攔截此請求刊苍,同時根據(jù)url中的不同信息作出不同響應(yīng)既们。但是native響應(yīng)后無法回調(diào)給h5。