WKWebKit與JavaScript交互
JS調(diào)用Native
WKWebKit支持JavaScript的3個彈窗函數(shù),WKUIDelegate提供3個代理方法與之對應(yīng)處理
- alert()
js示例代碼
alert('你的操作有誤')
WKUIDelegate代理方法:
- (void)webView:(WKWebView *)webView
runJavaScriptAlertPanelWithMessage:(NSString *)message
initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
//message == “你的操作有誤”
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"確定" style:
UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler();//用戶點擊“確定”通知js回調(diào)
}]];
[self presentViewController:alert animated:YES completion:NULL];
}
- confirm()
js示例代碼
var userOperation = confirm('你確定要刪除嗎赃泡?')
//confirm()的返回值是一個布爾值
WKUIDelegate代理方法:
- (void)webView:(WKWebView *)webView
runJavaScriptConfirmPanelWithMessage:(NSString *)message
initiatedByFrame:(WKFrameInfo *)frame
completionHandler:(void (^)(BOOL result))completionHandler
{
//message == "你確定要刪除嗎来农?"
UIAlertController *alert = [UIAlertController alertControllerWithTitle:
@"警告" message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"是"
style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action){
completionHandler(YES);//回調(diào)給js鞋真,通知用戶點擊了“是”。
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"否"
style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler(NO);//回調(diào)給js沃于,通知用戶點擊了“否”灿巧。
}]];
[self presentViewController:alert animated:YES completion:NULL];
}
- prompt()
js示例代碼
var text = prompt('提示','請輸入你的真實姓名')
//prompt()的返回值是一個字符串
WKUIDelegate代理方法:
- (void)webView:(WKWebView *)webView
runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt
defaultText:(nullable NSString *)defaultText
initiatedByFrame:(WKFrameInfo *)frame
completionHandler:(void (^)(NSString * _Nullable result))completionHandler
{
//prompt == "提示", defaultText == "請輸入你的真實姓名"
UIAlertController *alert = [UIAlertController alertControllerWithTitle:
prompt message:defaultText
preferredStyle:UIAlertControllerStyleAlert];
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.textColor = [UIColor redColor];
}];
[alert addAction:[UIAlertAction actionWithTitle:@"完成"
style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler([[alert.textFields lastObject] text]);
//用戶輸入的文本回調(diào)給js
}]];
[self presentViewController:alert animated:YES completion:NULL];
}
JavaScript調(diào)用Navtive自定義類的接口
WKWebView中的js runtime里事先注入了一個window.webkit.messageHandlers.{NAME}.postMessage()
方法揽涮,我們可以使用這個方法直接向Native層傳一個消息對象抠藕。其中{NAME}
是一個WKScriptMessageHandler
對象的名稱,WKWebView事先注冊這個名稱蒋困,Native接收到JS傳來的消息盾似,可以用這個名稱進行區(qū)別處理。
JS給Native發(fā)送消息對象
var message = {'methodName':methodName,'params':params,'callBackName':callBackName};
window.webkit.messageHandlers.TDWebKit.postMessage(message);
//TDWebKit是iOS客戶端與web端約定好的一個消息處理對象名稱
//message對象具體字段也需要客戶端與web端約定好
js如果需要得到客戶端返回的消息,需要一個寫一個callBack回調(diào)函數(shù)
callBackName:function(data){
//to do something...
},
客戶端創(chuàng)建一個WKScriptMessageHandler
對象來處理JS發(fā)過來的消息對象
TDMessageHandler.h
#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>
#import "FMMacros.h"
extern NSString *const TDWebKit;
@interface TDMessageHandler : NSObject<WKScriptMessageHandler>
SINGLETON_DECLARE()
- (void)joinWebView:(WKWebView *)webView;
@end
TDMessageHandler.m
#import "TDMessageHandler.h"
NSString *const TDWebKit = @"TDWebKit";
@interface TDMessageHandler ()
@property (nonatomic, weak) WKWebView *webView;
@end
@implementation TDMessageHandler
SINGLETON_IMPL(TDMessageHandler)
- (void)joinWebView:(WKWebView *)webView {
self.webView = webView;
}
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
if ([message.name isEqualToString:TDWebKit]) {
NSString *methodName = message.body[@"methodName"];
NSDictionary *params = message.body[@"params"];
NSString *callBackName = message.body[@"callBackName"];
if (callBackName) {
WeakSelf()
[self interactWitMethodName:methodName params:params callBack:^(id response) {
//native調(diào)用js零院,web端需要有一個回調(diào)函數(shù)callBackName(response);
NSString *js = [NSString stringWithFormat:@"%@('%@');",callBackName,response];
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.webView evaluateJavaScript:js completionHandler:^(id _Nullable data, NSError * _Nullable error) {
if (error) {
NSLog(@"native調(diào)用js失敻仍尽: %@",[error localizedDescription]);
}
}];
});
}];
}
else{
[self interactWitMethodName:methodName params:params callBack:nil];
}
}
}
- (void)interactWitMethodName:(NSString *)methodName params:(NSDictionary *)params callBack:(void(^)(id response))callBack{
if (params) {
methodName = [methodName stringByAppendingString:@":"];
if (callBack) {
methodName = [methodName stringByAppendingString:@"callBack:"];
SEL selector = NSSelectorFromString(methodName);
NSArray *paramArray =@[params,callBack];
if ([self respondsToSelector:selector]) {
[self performSelector:selector withObjects:paramArray];
}
}
else {
SEL selector = NSSelectorFromString(methodName);
NSArray *paramArray =@[params];
if ([self respondsToSelector:selector]) {
[self performSelector:selector withObjects:paramArray];
}
}
}
else{
if (callBack) {
methodName = [methodName stringByAppendingString:@":"];
SEL selector = NSSelectorFromString(methodName);
NSArray *paramArray =@[callBack];
if ([self respondsToSelector:selector]) {
[self performSelector:selector withObjects:paramArray];
}
}
else {
SEL selector = NSSelectorFromString(methodName);
if ([self respondsToSelector:selector]) {
[self performSelector:selector withObjects:nil];
}
}
}
}
- (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects {
NSMethodSignature *signature = [self methodSignatureForSelector:aSelector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:self];
[invocation setSelector:aSelector];
NSUInteger i = 1;
for (id object in objects) {
id tempObject = object;
[invocation setArgument:&tempObject atIndex:++i];
}
[invocation invoke];
if ([signature methodReturnLength]) {
id data;
[invocation getReturnValue:&data];
return data;
}
return nil;
}
@end
這里建一個TDMessageHandler的分類,在分類里提供JS發(fā)送消息處理的接口
TDMessageHandler+WebKit.h
#import "TDMessageHandler.h"
@interface TDMessageHandler (WebKit)
- (void)todo;
- (void)share:(NSDictionary *)params callBack:(void(^)(BOOL success))callBack;
- (void)getPhoto:(void(^)(UIImage *image))callBack;
@end
TDMessageHandler+WebKit.m
#import "TDMessageHandler+WebKit.h"
@implementation TDMessageHandler (WebKit)
- (void)todo {
NSLog(@"to do something...");
}
- (void)share:(NSDictionary *)params callBack:(void(^)(BOOL success))callBack {
//params 分享所需要的參數(shù)
if (callBack) {
//分享是否成功回調(diào)給JS
callBack(true);
}
}
- (void)getPhoto:(void(^)(UIImage *image))callBack {
//TODO 調(diào)用系統(tǒng)相機或者相冊
if (callBack) {
//選出的相片回調(diào)給JS
callBack([UIImage new]);
}
}
@end
WKWebView注冊一個名稱為TDWebKit
的TDMessageHandler
對象
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.userContentController = [[WKUserContentController alloc] init];
[config.userContentController addScriptMessageHandler:[TDMessageHandler sharedInstance] name:TDWebKit];
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
Native調(diào)用JS
WKWebView可以事先注入一段JS
NSString JSString = @"js string...";
WKUserScript *usrScript = [[WKUserScript alloc] initWithSource:JSString injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.userContentController = [[WKUserContentController alloc] init];
config.userContentController = [[WKUserContentController alloc] init];
[config.userContentController addUserScript:usrScript];
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
Native調(diào)用JS
[self.webView evaluateJavaScript:@"js.aFunction()" completionHandler:^(id _Nullable data, NSError * _Nullable error) {
if (error) {
NSLog(@"native調(diào)用js失敻娉: %@",[error localizedDescription]);
}
}];