七行JSON代碼將你的網(wǎng)站變成移動(dòng)應(yīng)用

2022-07-07    分類: 網(wǎng)站建設(shè)

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


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


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


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


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


在介紹具體做法前你可能會(huì)問:“看著挺酷,但除了在原生應(yīng)用框架內(nèi)展示W(wǎng)eb頁面之外,這種技術(shù)還有什么意義?”


問得好!這也是本文要講的重點(diǎn)。我們只需要?jiǎng)?chuàng)建一個(gè)無縫的Web視圖與應(yīng)用間雙向通信,借此,父應(yīng)用就可以觸發(fā)Web視圖內(nèi)的任何JavaScript函數(shù),隨后Web視圖即可從外部調(diào)用原生API。


例如:


請(qǐng)注意,這個(gè)視圖包含:


原生導(dǎo)航條,以及內(nèi)置的切換功能

一個(gè)Web視圖,其中嵌入了一個(gè)可以生成二維碼的Web應(yīng)用

在底部包含一個(gè)原生的文字輸入組件

上述所有這一切只需要略微調(diào)整JSON代碼的屬性即可實(shí)現(xiàn)。


最后請(qǐng)注意,隨著在文字輸入?yún)^(qū)輸入不同內(nèi)容,二維碼也會(huì)產(chǎn)生相應(yīng)變化。輸入的文字可觸發(fā)二維碼生成器Web應(yīng)用內(nèi)部的JavaScript函數(shù)重新生成二維碼圖像。


目前還沒有任何一個(gè)開發(fā)框架曾試圖從根本上解決“Web視圖與原生應(yīng)用無縫集成”的問題,因?yàn)檫@些框架都專注于完全原生,或完全HTML5的做法。


無論什么時(shí)候當(dāng)我們聽到有人討論移動(dòng)應(yīng)用的未來時(shí),很可能會(huì)聽到類似“到底是HTML5還是原生方法會(huì)最終勝出呢?”這樣的說法。


似乎沒人覺得native和html可以共存,而且二者的協(xié)同和最終實(shí)現(xiàn)似乎也并不容易。


本文我將要介紹:


為何Web引擎與原生組件的融合通常是一種更好的做法。

為何HTML與原生的無縫集成那么難,具體又該如何實(shí)現(xiàn)。

更重要的是,該如何使用這樣的技術(shù)快速構(gòu)建自己的應(yīng)用。

為何要在原生應(yīng)用中使用HTML?


在進(jìn)一步介紹前,首先一起看看這樣做是好是壞,以及什么時(shí)候適合使用這種方法。這種做法的一些潛在用例如下:


1. 使用Web原生功能


應(yīng)用中的部分內(nèi)容使用Web引擎來實(shí)現(xiàn)也許是一種更適合的做法。例如WebSocket是一種原生的Web功能,主要面向Web環(huán)境而設(shè)計(jì)。這種情況下就更適合使用內(nèi)建的Web引擎(iOS的WKWebView以及Android的WebView),而非安裝某些只能“模擬”WebSocket的第三方庫。


無需額外安裝任何代碼,使用免費(fèi)工具即可實(shí)現(xiàn)目標(biāo),這樣豈不是更好。同時(shí)這也催生了下一個(gè)原因。


2. 避免二進(jìn)制文件體積過大


有些功能也許需要借助龐大的第三方庫,而你可能希望能快速用上這樣的功能。


例如,為了以原生方式包含二維碼圖像生成器,可能需要安裝某些第三方庫,這會(huì)導(dǎo)致二進(jìn)制文件體積增大。但如果使用Web視圖引擎并通過一個(gè)簡單的<script src>調(diào)用JavaScript庫,就可以免費(fèi)實(shí)現(xiàn)這一切,并且避免了使用第三方原生庫。


3. 缺乏可靠的移動(dòng)庫


對(duì)于一些前沿技術(shù),可能暫時(shí)并不具備穩(wěn)定可靠的移動(dòng)端實(shí)現(xiàn)。


好在大部分此類技術(shù)都具備Web實(shí)現(xiàn),因此高效的集成方法就是使用JavaScript庫。


4. 構(gòu)建部分原生,部分基于Web的應(yīng)用


很多新手開發(fā)者想要將自己的網(wǎng)站移植為移動(dòng)應(yīng)用,但在發(fā)現(xiàn)自己現(xiàn)有網(wǎng)站的部分功能過于復(fù)雜,無法面向每種移動(dòng)平臺(tái)快速重寫時(shí),往往會(huì)感到沮喪或受挫。


例如你可能有一個(gè)非常復(fù)雜的Web頁面無法快速轉(zhuǎn)換為移動(dòng)應(yīng)用,但網(wǎng)站的其他內(nèi)容可以很容易地轉(zhuǎn)換。


面對(duì)這種情況,如果通過某種方法將應(yīng)用的大部分內(nèi)容以原生方式構(gòu)建,對(duì)于特別復(fù)雜的頁面直接將其以HTML的形式無縫集成到應(yīng)用中,是不是很棒啊。


這是如何實(shí)現(xiàn)的?


A. Jasonette


Jasonette是一種基于標(biāo)記語言,構(gòu)建跨平臺(tái)原生應(yīng)用的開源方法。


該技術(shù)看似Web瀏覽器,但并不會(huì)將HTML標(biāo)記語言解釋為Web頁面,而是會(huì)將JSON標(biāo)記解釋為iOS和Android上的原生應(yīng)用。


正如所有Web瀏覽器都有完全相同的代碼,但只要按需解釋不同類型的HTML標(biāo)記,即可為用戶提供所有不同類型的Web應(yīng)用,所有Jasonette應(yīng)用也有著完全相同的庫,可按需解釋不同類型的JSON標(biāo)記并創(chuàng)建出你的應(yīng)用。開發(fā)者完全無需觸及代碼本身,只需要編寫標(biāo)記,將代碼實(shí)時(shí)“翻譯”為原生應(yīng)用,即可開發(fā)出自己的應(yīng)用來。


有關(guān)Jasonette的詳細(xì)介紹可以參閱這里。


雖然Jasonette的核心作用在于構(gòu)建原生應(yīng)用,但本文的重點(diǎn)在于介紹如何將HTML集成到核心原生引擎中,接下來就一起了解一下吧。


B. Jasonette Web容器


原生應(yīng)用很棒,但有時(shí)候我們依然需要使用Web功能。


但Web視圖與原生應(yīng)用的集成是個(gè)麻煩的過程。無縫的集成要求:


Web視圖應(yīng)作為原生布局的一部分進(jìn)行集成:Web視圖應(yīng)作為原生布局的一部分納入應(yīng)用中,并且操作方式應(yīng)與其他任何原生UI組件保持一致。否則會(huì)讓用戶感覺很笨拙,并且感覺上就像自己實(shí)際上是在訪問網(wǎng)站那樣。

父應(yīng)用可以控制子Web容器:父應(yīng)用應(yīng)能隨意控制子Web視圖。

子Web容器可觸發(fā)父應(yīng)用的原生事件:子應(yīng)用應(yīng)該能觸發(fā)父應(yīng)用的事件以運(yùn)行原生API。

這是一個(gè)非常繁重的工作,因此先從第一個(gè)環(huán)節(jié)著手介紹:直接將Web容器嵌入原生布局?—并將其作為第1版發(fā)布:


JSON Web容器,JSON中的HTML將變?yōu)樵鷳?yīng)用組件。


僅這一點(diǎn)就已經(jīng)很實(shí)用了,但由于無法交互,依然存在一定的局限。


父應(yīng)用無法控制子Web容器,子容器無法向父應(yīng)用發(fā)送任何事件通知,這導(dǎo)致Web容器與外界完全隔離。


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


發(fā)布第1版之后,我們開始處理第二個(gè)問題:為Web容器添加交互能力。


下文將介紹如何為之前創(chuàng)建的靜態(tài)Web容器添加交互能力,讓它變得更強(qiáng)大。


實(shí)現(xiàn):交互式Web容器


1. 通過URL加載


問題


之前在第1版中,為了使用Web容器作為后臺(tái)視圖組件,我們首先需要將$jason.body.background.type設(shè)置為"html",隨后在$jason.body.background.text屬性下添加硬編碼的HTML文本,例如這樣:


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


解決方案


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


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


2. 父應(yīng)用與Web容器的雙向通信


問題


之前,Web容器只能用于展示內(nèi)容,無法交互。這意味著下列做法全部無法實(shí)現(xiàn):


Jasonette到Web容器的通信:從Jasonette中調(diào)用Web容器內(nèi)部的JavaScript函數(shù)。

Web容器到Jasonette的通信:從Web容器代碼中調(diào)用原生API。

此時(shí)我們只能展示W(wǎng)eb容器的內(nèi)容。這就像網(wǎng)頁中嵌入的iframe框架,主頁面完全無法訪問iframe框架中的內(nèi)容。


解決方案


Jasonette大的目標(biāo)在于設(shè)計(jì)一種可以描述跨平臺(tái)移動(dòng)應(yīng)用的標(biāo)準(zhǔn)化標(biāo)記語言。因此我們需要這個(gè)標(biāo)記語言能夠全面地描述父應(yīng)用和子Web容器之間的雙向通信。


為此我在父應(yīng)用和子Web容器之間使用了一種基于JSON-RPC的通信管道。由于Jasonette中的一切都是通過JSON對(duì)象表達(dá)的,因此使用JSON-RPC標(biāo)準(zhǔn)格式作為通信協(xié)議就成了一種非常自然合理的方式。


為了讓JavaScript函數(shù)能夠調(diào)用Web容器,需要聲明一個(gè)名為$agent.request的操作:


$agent.request是一種原生API,可觸發(fā)JSON-RPC請(qǐng)求并發(fā)送給Web容器。為了使用該API,必須將options對(duì)象作為參數(shù)傳遞。


options對(duì)象實(shí)際上是發(fā)送給Web容器的JSON-RPC請(qǐng)求。每個(gè)屬性的含義如下:


id:Web容器構(gòu)建在一種名為Agent的底層架構(gòu)基礎(chǔ)上,通常來說,我們可以為一個(gè)視圖使用多個(gè)Agent,每個(gè)Agent可以有自己的ID。但Web容器是一種特殊類型的Agent,只能使用$webcontainer作為ID,因此這里需要使用ID。

method:要調(diào)用的JavaScript函數(shù)名稱。

params:傳遞給JavaScript函數(shù)的參數(shù)數(shù)組。

因此完整來看,所用的標(biāo)記應(yīng)該是類似這樣的:


這串標(biāo)記實(shí)際上是在說:


當(dāng)視圖加載(load)時(shí),向Web容器Agent發(fā)送一個(gè)JSON-RPC請(qǐng)求($agent.request),而具體的請(qǐng)求是通過options指定的。


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


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


上文介紹了父應(yīng)用如何觸發(fā)子Web容器的JavaScript函數(shù)調(diào)用,我們還可以反著來,讓W(xué)eb容器觸發(fā)父應(yīng)用的原生API。


詳情請(qǐng)參閱Agent文檔。


范例


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


其中底部的文字輸入組件是100%原生的。

二維碼由作為Web應(yīng)用運(yùn)行的Web容器生成。

當(dāng)用戶輸入內(nèi)容并按下“生成”,將調(diào)用Web容器Agent中的$agent.request操作,進(jìn)而調(diào)用JavaScript函數(shù)“qr”。

具體示例可以參閱這里。


3. 腳本注入


問題


有時(shí)候我們可能需要在Web容器完成初始HTML加載后,動(dòng)態(tài)地將JavaScript代碼注入Web容器。


假設(shè)要構(gòu)建一個(gè)自定義的Web瀏覽器應(yīng)用,我們可能希望將自己的自定義JavaScript注入到每個(gè)Web視圖,借此定制Web視圖的行為,這有點(diǎn)類似于Web瀏覽器的擴(kuò)展。


就算不需要構(gòu)建Web瀏覽器,當(dāng)希望為所包含的內(nèi)容不由我們控制的URL實(shí)現(xiàn)自定義行為時(shí),同樣需要使用腳本注入的方法。原生應(yīng)用和Web容器只能通過$agent API通信,但如果無法更改HTML內(nèi)容,只能通過動(dòng)態(tài)注入的方式將$agent接口加入Web容器。


解決方案


正如上文所述,$jason.body.background這個(gè)Web容器也是一個(gè)agent,這意味著我們可以使用與普通Agent完全相同的$agent.inject方法。


4. 對(duì)URL點(diǎn)擊的處理


以往,Web容器只能通過兩種方式處理鏈接點(diǎn)擊操作:


只讀:將Web容器視作只讀的,忽略所有諸如觸控或滾動(dòng)等事件。此時(shí)所有Web容器都是只讀的,除非明確令其表現(xiàn)得像是普通瀏覽器,具體做法見下文。

普通瀏覽器行為:像是普通瀏覽器那樣,允許用戶與頁面交互。為此需要進(jìn)行聲明,將"type": "$default"設(shè)置為action屬性。

問題


兩者均為“全無或全有(All or nothing)”解決方案。


對(duì)于“只讀”,Web容器會(huì)忽略用戶的所有交互操作。

對(duì)于“普通瀏覽器行為”,Web容器的表現(xiàn)將與瀏覽器一致。點(diǎn)擊鏈接后,將像普通網(wǎng)頁那樣刷新頁面展示鏈接內(nèi)容,但無法劫持該點(diǎn)擊并調(diào)用其他原生API。

解決方案


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


一起看一個(gè)例子:


在這里我們?yōu)閃eb容器附加了"trigger": "displayBanner",這意味著當(dāng)用戶點(diǎn)擊Web容器內(nèi)的任何鏈接后,將觸發(fā)displayBanner操作,而非直接交由Web視圖處理。


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


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


用自定義Web瀏覽器的實(shí)現(xiàn)作為另一個(gè)例子一起來看看:


我們會(huì)檢查URL是否包含字符串signin,并根據(jù)結(jié)果執(zhí)行兩個(gè)不同操作。


如果包含signin,打開一個(gè)新視圖并以原生方式完成登錄操作。

如果不包含signin,則直接運(yùn)行"type": "$default"操作,實(shí)現(xiàn)類似普通瀏覽器的行為。

用法示范


構(gòu)建自定義Web瀏覽器


利用新版Web容器的下列特性,可以實(shí)現(xiàn)很多有趣的操作:


通過url屬性實(shí)現(xiàn)自我加載,并充當(dāng)一個(gè)功能齊備的瀏覽器。

根據(jù)URL的不同,選擇性地處理鏈接點(diǎn)擊操作。

我們甚至可以通過幾十行JSON代碼構(gòu)建一個(gè)自定義的Web瀏覽器。由于現(xiàn)在可以劫持每個(gè)鏈接點(diǎn)擊,因此可以檢查$jason.url,并根據(jù)結(jié)果運(yùn)行我們需要的任何操作。


例如下面的例子:


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


從右圖可以看到,點(diǎn)擊鏈接后可以用原生方式轉(zhuǎn)換至另一個(gè)JASON視圖。


這一切都可以根據(jù)$jason.url的值選擇性地觸發(fā)實(shí)現(xiàn)。


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


第2步:根據(jù)$jason.url的值運(yùn)行visit內(nèi)部的相關(guān)操作


在下列代碼中,我們會(huì)檢查$jason.url是否與newest、show、ask等內(nèi)容(均為頂級(jí)菜單項(xiàng)鏈接)相符。如果相符,設(shè)置"type": "$default"即可讓W(xué)eb容器做出與普通瀏覽器一樣的行為。


如果模式不符,則可通過原生的$href轉(zhuǎn)換打開一個(gè)新視圖,并將點(diǎn)擊的鏈接作為參數(shù)傳遞過去。


該Web瀏覽器的完整JSON標(biāo)記請(qǐng)參閱這里(僅48行?。?。


瞬間構(gòu)建“混合”應(yīng)用


人們通常在說“混合”應(yīng)用時(shí),主要是指封裝在原生應(yīng)用框架內(nèi)部的HTML Web應(yīng)用。


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


Web視圖與原生視圖的交織應(yīng)當(dāng)盡可能無縫,使得用戶完全無法分辨。


在這個(gè)例子中,我創(chuàng)建了一個(gè)可以在Web容器中顯示jasonbase.com的內(nèi)容,并將其作為主頁視圖的應(yīng)用。


Jasonbase是我開發(fā)的免費(fèi)JSON托管服務(wù),該服務(wù)可以很簡單地用于托管Jasonette應(yīng)用所用到的JSON標(biāo)記。


當(dāng)然,這本身是個(gè)網(wǎng)站,但我將其嵌入到Jasonette中,因此在點(diǎn)擊鏈接后并不會(huì)打開網(wǎng)頁,而是會(huì)通過原生的$href轉(zhuǎn)換展示原生的JASON視圖。


完全無需觸及Jasonbase.com的代碼就可以構(gòu)建出這個(gè)應(yīng)用。


只需要將網(wǎng)站作為Web容器嵌入Jasonette,隨后劫持鏈接點(diǎn)擊操作的原生處理方式,這樣就可以實(shí)現(xiàn)原生應(yīng)用所具備的各類功能,例如觸發(fā)原生API以及進(jìn)行原生轉(zhuǎn)換。


完整代碼可參閱這里。


結(jié)論


在我看來,讓這一切如此令人贊嘆的原因在于,在框架層面上即可妥善處理好一切。所有最困難的工作都是在后臺(tái)完成的。


應(yīng)用開發(fā)者并不需要自行費(fèi)時(shí)費(fèi)力從零開始實(shí)現(xiàn)下列這一切:


將Web視圖嵌入原生布局

創(chuàng)建JavaScript橋,以便讓應(yīng)用能夠調(diào)用Web視圖中的函數(shù)

創(chuàng)建原生事件處理架構(gòu),以便讓W(xué)eb視圖能夠觸發(fā)父應(yīng)用的原生事件

整個(gè)解決方案創(chuàng)建了下列內(nèi)容組成的抽象:


聲明式標(biāo)記語言:用于描述如何將Web視圖嵌入原生應(yīng)用。

通信協(xié)議(JSON-RPC):用于在應(yīng)用及其子Web視圖之間實(shí)現(xiàn)極為簡單的通信。

我并不覺得這種方法可以解決所有問題,但從自己的用例來看,至少可以說這是個(gè)不錯(cuò)的解決方案。


我試著以非常前沿的技術(shù)來構(gòu)建應(yīng)用,而這些技術(shù)已經(jīng)前沿到在移動(dòng)端還沒有任何穩(wěn)定可靠的實(shí)現(xiàn)(由于協(xié)議的一些本質(zhì),甚至不清楚最終是否會(huì)有移動(dòng)端的實(shí)現(xiàn))。好在這些技術(shù)都有JavaScript實(shí)現(xiàn),因此不費(fèi)什么事就可以輕松地將其與應(yīng)用相集成。


總的來說,這種技術(shù)很棒,我對(duì)目前的效果非常滿意。最新版文檔已經(jīng)包含了所有新功能,歡迎大家深入研究并嘗試。


聲明:能力越大,需要擔(dān)負(fù)的責(zé)任也就越大


最后我想說:雖然這種新技術(shù)確實(shí)很強(qiáng)大,但我覺得大家在開發(fā)應(yīng)用時(shí)都應(yīng)該在用戶體驗(yàn)方面進(jìn)行更全面的權(quán)衡。


有些人可能會(huì)借助這種技術(shù)構(gòu)建完全由Web視圖組成的應(yīng)用,但說到底這樣的做法,你的應(yīng)用實(shí)際上就只是一個(gè)網(wǎng)站,已經(jīng)與開發(fā)專屬應(yīng)用的本意背道而馳了。


需要強(qiáng)調(diào)的是,我并不認(rèn)為你的每個(gè)應(yīng)用都應(yīng)同時(shí)包含HTML和原生組件。我只是認(rèn)為,這樣的做法對(duì)很多面臨某些具體狀況的人會(huì)顯得較為有用。只不過別過火就好。


閱讀原文


本文最初發(fā)布于Ethan的博客,經(jīng)原作者授權(quán)由InfoQ中文站翻譯并分享。英文原文請(qǐng)看:How to Turn Your Website into a Mobile App with 7 Lines of JSON

網(wǎng)站標(biāo)題:七行JSON代碼將你的網(wǎng)站變成移動(dòng)應(yīng)用
分享網(wǎng)址:http://www.muchs.cn/news42/175292.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗(yàn)、網(wǎng)站排名手機(jī)網(wǎng)站建設(shè)、網(wǎng)站策劃、Google響應(yīng)式網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁設(shè)計(jì)