七行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(同微信)

相關文章
相關標籤/搜索