七行JSON程式碼將你的網站變成移動應用

jihong10102006發表於2018-04-24
引用
作者|Ethan
譯者|大愚若智
編輯|覃雲

本文介紹了藉助 Jasonette 將 Web 檢視和原生元件融合構建真正“混合”應用的做法。
七行JSON程式碼將你的網站變成移動應用

如果我告訴你,只需要 上述 7 行橙色的 JSON 程式碼 就可以將一個網站變成移動應用,你相信嗎?完全不需要使用某種框架 API 重寫網站,就可以獲得與移動應用相同的行為。如果你已經有一個現成的網站,只需要簡單地引用 URL 就可以將其“打包”為原生應用。

而如果在此基礎上,只需要略微調整 JSON 程式碼內容,就可以直接訪問所有原生 API、原生 UI 元件以及原生檢視切換(View Transition)。

最簡化的範例效果如下圖所示:
七行JSON程式碼將你的網站變成移動應用

從中可以看出,我嵌入了一個 GitHub.com 的 Web 頁面,但介面上其餘佈局均為原生 UI 元件,例如 導航條 以及 底部的標籤欄。而我們並不需要使用任何 API 重寫網站,就可以自動獲得原生的切換效果。

在介紹具體做法前你可能會問:“看著挺酷,但除了在原生應用框架內展示 Web 頁面之外,這種技術還有什麼意義?”

問得好!這也是本文要講的重點。我們只需要建立一個無縫的 Web 檢視與應用間雙向通訊,藉此,父應用就可以觸發 Web 檢視內的任何 JavaScript 函式,隨後 Web 檢視即可從外部呼叫原生 API。

例如:
七行JSON程式碼將你的網站變成移動應用

請注意,這個檢視包含:
  • 原生導航條,以及內建的切換功能
  • 一個 Web 檢視,其中嵌入了一個可以生成二維碼的 Web 應用
  • 在底部包含一個原生的文字輸入元件
上述所有這一切只需要略微調整 JSON 程式碼的屬性即可實現。

最後請注意,隨著在文字輸入區輸入不同內容,二維碼也會產生相應變化。輸入的文字可觸發二維碼生成器 Web 應用內部的 JavaScript 函式重新生成二維碼影像。

目前還沒有任何一個開發框架曾試圖從根本上解決“Web 檢視與原生應用無縫整合”的問題,因為這些框架都專注於完全原生,或完全 HTML5 的做法。

無論什麼時候當我們聽到有人討論移動應用的未來時,很可能會聽到類似“到底是 HTML5 還是原生方法會最終勝出呢?”這樣的說法。

似乎沒人覺得native和html可以共存,而且二者的協同和最終實現似乎也並不容易。

本文我將要介紹:
  • 為何 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 檢視與原生應用的整合是個麻煩的過程。無縫的整合要求:
  • Web 檢視應作為原生布局的一部分進行整合:Web 檢視應作為原生布局的一部分納入應用中,並且操作方式應與其他任何原生 UI 元件保持一致。否則會讓使用者感覺很笨拙,並且感覺上就像自己實際上是在訪問網站那樣。
  • 父應用可以控制子 Web 容器:父應用應能隨意控制子 Web 檢視。
  • 子 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 文字,例如這樣:
七行JSON程式碼將你的網站變成移動應用

一般來說,人們往往更希望直接使用 Web URL 對容器進行例項化,而不希望將整個 HTML 程式碼以硬編碼的方式作為一行程式碼加入。

解決方案

Web 容器 2.0 增加了url屬性,我們可以嵌入file://形式的本地 HTML,例如這樣(可以從伴隨應用釋出的本地 HTML 檔案載入):
七行JSON程式碼將你的網站變成移動應用

或者也可以嵌入遠端的http[s]:// URL,例如這樣(可以從遠端 HTML 載入):
七行JSON程式碼將你的網站變成移動應用

2. 父應用與 Web 容器的雙向通訊

問題

之前,Web 容器只能用於展示內容,無法互動。這意味著 下列做法全部無法實現:

  • Jasonette 到 Web 容器的通訊:從 Jasonette 中呼叫 Web 容器內部的 JavaScript 函式。
  • Web 容器到 Jasonette 的通訊:從 Web 容器程式碼中呼叫原生 API。
此時我們只能展示 Web 容器的內容。這就像網頁中嵌入的 iframe 框架,主頁面完全無法訪問 iframe 框架中的內容。

解決方案

Jasonette 最大的目標在於設計一種可以描述跨平臺移動應用的標準化標記語言。因此我們需要這個標記語言能夠全面地描述父應用和子 Web 容器之間的雙向通訊。

為此我在父應用和子 Web 容器之間使用了一種基於 JSON-RPC 的通訊管道。由於 Jasonette 中的一切都是通過 JSON 物件表達的,因此使用 JSON-RPC 標準格式作為通訊協議就成了一種非常自然合理的方式。
七行JSON程式碼將你的網站變成移動應用

為了讓 JavaScript 函式能夠呼叫 Web 容器,需要宣告一個名為$agent.request的操作:
七行JSON程式碼將你的網站變成移動應用

$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 函式的引數陣列。
因此完整來看,所用的標記應該是類似這樣的:
七行JSON程式碼將你的網站變成移動應用

這串標記實際上是在說:

當檢視載入($jason.head.actions.$load)時,向 Web 容器 Agent 傳送一個 JSON-RPC 請求($agent.request),而具體的請求是通過options指定的。

Web 容器在 $jason.body.background 下定義,本例中將會載入一個名為file://index.html的本地檔案。

隨後會查詢一個名為 login 的 JavaScript 函式並傳遞params下的兩個引數("alice"和"1234")。
七行JSON程式碼將你的網站變成移動應用

上文介紹了父應用如何觸發子 Web 容器的 JavaScript 函式呼叫,我們還可以反著來,讓 Web 容器觸發父應用的原生 API。

詳情請參閱 Agent 文件。

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

範 例  

繼續回到上文介紹的二維碼生成器範例:
七行JSON程式碼將你的網站變成移動應用

  • 其中 底部的文字輸入元件是 100% 原生的。
  • 二維碼由 作為 Web 應用執行 的 Web 容器生成。
  • 當使用者輸入內容並按下“生成”,將呼叫 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 方法。
七行JSON程式碼將你的網站變成移動應用

4. 對 URL 點選的處理

以往,Web 容器只能通過兩種方式處理連結點選操作:
  • 只讀:將 Web 容器視作只讀的,忽略所有諸如觸控或滾動等事件。此時所有 Web 容器都是隻讀的,除非明確令其表現得像是普通瀏覽器,具體做法見下文。
  • 普通瀏覽器行為:像是普通瀏覽器那樣,允許使用者與頁面互動。為此需要進行宣告,將"type": "$default"設定為action屬性。
問題

兩者均為 “全無或全有(All or nothing)”解決方案。
  • 對於“只讀”,Web 容器會忽略使用者的所有互動操作。
  • 對於“普通瀏覽器行為”,Web 容器的表現將與瀏覽器一致。點選連結後,將像普通網頁那樣重新整理頁面展示連結內容,但無法劫持該點選並呼叫其他原生 API。
解決方案

通過使用新的 Web 容器,可以將任何action附加到$jason.body.background這個 Web 容器,進而處理連結點選之類的事件。
七行JSON程式碼將你的網站變成移動應用

一起看一個例子:
七行JSON程式碼將你的網站變成移動應用

在這裡我們為 Web 容器附加了"trigger": "displayBanner",這意味著當使用者點選 Web 容器內的任何連結後,將觸發displayBanner操作,而非直接交由 Web 檢視處理。

此外如果檢視displayBanner操作會發現,這裡出現了變數$jason。在本例中,點選的連結將通過$jason變數傳遞。例如,如果點選一個名為"https://google.com"的 URL,$jason將獲得下列值:
七行JSON程式碼將你的網站變成移動應用

這意味著我們可以 檢查 $jason.url 的值 進而選擇性地觸發不同操作。

用自定義 Web 瀏覽器的實現作為另一個例子一起來看看:
七行JSON程式碼將你的網站變成移動應用

我們會檢查 URL 是否包含字串signin,並根據結果執行兩個不同操作。
  • 如果包含signin,開啟一個新檢視並以原生方式完成登入操作。
  • 如果不包含signin,則直接執行"type": "$default"操作,實現類似普通瀏覽器的行為。
用法示範

構建自定義 Web 瀏覽器

利用新版 Web 容器的下列特性,可以實現很多有趣的操作:
  • 通過url屬性實現自我載入,並充當一個功能齊備的瀏覽器。
  • 根據 URL 的不同,選擇性地處理連結點選操作。
我們甚至可以通過幾十行 JSON 程式碼構建一個自定義的 Web 瀏覽器。由於現在可以劫持每個連結點選,因此可以檢查$jason.url,並根據結果執行我們需要的任何操作。

例如下面的例子:
七行JSON程式碼將你的網站變成移動應用
七行JSON程式碼將你的網站變成移動應用

從上圖可以看到,點選連結後的行為與普通瀏覽器無異("type": "$default")。

從下圖可以看到,點選連結後可以用原生方式轉換至另一個 JASON 檢視。

這一切都可以根據$jason.url的值選擇性地觸發實現。

第 1 步:向 Web 容器附加一個名為visit的操作:
七行JSON程式碼將你的網站變成移動應用

第 2 步:根據$jason.url的值執行visit內部的相關操作

在下列程式碼中,我們會檢查$jason.url是否與newest、show、ask等內容(均為頂級選單項鍊接)相符。如果相符,設定"type": "$default"即可讓 Web 容器做出與普通瀏覽器一樣的行為。

如果模式不符,則可通過原生的$href轉換開啟一個新檢視,並將點選的連結作為引數傳遞過去。
七行JSON程式碼將你的網站變成移動應用

該 Web 瀏覽器的完整 JSON 標記請參閱(僅 48 行!):

https://github.com/Jasonette/Jasonpedia/blob/gh-pages/webcontainer/agent/hijack.json
瞬間構建“混合”應用

人們通常在說“混合”應用時,主要是指封裝在原生應用框架內部的 HTML Web 應用。

但此處說的並不是這種應用。這裡所謂的“混合”是指真正的混合應用,也就是可以同時包含多個原生檢視以及多個基於 Web 的檢視的應用。在這種應用中,一個檢視可以有多個原生 UI 元件,以及一個用相同原生布局渲染的 Web 容器。

Web 檢視與原生檢視的交織應當儘可能無縫,使得使用者完全無法分辨。
七行JSON程式碼將你的網站變成移動應用

在這個例子中,我建立了一個可以在 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 檢視能夠觸發父應用的原生事件
整個解決方案建立了下列內容組成的抽象:
  • 宣告式標記語言:用於描述如何將 Web 檢視嵌入原生應用。
  • 通訊協議(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
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 79 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 1.8 MB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 392.8 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 30.6 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 22.3 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 27.4 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 79.1 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 21.2 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 63.4 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 4.4 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 392.8 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 119 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 126.3 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 64.3 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 6.4 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 74.3 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 1.6 MB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 964.8 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 28.1 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 71.1 KB
  • 七行JSON程式碼將你的網站變成移動應用
  • 大小: 1.8 MB
來自: 前端之巔

相關文章