把转变为json
by Ethan
通过伊桑
将Web引擎融合到本机应用程序的新方法 (A New Approach for Blending Web Engine into Native Apps)
What if I told you the 7 lines of JSON above, colored in orange is all you need to turn a website into a mobile app? No need to rewrite your website using some framework API just to make it behave like a mobile app. Just bring your existing website as is, and blend it into a native app with a simple URL reference.
如果我告诉您上述JSON的7行(用橙色涂成橙色 ),将网站变成移动应用程序只需要什么? 无需使用某些框架API来重写您的网站,仅使它的行为类似于移动应用即可。 只需将您现有的网站保持原样,然后使用简单的URL引用将其混合到本机应用程序中即可。
And what if, just by tweaking the JSON markup a bit, you can access all the native APIs, native UI components, as well as native view transitions out of the box?
而且,如果仅通过稍微调整JSON标记就可以直接使用所有本机API,本机UI组件以及本机视图转换,该怎么办?
Here’s what a minimal example looks like in action:
这是一个实际的最小示例:
Notice how I’ve embedded a github.com web page but the rest of the layout is all native UI components, such as the navigation header and the bottom tab bar. And the transition is automatically native without you having to rewrite the website using any APIs.
请注意,我是如何嵌入github.com网页的,但是其余的布局都是本机UI组件,例如导航标题和底部的标签栏 。 并且过渡是自动的本机,而无需使用任何API重写网站。
Before I explain how, you may ask: “That’s cool, but can you do anything meaningful other than just displaying the web page in a native app frame?”
在我解释如何做之前,您可能会问:“这很酷,但是除了将网页显示在本机应用程序框架中之外,您还能做其他有意义的事情吗?”
Great question, because that’s the main topic of this post. All you need to do is create a seamless 2-way communication channel between the web view and the app, so the parent app can trigger any JavaScript functions inside the web view and the web view can reach outside to call native APIs.
很好的问题,因为这是本文的主题。 您需要做的就是在Web视图和应用之间创建无缝的双向通讯渠道 ,以便父应用可以触发Web视图内部的任何JavaScript函数,并且Web视图可以到达外部以调用本地API。
Here’s one such example:
这是一个这样的例子:
Note that this view contains:
请注意,此视图包含:
- Native navigation header, complete with built-in transition functionality
本机导航标题,具有内置的转换功能
- A Web view, which embeds a QR code generator web app
Web视图,其中嵌入了QR码生成器Web应用程序
- A native chat input component at the bottom
底部的本地聊天输入组件
All this can be described by just tweaking some of the JSON markup attributes we saw above.
所有这些都可以通过调整一些我们在上面看到的JSON标记属性来描述。
Finally, note that the QR code changes as you enter something from the chat input. The chat input triggers a JavaScript function inside the QR code web app that re-generates the image.
最后,请注意,当您从聊天输入中输入内容时,QR码会更改。 聊天输入触发QR代码Web应用程序内JavaScript函数,该函数重新生成图像。
No app development framework has tried to fundamentally solve this problem of “seamless integration of web view into native apps” because they’re all focused on picking either 100% native or 100% HTML5 side.
没有应用程序开发框架试图从根本上解决“将Web视图无缝集成到本机应用程序”这一问题,因为它们都集中在选择100%本机或100%HTML5方面。
Whenever you hear someone talk about the future of mobile apps, you would probably hear them talk about “Will it be the HTML5 approach that wins out? Or will it be native?”
每当您听到有人谈论移动应用程序的未来时,您可能就会听到他们谈论“将是HTML5的方法胜出吗? 还是本地的?”
None of them see native
and html
as something that could co-exist and furthermore, create synergy and achieve things that are not easily possible otherwise.
他们都没有将native
和html
视为可以共存的东西,此外,它们还可以产生协同作用,并实现原本不容易实现的事情。
In this article I’m going to explain:
在本文中,我将解释:
- Why blending web engine and native components is often a good idea.
为什么混合Web引擎和本机组件通常是一个好主意。
- Why a seamless integration of HTML and Native is not easy, and how I implemented one.
为什么不容易将HTML和Native进行无缝集成,以及我是如何实现的。
- Most importantly, how YOU can use it to build your own app instantly.
最重要的是,如何使用它立即构建自己的应用程序。
为什么要在本机应用程序中使用HTML? (Why would you use HTML in a native app?)
Before we go further, let’s first discuss whether this is even a good idea, and when you may want to take this approach. Here are some potential use cases:
在继续之前,我们先讨论一下这是否是个好主意,以及何时使用此方法。 以下是一些潜在的用例:
1.使用Web本机功能 (1. Use Web Native Features)
Some parts of your app may be better implemented using the web engine. For example, Websocket is a web-native feature that’s designed for the web environment. In this case it makes sense to use the built-in web engine (WKWebView for iOS and WebView for Android) instead of installing a 3rd party library that essentially “emulates” Websocket.
使用网络引擎可能会更好地实现您应用的某些部分。 例如, Websocket是针对Web环境设计的Web原生功能。 在这种情况下,使用内置的Web引擎( 适用于iOS的WKWebView和适用于Android的WebView )是有意义的,而不是安装本质上“模仿” Websocket的第三方库。
No need to install additional code just to do something that you can do for free, which brings us to the next point.
无需安装其他代码即可完成您可以免费做的事情,这将使我们进入下一步。
2.避免大二进制文件 (2. Avoid Large Binary Size)
You may want to quickly incorporate features that will otherwise require a huge 3rd party library.
您可能需要快速合并一些功能,否则这些功能将需要庞大的第三方库。
For example, to incorporate a QR code image generator natively, you will need to install some 3rd party library which will increase the binary size. But if you use the web view engine and a JavaScript library through a simple <script s
rc>, you get all that for free, and you don’t need to install any 3rd party native libraries.
例如,要在本地合并QR码图像生成器,您将需要安装一些第三方库,这会增加二进制文件的大小。 但是,如果您通过简单的<script s
rc>使用Web视图引擎和JavaScript库,则可以免费获得所有内容,而无需安装任何第三方的本机库。
3.不存在可靠的移动图书馆 (3. No Reliable Mobile Library Exists)
For some cutting edge technologies, there is no reliable and stable mobile implementation yet.
对于某些尖端技术,尚没有可靠且稳定的移动实现。
Fortunately most of these technologies have web implementations, so the most efficient way to integrate them is to use their JavaScript library.
幸运的是,这些技术中的大多数都具有Web实现,因此集成它们的最有效方法是使用其JavaScript库。
4.构建部分本地的,基于网络的应用 (4. Build part-native, part-web-based apps)
Many new developers looking to port their website into a mobile app get discouraged or overwhelmed when they find out some of their existing website features are too complex to quickly rewrite from scratch for each mobile platform.
当许多新的开发人员发现自己现有的某些网站功能过于复杂而无法为每个移动平台快速从头开始重写时,他们会灰心或不知所措。
For example, you may have a single web page that’s too complex to immediately convert to a mobile app, but the rest of your website may be easily converted.
例如,您可能只有一个网页太复杂而无法立即转换为移动应用程序,但是您网站的其余部分可能很容易转换。
In this case, it would be nice if there was a way to build most of the app natively, but for that particular complex web page, somehow seamlessly integrate it into the app as HTML.
在这种情况下,如果有一种方法可以原生构建大部分应用程序,那将是很好的选择,但是对于该特定的复杂网页,以某种方式将其作为HTML无缝集成到应用程序中。
它是如何工作的? (How does it work?)
贾森内特 (A. Jasonette)
Jasonette is an open source, markup-based approach to building cross-platform native apps.
Jasonette是一种基于标记的开源方法,用于构建跨平台的本机应用程序。
It’s like a web browser, but instead of interpreting HTML markup into web pages, it interprets JSON markup into native apps on iOS and Android.
它就像一个网络浏览器,但是没有将HTML标记解释为网页,而是将JSON标记解释为iOS和Android上的本机应用程序。
Just like how all web browsers have exactly the same code but can deliver you all kinds of different web apps by interpreting various HTML markup on demand, all Jasonette apps have exactly the same binary, and it interprets various JSON markup on demand to create your app. The developers never need to touch the code. Instead, you build apps by writing a markup that translates to native app in real-time.
就像所有网络浏览器具有完全相同的代码,但是可以通过按需解释各种HTML标记为您提供各种不同的Web应用程序一样,所有Jasonette应用程序都具有完全相同的二进制文件,并且可以按需解释各种JSON标记来创建您的应用程序。 开发人员无需触摸代码。 相反,您可以通过编写可实时转换为本地应用程序的标记来构建应用程序。
You can learn more about Jasonette here.
您可以在此处了解有关Jasonette的更多信息。
While Jasonette at its core is all about building native apps, this particular article is about integrating HTML into the core native engine, so let’s talk about that.
Jasonette的核心是构建本机应用程序,而这篇特别文章是关于将HTML集成到核心本机引擎中的,所以让我们来谈谈。
B. Jasonette Web容器 (B. Jasonette Web Container)
Native apps are great but sometimes we need to make use of web features.
本机应用程序很棒,但有时我们需要利用网络功能。
But integrating web views into a native app is a tricky business. A seamless integration requires:
但是将Web视图集成到本地应用程序中是一项棘手的工作。 无缝集成需要:
Web view should be integrated as a part of native layout: The web view should blend into the app as a part of the native layout and is treated just like any other native UI components. Otherwise it will feel clunky, and it will feel exactly like what it is — a website.
Web视图应作为本机布局的一部分集成: Web视图应作为本机布局的一部分融合到应用程序中,并且与其他任何本机UI组件一样被对待。 否则,它将感觉笨拙,并且会感觉完全像是一个网站。
Parent app can control child web container: The parent app should be able to freely control the child web view.
父级应用程序可以控制子级Web容器:父级应用程序应能够自由控制子级Web视图。
Child web container can trigger native events on the parent app: The child app should be able to trigger the parent app’s events to run native APIs.
子Web容器可以触发父应用程序上的本机事件:子应用程序应能够触发父应用程序的事件以运行本机API。
These are a lot of work, so I first worked on only the first piece of the puzzle — simply embedding a web container into native layout — and released it as version 1:
这些工作量很大,因此我首先仅解决难题的第一部分- 只需将Web容器嵌入本机布局中 ,然后将其发布为版本1:
JSON Web ContainerHTML inside JSON Turns into Native App Componentsjasonette.com
JSON中的JSON Web容器 HTML变成了本机应用程序组件 jasonette.com
This was already pretty useful, but it still had the limitation of being non-interactive.
这已经非常有用,但是仍然存在非交互式的局限性。
The parent app couldn’t control the child web container, and the child couldn’t notify the parent of any event, keeping the web container completely isolated from the outside world.
父级应用程序无法控制子级Web容器,子级也无法将任何事件通知父级,从而使Web容器与外界完全隔离。
C. Jasonette Web容器2.0:使其具有交互性 (C. Jasonette Web Container 2.0: Make it Interactive)
After releasing version 1, I experimented with the second piece of the puzzle — adding interactivity to the web container.
发布版本1后,我尝试了第二个难题– 为Web容器增加了交互性。
The next section explains the solutions that were added to make the previously-static web containers interactive, making them significantly more powerful.
下一节将说明为使以前静态的Web容器具有交互性而添加的解决方案,从而使它们明显更强大。
实施:交互式Web容器 (Implementation: Interactive Web Container)
1.通过URL加载 (1. Load by URL)
问题 (Problem)
Previously in version 1, to use web container as a background view component, you had to first set the $jason.body.background.type
to "html"
and then hard-code the HTML text under $jason.body.background.text
attribute like this:
在以前的版本1中,要将Web容器用作背景视图组件,必须首先将$jason.body.background.type
设置为"html"
,然后将HTML文本硬编码在$jason.body.background.text
像这样的属性 :
{ "$jason": { "head": { ... }, "body": { "background": { "type": "html", "text": "<html><body><h1>Hello World</h1></body></html>" } } }}
Naturally people wanted to be able to instantiate the container using simply a web URL instead of having to hardcode the entire HTML text in a single line.
自然,人们希望能够仅使用Web URL实例化容器,而不必在一行中对整个HTML文本进行硬编码。
解 (Solution)
Web container 2.0 has added the url
attribute. You can embed a local file://
HTML like this (it loads from the local HTML file you ship with the app):
Web容器2.0已添加url
属性。 您可以像这样嵌入本地file://
HTML(它会从与应用一起提供的本地HTML文件中加载):
{ "$jason": { "head": { ... }, "body": { "background": { "type": "html", "url": "file://index.html" } } }}
Or embed a remote http[s]://
URL like this (it loads from a remote HTML):
或嵌入这样的远程http[s]://
URL(从远程HTML加载):
{ "$jason": { "head": { ... }, "body": { "background": { "type": "html", "url": "https://news.ycombinator.com" } } }}
2.父应用程序<=> Web容器通信 (2. Parent App <=> Web Container Communication)
问题 (Problem)
Previously, web containers were only for displaying content, and not interactive. This meant NONE of the following was possible:
以前,Web容器仅用于显示内容,而不用于交互。 这意味着不可能执行以下操作:
Jasonette => Web Container: Call JavaScript functions inside the web container from Jasonette.
Jasonette => Web Container :从Jasonette调用Web容器内JavaScript函数。
Web Container => Jasonette: Call native API from web container code.
Web容器=> Jasonet te:从Web容器代码中调用本地API。
All you could do was display the web container. This was similar to how you would embed an iframe in a web page, but the main web page had no access to what was inside the iframe.
您所能做的就是显示Web容器。 这类似于将iframe嵌入网页中的方式,但是主网页无法访问iframe内部的内容。
解 (Solution)
The whole point of Jasonette is to design a standard markup language to describe cross platform mobile apps. In this case, we needed a markup language that could comprehensively describe communications between the parent app and the child web container.
Jasonette的全部重点是设计一种标准的标记语言来描述跨平台的移动应用程序。 在这种情况下,我们需要一种可以全面描述父应用程序和子Web容器之间的通信的标记语言。
To achieve this, I came up with a JSON-RPC
based communication channel between the parent app and the child web container. Since everything on Jasonette is expressed in JSON objects, it made perfect sense to use the JSON-RPC standard format as the communication protocol.
为此,我想出了父应用程序和子Web容器之间基于JSON-RPC
的通信通道。 由于Jasonette上的所有内容都以JSON对象表示,因此使用JSON-RPC标准格式作为通信协议是很有意义的。
To make a JavaScript function call into the web container, we declare an action called $agent.request
:
为了对Web容器进行JavaScript函数调用,我们声明了一个名为$agent.request
:
{ "type": "$agent.request", "options": { "id": "$webcontainer", "method": "login", "params": ["username", "password"] }}
$agent.request
is the native API that triggers a JSON-RPC request into the web container. To use it, we must pass an options
object as its parameter.
$agent.request
是本机API,可触发JSON-RPC请求进入Web容器。 要使用它,我们必须传递一个options
对象作为它的参数。
The options
object is the actual JSON-RPC request that will be sent to the web container. Let’s look at what each attribute means:
options
对象是将发送到Web容器的实际JSON-RPC请求 。 让我们看一下每个属性的含义:
id
: Web container is built on top of a lower level architecture called agent. Normally you can have multiple agents for a single view, and each agent can have its unique ID. But Web container is a special type of agent which can only have the id of$webcontainer
, which is why we use that ID here.id
:Web容器建立在称为agent的较低级架构之上。 通常,一个视图可以有多个代理,每个代理可以有其唯一的ID。 但是Web容器是一种特殊类型的代理,只能具有$webcontainer
的ID ,这就是我们在此处使用该ID的原因。method
: The JavaScript function name to callmethod
:要调用JavaScript函数名称params
: The array of parameters to pass to the JavaScript function.params
:传递给JavaScript函数的参数数组。
The full markup would look something like this:
完整的标记如下所示:
{ "$jason": { "head": { "actions": { "$load": { "type": "$agent.request", "options": { "id": "$webcontainer", "method": "login", "params": ["alice", "1234"] } } } }, "body": { "header": { "title": "Web Container 2.0" }, "background": { "type": "html", "url": "file://index.html" } } }}
This markup is saying:
这个标记说:
When the view loads ($jason.head.actions.$load
), make a JSON-RPC request into the web container agent ($agent.request
) where the request is specified under options
.
当视图加载( $jason.head.actions.$load
)时,向Web容器代理( $agent.request
)发出JSON-RPC请求,该请求在options
下指定。
The web container is defined under $jason.body.background
, which in this case loads a local file called file://index.html
.
Web容器在$jason.body.background
下定义,在这种情况下,该容器将加载名为file://index.html
的本地文件。
It will look for a JavaScript function called login
and pass the two arguments under params
( "alice"
and "1234"
)
它将寻找一个名为login
JavaScript函数,并在params
下传递两个参数( "alice"
和"1234"
)
login("alice", "1234")
I’ve only explained how the parent app can trigger the child web container’s JavaScript function calls, but you can also do the opposite and let the web container trigger the parent app’s native API.
我仅说明了父应用程序如何触发子Web容器JavaScript函数调用,但是您也可以执行相反的操作,并让Web容器触发父应用程序的本机API 。
To learn more, check out the agent documentation.
要了解更多信息,请查看代理文档 。
例 (Example)
Let’s come back to the QR code example I briefly shared above:
回到上面我简短分享的QR代码示例:
The QR code is generated by the web container as a web app.
QR代码是由Web容器作为Web应用程序生成的 。
When a user enters something and presses “Generate,” it calls
$agent.request
action into the web container agent, calling the JavaScript function “qr”当用户输入内容并按“ Generate”时,它将在Web容器代理中调用
$agent.request
操作,并在JavaScript函数中调用“ qr”
You can check out the example here.
您可以在此处查看示例。
3.脚本注入 (3. Script Injection)
问题 (Problem)
Sometimes you may want to dynamically inject JavaScript code into the web container AFTER it’s finished loading the initial HTML.
有时,您可能希望在JavaScript代码完成加载初始HTML之后将其动态注入Web容器中。
Imagine you want to build a custom web browser app. You may want to inject your own custom JavaScript into every web view to customize the web view’s behavior, kind of like how web browser extensions work.
假设您要构建一个自定义Web浏览器应用程序。 您可能希望将自己的自定义JavaScript注入每个Web视图中,以自定义Web视图的行为,就像Web浏览器扩展的工作方式一样。
Even if you’re not building a web browser, you may want to use the script injection method whenever you want a custom behavior for a URL whose content you have no control over. The only way to communicate between the native app and the web container is through the $agent
API. But if you can’t change the HTML content, the only way to add the $agent
interface into the web container is through dynamic injection.
即使您不构建Web浏览器,也可能希望在您希望对其内容无法控制的URL进行自定义行为时使用脚本注入方法。 在本机应用程序和Web容器之间进行通信的唯一方法是通过$agent
API。 但是,如果您无法更改HTML内容,则将$agent
接口添加到Web容器的唯一方法是通过动态注入。
解 (Solution)
As mentioned in the previous section, the $jason.body.background
web container is just another agent
. This means you can use the same $agent.inject
method available to regular agents.
如上一节所述, $jason.body.background
Web容器只是另一个agent
。 这意味着您可以使用常规代理可用的相同$agent.inject
方法。
4. URL单击处理 (4. URL Click Handling)
In the past, there were only two ways a web container could handle link clicks:
过去,Web容器只能通过两种方式处理链接点击:
Readonly: Treat the web container as readonly and ignore all events such as touch or scroll. All web containers are readonly unless you tell them to behave like a regular browser, as described below.
只读:将Web容器视为只读,并忽略所有事件,例如触摸或滚动。 所有Web容器都是只读的,除非您告诉它们像常规浏览器一样运行,如下所述。
Regular Browser Behavior: Let users interact with the page by behaving like a normal browser. You declare it by setting
"type": "$default"
as itsaction
attribute.常规的浏览器行为:让用户可以像普通浏览器一样与页面进行交互。 您可以通过将
"type": "$default"
为其action
属性来声明它。
问题 (Problem)
Both are “all or nothing” solutions.
两者都是“全有或全无”的解决方案 。
- In the “Readonly” case, all your interactions are completely ignored by the web container.
在“只读”情况下,Web容器将完全忽略您的所有交互。
- In the “Regular Browser Behavior” case, the web container functions literally as a browser. When you click a link, it would just send you to that link by refreshing the page just like a web page. There was no way to hijack the click and call some native API.
在“常规浏览器行为”的情况下,Web容器实际上是充当浏览器。 当您单击链接时,它将像刷新网页一样通过刷新页面将您发送到该链接。 无法劫持点击并调用某些本机API。
解 (Solution)
With the new web container, you can now attach any action
on the $jason.body.background
web container to handle link click events.
使用新的Web容器,您现在可以在$jason.body.background
Web容器上附加任何action
来处理链接单击事件。
Let’s look at an example:
让我们看一个例子:
{ "$jason": { "head": { "actions": { "displayBanner": { "type": "$util.banner", "options": { "title": "Clicked", "description": "Link {
{$jason.url}} clicked!" } } } }, "body": { "background": { "type": "html", "url": "file://index.html", "action": { "trigger": "displayBanner" } } } }}
Here we have attached "trigger": "displayBanner"
to the web container. This means that when a user clicks any link in the web container, it will trigger displayBanner
action instead of letting the web view handle it.
在这里,我们将"trigger": "displayBanner"
附加到Web容器。 这意味着,当用户单击Web容器中的任何链接时,它将触发displayBanner
操作,而不是让Web视图处理它。
Also, if you look at the displayBanner
action, you’ll notice the $jason
variable. In this case, the clicked link will be passed through the $jason
variable. For example, if you clicked a URL named "https://google.com"
, the $jason
will have the following value:
另外,如果查看displayBanner
动作,您会注意到$jason
变量。 在这种情况下,单击的链接将通过$jason
变量传递。 例如,如果您单击名为"https://google.com"
的URL,则$jason
将具有以下值:
{ "url": "https://google.com"}
This means you can selectively trigger different actions by checking the $jason.url
value.
这意味着您可以通过检查$jason.url
值来有选择地触发不同的操作。
Let’s take another example where we implement a custom web browser:
让我们再来看一个实现自定义Web浏览器的示例:
{ "$jason": { "head": { "actions": { "handleLink": [{ "{
{#if $jason.url.indexOf('signin') !== -1 }}": { "type": "$href", "options": { "url": "file://key.html" } } }, { "{
{#else}}": { "type": "$default" } }] } }, "body": { "background": { "type": "html", "url": "file://index.html", "action": { "trigger": "handleLink" } } } }}
We test if the URL contains the string signin
and then run two different actions depending on the result.
我们测试URL是否包含字符串signin
,然后根据结果运行两个不同的操作。
If it contains
signin
, it opens a new view to take care of signing in natively.如果包含
signin
,它将打开一个新视图以照顾本地登录。If it doesn’t contain
signin
, just run the"type": "$default"
action so that it behaves like a regular browser.如果它不包含
signin
,只需运行"type": "$default"
操作,使其表现得像普通浏览器。
用法示例 (Example Usage)
构建自定义的Web浏览器 (Building a custom web browser)
We can now take advantage of the fact that the new web container can:
现在,我们可以利用新的Web容器可以做到这一点:
Take a
url
attribute to load itself, functioning as a full-fledged browser使用
url
属性来加载自身,作为成熟的浏览器- Selectively handle link clicks depending on the URL
根据URL选择性处理链接点击
We can even build a custom web browser app with just a dozen lines of JSON. Since we can now hijack every link click, we can take a look at $jason.url
and run whatever actions we want depending on the URL.
我们甚至可以只用十几行JSON构建自定义的Web浏览器应用程序。 由于我们现在可以劫持每个链接单击,因此我们可以查看$jason.url
并根据URL进行所需的任何操作。
For example, take a look at the example below:
例如,看下面的例子:
On the left side we see that clicking a link behaves like a regular browser ("type": "$default"
)
在左侧,我们看到单击链接的行为类似于常规浏览器( "type": "$default"
)
On the right side we see that clicking a link does a native transition to another JASON view.
在右侧,我们看到单击链接会进行本机转换到另一个JASON视图。
All this can be achieved by selectively triggering different actions based on $jason.url
.
所有这些都可以通过基于$jason.url
选择性地触发不同的动作来实现。
Step 1. Attach an action named visit
to the web container like this:
步骤1.将名为visit
的操作附加到Web容器,如下所示:
{ ... "body": { "background": { "type": "html", "url": "https://news.ycombinator.com", "action": { "trigger": "visit" } } }}
Step 2. Run relevant actions inside visit,
based on $jason.url
步骤2.根据$jason.url
在visit,
运行相关操作
In the following code, we’re checking if $jason.url
matches newest
, show
, ask
, and so on (they’re the top menu item links). If they do, we let the web container behave like a regular browser by setting "type": "$default"
在下面的代码中,我们正在检查$jason.url
匹配newest
, show
, ask
等(它们是顶部菜单项的链接)。 如果这样做,我们可以通过设置"type": "$default"
使Web容器像常规浏览器一样工作
If they don’t match the pattern, we make a native $href
transition to a new view and pass the clicked link as a parameter.
如果它们与模式不匹配,我们将执行本机$href
过渡到新视图,然后将单击的链接作为参数传递。
..."actions": { "visit": [ { "{
{#if /\\/(newest|show|ask)$/.test($jason.url) }}": { "type": "$default" } }, { "{
{#else}}": { "type": "$href", "options": { "url": "https://jasonette.github.io/Jasonpedia/webcontainer/agent/hijack.json", "preload": { "background": "#ffffff" }, "options": { "url": "{
{$jason.url}}" } } } } ]},
Check out the full JSON markup for the web browser here (it’s only 48 lines!).
在此处查看 Web浏览器的完整JSON标记(只有48行!)。
即时的“混合”应用 (Instant “Hybrid” App)
When people normally talk about “hybrid” apps, they mostly mean HTML web apps wrapped inside a native app frame.
人们通常谈论“混合”应用程序时,通常指的是将HTML Web应用程序包装在本机应用程序框架中。
But that’s not what I mean here. When I say “Hybrid,” I mean a truly hybrid app, where one app can have multiple native views and multiple web-based views simultaneously. Also where one view can have multiple native UI components and a web container rendered in the same native layout.
但这不是我的意思。 当我说“ Hybrid”时,是指真正的混合应用程序,其中一个应用程序可以同时具有多个本机视图和多个基于Web的视图。 同样,一个视图可以具有以相同的本机布局呈现的多个本机UI组件和一个Web容器。
The cross-over between web-based view and native view should be so seamless that it’s hard to tell where one starts and ends.
基于Web的视图和本机视图之间的交叉应该是如此无缝,以至于很难说出起点和终点。
In this example, I’ve created an app that displays jasonbase.com in a web container as the home view.
在此示例中,我创建了一个应用程序,该应用程序将Web容器中的jasonbase.com显示为主视图。
Jasonbase is a free JSON hosting service I built to easily host JSON markup for Jasonette apps.
Jasonbase是免费的JSON托管服务,我构建该服务是为了轻松托管Jasonette应用程序的JSON标记。
Naturally, it’s just a website, but I have embedded it in Jasonette so that when you click the link, instead of opening a web page, it makes a native $href
transition to a native JASON view.
自然地,这只是一个网站,但我已将其嵌入Jasonette中,因此,当您单击链接时,无需打开网页,而是将本机$href
转换为本机JASON视图。
I didn’t have to touch any of Jasonbase.com’s code to build this app.
我无需触摸Jasonbase.com的任何代码即可构建此应用。
I simply embedded the website into Jasonette as a web container, and hijacked the link clicks to handle them natively, so it can do all the native stuff like triggering native APIs and making native transitions.
我只是将网站作为Web容器嵌入Jasonette中,并劫持了链接点击以本地处理它们,因此它可以执行所有本地工作,例如触发本地API和进行本地转换。
You can check out the code here.
您可以在此处签出代码。
结论 (Conclusion)
In my opinion, what makes all this work fabulously is that everything is taken care of on the framework level. All the hard work is taken care of behind the scenes.
我认为,使所有这些工作变得如此出色的原因是, 所有事情都在框架级别得到了照顾 。 所有的辛苦工作都在后台进行。
Instead of putting the burden on the app developers to implement all of the following from scratch:
不必为应用程序开发人员负担从头开始实现以下所有任务的负担:
- Embed a webview into native layout
将Webview嵌入本机布局
- Create a JavaScript bridge so the app can make function calls into the web view
创建一个JavaScript桥,以便该应用可以对Web视图进行函数调用
- Creating a native event handling architecture so the web view can trigger native events on the parent app
创建本机事件处理架构,以便Web视图可以在父应用程序上触发本机事件
The solution was to create an abstraction made up of:
解决方案是创建一个包含以下内容的抽象:
Declarative Markup Language: for describing how to embed a web view into a native app
声明性标记语言:用于描述如何将Web视图嵌入到本机应用程序中
Communication Protocol (JSON-RPC): to allow dead-simple interactions between the app and its child web views.
通信协议(JSON-RPC):允许应用与其子Web视图之间进行简单的交互。
I don’t claim this approach to be the ultimate solution to solve everything, but I’m happy to say that this has been a great solution for my own use case.
我并不是说这种方法是解决所有问题的最终解决方案,但是我很高兴地说这对于我自己的用例来说是一个很好的解决方案。
I was trying to build an app that builds on a super edge technology which has no stable and reliable mobile implementations (and it’s not clear if there ever will be a mobile implementation due to the protocol’s nature). Thankfully it had JavaScript implementations so I could easily integrate it into the app without hassle.
我试图构建一个基于超级边缘技术的应用程序,该技术没有稳定可靠的移动实现(由于协议的性质,目前尚不清楚是否会有移动实现)。 幸运的是,它具有JavaScript实现,因此我可以轻松地将其集成到应用程序中。
Overall, it’s been great and I’m satisfied with how it turned out. The documentation is up to date to reflect all the new features, so feel free to dig in and play around.
总的来说,这很棒,我对结果感到满意。 该文档是最新的,可以反映所有新功能,因此可以随时进行探索和探索。
Disclaimer: With great power comes great responsibility
免责声明:强大的力量伴随着巨大的责任
I would like to end with a disclaimer: as great as this newly found power is, I think you need to keep a balance to build an app with a great user experience.
我想以免责声明结尾:尽管有这种新发现的强大功能,但我认为您需要保持平衡以构建具有出色用户体验的应用程序。
Some may take this and build an entire app using web views only, but then you will end up with an app that’s basically just a website, which defeats the purpose of building a dedicated app.
有些人可能会这样做并且仅使用网络视图来构建整个应用程序,但是最终您将得到一个基本上只是一个网站的应用程序,这违背了构建专用应用程序的目的。
I emphasize that I’m not saying you should always build apps with both HTML and native. I am saying this can be very useful for many people in different situations. Just don’t go overboard with it.
我要强调的是,我并不是说您应该始终使用HTML和本机构建应用程序。 我是说这对处于不同情况下的许多人非常有用。 只是不要太过分。
Follow Along to Learn More
跟随以了解更多
There are many different configurations in which the Jasonette native core and its child web container can communicate to get things done in creative and powerful ways, and this post is just scratching the surface.
Jasonette本机核心和它的子Web容器可以通过多种不同的配置进行通信,从而以富有创意和强大的方式完成工作,而本文只是从头开始。
Going forward I’m planning to share more of these use cases and tutorials, so if you’re interested, please follow along on medium or twitter.
展望未来,我打算分享更多这些用例和教程,因此,如果您有兴趣,请继续使用medium或twitter 。
把转变为json