閱讀更多

0頂
0踩

Web前端

轉載新聞 七行JSON代碼將你的網站變成移動應用

2018-04-24 13:00 by 副主編 jihong10102006 評論(1) 有43809人瀏覽
引用
作者|Ethan
譯者|大愚若智
編輯|覃云

本文介紹了借助 Jasonette 將 Web 視圖和原生組件融合構建真正“混合”應用的做法。

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

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

最簡化的范例效果如下圖所示:

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

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

問得好!這也是本文要講的重點。我們只需要創建一個無縫的 Web 視圖與應用間雙向通信,借此,父應用就可以觸發 Web 視圖內的任何 JavaScript 函數,隨后 Web 視圖即可從外部調用原生 API。

例如:

請注意,這個視圖包含:
  • 原生導航條,以及內置的切換功能
  • 一個 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 文本,例如這樣:

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

解決方案

Web 容器 2.0 增加了url屬性,我們可以嵌入file://形式的本地 HTML,例如這樣(可以從伴隨應用發布的本地 HTML 文件加載):

或者也可以嵌入遠程的http[s]:// URL,例如這樣(可以從遠程 HTML 加載):

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

問題

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

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

解決方案

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

為此我在父應用和子 Web 容器之間使用了一種基于 JSON-RPC 的通信管道。由于 Jasonette 中的一切都是通過 JSON 對象表達的,因此使用 JSON-RPC 標準格式作為通信協議就成了一種非常自然合理的方式。

為了讓 JavaScript 函數能夠調用 Web 容器,需要聲明一個名為$agent.request的操作:

$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 函數的參數數組。
因此完整來看,所用的標記應該是類似這樣的:

這串標記實際上是在說:

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

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

隨后會查找一個名為 login 的 JavaScript 函數并傳遞params下的兩個參數("alice"和"1234")。

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

詳情請參閱 Agent 文檔。

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

范 例  

繼續回到上文介紹的二維碼生成器范例:

  • 其中 底部的文字輸入組件是 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 方法。

4. 對 URL 點擊的處理

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

兩者均為 “全無或全有(All or nothing)”解決方案。
  • 對于“只讀”,Web 容器會忽略用戶的所有交互操作。
  • 對于“普通瀏覽器行為”,Web 容器的表現將與瀏覽器一致。點擊鏈接后,將像普通網頁那樣刷新頁面展示鏈接內容,但無法劫持該點擊并調用其他原生 API。
解決方案

通過使用新的 Web 容器,可以將任何action附加到$jason.body.background這個 Web 容器,進而處理鏈接點擊之類的事件。

一起看一個例子:

在這里我們為 Web 容器附加了"trigger": "displayBanner",這意味著當用戶點擊 Web 容器內的任何鏈接后,將觸發displayBanner操作,而非直接交由 Web 視圖處理。

此外如果查看displayBanner操作會發現,這里出現了變量$jason。在本例中,點擊的鏈接將通過$jason變量傳遞。例如,如果點擊一個名為"https://google.com"的 URL,$jason將獲得下列值:

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

用自定義 Web 瀏覽器的實現作為另一個例子一起來看看:

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

構建自定義 Web 瀏覽器

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

例如下面的例子:


從上圖可以看到,點擊鏈接后的行為與普通瀏覽器無異("type": "$default")。

從下圖可以看到,點擊鏈接后可以用原生方式轉換至另一個 JASON 視圖。

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

第 1 步:向 Web 容器附加一個名為visit的操作:

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

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

如果模式不符,則可通過原生的$href轉換打開一個新視圖,并將點擊的鏈接作為參數傳遞過去。

該 Web 瀏覽器的完整 JSON 標記請參閱(僅 48 行?。?

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

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

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

Web 視圖與原生視圖的交織應當盡可能無縫,使得用戶完全無法分辨。

在這個例子中,我創建了一個可以在 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
  • 大小: 79 KB
  • 大小: 1.8 MB
  • 大小: 392.8 KB
  • 大小: 30.6 KB
  • 大小: 22.3 KB
  • 大小: 27.4 KB
  • 大小: 79.1 KB
  • 大小: 21.2 KB
  • 大小: 63.4 KB
  • 大小: 4.4 KB
  • 大小: 392.8 KB
  • 大小: 119 KB
  • 大小: 126.3 KB
  • 大小: 64.3 KB
  • 大小: 6.4 KB
  • 大小: 74.3 KB
  • 大小: 1.6 MB
  • 大小: 964.8 KB
  • 大小: 28.1 KB
  • 大小: 71.1 KB
  • 大小: 1.8 MB
來自: 前端之巔
0
0
評論 共 1 條 請登錄后發表評論
1 樓 zhaobo123 2018-05-08 10:14
cool!

發表評論

您還沒有登錄,請您登錄后再發表評論

相關推薦

  • 將你的電腦變成WIF

    將你的電腦變成WIFI。。讓手機上網。無需軟件。一定能用的,內含圖文。

  • 1秒將你的電腦變成ftp服務器

    1秒將你的電腦變成ftp服務器..........................................

  • 一秒鐘將你的電腦變成FTP服務器

  • 一秒將你的電腦變成ftp服務器

    一秒將你的電腦變成ftp服務器一秒將你的電腦變成ftp服務器

  • 將你的 CentOS 變成 OSPF 路由器

    導讀 Quagga是一個開源路由軟件套件,可以將Linux變成支持如RIP、OSPF、BGP和IS-IS等主要路由協議的路由器。它具有對IPv4和IPv6的完整支持,并支持路由/前綴過濾。Quagga可以是你生命中的救星,以防你的生產路由器一旦宕機,而你沒有備用的設備而只能等待更換。通過適當的配置,Quagga甚至可以作為生產路由器。 本教程中,我們將連接假設之間具有專線連

  • 如何將你網站升至XHTML?

    首先我們為什么要將網站升至XHTML,因為XHTML是一種更加嚴格和更加純凈的HTML版本,它是由XML和HTML組合而成的,XML是用來裝載數據的,標簽必須被正確地標記,而HTML是用來顯示數據的,因此將兩者的長處結合起來,就有了XHTML。在一般的網站中,有部分的代碼沒有按照HTML的規則也依舊可以運行,這樣子不利于文檔的維護,導致不良的文檔結構形式,而XHTML是W3C的一種標準,它的目標就

  • 七行代碼一個錯誤大家看看

  • [深度學習]七行代碼體驗深度學習的神奇

    簡介 這是深度學習系列的第一節,這個課程是為了讓深度學習更能為大眾接受,為了那些在機器學習和數學方面沒有很深厚背景的同學設計。我們強烈相信深度學習將在很多領域產生變革;比如,這個課程的對象是有計算機編程背景的同學以及想在他們專業領域引用這些技術的人。 這節課的最后,我們將理解如何僅用七行代碼寫出有使用意義的深度學習技術。 為什么現在要學習深度學習技術? 由于下面3個關鍵原因,深度學習現

  • Python-Emojify將你的面部表情變成emoji表情符號

    Emojify - 將你的面部表情變成emoji表情符號

  • 分享 不用路由器!將你的mac變成wifi熱點!

  • 一秒將你的電腦變成ftp服務器(軟件及用法)

    一秒將你的電腦變成ftp服務器 此程序無需安裝。打開后,FTP文件夾默認位置是C:\TEMP 更改FTP文件夾位置:斷開FTP服務,然后自行選擇位置。 比如你的IP是222.71.75.106 那么你的FTP地址就是: FTP://222.71.75.106 連接FTP://222.71.75.106就可以下載你放在FTP文件夾里的東西了. 你的電腦變成ftp服務器了.想讓朋友與你共享你的資料,把你的FTP地址給他,讓他自己下載吧,省著你手動給他傳了. 友情提示:本人已經測試,確實有用.經卡巴2009,NOD32和AVG查殺無毒..

  • python 七行代碼,搞定解析歌詞

  • json變成"·· 怎么解決

    [img=https://img-bbs.csdn.net/upload/201505/20/1432113615_852667.png][/img]rn原本應該是這樣的。rn但是輸出到頁面。就變成這樣了。。該如果解決。。rn[img=https://img-bbs.csdn.net/upload/201505/20/1432113720_998919.png][/img]rn

  • json變成樹形數組

  • 字符串怎么變成json

    var jString = "name=xiaoming&age=18"rn用什么方法可以將字符串jString變成"name":"xiaoming","age":"18"

  • 一行代碼網站變成黑白色調

  • 網站變成灰色,紀念日代碼@IE下

    這個是使網站變成黑白的一段代碼,記錄一下,如果有更好的請留言: 樣式表: [code=&quot;java&quot;] html{filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale='1');} [/code] JS的方式: [code=&quot;java&quot;] parent.document.getElementsByT...

  • 移動應用

  • 程序第七行報錯 BC30002: 未定義類型“SQLConnection”。第七行代碼如下Dim MyConnection As SQLConnection

    rn程序代碼如下提示第七行錯誤,不知道什么意思,應怎么改,會的人請幫忙指正一下rn<%@ Import Namespace="System.Data" %>rn <%@ Import Namespace="System.Data.SQL" %>rn rn rnrnrn Page_load事件演示rn rn

  • Android代碼-適用于移動應用的mopub-sdk

Global site tag (gtag.js) - Google Analytics