美文网首页
iOS中 wkwebView与js 简单交互

iOS中 wkwebView与js 简单交互

作者: wxw_威 | 来源:发表于2021-06-24 10:42 被阅读0次

iOS 代码

js调用OC 方法

1、添加方法

self.configuration = [[WKWebViewConfiguration alloc] init];
self.configuration.userContentController = [[WKUserContentController alloc] init];
[self.configuration.userContentController addScriptMessageHandler:self name:@"sendEvent"];

2、接收js调用oc 的代理方法

- (void)userContentController:(WKUserContentController*)userContentController didReceiveScriptMessage:(WKScriptMessage*)message {
   //  根据返回的方法名判断
  //message.name
    if ([message.name isEqualToString:@"sendEvent"]) {
    }
}

3、移除js的监听方法

-(void)dealloc {
  [self.configuration.userContentController removeScriptMessageHandlerForName:@"sendEvent"];
}  

oc调用js方法

1、一般是原生导航栏按钮按钮点击事件有H5里的js 方法响应处理。

- (void) handleShareEvent {
    NSString *promptCode = [NSString stringWithFormat:@"callShare()"];      //空字符串
    
//    测试过将字典类型的数据转成字符串,是可以成功的
//    NSDictionary *dic = @{
//        @"key": @"123"
//    };
//    // 字典 => 字符串
//    NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
//    NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//    NSString *promptCode = [NSString stringWithFormat:@"verifyCodeCallback(%@)",string];



//    给js 传值,目前看来只能传一个json过去,如果传一个字典型数组的话,首先要将字典转成字符串,然后再把数组转成字符串
//    NSArray *arr = @[
//        @{@"key": @"123"},
//        @{@"key": @"321"},
//    ];
//    NSMutableArray *marr = [NSMutableArray array];
//    for (NSDictionary *dic in arr) {
//        NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
//        NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//        [marr addObject:s];
//    }
//    NSString *string = [marr componentsJoinedByString:@","];
//    NSString *promptCode = [NSString stringWithFormat:@"verifyCodeCallback([%@])",string];



//    如果是字符串行数组,直接将数组转成字符串就好了
//    NSArray *arr = @[@"1", @"2"];
//    NSString *string = [marr componentsJoinedByString:@","];
//    NSString *promptCode = [NSString stringWithFormat:@"verifyCodeCallback([%@])",string];
    
    
    [self.wkWebView evaluateJavaScript:promptCode completionHandler:^(id object,NSError *error) {
        NSLog(@"js交互error:%@", error);
    }];
}

下面是一个不算太完整、可能有bug、代码比较凌乱的一个小demo。

.h文件

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface CirCleCrmWebViewController : UIViewController

///目标URL
@property (strong, nonatomic) NSURL *homeUrl;

@end

.m 文件

#import "CirCleCrmWebViewController.h"
#import <WebKit/WebKit.h>

#define WebViewNav_TintColor ([UIColor orangeColor])

@interface CirCleCrmWebViewController ()<WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler>

@property (strong, nonatomic) WKWebView *wkWebView;

@property (strong, nonatomic) UIProgressView *progressView;

@property (strong, nonatomic) WKWebViewConfiguration *configuration;
@property (assign, nonatomic) CGFloat safaTop;
@property (assign, nonatomic) CGFloat safabottom;

@end

@implementation CirCleCrmWebViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 初始化视图
    [self initUI];
    
    [self addLeftNavigationItem];

    
}

#pragma mark -- 添加返回按钮
- (void) addLeftNavigationItem {
    UIBarButtonItem *leftButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回"
                                                                  style:UIBarButtonItemStylePlain
                                                                  target:self
                                                                      action:@selector(backBtnPressed:)];
    self.navigationItem.leftBarButtonItem = leftButtonItem;
}

- (void)backBtnPressed:(id)sender {
    if (self.wkWebView.canGoBack) {
        [self.wkWebView goBack];
        if (self.navigationItem.leftBarButtonItems.count == 1) {
            [self configColseItem];
        }
    } else {
        [self closeWebView];
    }
}

- (void)configColseItem {
    
    // 导航栏的关闭按钮
    UIButton *colseBtn = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 44, 44)];
    [colseBtn setTitle:@"关闭" forState:UIControlStateNormal];
    [colseBtn setTitleColor:WebViewNav_TintColor forState:UIControlStateNormal];
    [colseBtn addTarget:self action:@selector(colseBtnPressed:) forControlEvents:UIControlEventTouchUpInside];
    [colseBtn sizeToFit];
    
    UIBarButtonItem *colseItem = [[UIBarButtonItem alloc] initWithCustomView:colseBtn];
    NSMutableArray *newArr = [NSMutableArray arrayWithObjects:self.navigationItem.leftBarButtonItem,colseItem, nil];
    self.navigationItem.leftBarButtonItems = newArr;
}

// 关闭按钮点击
- (void)colseBtnPressed:(id)sender {
    [self closeWebView];
}

#pragma mark -- 添加导航栏右侧按钮
- (void) addRightNavigationItem:(NSDictionary *)body {
    
    // 发送按钮
    UIButton *sendButton=[UIButton buttonWithType:UIButtonTypeCustom];
    [sendButton addTarget:self action:@selector(sendCopywritingClick:) forControlEvents:UIControlEventTouchUpInside];
    [sendButton setTitle:@"发送" forState:UIControlStateNormal];
    [sendButton setTitleColor:[UIColor systemBlueColor] forState:UIControlStateNormal];
    sendButton.frame=CGRectMake(0, 0, 40, 40);

    UIBarButtonItem *writingSendItem = [[UIBarButtonItem alloc] initWithCustomView:sendButton];

    [self.navigationItem setRightBarButtonItems:[NSArray arrayWithObjects: writingSendItem,nil]];

}

- (UIImage *)reSizeImage:(UIImage *)image toSize:(CGSize)reSize
{
    UIGraphicsBeginImageContext(CGSizeMake(reSize.width, reSize.height));
    [image drawInRect:CGRectMake(0, 0, reSize.width, reSize.height)];
    UIImage *reSizeImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return [reSizeImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
}


// 事件 - 发送
- (void)sendCopywritingClick:(id) sender {
    [self handleSenderEvent];
}


#pragma mark -- 关闭页面
- (void) closeWebView {
    [self dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark --- 初始化UI
- (void) initUI {
    self.safaTop = 0;
    
    if (@available(ios 11.0,*)) {
        UIWindow *window = UIApplication.sharedApplication.keyWindow;
        self.safaTop = window.safeAreaInsets.top;
        self.safabottom =  window.safeAreaInsets.bottom;
    }
    
    [self initWkWebView];
    
//    初始化进度条
    [self initProgressView];
    
    [self.wkWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
}

// 初始化wkwebview
- (void)initWkWebView {
    // 注入 js 方法
    self.configuration = [[WKWebViewConfiguration alloc] init];
    self.configuration.userContentController = [[WKUserContentController alloc] init];
    [self.configuration.userContentController addScriptMessageHandler:self name:@"sendEvent"];

    self.configuration.preferences.javaScriptEnabled = YES;
    
    WKPreferences *preference = [[WKPreferences alloc]init];
    /// 最小字体大小 当将javaScriptEnabled属性设置为NO时,可以看到明显的效果
    preference.minimumFontSize = 1.0;
    /// 设置是否支持javaScript 默认是支持的
    preference.javaScriptEnabled = YES;
    /// 在iOS上默认为NO,表示是否允许不经过用户交互由javaScript自动打开窗口
    preference.javaScriptCanOpenWindowsAutomatically = YES;
    self.configuration.preferences = preference;
    
    self.wkWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 44 + self.safaTop, self.view.frame.size.width, self.view.frame.size.height - self.safabottom - self.safaTop - 44) configuration:self.configuration];
    self.wkWebView.UIDelegate = self;
    self.wkWebView.navigationDelegate = self;
    self.wkWebView.allowsBackForwardNavigationGestures = NO;
    
    [self.wkWebView loadRequest:[NSURLRequest requestWithURL:self.homeUrl]];
        
    [self.view addSubview:self.wkWebView];
}

- (void)initProgressView {
    self.progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 44 + self.safaTop , self.view.frame.size.width, 1)];
    
    self.progressView.progressTintColor = [UIColor systemBlueColor];
    self.progressView.trackTintColor = [UIColor whiteColor];
    
    self.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
    [self.view addSubview:self.progressView];
}

- (void)reloadReqeust {
    [self.wkWebView reload];
}

// 显示提示框
- (void) showAlertView:(NSString *)content {
    UIAlertController *alertC = [UIAlertController alertControllerWithTitle:@"" message:content preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *cancelActio = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
    }];
    [alertC addAction:cancelActio];
    [self presentViewController:alertC animated:YES completion:nil];
}

// 显示弹框
- (void)showAlert {
    UIAlertController *alertC = [UIAlertController alertControllerWithTitle:@"" message:@"加载失败,退出重新加载。" preferredStyle:UIAlertControllerStyleAlert];
    
    __weak typeof(self) weakself=self;
    UIAlertAction *sureAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        [weakself closeWebView];
    }];
    
    [alertC addAction:sureAction];
    [self presentViewController:alertC animated:YES completion:nil];
}

//监听wkwebview 进度条变化
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"estimatedProgress"]) {
        self.progressView.progress = self.wkWebView.estimatedProgress;
        if (self.progressView.progress == 1) {
            /*
             *添加一个简单的动画,将progressView的Height变为1.4倍,在开始加载网页的代理中会恢复为1.5倍
             *动画时长0.25s,延时0.3s后开始动画
             *动画结束后将progressView隐藏
             */
            __weak typeof (self)weakSelf = self;
            [UIView animateWithDuration:0.25f delay:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{
                weakSelf.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
            } completion:^(BOOL finished) {
                weakSelf.progressView.hidden = YES;
            }];
        }
    }else{
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

#pragma mark -- 加载进度条
#pragma mark -- 开始加载
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
    NSLog(@"开始加载网页");
    //开始加载网页时展示出progressView
    self.progressView.hidden = NO;
       //开始加载网页的时候将progressView的Height恢复为1.5倍
    self.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
}

#pragma mark -- 加载完成
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    NSLog(@"加载完成");
}

#pragma mark -- 开始失败
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
    NSLog(@"加载失败");
    [self showAlert];
}

#pragma mark -- WKScriptMessageHandler
- (void)userContentController:(WKUserContentController*)userContentController didReceiveScriptMessage:(WKScriptMessage*)message {
    NSLog(@"js 调用OC 方法,回调!");
    NSLog(@"返回的数据:%@", message.body);
    if ([message.name isEqualToString:@"sendEvent"]) {
        [self handleSendWithJSEvent:message.body];
    } 
    
}

#pragma mark -- js 交互事件处理
// 标题
- (void) handleSendWithJSEvent:(NSDictionary *)body {
    self.title = [body objectForKey:@"title"];
    
    [self addRightNavigationItem:body];
}

#pragma mark -- oc 调用js 方法

- (void)handleSenderEvent {
    NSString *promptCode = [NSString stringWithFormat:@"callSend()"];
    [self.wkWebView evaluateJavaScript:promptCode completionHandler:^(id object,NSError *error) {
        NSLog(@"js交互error:%@", error);
    }];
}
- (void) closeH5Dialog {
    NSString *promptCode = [NSString stringWithFormat:@"callCloseShareDialog()"];
    [self.wkWebView evaluateJavaScript:promptCode completionHandler:^(id object,NSError *error) {
        NSLog(@"js交互error:%@", error);
    }];
}

- (void) takeScreenShotEvent {
    NSString *promptCode = [NSString stringWithFormat:@"screenShotEvent()"];
    [self.wkWebView evaluateJavaScript:promptCode completionHandler:^(id object,NSError *error) {
        NSLog(@"js交互error:%@", error);
    }];
}

#pragma mark -- 发布通知
// 发布通知
- (void) sendNotification:(NSDictionary *)dic {
    
    [[NSNotificationCenter defaultCenter] postNotificationName:YQKETOXCSHAREPLATENOTIFICATION object:nil userInfo:dic];
}

-(void)dealloc {
    // 离开页面移除js监听方法
    [self.configuration.userContentController removeScriptMessageHandlerForName:@"sendEvent"];
}

@end

HTMl 代码

js 调用oc 方法

window.webkit.messageHandlers.setPageTitle.postMessage({title: 'test'})

js 调用android 方法

window.client.setPageTitle({title: 'test'})

oc 调用 JS 方法, android 调用js 方法也可以这么写,但是我记得android调用的方法可以不用在mounted()中去声明

  mounted() {
    window.verifyCodeCallback = this.verifyCodeCallback;
  },
  method: {
    verifyCodeCallback(v) {
      this.content = v
      alert(v)
    }
  }

有问题欢迎指出!

相关文章

网友评论

      本文标题:iOS中 wkwebView与js 简单交互

      本文链接:https://www.haomeiwen.com/subject/xdjwyltx.html