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

Swift-WKWebView与JavaScript的细节,H5页面跳转原生界面

2017-07-04 12:02 344 查看
大家(也包括我)要学会 明白一件事情(注意断句,哈哈)。优秀的程序猿会将问题简单化。

世界上有10种人,一种是先把问题复杂化,然后在一点点的做减法;另一种是先把问题简单化,然后在慢慢的做加法;(好了该进入正题了哈哈!) 文中有源码地址

一,加载HTML的几种方式

/**
*  1,加载网络html
*/
NSString * surl = @"http://192.168.3.134:7080/toCompanyTouch";
NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:surl]];
[self.wkwebView loadRequest:request];
/**
*  2,加载本地html 资源(内容)
*/
NSURL * url =[[NSBundle mainBundle] URLForResource:@"testH5" withExtension:@"html"];
NSString *path = [[NSBundle mainBundle] pathForResource:@"testH5" ofType:@"html"];
NSString * htmlString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[self.wkwebView loadHTMLString:htmlString baseURL:url];
/**
*  3,加载本地html url
*/
NSURL * url2 =[[NSBundle mainBundle] URLForResource:@"testH5" withExtension:@"html"];
[self.wkwebView loadFileURL:url2 allowingReadAccessToURL:url2];


Native和js交互没有想象中那么不着边际

二,UIWebView与JS交互

首先使用到
<JavaScriptCore/JavaScriptCore.h>
框架中的
JSContext
JSExport
对象。

JSContext
Native和JS交互时,连接两者的上下文,

JSExport
Native和JS交互协议。(实现方法调用时必须实现的协议)

然后通过
KVC
的方式获得
JSContext
(上线时可能有风险,还可以通过KVO的方式获得)

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
JSContext * context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
// self 是装有 UIWebView的控制器,并且它遵守了 JSExport 协议
//把self这个对象放到上下文中,通过VC这个key可以找到self这个对象
[context setObject:self forKeyedSubscript:@"VC"];
}


在然后就可以在
JS
页面中使用这个
VC
了,
VC
能对应上
OC
中那个
controller


不要忘记在
UIViewController
中遵守并实现
JSExport


//遵守协议
@protocol JS_OCCOnnectProtocolInWeb <JSExport>
- (void)testLog:(NSDictionary*)dict;
@end
@interface UIWeb_VC () <UIWebViewDelegate,JS_OCCOnnectProtocolInWeb>
@property UIWebView * webView;
@end

@implementation UIWeb_VC
//实现协议方法
- (void)testLog:(NSDictionary*)dict
{
NSLog(@"---testLog--");
NSLog(@"dict=[%@]",dict);
}
@end


最后在
js
中调用就方便了

<button onclick="VC.testLog({'page':'testVC'})">UIWeb测试</button>


打印信息如下

2017-12-06 15:18:58.645195+0800 TestHybriod[2378:1026324] ---testLog--
2017-12-06 15:18:58.646071+0800 TestHybriod[2378:1026324] dict=[{
page = testVC;
}]


三,WKWebView与JS交互

1,
WebKit
WKWebView
使用的是
Safari
的浏览器内核,在性能上高于
UIWebView


wk的交互需要用到
MessageHandler
,在实例化
WKWebView
时配置一下
WKUserContentController
,并且遵守
WKScriptMessageHandler
协议实现他的方法

- (void)viewDidLoad {
[super viewDidLoad];
WKWebViewConfiguration * config = [[WKWebViewConfiguration alloc]init];
config.userContentController =[[WKUserContentController alloc]init];
//意思是将名字为 ocWkModth 的方法注册到js中
[config.userContentController addScriptMessageHandler:self name:@"ocWkModth"];
self.wkwebView = [[WKWebView alloc]initWithFrame:self.view.boundsconfiguration:config];
}


WKScriptMessageHandler
协议的方法。在这里可以接收到
js
传来的参数

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
NSLog(@"body=[%@]",message.body);
NSLog(@"name=[%@]",message.name);
NSLog(@"frameInfo.absoluteString=[%@]",message.frameInfo.request.URL.absoluteString);

}


在JS中调用如下方法可以将信息传递到OC的
WKScriptMessageHandler
协议方法中

<a class="test-btn" onclick="window.webkit.messageHandlers.ocWkModth.postMessage({'page':'testVC','result':'success'})">测试</a>


打印信息如下

2017-12-06 14:24:47.955640+0800 TestHybriod[2047:784478] body=[{
page = testVC;
result = success;
}]
2017-12-06 14:24:47.955845+0800 TestHybriod[2047:784478] name=[ocWkModth]


源码-地址

四,其他粗暴的方法

在Native和js交互肯定是需要一个桥梁,在UIWebView中使用的是下面这个方法

webView.stringByEvaluatingJavaScript(from: "document.getElementById('index-kw').value = '1234';");


在WKWebView中使用的是

webView.evaluateJavaScript("document.getElementById('index-kw').value = '1234abcd';") { (any, err) -> Void in
NSLog("any=" + (any as! String));
}
/*其实就是这个样子的,后面是swift的闭包*/
webView.evaluateJavaScript("document.getElementById('index-kw').value = '1234abcd';", completionHandler: nil);


这两个方法是有返回值的,返回值就是html5页面中 element的value(可以片面的理解为UILable的text),虽然这个方法能执行JavaScript的代码,但只局限为可操作的一些元素和方法,这里给大家解释一下js一些简单的方法

/*通过这个id可以得到某个元素或者标签*/
var lable_btn = document.getElementById('某个元素或者标签的id');
/*可以set和get元素或者标签的value*/
lable_btn.value = 'value的值';
/*通过这个ClassName可以得到某个元素或者标签  的数组*/
var nodesInput = document.getElementsByClassName('input');
nodesInput[0].value = 'test';


在h5页面加载完成后,执行以下操作

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {

webView.evaluateJavaScript("document.getElementById('index-kw').value = '1234';", completionHandler: nil);

/*其实就是这个样子的,后面是swift的闭包*/
webView.evaluateJavaScript("document.getElementById('index-kw').value = '1234abcd';") { (any, err) -> Void in
/*any 其实就是返回值*/
NSLog("any=" + (any as! String));
}

}


*效果如下,其中 index-kw 是百度收索框的元素 id,给这个id的value,赋值。出现如下效果

这就是一个简单的交互*



但在实际开发中可能需要一些更高级的交互,这里没有使用网上的一些框架

/*这里可以监听和拦截 h5 页面的 alert*/
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
if message == "商量好的信息" {
/*这里可以谈一个native的弹窗*/
//UIAlertController ....
}
}


五,其他的交互机制–拦截机制

======H5页面跳转原生界面======

1,项目配置

在 info 里面 添加 URL Schemes

我在里添加的是
com.sir.pppig




然后在 appDegelate.m 中,监听

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
NSLog(@"----]");
if (!url) {  return NO; }
// 可以在这里处理打开APP后的 业务逻辑
NSLog(@"new url= [%@]", url);
return YES;
}


2,第一种 事件触发

然后在浏览器中输入 com.sir.pppig://, 就可以打开APP了,



点击 open ,打开APP,



3,第二种事件触发

在h5页面触发,

<div>
<h1>测试页面</h1>
<a id="openApp" href="com.sir.pppig://" style="border-radius: 0.05rem; display:block;margin:0 auto;padding:.1rem;color:#fff;background:#f07a0e;width:1.2rem;margin-bottom:.2rem;">打开APP</a >
<script>
document.getElementById('openApp').onclick = function (e) {
/* location.href = 'com.sir.pppig://';
setTimeout(function() {
location.href = '/toAppMobilePageTouch';
}, 250);
setTimeout(function() {
location.reload();
}, 1000); */
/*  var ifr = document.createElement('iframe');
ifr.src = 'com.sir.pppig://';
ifr.style.display = 'none';
document.body.appendChild(ifr);
setTimeout(function(){
document.body.removeChild(ifr);
}, 3000); */
}
</script>
</div>


开发中可能会遇到这样的需求:从Native跳转到H5页面需要将用户信息传递或者携带过去!!!有没有遇到过。反正我是遇到过!

遇到这样的需求,是需要结合实际情况的。

如果移动端后台和h5(PC端)用的同一个Web项目,那么实现这个效果不难,一般用sessionId或者是UserId来标识用户,作为用户的识别码。如果他们在同一个后台项目,那么在跳转到h5页面时,可以将 sessionId或者是UserId 以参数的形式传递过去(可以理解为GET请求,但是要注意安全性),那么可以在h5页面得到用户信息

如果 移动端后台和h5(PC端)用的不是同一个Web项目,那么实现起来难,而且效率低,这里不说明!

有时候用户在webView上的数据希望能保留一段时间,那么可以让h5的开发人员,做一下localStorage或者cookie技术!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript swift
相关文章推荐