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)
}
}
有问题欢迎指出!
网友评论