本来用WKWebViewJavascriptBridge这个三方库,但是前端已经写好了,不愿意在js中加入WKWebViewJavascriptBridge的代码,选择使用wk原生交互
交互不成功
可能是因为前端写法问题代码
#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);
}