您的位置:首页 > 移动开发 > IOS开发

iOS WKWebView与JS交互及不能释放问题

2017-12-25 10:33 1676 查看
用户操作交互

就是截获JS调用alert、confirm、prompt函数,来使用原生控件实现样式及操作,并将用户操作回调给JS

代理:WKUIDelegate

具体步骤:

1、设置代理

webView.UIDelegate = self;


2、完成代理方法

部分代理方法

// 在JS端调用alert函数时,会触发此代理方法。
// JS端调用alert时所传的数据可以通过message拿到
// 在原生得到结果后,需要回调JS,是通过completionHandler回调
-(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;

// JS端调用confirm函数时,会触发此方法
// 通过message可以拿到JS端所传的数据
// 在iOS端显示原生alert得到YES/NO后
// 通过completionHandler回调给JS端
-(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler;

// JS端调用prompt函数时,会触发此方法
// 要求输入一段文本
// 在原生输入得到文本内容后,通过completionHandler回调给JS
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler;


演示:



自定义方法

就是截获JS调用自定义方法,实现某些功能

代理:WKScriptMessageHandler

具体步骤:

1、注册方法

[webView.configuration.userContentController addScriptMessageHandler:self name:@"copyWeiXinHao"];   // 复制微信号
[webView.configuration.userContentController addScriptMessageHandler:self name:@"goToWeiXinApp"];   // 跳转微信App
[webView.configuration.userContentController addScriptMessageHandler:self name:@"getCurrentContent"];   // 获取原生剪切板内容


2、实现WKScriptMessageHandler方法、注册的方法

// message.name为方法名
// message.body为js传递的参数,是个id类型
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
if ([message.name isEqualToString:@"copyWeiXinHao"]) {
NSString *wxh = message.body;
NSLog(@"微信号:%@",wxh);
[self copyWeiXinHao:wxh];
}
else if ([message.name isEqualToString:@"getCurrentContent"]) {
NSString *content = [self getCurrentContent];
NSString *promptCode = [NSString stringWithFormat:@"getCurrentWeiXinHao(\"%@\")",content];
// OC传递数据给JS
[self.webView.webView evaluateJavaScript:promptCode completionHandler:^(id _Nullable response, NSError * _Nullable error) {
}];
}
else if ([message.name isEqualToString:@"goToWeiXinApp"]) {
[self goToWeiXinApp];
}
}
// 复制微信号
-(void)copyWeiXinHao:(NSString *)wxh{
[[UIPasteboard generalPasteboard] setString:wxh];
}
// 当前剪切板信息
-(NSString*)getCurrentContent{
return [[UIPasteboard generalPasteboard] string];
}
// 跳转微信应用
-(void)goToWeiXinApp{
NSURL *url = [NSURL URLWithString:@"weixin://"];
BOOL canOpen = [[UIApplication sharedApplication] canOpenURL:url];
if (canOpen){   //打开微信
[[UIApplication sharedApplication] openURL:url];
}else {
NSLog(@"您的设备尚未安装微信");
}
}


3、移除监听

-(void)dealloc{
// 根据name移除
[self.webView.webView.configuration.userContentController removeScriptMessageHandlerForName:@"copyWeiXinHao"];
//    [self.webView.webView.configuration.userContentController removeAllUserScripts]; // 移除所有
}


补充:

1、JS传递OC

function 方法名() {
window.webkit.messageHandlers.方法名.postMessage('参数');
}


2、OC传递JS

[webView evaluateJavaScript:@"方法名(参数)" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
}];


演示:



补充:JS文件

<!doctype html>
<html>
<head>
<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, target-densitydpi=device-dpi"/>

<title>JSCallOC</title>

<style>
*
{
//-webkit-tap-highlight-color: rgba(0,0,0,0);
text-decoration: none;
}

html,body
{
-webkit-touch-callout: none;                /* prevent callout to copy image, etc when tap to hold */
-webkit-text-size-adjust: none;             /* prevent webkit from resizing text to fit */
-webkit-user-select: none;                  /* prevent copy paste, to allow, change 'none' to 'text' */
}

#div-a
{
background:#FBA;
color:#FFF;

border-radius: 25px 5px;
}

</style>

</head>

<body style="background:#CDE; color:#FFF">

<div id="div-a">
<center>
<br/>

<input type="button" value=alert onclick="alert('禁止操作');" />
<br/>
<br/>

<input type="button" value="confirm" onclick="confirm('确定提交吗?');" />
<br/>
<br/>

<input type="button" value="prompt" onclick="prompt('请输入姓名');" />
<br/>
<br/>

<input type="button" value="复制微信号" onclick="copyWeiXinHao();" />
<br/>
<br/>

<input type="button" value="跳转微信" onclick="goToWeiXinApp();" />
<br/>
<br/>

<input type="button" value="获取应用剪切板内容" onclick="getCurrentContent();" />
<br/>
<br/>

<a id="push" href="#" onclick="">
xxx
</a>

</center>
</div>

<script type="text/javascript">

function copyWeiXinHao() {
window.webkit.messageHandlers.copyWeiXinHao.postMessage('476512340');
}

function goToWeiXinApp() {
window.webkit.messageHandlers.goToWeiXinApp.postMessage('');
}

function getCurrentContent() {
window.webkit.messageHandlers.getCurrentContent.postMessage('');
}

function getCurrentWeiXinHao(wxh) {
document.getElementById('push').innerText = wxh;
}

</script>

</body>

</html>


demo演示地址

⚠️ 坑:

1、WKWebView执行js代码,要先被加载到父视图上

2、关于不能释放问题的解决方案

思路:另外创建一个弱引用代理对象,然后通过代理对象回调指定的self

.h 文件

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

@interface WeakScriptMessageDelegate : NSObject<WKScriptMessageHandler>

@property (nonatomic,weak)id<WKScriptMessageHandler> scriptDelegate;

- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate;

@end


.m 文件

#import "WeakScriptMessageDelegate.h"

@implementation WeakScriptMessageDelegate
- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate
{
self = [super init];
if (self) {
_scriptDelegate = scriptDelegate;
}
return self;
}

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{

[self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
}
@end


使用

1、导入该类

// addScriptMessageHandler 使用新类

[_webView.configuration.userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"xxxx"];


2、依旧removeAllUserScripts

- (void)dealloc{
[self.webView.configuration.userContentController removeAllUserScripts];
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ios