七行JSON代码将你的网站变成移动应用

七行JSON代码将你的网站变成移动应用


image.png

做者|Ethan译者|大愚若智编辑|覃云本文介绍了借助 Jasonette 将 Web 视图和原生组件融合构建真正“混合”应用的作法。html

image.png


若是我告诉你,只须要 上述 7 行橙色的 JSON 代码 就能够将一个网站变成移动应用,你相信吗?彻底不须要使用某种框架 API 重写网站,就能够得到与移动应用相同的行为。若是你已经有一个现成的网站,只须要简单地引用 URL 就能够将其“打包”为原生应用。前端

而若是在此基础上,只须要略微调整 JSON 代码内容,就能够直接访问全部原生 API、原生 UI 组件以及原生视图切换(View Transition)。git

最简化的范例效果以下图所示:image.pnggithub


从中能够看出,我嵌入了一个 GitHub.com 的 Web 页面,但界面上其他布局均为原生 UI 组件,例如 导航条 以及 底部的标签栏。而咱们并不须要使用任何 API 重写网站,就能够自动得到原生的切换效果。web

在介绍具体作法前你可能会问:“看着挺酷,但除了在原生应用框架内展现 Web 页面以外,这种技术还有什么意义?”json

问得好!这也是本文要讲的重点。咱们只须要建立一个无缝的 Web 视图与应用间双向通讯,借此,父应用就能够触发 Web 视图内的任何 JavaScript 函数,随后 Web 视图便可从外部调用原生 API。数组

例如:image.png浏览器

请注意,这个视图包含:微信

  1. 原生导航条,以及内置的切换功能前端工程师

  2. 一个 Web 视图,其中嵌入了一个能够生成二维码的 Web 应用

  3. 在底部包含一个原生的文字输入组件

上述全部这一切只须要略微调整 JSON 代码的属性便可实现。

最后请注意,随着在文字输入区输入不一样内容,二维码也会产生相应变化。输入的文字可触发二维码生成器 Web 应用内部的 JavaScript 函数从新生成二维码图像。

目前尚未任何一个开发框架曾试图从根本上解决“Web 视图与原生应用无缝集成”的问题,由于这些框架都专一于彻底原生,或彻底 HTML5 的作法。

不管何时当咱们听到有人讨论移动应用的将来时,极可能会听到相似“究竟是 HTML5 仍是原生方法会最终胜出呢?”这样的说法。

彷佛没人以为nativehtml能够共存,并且两者的协同和最终实现彷佛也并不容易。

本文我将要介绍:

  • 为什么 Web 引擎与原生组件的融合一般是一种更好的作法。

  • 为什么 HTML 与原生的无缝集成那么难,具体又该如何实现。

  • 更重要的是,该如何使用这样的技术快速构建本身的应用。

为什么要在原生应用中使用 HTML?

在进一步介绍前,首先一块儿看看这样作是好是坏,以及何时适合使用这种方法。这种作法的一些潜在用例以下:

 1. 使用 Web 原生功能

应用中的部份内容使用 Web 引擎来实现也许是一种更适合的作法。例如 WebSocket 是一种原生的 Web 功能,主要面向 Web 环境而设计。这种状况下就更适合使用内建的 Web 引擎(iOS 的 WKWebView 以及 Android 的 WebView),而非安装某些只能“模拟”WebSocket 的第三方库。

无需额外安装任何代码,使用免费工具便可实现目标,这样岂不是更好。同时这也催生了下一个缘由。

 2. 避免二进制文件体积过大

有些功能也许须要借助庞大的第三方库,而你可能但愿能快速用上这样的功能。

例如,为了以原生方式包含二维码图像生成器,可能须要安装某些第三方库,这会致使二进制文件体积增大。但若是使用 Web 视图引擎并经过一个简单的<script src>调用 JavaScript 库,就能够免费实现这一切,而且避免了使用第三方原生库。

 3. 缺少可靠的移动库

对于一些前沿技术,可能暂时并不具有稳定可靠的移动端实现。

好在大部分此类技术都具有 Web 实现,所以最高效的集成方法就是使用 JavaScript 库。

 4. 构建部分原生,部分基于 Web 的应用

不少新手开发者想要将本身的网站移植为移动应用,但在发现本身现有网站的部分功能过于复杂,没法面向每种移动平台快速重写时,每每会感到沮丧或受挫。

例如你可能有一个很是复杂的 Web 页面没法快速转换为移动应用,但网站的其余内容能够很容易地转换。

面对这种状况,若是经过某种方法将应用的大部份内容以原生方式构建,对于特别复杂的页面直接将其以 HTML 的形式无缝集成到应用中,是否是很棒啊。

这是如何实现的? A. Jasonette

Jasonette 是一种基于标记语言,构建跨平台原生应用的开源方法。

该技术看似 Web 浏览器,但并不会将 HTML 标记语言解释为 Web 页面,而是会将 JSON 标记解释为 iOS 和 Android 上的原生应用。

正如全部 Web 浏览器都有彻底相同的代码,但只要按需解释不一样类型的 HTML 标记,便可为用户提供全部不一样类型的 Web 应用,全部 Jasonette 应用也有着彻底相同的库,可按需解释不一样类型的 JSON 标记并建立出你的应用。开发者彻底无需触及代码自己,只须要编写标记,将代码实时“翻译”为原生应用,便可开发出本身的应用来。

虽然 Jasonette 的核心做用在于构建原生应用,但本文的重点在于介绍如何将 HTML 集成到核心原生引擎中,接下来就一块儿了解一下吧。

 B. Jasonette Web 容器

原生应用很棒,但有时候咱们依然须要使用 Web 功能。

但 Web 视图与原生应用的集成是个麻烦的过程。无缝的集成要求:

  1. Web 视图应做为原生布局的一部分进行集成:Web 视图应做为原生布局的一部分归入应用中,而且操做方式应与其余任何原生 UI 组件保持一致。不然会让用户感受很笨拙,而且感受上就像本身其实是在访问网站那样。

  2. 父应用能够控制子 Web 容器:父应用应能随意控制子 Web 视图。

  3. 子 Web 容器可触发父应用的原生事件:子应用应该能触发父应用的事件以运行原生 API。

这是一个很是繁重的工做,所以先从第一个环节着手介绍:直接将 Web 容器嵌入原生布局 —并将其做为第 1 版发布:

JSON Web 容器,JSON 中的 HTML 将变为原生应用组件。

仅这一点就已经很实用了,但因为没法交互,依然存在必定的局限。

父应用没法控制子 Web 容器,子容器没法向父应用发送任何事件通知,这 致使 Web 容器与外界彻底隔离

 C. Jasonette Web 容器 2.0:使其可交互

发布第 1 版以后,咱们开始处理第二个问题:为 Web 容器添加交互能力

下文将介绍如何为以前建立的静态 Web 容器添加交互能力,让它变得更强大。

实现:交互式 Web 容器1. 经过 URL 加载 问题

以前在第 1 版中,为了使用 Web 容器做为后台视图组件,咱们首先须要将$jason.body.background.type设置为"html",随后在$jason.body.background.text属性下添加硬编码的 HTML 文本,例如这样:image.png

通常来讲,人们每每更但愿直接使用 Web URL 对容器进行实例化,而不但愿将整个 HTML 代码以硬编码的方式做为一行代码加入。

 解决方案

Web 容器 2.0 增长了url属性,咱们能够嵌入file://形式的本地 HTML,例如这样(能够从伴随应用发布的本地 HTML 文件加载):image.png

或者也能够嵌入远程的http[s]:// URL,例如这样(能够从远程 HTML 加载):image.png

2. 父应用与 Web 容器的双向通讯 问题

以前,Web 容器只能用于展现内容,没法交互。这意味着 下列作法所有没法实现

  1. Jasonette 到 Web 容器的通讯:从 Jasonette 中调用 Web 容器内部的 JavaScript 函数。

  2. Web 容器到 Jasonette 的通讯:从 Web 容器代码中调用原生 API。

此时咱们只能展现 Web 容器的内容。这就像网页中嵌入的 iframe 框架,主页面彻底没法访问 iframe 框架中的内容。

 解决方案

Jasonette 最大的目标在于设计一种能够描述跨平台移动应用的标准化标记语言。所以咱们须要这个标记语言可以全面地描述父应用和子 Web 容器之间的双向通讯。

为此我在父应用和子 Web 容器之间使用了一种基于 JSON-RPC 的通讯管道。因为 Jasonette 中的一切都是经过 JSON 对象表达的,所以使用 JSON-RPC 标准格式做为通讯协议就成了一种很是天然合理的方式。image.png

为了让 JavaScript 函数可以调用 Web 容器,须要声明一个名为$agent.request的操做:image.png

$agent.request 是一种原生 API,可触发 JSON-RPC 请求并发送给 Web 容器。为了使用该 API,必须将options对象做为参数传递。

options对象其实是发送给 Web 容器的 JSON-RPC 请求。每一个属性的含义以下:

  • id:Web 容器构建在一种名为 Agent 的底层架构基础上,一般来讲,咱们能够为一个视图使用多个 Agent,每一个 Agent 能够有本身的惟一 ID。但 Web 容器是一种特殊类型的 Agent,只能使用 $webcontainer 做为 ID,所以这里须要使用 ID。

  • method:要调用的 JavaScript 函数名称。

  • params:传递给 JavaScript 函数的参数数组。

所以完整来看,所用的标记应该是相似这样的:image.png

这串标记其实是在说:

当视图加载($jason.head.actions.$load)时,向 Web 容器 Agent 发送一个 JSON-RPC 请求($agent.request),而具体的请求是经过options指定的。

Web 容器在 $jason.body.background 下定义,本例中将会加载一个名为file://index.html的本地文件。

随后会查找一个名为 login 的 JavaScript 函数并传递params下的两个参数("alice""1234")。image.png

上文介绍了父应用如何触发子 Web 容器的 JavaScript 函数调用,咱们还能够反着来,让 Web 容器触发父应用的原生 API。

详情请参阅 Agent 文档。

Agent 文档: https://docs.jasonette.com/agents/

  范 例   

继续回到上文介绍的二维码生成器范例:image.png


  1. 其中 底部的文字输入组件是 100% 原生的。

  2. 二维码由 做为 Web 应用运行 的 Web 容器生成。

  3. 当用户输入内容并按下“生成”,将调用 Web 容器 Agent 中的$agent.request操做,进而调用 JavaScript 函数“qr”。

具体示例能够参阅:

https://github.com/Jasonette/Jasonpedia/blob/gh-pages/webcontainer/agent/fn/index.json

3. 脚本注入 问题

有时候咱们可能须要在 Web 容器完成初始 HTML 加载后,动态地将 JavaScript 代码注入 Web 容器。

假设要构建一个自定义的 Web 浏览器应用,咱们可能但愿将本身的自定义 JavaScript 注入到每一个 Web 视图,借此定制 Web 视图的行为,这有点相似于 Web 浏览器的扩展。

就算不须要构建 Web 浏览器,当但愿为所包含的内容不禁咱们控制的 URL 实现自定义行为时,一样须要使用脚本注入的方法。原生应用和 Web 容器只能经过$agent API 通讯,但若是没法更改 HTML 内容,只能经过动态注入的方式将$agent接口加入 Web 容器。

 解决方案

正如上文所述,$jason.body.background这个 Web 容器也是一个agent,这意味着咱们可使用与普通 Agent 彻底相同的 $agent.inject 方法。image.png

4. 对 URL 点击的处理

以往,Web 容器只能经过两种方式处理连接点击操做:

  1. 只读:将 Web 容器视做只读的,忽略全部诸如触控或滚动等事件。此时全部 Web 容器都是只读的,除非明确令其表现得像是普通浏览器,具体作法见下文。

  2. 普通浏览器行为:像是普通浏览器那样,容许用户与页面交互。为此须要进行声明,将"type": "$default"设置为action属性。

 问题

二者均为 “全无或全有(All or nothing)”解决方案

  • 对于“只读”,Web 容器会忽略用户的全部交互操做。

  • 对于“普通浏览器行为”,Web 容器的表现将与浏览器一致。点击连接后,将像普通网页那样刷新页面展现连接内容,但没法劫持该点击并调用其余原生 API。

 解决方案

经过使用新的 Web 容器,能够将任何action附加到$jason.body.background这个 Web 容器,进而处理连接点击之类的事件。image.png

一块儿看一个例子:image.png

在这里咱们为 Web 容器附加了"trigger": "displayBanner",这意味着当用户点击 Web 容器内的任何连接后,将触发displayBanner操做,而非直接交由 Web 视图处理。

此外若是查看displayBanner操做会发现,这里出现了变量$jason。在本例中,点击的连接将经过$jason变量传递。例如,若是点击一个名为"https://google.com"的 URL,$jason将得到下列值:image.png

这意味着咱们能够 检查 $jason.url 的值 进而选择性地触发不一样操做。

用自定义 Web 浏览器的实现做为另外一个例子一块儿来看看:image.png

咱们会检查 URL 是否包含字符串signin,并根据结果执行两个不一样操做。

  1. 若是包含signin,打开一个新视图并以原生方式完成登陆操做。

  2. 若是不包含signin,则直接运行"type": "$default"操做,实现相似普通浏览器的行为。

用法示范 构建自定义 Web 浏览器

利用新版 Web 容器的下列特性,能够实现不少有趣的操做:

  1. 经过url属性实现自我加载,并充当一个功能齐备的浏览器。

  2. 根据 URL 的不一样,选择性地处理连接点击操做。

咱们甚至能够经过几十行 JSON 代码构建一个自定义的 Web 浏览器。因为如今能够劫持每一个连接点击,所以能够检查$jason.url,并根据结果运行咱们须要的任何操做。

例以下面的例子:

image.png


image.png

spacer.gif

spacer.gif

从上图能够看到,点击连接后的行为与普通浏览器无异("type": "$default")。

从下图能够看到,点击连接后能够用原生方式转换至另外一个 JASON 视图。

这一切均可以根据$jason.url的值选择性地触发实现。

第 1 步:向 Web 容器附加一个名为visit的操做image.png

第 2 步:根据$jason.url的值运行visit内部的相关操做

在下列代码中,咱们会检查$jason.url是否与newestshowask等内容(均为顶级菜单项连接)相符。若是相符,设置"type": "$default"便可让 Web 容器作出与普通浏览器同样的行为。

若是模式不符,则可经过原生的$href转换打开一个新视图,并将点击的连接做为参数传递过去。image.png

该 Web 浏览器的完整 JSON 标记请参阅(仅 48 行!):

https://github.com/Jasonette/Jasonpedia/blob/gh-pages/webcontainer/agent/hijack.json

 瞬间构建“混合”应用

人们一般在说“混合”应用时,主要是指封装在原生应用框架内部的 HTML Web 应用。

但此处说的并非这种应用。这里所谓的“混合”是指真正的混合应用,也就是能够同时包含多个原生视图以及多个基于 Web 的视图的应用。在这种应用中,一个视图能够有多个原生 UI 组件,以及一个用相同原生布局渲染的 Web 容器。

Web 视图与原生视图的交织应当尽量无缝,使得用户彻底没法分辨。image.png

在这个例子中,我建立了一个能够在 Web 容器中显示 jasonbase.com 的内容,并将其做为主页视图的应用。

Jasonbase 是我开发的免费 JSON 托管服务,该服务能够很简单地用于托管 Jasonette 应用所用到的 JSON 标记。

固然,这自己是个网站,但我将其嵌入到 Jasonette 中,所以在点击连接后并不会打开网页,而是会经过原生的$href转换展现原生的 JASON 视图。

彻底无需触及 Jasonbase.com 的代码就能够构建出这个应用。

只须要将网站做为 Web 容器嵌入 Jasonette,随后劫持连接点击操做的原生处理方式,这样就能够实现原生应用所具有的各种功能,例如触发原生 API 以及进行原生转换。

完整代码可参阅这里:

https://github.com/Jasonette/Jasonpedia/blob/gh-pages/webcontainer/agent/hybrid.json

  结 论  

在我看来,让这一切如此使人赞叹的缘由在于,在框架层面上便可妥善处理好一切。全部最困难的工做都是在后台完成的。

应用开发者并不须要自行费时费力从零开始实现下列这一切:

  • 将 Web 视图嵌入原生布局

  • 建立 JavaScript 桥,以便让应用可以调用 Web 视图中的函数

  • 建立原生事件处理架构,以便让 Web 视图可以触发父应用的原生事件

整个解决方案建立了下列内容组成的抽象:

  1. 声明式标记语言:用于描述如何将 Web 视图嵌入原生应用。

  2. 通讯协议(JSON-RPC):用于在应用及其子 Web 视图之间实现极为简单的通讯。

我并不以为这种方法能够解决全部问题,但从本身的用例来看,至少能够说这是个不错的解决方案。

我试着以很是前沿的技术来构建应用,而这些技术已经前沿到在移动端尚未任何稳定可靠的实现(因为协议的一些本质,甚至不清楚最终是否会有移动端的实现)。好在这些技术都有 JavaScript 实现,所以不费什么事就能够轻松地将其与应用相集成。

总的来讲,这种技术很棒,我对目前的效果很是满意。最新版文档 已经包含了全部新功能,欢迎你们深刻研究并尝试。

声明:能力越大,须要担负的责任也就越大

最后我想说:虽然这种新技术确实很强大,但我以为你们在开发应用时都应该在用户体验方面进行更全面的权衡。

有些人可能会借助这种技术构建彻底由 Web 视图组成的应用,但说到底这样的作法,你的应用实际上就只是一个网站,已经与开发专属应用的本意背道而驰了。

须要强调的是,我并不认为你的每一个应用都应同时包含 HTML 和原生组件。我只是认为,这样的作法对不少面临某些具体情况的人会显得较为有用,只不过别过火就好。

 相关连接

最新版文档:

https://docs.jasonette.com/web/

原文连接:

https://medium.freecodecamp.org/how-to-turn-your-website-into-a-mobile-app-with-7-lines-of-json-631c9c9895f5

前端之巅

「前端之巅」是 InfoQ 旗下关注大前端技术的垂直社群。紧跟时代潮流,共享一线技术,欢迎关注。

 活动推荐

PWA、Web 框架、UI 与动画、Node... 大前端的下一站在哪里?前端工程师的价值和成长路径是什么?GMTC2018 上,来自 Google、Facebook、BAT 等 60+ 国内外一线前端大牛,将与你面对面探讨大前端领域最新技术趋势和实践,想要升职加薪就快来吧!扫描下方二维码或点击“阅读原文”了解更多大会详情!

目前大会 8 折热销中,团购更优惠,购票咨询:18514549229(同微信)

相关文章
相关标签/搜索