首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

专为你定制的 JS/Natvie 交互专题

2018 年距离第一代 iOS 系统发布(2007 年)已经过去 11 年,这 11 年中移动端日益成熟,Web 端的时代逐步转移到了移动端,自然而然 Web 端的开发技术栈开始逐步移动到移动端。这就引发一个尴尬的局面,Web 端的同学不了解移动端的开发知识,移动端不了解 Web 端的开发知识。为了解决这个问题,知识小集打算从基础出发,介绍 JavaScript 与 iOS 交互时用到的技术点,比如 JavaScriptCore、JavaScript 基础、JavaScriptCore 的实际使用场景(深度刨析 JSPatch 的实现)等。而今天这篇就是其中的一篇,主要介绍一个 Hybrid WebView 的实现。接下来我们会把文章逐步发出来供我们的读者朋友参考,我们初步定的目录如下(如果你不想错过我们这个专题,关注我们的公众号【知识小集】吧,关于这个专题有什么建议都可以通过公众号告诉我们):

前言

JavaScript 基础知识

JavaScript 进阶

JavaScript-native 调试

开启本地 Webserver

WKWebView 概述

JavaScriptCore 总览

JavaScript 与 ObjectiveC 间的类型转换

JavaScript 与 ObjectiveC 通信

ObjectiveC 与 JavaScript 通信

自己动手实现一个 Hybrid WebView

JSPatch 中的 JavaScriptCore

JSPatch 中的 Runtime

JSPatch 原理深度刨析

JSPatch 杂谈

读 Aspects 理解 runtime

自己动手实现一个 Hybrid WebView

如今,端与 Web 页的交互越来越频繁,很多页面都交给 Web 页面来实现,而有些情况下 Web 需要与端进行交互。面对这种需求,各种第三方库源源不断出现,而 WebViewJavascriptBridge 无疑是 star 最多的一个。其实目前在 iOS 开发当中,大多数都切换到了 WKWebView,且对 Web 的交互越来越重,所以不妨自己实现一个 Hybrid WebView 来满足自己的业务需求。一个 Hybrid WebView 最基本的应该满足双方可以自由通信。

WebView 上的事件可以传递到端上;

WebView 可以从端上获取数据;

端可以监听到 WebView 上发生的事件。

本文旨在说明一个 Hybrid WebView 需要的技术手段,所以打算从一个具体的需求出发,一步一步搭建一个 Hybrid WebView。大多数的文章只会讲解端上如何实现,而本文会结合前端一块讲讲两端是如何实现的。

需求说明

Web 页面上有一张图和一个保存按钮,当点击保存按钮时会提示用户是否需要保存图片到相册。如果保存成功,按钮的标题将变为已保存,否则标题为保存到相册。如果已保存,下次进入 Web 页时显示已保存。

分析上面的需求,可以拆分为:

页面加载后,需要获取图片是否已经保存过,如果已保存,按钮的标题为“已保存”,否则为“保存到相册”;

点击按钮需要提示用户“是否需要保存图片到相册”,点击“保存”执行保存操作。点击取消将什么也不做;

保存成功,按钮上的标题需要变为“已保存”。

分析完上面具体需求后,转换为技术需要考虑的问题:

页面加载后,Web 页可以从端上获取到图片是否已经保存的状态;

点击保存按钮,需要在端上提示用户,用户点击保存需要把图片保存到相册,这时需要获取到当前显示的图片,也就是说需要把 Web 页面中的数据传递到端;

保存成功后需要修改 Web 页面按钮的标题。

先做一个 Web 页面

整体页面是如上图所示。我们逐步刨析是如何实现的。

在前面的章节中(这些章节后续会发出来),已经介绍了在 Web 页面中执行 JavaScript 。可以把一段 JavaScript 代码嵌入到 HTML 中,这时在 HTML 中可以直接调用 JavaScript 代码,而 JavaScript 可以通过 DOM 动态来操作 HTML 中的标签,这样即可以达到动态修改 Web 页的目的。

Web与端通信的JS代码,这段代码是嵌入在 HTML 中的。

// 标记保存的状态

varsaved =false;

// 保存事件

functionsaveaction(){

if(saved) {

return;

}

alert("确定要保存该图片吗?");

// 发送消息给客户端 JS 中发送消息给 OC

varparam = {url:"https://raw.githubusercontent.com/iOS-Tips/iOS-tech-set/master/images/qrcode.jpg"};

window.webkit.messageHandlers.JSBridge.postMessage(JSON.stringify(param));

};

// 保存成功后端会调用这个方法通知Web页保存成功

functionsave_success(){

change_state(true);

};

// 修改是否已保存的状态,修改按钮标题

functionchange_state(issaved){

saved = issaved;

varbutton =document.getElementById('saveid');

if(issaved){

// 如果已经保存,修改按钮的标题为已保存,否则显示 保存到相册

button.innerText ="已保存";

}else{

button.innerText ="保存到相册";

}

}

保存到相册按钮,监听点击事件,当点击按钮后会调用 函数。

保存到相册

而 函数首先会发一个 到端,端会执行 代理方法,我们在这个方法中需要弹出端内的提示框:

- (void)webView:(WKWebView*)webView runJavaScriptAlertPanelWithMessage:(NSString*)message initiatedByFrame:(WKFrameInfo*)frame completionHandler:(void(^)(void))completionHandler

{

UIAlertController*alert = [UIAlertControlleralertControllerWithTitle:@"温馨提示"message:message preferredStyle:UIAlertControllerStyleAlert];

[alert addAction:[UIAlertActionactionWithTitle:@"保存"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction* _Nonnull action) {

self.isOKAction =YES;

completionHandler();

}]];

[alert addAction:[UIAlertActionactionWithTitle:@"取消"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction* _Nonnull action) {

self.isOKAction =NO;

completionHandler();

}]];

[selfpresentViewController:alert animated:YEScompletion:nil];

}

当用户点击保存按钮后,会保存图片到相册。所以客户端需要拿到图片的地址,这是需要给端发送图片的地址。如果想给端发送一条消息,直接在 Web 页通过 JavaScript 执行,其中 xxxx 是端与Web之间约定的名字。

而我们此时定义的名字是 ,当用户点击保存后,需要根据Web传递过来的 URL 保存图片。

varparam = {url:"https://raw.githubusercontent.com/iOS-Tips/iOS-tech-set/master/images/qrcode.jpg"};

window.webkit.messageHandlers.JSBridge.postMessage(JSON.stringify(param));

当端接收到 Web 发过来的消息后,会调用 的代理方法,在这个方法中我们来下载图片并保存到相册:

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

{

if([message.body isKindOfClass:[NSStringclass]]) {

if([message.name isEqualToString:kScriptMsgName] &&self.isOKAction) {

// 保存图片

NSDictionary*msgInfo = [NSJSONSerializationJSONObjectWithData:[message.body dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragmentserror:nil];

UIImage*image = [[UIImagealloc] initWithData:[NSDatadataWithContentsOfURL:[NSURLURLWithString:msgInfo[@"url"]]]];

if(image) {

UIImageWriteToSavedPhotosAlbum(image,self,@selector(imageSavedToPhotosAlbum:didFinishSavingWithError:contextInfo:),nil);

}

}

}

}

当把图片保存到相册后,需要刷新 Web 页面上的按钮的标题,这时需要执行 Web 页中已经定义好的 方法:

- (void)updateSaveState:(BOOL)isSave

{

NSString*script = isSave ?@"change_state(true);":@"change_state(false);";

[self.webView evaluateJavaScript:script completionHandler:^(id_Nullable msg,NSError* _Nullable error) {}];

}

至此,我们还剩下最后一件事没有完成,当加载出 WebView 后,需要根据本地是否已经保存了图片更新按钮的标题,直接调用 函数即可。

总结

本文主要介绍一个 Hybrid WebView 如何实现,它仅仅是从一个具体的需求出发,而如果做一个通用 Hybrid WebView 框架需要两端设计一种通信规则。具体细节可以参考味精的两篇关于 Hybrid 的实践 (从零收拾一个hybrid框架)。本文的 demo 会在这个专题完成后一块放出。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180717G083RL00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券