WKWebView原生交互

本来用WKWebViewJavascriptBridge这个三方库,但是前端已经写好了,不愿意在js中加入WKWebViewJavascriptBridge的代码,选择使用wk原生交互

交互不成功

可能是因为前端写法问题
WKWebView原生交互_第1张图片
55555.png

代码

#import 
#import 
// 计算wkWebView进度条
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (object == self.webView && [keyPath isEqualToString:@"estimatedProgress"]) {
        CGFloat newprogress = [[change objectForKey:NSKeyValueChangeNewKey] doubleValue];
        if (newprogress == 1) {
            self.progressView.hidden = YES;
            [self.progressView setProgress:0 animated:NO];
        }else {
            self.progressView.hidden = NO;
            [self.progressView setProgress:newprogress animated:YES];
        }
    }
}

- (WKWebView *)webView
{
    if (!_webView) {
        WKWebViewConfiguration *config = [WKWebViewConfiguration new];
        
        //初始化偏好设置属性:preferences
        config.preferences = [WKPreferences new];
        //The minimum font size in points default is 0;
        config.preferences.minimumFontSize = 10;
        //是否支持JavaScript
        config.preferences.javaScriptEnabled = YES;
        //不通过用户交互,是否可以打开窗口
        config.preferences.javaScriptCanOpenWindowsAutomatically = NO;
        //通过JS与webView内容交互
        config.userContentController = [WKUserContentController new];
        // 注入JS对象名称senderModel,当JS通过senderModel来调用时,我们可以在WKScriptMessageHandler代理中接收到
        [config.userContentController addScriptMessageHandler:self name:@"getStorage"];
        [config.userContentController addScriptMessageHandler:self name:@"setStorage"];
        [config.userContentController addScriptMessageHandler:self name:@"rmStorage"];
        [config.userContentController addScriptMessageHandler:self name:@"navigateTo"];
        [config.userContentController addScriptMessageHandler:self name:@"navigateUrl"];
        [config.userContentController addScriptMessageHandler:self name:@"navigateClose"];
        
        
        _webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-kNavBarBottom) configuration:config];
        _webView.backgroundColor = [UIColor clearColor];
        [_webView setUserInteractionEnabled:YES];//是否支持交互
        _webView.navigationDelegate = self;
        _webView.customUserAgent = @"UTOOCLIENT/IOS/V4";
        
        [_webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
        [self.view addSubview:_webView];
        
        _webView.UIDelegate = self;
    }
    return _webView;
}

#pragma mark -js调用OC的回调
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    NSDictionary *paramaters = message.body;
    NSLog(@"JS 调用了 %@ 方法,传回参数 %@",message.name,paramaters);
    if ([message.name isEqualToString:@"getStorage"])
    {
        
    }
}

问题:通常JS调用native需要返回值

方法一:

在js的回调方法didReceiveScriptMessage被调用后,需要前端配合再写个js的方法,将js调用native的返回值通过native调用js方法把参数传过去。

//js方法
NSString *functionName = [parameters objectForKey:@"funcName"];
        if ([functionName isEqualToString:@"TestEvent"]) {
            NSString *jsFunction = @"window.TestEvent("参数")";
            [self.webView evaluateJavaScript:jsFunction completionHandler:^(id _Nullable data, NSError * _Nullable error) {
                NSLog(@"穿过偶来%@",data);
            }];

方法二: 代理解析

在我们写WKWebView的时候需要遵守WKUIDelegate协议(记得加webView的代理) 其中里面有这几个方法

不再需要didReceiveScriptMessage方法

// 获取js 里面的提示
-(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
    
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }]];
    
    [self presentViewController:alert animated:YES completion:NULL];
}

// js 信息的交流
-(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler
{
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(YES);
    }]];
    [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(NO);
    }]];
    [self presentViewController:alert animated:YES completion:NULL];
}

// 交互。可输入的文本。
-(void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler
{
    
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"textinput" message:@"JS调用输入框" 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]);
    }]];

    [self presentViewController:alert animated:YES completion:NULL];
    
}

以上三个方法都是在js调用alert confirm prompt 的时候 进行拦截 然后弹出系统样式的界面

-runJavaScriptConfirmPanelWithMessage这个代理方法是在JS 调用 alert('xxx')的时候会调用 且回调函数参数为空

-runJavaScriptConfirmPanelWithMessage这个代理方法是在JS调用confirm函数的时候会进行拦截调用 且回调函数参数为Bool值 同步告诉JS 当前用户点击了确定按钮还是取消按钮

-runJavaScriptTextInputPanelWithPrompt 这个代理方法是在JS调用prompt函数的时候进行拦截调用的 且回调函数的参数为NSString类型

我不需要那个弹出窗怎么办 其实你不需要的话 直接在代理方法中写
completionHandler("xxxx");就行 不需要写UIAlertController那一大堆

js写法

js也要修改下代码,不能再用postMessage方式

var JS_Fun_05 = function (){
    var args = arguments;
    var type = "JSbridge";
    var functionName = "OC_Fun_05";
    var payload = {"type": type, "functionName": name, "arguments": args};
    var res = prompt(JSON.stringify(payload));
};

关键代码:window.prompt(text,defaultText);
prompt 就是上面JS text参数

本地修改runJavaScriptTextInputPanelWithPrompt方法

- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{
    NSString *callbackString = @"1";
    
    NSError *err = nil;
    NSData *dataFromString = [prompt dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *parameters = [NSJSONSerialization JSONObjectWithData:dataFromString options:NSJSONReadingMutableContainers error:&err];
    if (!err) {
        NSString *functionName = [parameters objectForKey:@"funcName"];
//做爱    做的事
}
completionHandler(callbackString);
}

你可能感兴趣的:(WKWebView原生交互)