2022-07-07 分類: 網(wǎng)站建設(shè)
本文介紹了借助Jasonette將Web視圖和原生組件融合構(gòu)建真正“混合”應(yīng)用的做法。
如果我告訴你,只需要上述7行橙色的JSON代碼就可以將一個網(wǎng)站變成移動應(yīng)用,你相信嗎?完全不需要使用某種框架API重寫網(wǎng)站,就可以獲得與移動應(yīng)用相同的行為。如果你已經(jīng)有一個現(xiàn)成的網(wǎng)站,只需要簡單地引用URL就可以將其“打包”為原生應(yīng)用。
而如果在此基礎(chǔ)上,只需要略微調(diào)整JSON代碼內(nèi)容,就可以直接訪問所有原生API、原生UI組件以及原生視圖切換(View Transition)。
最簡化的范例效果如下圖所示:
從中可以看出,我嵌入了一個GitHub.com的Web頁面,但界面上其余布局均為原生UI組件,例如導(dǎo)航條以及底部的標(biāo)簽欄。而我們并不需要使用任何API重寫網(wǎng)站,就可以自動獲得原生的切換效果。
在介紹具體做法前你可能會問:“看著挺酷,但除了在原生應(yīng)用框架內(nèi)展示W(wǎng)eb頁面之外,這種技術(shù)還有什么意義?”
問得好!這也是本文要講的重點。我們只需要創(chuàng)建一個無縫的Web視圖與應(yīng)用間雙向通信,借此,父應(yīng)用就可以觸發(fā)Web視圖內(nèi)的任何JavaScript函數(shù),隨后Web視圖即可從外部調(diào)用原生API。
例如:
請注意,這個視圖包含:
原生導(dǎo)航條,以及內(nèi)置的切換功能
一個Web視圖,其中嵌入了一個可以生成二維碼的Web應(yīng)用
在底部包含一個原生的文字輸入組件
上述所有這一切只需要略微調(diào)整JSON代碼的屬性即可實現(xiàn)。
最后請注意,隨著在文字輸入?yún)^(qū)輸入不同內(nèi)容,二維碼也會產(chǎn)生相應(yīng)變化。輸入的文字可觸發(fā)二維碼生成器Web應(yīng)用內(nèi)部的JavaScript函數(shù)重新生成二維碼圖像。
目前還沒有任何一個開發(fā)框架曾試圖從根本上解決“Web視圖與原生應(yīng)用無縫集成”的問題,因為這些框架都專注于完全原生,或完全HTML5的做法。
無論什么時候當(dāng)我們聽到有人討論移動應(yīng)用的未來時,很可能會聽到類似“到底是HTML5還是原生方法會最終勝出呢?”這樣的說法。
似乎沒人覺得native和html可以共存,而且二者的協(xié)同和最終實現(xiàn)似乎也并不容易。
本文我將要介紹:
為何Web引擎與原生組件的融合通常是一種更好的做法。
為何HTML與原生的無縫集成那么難,具體又該如何實現(xiàn)。
更重要的是,該如何使用這樣的技術(shù)快速構(gòu)建自己的應(yīng)用。
為何要在原生應(yīng)用中使用HTML?
在進(jìn)一步介紹前,首先一起看看這樣做是好是壞,以及什么時候適合使用這種方法。這種做法的一些潛在用例如下:
1. 使用Web原生功能
應(yīng)用中的部分內(nèi)容使用Web引擎來實現(xiàn)也許是一種更適合的做法。例如WebSocket是一種原生的Web功能,主要面向Web環(huán)境而設(shè)計。這種情況下就更適合使用內(nèi)建的Web引擎(iOS的WKWebView以及Android的WebView),而非安裝某些只能“模擬”WebSocket的第三方庫。
無需額外安裝任何代碼,使用免費工具即可實現(xiàn)目標(biāo),這樣豈不是更好。同時這也催生了下一個原因。
2. 避免二進(jìn)制文件體積過大
有些功能也許需要借助龐大的第三方庫,而你可能希望能快速用上這樣的功能。
例如,為了以原生方式包含二維碼圖像生成器,可能需要安裝某些第三方庫,這會導(dǎo)致二進(jìn)制文件體積增大。但如果使用Web視圖引擎并通過一個簡單的<script src>調(diào)用JavaScript庫,就可以免費實現(xiàn)這一切,并且避免了使用第三方原生庫。
3. 缺乏可靠的移動庫
對于一些前沿技術(shù),可能暫時并不具備穩(wěn)定可靠的移動端實現(xiàn)。
好在大部分此類技術(shù)都具備Web實現(xiàn),因此高效的集成方法就是使用JavaScript庫。
4. 構(gòu)建部分原生,部分基于Web的應(yīng)用
很多新手開發(fā)者想要將自己的網(wǎng)站移植為移動應(yīng)用,但在發(fā)現(xiàn)自己現(xiàn)有網(wǎng)站的部分功能過于復(fù)雜,無法面向每種移動平臺快速重寫時,往往會感到沮喪或受挫。
例如你可能有一個非常復(fù)雜的Web頁面無法快速轉(zhuǎn)換為移動應(yīng)用,但網(wǎng)站的其他內(nèi)容可以很容易地轉(zhuǎn)換。
面對這種情況,如果通過某種方法將應(yīng)用的大部分內(nèi)容以原生方式構(gòu)建,對于特別復(fù)雜的頁面直接將其以HTML的形式無縫集成到應(yīng)用中,是不是很棒啊。
這是如何實現(xiàn)的?
A. Jasonette
Jasonette是一種基于標(biāo)記語言,構(gòu)建跨平臺原生應(yīng)用的開源方法。
該技術(shù)看似Web瀏覽器,但并不會將HTML標(biāo)記語言解釋為Web頁面,而是會將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)記,將代碼實時“翻譯”為原生應(yīng)用,即可開發(fā)出自己的應(yīng)用來。
有關(guān)Jasonette的詳細(xì)介紹可以參閱這里。
雖然Jasonette的核心作用在于構(gòu)建原生應(yīng)用,但本文的重點在于介紹如何將HTML集成到核心原生引擎中,接下來就一起了解一下吧。
B. Jasonette Web容器
原生應(yīng)用很棒,但有時候我們依然需要使用Web功能。
但Web視圖與原生應(yīng)用的集成是個麻煩的過程。無縫的集成要求:
Web視圖應(yīng)作為原生布局的一部分進(jìn)行集成:Web視圖應(yīng)作為原生布局的一部分納入應(yīng)用中,并且操作方式應(yīng)與其他任何原生UI組件保持一致。否則會讓用戶感覺很笨拙,并且感覺上就像自己實際上是在訪問網(wǎng)站那樣。
父應(yīng)用可以控制子Web容器:父應(yīng)用應(yīng)能隨意控制子Web視圖。
子Web容器可觸發(fā)父應(yīng)用的原生事件:子應(yīng)用應(yīng)該能觸發(fā)父應(yīng)用的事件以運行原生API。
這是一個非常繁重的工作,因此先從第一個環(huán)節(jié)著手介紹:直接將Web容器嵌入原生布局?—并將其作為第1版發(fā)布:
JSON Web容器,JSON中的HTML將變?yōu)樵鷳?yīng)用組件。
僅這一點就已經(jīng)很實用了,但由于無法交互,依然存在一定的局限。
父應(yīng)用無法控制子Web容器,子容器無法向父應(yīng)用發(fā)送任何事件通知,這導(dǎo)致Web容器與外界完全隔離。
C. Jasonette Web容器2.0:使其可交互
發(fā)布第1版之后,我們開始處理第二個問題:為Web容器添加交互能力。
下文將介紹如何為之前創(chuàng)建的靜態(tài)Web容器添加交互能力,讓它變得更強(qiáng)大。
實現(xiàn):交互式Web容器
1. 通過URL加載
問題
之前在第1版中,為了使用Web容器作為后臺視圖組件,我們首先需要將$jason.body.background.type設(shè)置為"html",隨后在$jason.body.background.text屬性下添加硬編碼的HTML文本,例如這樣:
一般來說,人們往往更希望直接使用Web URL對容器進(jìn)行實例化,而不希望將整個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)容,無法交互。這意味著下列做法全部無法實現(xiàn):
Jasonette到Web容器的通信:從Jasonette中調(diào)用Web容器內(nèi)部的JavaScript函數(shù)。
Web容器到Jasonette的通信:從Web容器代碼中調(diào)用原生API。
此時我們只能展示W(wǎng)eb容器的內(nèi)容。這就像網(wǎng)頁中嵌入的iframe框架,主頁面完全無法訪問iframe框架中的內(nèi)容。
解決方案
Jasonette大的目標(biāo)在于設(shè)計一種可以描述跨平臺移動應(yīng)用的標(biāo)準(zhǔn)化標(biāo)記語言。因此我們需要這個標(biāo)記語言能夠全面地描述父應(yīng)用和子Web容器之間的雙向通信。
為此我在父應(yīng)用和子Web容器之間使用了一種基于JSON-RPC的通信管道。由于Jasonette中的一切都是通過JSON對象表達(dá)的,因此使用JSON-RPC標(biāo)準(zhǔn)格式作為通信協(xié)議就成了一種非常自然合理的方式。
為了讓JavaScript函數(shù)能夠調(diào)用Web容器,需要聲明一個名為$agent.request的操作:
$agent.request是一種原生API,可觸發(fā)JSON-RPC請求并發(fā)送給Web容器。為了使用該API,必須將options對象作為參數(shù)傳遞。
options對象實際上是發(fā)送給Web容器的JSON-RPC請求。每個屬性的含義如下:
id:Web容器構(gòu)建在一種名為Agent的底層架構(gòu)基礎(chǔ)上,通常來說,我們可以為一個視圖使用多個Agent,每個Agent可以有自己的ID。但Web容器是一種特殊類型的Agent,只能使用$webcontainer作為ID,因此這里需要使用ID。
method:要調(diào)用的JavaScript函數(shù)名稱。
params:傳遞給JavaScript函數(shù)的參數(shù)數(shù)組。
因此完整來看,所用的標(biāo)記應(yīng)該是類似這樣的:
這串標(biāo)記實際上是在說:
當(dāng)視圖加載(load)時,向Web容器Agent發(fā)送一個JSON-RPC請求($agent.request),而具體的請求是通過options指定的。
Web容器在$jason.body.background下定義,本例中將會加載一個名為file://index.html的本地文件。
隨后會查找一個名為login的JavaScript函數(shù)并傳遞params下的兩個參數(shù)("alice"和"1234")。
上文介紹了父應(yīng)用如何觸發(fā)子Web容器的JavaScript函數(shù)調(diào)用,我們還可以反著來,讓W(xué)eb容器觸發(fā)父應(yīng)用的原生API。
詳情請參閱Agent文檔。
范例
繼續(xù)回到上文介紹的二維碼生成器范例:
其中底部的文字輸入組件是100%原生的。
二維碼由作為Web應(yīng)用運行的Web容器生成。
當(dāng)用戶輸入內(nèi)容并按下“生成”,將調(diào)用Web容器Agent中的$agent.request操作,進(jìn)而調(diào)用JavaScript函數(shù)“qr”。
具體示例可以參閱這里。
3. 腳本注入
問題
有時候我們可能需要在Web容器完成初始HTML加載后,動態(tài)地將JavaScript代碼注入Web容器。
假設(shè)要構(gòu)建一個自定義的Web瀏覽器應(yīng)用,我們可能希望將自己的自定義JavaScript注入到每個Web視圖,借此定制Web視圖的行為,這有點類似于Web瀏覽器的擴(kuò)展。
就算不需要構(gòu)建Web瀏覽器,當(dāng)希望為所包含的內(nèi)容不由我們控制的URL實現(xiàn)自定義行為時,同樣需要使用腳本注入的方法。原生應(yīng)用和Web容器只能通過$agent API通信,但如果無法更改HTML內(nèi)容,只能通過動態(tài)注入的方式將$agent接口加入Web容器。
正如上文所述,$jason.body.background這個Web容器也是一個agent,這意味著我們可以使用與普通Agent完全相同的$agent.inject方法。
4. 對URL點擊的處理
以往,Web容器只能通過兩種方式處理鏈接點擊操作:
只讀:將Web容器視作只讀的,忽略所有諸如觸控或滾動等事件。此時所有Web容器都是只讀的,除非明確令其表現(xiàn)得像是普通瀏覽器,具體做法見下文。
普通瀏覽器行為:像是普通瀏覽器那樣,允許用戶與頁面交互。為此需要進(jìn)行聲明,將"type": "$default"設(shè)置為action屬性。
問題
兩者均為“全無或全有(All or nothing)”解決方案。
對于“只讀”,Web容器會忽略用戶的所有交互操作。
對于“普通瀏覽器行為”,Web容器的表現(xiàn)將與瀏覽器一致。點擊鏈接后,將像普通網(wǎng)頁那樣刷新頁面展示鏈接內(nèi)容,但無法劫持該點擊并調(diào)用其他原生API。
解決方案
通過使用新的Web容器,可以將任何action附加到$jason.body.background這個Web容器,進(jìn)而處理鏈接點擊之類的事件。
一起看一個例子:
在這里我們?yōu)閃eb容器附加了"trigger": "displayBanner",這意味著當(dāng)用戶點擊Web容器內(nèi)的任何鏈接后,將觸發(fā)displayBanner操作,而非直接交由Web視圖處理。
此外如果查看displayBanner操作會發(fā)現(xiàn),這里出現(xiàn)了變量$jason。在本例中,點擊的鏈接將通過$jason變量傳遞。例如,如果點擊一個名為"https://google.com"的URL,$jason將獲得下列值:
這意味著我們可以檢查$jason.url的值進(jìn)而選擇性地觸發(fā)不同操作。
用自定義Web瀏覽器的實現(xiàn)作為另一個例子一起來看看:
我們會檢查URL是否包含字符串signin,并根據(jù)結(jié)果執(zhí)行兩個不同操作。
如果包含signin,打開一個新視圖并以原生方式完成登錄操作。
如果不包含signin,則直接運行"type": "$default"操作,實現(xiàn)類似普通瀏覽器的行為。
用法示范
構(gòu)建自定義Web瀏覽器
利用新版Web容器的下列特性,可以實現(xiàn)很多有趣的操作:
通過url屬性實現(xiàn)自我加載,并充當(dāng)一個功能齊備的瀏覽器。
根據(jù)URL的不同,選擇性地處理鏈接點擊操作。
我們甚至可以通過幾十行JSON代碼構(gòu)建一個自定義的Web瀏覽器。由于現(xiàn)在可以劫持每個鏈接點擊,因此可以檢查$jason.url,并根據(jù)結(jié)果運行我們需要的任何操作。
例如下面的例子:
從左圖可以看到,點擊鏈接后的行為與普通瀏覽器無異("type": "$default")。
從右圖可以看到,點擊鏈接后可以用原生方式轉(zhuǎn)換至另一個JASON視圖。
這一切都可以根據(jù)$jason.url的值選擇性地觸發(fā)實現(xiàn)。
第1步:向Web容器附加一個名為visit的操作:
第2步:根據(jù)$jason.url的值運行visit內(nèi)部的相關(guān)操作
在下列代碼中,我們會檢查$jason.url是否與newest、show、ask等內(nèi)容(均為頂級菜單項鏈接)相符。如果相符,設(shè)置"type": "$default"即可讓W(xué)eb容器做出與普通瀏覽器一樣的行為。
如果模式不符,則可通過原生的$href轉(zhuǎn)換打開一個新視圖,并將點擊的鏈接作為參數(shù)傳遞過去。
該Web瀏覽器的完整JSON標(biāo)記請參閱這里(僅48行?。?/p>
瞬間構(gòu)建“混合”應(yīng)用
人們通常在說“混合”應(yīng)用時,主要是指封裝在原生應(yīng)用框架內(nèi)部的HTML Web應(yīng)用。
但此處說的并不是這種應(yīng)用。這里所謂的“混合”是指真正的混合應(yīng)用,也就是可以同時包含多個原生視圖以及多個基于Web的視圖的應(yīng)用。在這種應(yīng)用中,一個視圖可以有多個原生UI組件,以及一個用相同原生布局渲染的Web容器。
Web視圖與原生視圖的交織應(yīng)當(dāng)盡可能無縫,使得用戶完全無法分辨。
在這個例子中,我創(chuàng)建了一個可以在Web容器中顯示jasonbase.com的內(nèi)容,并將其作為主頁視圖的應(yīng)用。
Jasonbase是我開發(fā)的免費JSON托管服務(wù),該服務(wù)可以很簡單地用于托管Jasonette應(yīng)用所用到的JSON標(biāo)記。
當(dāng)然,這本身是個網(wǎng)站,但我將其嵌入到Jasonette中,因此在點擊鏈接后并不會打開網(wǎng)頁,而是會通過原生的$href轉(zhuǎn)換展示原生的JASON視圖。
完全無需觸及Jasonbase.com的代碼就可以構(gòu)建出這個應(yīng)用。
只需要將網(wǎng)站作為Web容器嵌入Jasonette,隨后劫持鏈接點擊操作的原生處理方式,這樣就可以實現(xiàn)原生應(yīng)用所具備的各類功能,例如觸發(fā)原生API以及進(jìn)行原生轉(zhuǎn)換。
完整代碼可參閱這里。
結(jié)論
在我看來,讓這一切如此令人贊嘆的原因在于,在框架層面上即可妥善處理好一切。所有最困難的工作都是在后臺完成的。
應(yīng)用開發(fā)者并不需要自行費時費力從零開始實現(xiàn)下列這一切:
將Web視圖嵌入原生布局
創(chuàng)建JavaScript橋,以便讓應(yīng)用能夠調(diào)用Web視圖中的函數(shù)
創(chuàng)建原生事件處理架構(gòu),以便讓W(xué)eb視圖能夠觸發(fā)父應(yīng)用的原生事件
整個解決方案創(chuàng)建了下列內(nèi)容組成的抽象:
聲明式標(biāo)記語言:用于描述如何將Web視圖嵌入原生應(yīng)用。
通信協(xié)議(JSON-RPC):用于在應(yīng)用及其子Web視圖之間實現(xiàn)極為簡單的通信。
我并不覺得這種方法可以解決所有問題,但從自己的用例來看,至少可以說這是個不錯的解決方案。
我試著以非常前沿的技術(shù)來構(gòu)建應(yīng)用,而這些技術(shù)已經(jīng)前沿到在移動端還沒有任何穩(wěn)定可靠的實現(xiàn)(由于協(xié)議的一些本質(zhì),甚至不清楚最終是否會有移動端的實現(xiàn))。好在這些技術(shù)都有JavaScript實現(xiàn),因此不費什么事就可以輕松地將其與應(yīng)用相集成。
總的來說,這種技術(shù)很棒,我對目前的效果非常滿意。最新版文檔已經(jīng)包含了所有新功能,歡迎大家深入研究并嘗試。
聲明:能力越大,需要擔(dān)負(fù)的責(zé)任也就越大
最后我想說:雖然這種新技術(shù)確實很強(qiáng)大,但我覺得大家在開發(fā)應(yīng)用時都應(yīng)該在用戶體驗方面進(jìn)行更全面的權(quán)衡。
有些人可能會借助這種技術(shù)構(gòu)建完全由Web視圖組成的應(yīng)用,但說到底這樣的做法,你的應(yīng)用實際上就只是一個網(wǎng)站,已經(jīng)與開發(fā)專屬應(yīng)用的本意背道而馳了。
需要強(qiáng)調(diào)的是,我并不認(rèn)為你的每個應(yīng)用都應(yīng)同時包含HTML和原生組件。我只是認(rèn)為,這樣的做法對很多面臨某些具體狀況的人會顯得較為有用。只不過別過火就好。
閱讀原文
本文最初發(fā)布于Ethan的博客,經(jīng)原作者授權(quán)由InfoQ中文站翻譯并分享。英文原文請看:How to Turn Your Website into a Mobile App with 7 Lines of JSON
網(wǎng)站標(biāo)題:七行JSON代碼將你的網(wǎng)站變成移動應(yīng)用
分享網(wǎng)址:http://jinyejixie.com/news42/175292.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(liá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)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容