WKWebKit与JavaScript交互

WKWebKit与JavaScript交互

JS调用Native

WKWebKit支持JavaScript的3个弹窗函数,WKUIDelegate提供3个代理方法与之对应处理

  • 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回调
                      }]];
    
    [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);//回调给js,通知用户点击了“是”。
                                              }]];
    [alert addAction:[UIAlertAction actionWithTitle:@"否"
                                              style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
                                                  completionHandler(NO);//回调给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]);
                                                      //用户输入的文本回调给js
                                                  }]];
        
   [self presentViewController:alert animated:YES completion:NULL];
}

JavaScript调用Navtive自定义类的接口

WKWebView中的js runtime里事先注入了一个window.webkit.messageHandlers.{NAME}.postMessage()方法,我们可以使用这个方法直接向Native层传一个消息对象。其中{NAME}是一个WKScriptMessageHandler对象的名称,WKWebView事先注册这个名称,Native接收到JS传来的消息,可以用这个名称进行区别处理。

JS给Native发送消息对象

var message = {'methodName':methodName,'params':params,'callBackName':callBackName};
window.webkit.messageHandlers.TDWebKit.postMessage(message);
//TDWebKit是iOS客户端与web端约定好的一个消息处理对象名称
//message对象具体字段也需要客户端与web端约定好

js如果需要得到客户端返回的消息,需要一个写一个callBack回调函数

callBackName:function(data){
    //to do something...
},

客户端创建一个WKScriptMessageHandler对象来处理JS发过来的消息对象

TDMessageHandler.h

#import 
#import 
#import "FMMacros.h"

extern NSString *const TDWebKit;

@interface TDMessageHandler : NSObject
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调用js,web端需要有一个回调函数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调用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发送消息处理的接口

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 分享所需要的参数
    if (callBack) {
         //分享是否成功回调给JS
        callBack(true);
    }
}

- (void)getPhoto:(void(^)(UIImage *image))callBack {

    //TODO 调用系统相机或者相册
    if (callBack) {
       //选出的相片回调给JS
        callBack([UIImage new]);
    }
}

@end

WKWebView注册一个名称为TDWebKitTDMessageHandler对象

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调用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调用JS

[self.webView evaluateJavaScript:@"js.aFunction()" completionHandler:^(id _Nullable data, NSError * _Nullable error) {
                        
       if (error) {
           NSLog(@"native调用js失败: %@",[error localizedDescription]);
       }
                        
 }];

你可能感兴趣的:(WKWebKit与JavaScript交互)