為移動應用提供離線支持
對移動應用的離線支持可以理解為應用在網(wǎng)絡連接不穩(wěn)定的情況下能夠做出優(yōu)雅的反應的能力。在移動設備這一相對較新的技術背景中,新的問題也隨之產(chǎn)生,例如網(wǎng)絡連接的正?;虍惓?、高延遲以及低帶寬等情況。這些問題出現(xiàn)的時間并不算長,剛剛上手進行移動開發(fā)的工程師對此并不十分了解。除此之外,創(chuàng)建一個能夠適應不同網(wǎng)絡情況的移動應用可能還包括以下需求:
- 在網(wǎng)絡調用失敗的情況下顯示適當?shù)腻e誤信息。
- 允許在“訪客模式”下使用該應用,而某些特性只在用戶登錄之后才可以使用。
- 在UI上明確地顯示出網(wǎng)絡連接斷開的信息(連接模式/離線模式)。
- 在網(wǎng)絡連接斷開的情況下禁用某些控件。
- 在沒有網(wǎng)絡連接的情況下也允許用戶進行數(shù)據(jù)查詢與操作(離線數(shù)據(jù)訪問)。
- 在不同的網(wǎng)絡連接條件下對應用進行測試!
雖然以上這幾點從使用性的角度來看都是非常重要的,但其中某一點的復雜性尤為突出,即“離線數(shù)據(jù)訪問”。應用程序或許需要支持多種不同的離線數(shù)據(jù)訪問場景或是級別,在下文中我將一一進行講解。
本地緩存
應用程序在沒有網(wǎng)絡連接的情況下依然能夠顯示信息,而在連上網(wǎng)絡的情況下需要刷新數(shù)據(jù)。要實現(xiàn)這一點,需要在移動設備上對數(shù)據(jù)進行一定程度的持久化,并且通常需要保留一段時間。
對緩存中的數(shù)據(jù)進行刷新有三種不同的“策略”,接下來我將逐一進行分析。
網(wǎng)絡優(yōu)先
總是嘗試從服務器上獲取數(shù)據(jù),如果無法從服務器上獲取,再轉而從本地緩存中獲取數(shù)據(jù)。如果你特別希望總是顯示最近的、經(jīng)過更新的信息,那么這種策略對你非常有幫助。
本地優(yōu)先
在一段指定的時間之內完全不會從網(wǎng)絡上獲取數(shù)據(jù),而是通過本地緩存進行獲取。如果你的應用能夠接受顯示被緩存的數(shù)據(jù)而不存在什么風險,那么這種方式非常適合你。另一方面,這種方式的用戶體驗更好,因為通常來說不會產(chǎn)生任何延遲。
混合 / 智能
這種方式在從服務端獲取數(shù)據(jù)之前先從本地緩存中返回結果??梢赃x擇等待服務端的通知,或是在后臺對服務進行輪詢的方式,對本地的緩存數(shù)據(jù)進行刷新。這種機制能夠在性能與用戶體驗之間取得一種良好的平衡,而它仍然會對本地緩存進行定期刷新,避免了為用戶顯示“過期”數(shù)據(jù)的風險。
此外,通過某種服務端緩存的支持,可以有效地彌補本地緩存的不足之處。正如HTTP緩存一樣,當需要從服務器獲取數(shù)據(jù)的時候,客戶端可以通過發(fā)送一個“修訂號”以確認該數(shù)據(jù)是否已經(jīng)被更新了。服務端將檢查客戶端所發(fā)送的修訂號是否與服務器上的數(shù)據(jù)一致,根據(jù)結果不同,或者通知客戶端不必更新數(shù)據(jù),或者將***的數(shù)據(jù)返回。
示例場景
對于性能與用戶體驗的改進使得本地緩存在許多場景中非常實用,這種實用性的關鍵條件在于數(shù)據(jù)無需進行實時顯示。能夠將數(shù)據(jù)在本地緩存中保留的時間越長,這種方式的優(yōu)點就越突出。
這方面的例子包括用戶所感興趣的地區(qū)或聯(lián)系人,這種信息具有很高的實用性,同時又不太會非常頻繁地更新,因此是使用本地緩存理想的應用場景。
本地隊列
一旦應用程序失去了網(wǎng)絡連接,可以將服務器請求放入本地隊列,以便之后的處理。這種方式讓用戶能夠發(fā)起即發(fā)即棄(fire and forget)的操作,等到這些操作由服務器成功處理之后(如果確實經(jīng)過處理的話)收到操作完成的通知信息。
在本地隊列處理多個操作時,你需要考慮以下問題:
- 用戶應當收到該操作已加入隊列的通知。
- 用戶很可能想要了解隊列的實際狀態(tài),哪些操作已經(jīng)完成了,還有哪些操作還在等待中?
- 對于仍處于隊列中的操作來說,手動撤消或重試的能力或許是十分重要的。
- 一旦這些操作被發(fā)送到服務器,用戶希望了解最終的處理結果(成功或失?。?/li>
- 當操作進入隊列之后,用戶有可能需要重新啟動整個流程,因而需要中斷這個操作。
在使用者進行審核或測量等現(xiàn)場工作,以及發(fā)送報告時,本地隊列是一個很好的主意。如果這些操作不需要更新記錄,只是插入新記錄而已,那么整個實現(xiàn)會變得更加簡單,無需進行并發(fā)管理或沖突處理。
示例場景
本地隊列能夠幫助你在進行操作時無需等待其結果,這對于庫存檢查或審核等操作來說是非常重要的,讓使用者無需等待網(wǎng)絡連接也能夠使用該應用,或發(fā)送報告 。
數(shù)據(jù)同步
通過使用本地緩存與隊列,你就能夠保持設備與服務器數(shù)據(jù)的更新,這就是我們熟知的“同步”。有以下幾種方式可以實現(xiàn)數(shù)據(jù)同步。
保持移動端數(shù)據(jù)的更新
在這種場景下,你需要讓你的移動應用數(shù)據(jù)保持同步。有兩種方式可以實現(xiàn)這一需求:如上文所描述的方式一樣使用本地緩存、或者向服務器請求***的變更。這些***的變更也被稱為“增量”,能夠讓移動應用對服務器的當前狀態(tài)進行重建。為了能夠對***的更新進行查詢,你需要使用一些審核字段,例如‘UpdatedOn’、 ‘CreatedOn’和‘DeletedOn’。
在第二種場景中,數(shù)據(jù)在設備中并未修改,因此也無需處理任何沖突,因此服務器上的數(shù)據(jù)總是正確的。
保持服務器數(shù)據(jù)的更新
這一點可以通過使用本地隊列實現(xiàn),但僅僅使用隊列本身是不夠的。如果在我的請求發(fā)送到服務器時,服務器上的數(shù)據(jù)狀態(tài)與我嘗試進行修改的時候已經(jīng)有所變化,這時該如何處理?如果請求的執(zhí)行被延遲,例如出現(xiàn)網(wǎng)絡連接斷開的情況,就有可能造成并發(fā)沖突的增長。在這種情況下,開發(fā)者(或用戶)必須決定如何對服務器與應用中的變更進行“合并”。對于每一次數(shù)據(jù)沖突來說,有以下幾種合并方式:
- 保留設備上的版本
- 保留服務器上的版本
- 同時保留兩個版本
合并記錄的操作往往是由移動開發(fā)者通過自動化實現(xiàn)的。至于具體使用哪一種算法,要由應用程序的業(yè)務規(guī)則來確定。一旦出現(xiàn)無法完全自動化的情況,將提示用戶做出決定。
同時保持移動端與服務器的數(shù)據(jù)更新
這種方式也被稱為雙向同步。你很可能已經(jīng)猜到了,這種策略是對以上兩種技術的一個結合,它是目前所描述的場景中最完整,也是***大的。但請注意,雖然創(chuàng)建一種可以支持雙向同步的應用很有誘惑性,但它也是目前為止最為復雜的一種場景。而且問題不僅僅在于它的復雜性,正如我在本文中已經(jīng)提到的,雙向同步并不總是必要的。
示例場景
雙向同步為移動應用帶來了一個全新級別的用戶體驗,而必須使用雙向同步方式的關鍵條件之一是讓一個團隊或小組里的所有用戶都能夠及時了解其它人的活動情況。這方面的一個例子是協(xié)作應用,需要顯示更新、注釋或狀態(tài)變更的***狀態(tài)??梢韵胂笕绻幸粋€協(xié)作式的地址簿,那么團隊中的每位成員都能夠在任何時間更新其中的聯(lián)系人信息。
思考
為你創(chuàng)建的移動應用加入對離線場景的支持能夠極大地提高用戶體驗,但如何選擇合適的支持級別,并隨后實現(xiàn)這一功能,這并不是一件簡單的任務。我在下文中列舉了一些當你計劃為應用加入離線功能時應當考慮的問題。
數(shù)據(jù)大小
在進行數(shù)據(jù)本地緩存時,對于存儲的數(shù)據(jù)大小要有所警覺。盡量爭取在緩存的數(shù)據(jù)量與得到的用戶體驗改善之間達到一種良好的平衡,這一點十分重要。如果數(shù)據(jù)量十分龐大(例如保存一個完整的Sharepoint網(wǎng)站內容),你可能必須考慮為用戶提供一個選項,讓他選擇要將哪些數(shù)據(jù)進行緩存,以用于離線閱讀。
數(shù)據(jù)存儲
一定要對于如何進行數(shù)據(jù)存儲,以及存儲在何處作出明智的抉擇。這些數(shù)據(jù)是否包含敏感信息?如果是的話,就需要在保存數(shù)據(jù)時進行加密。而一旦你選擇了對數(shù)據(jù)進行加密,請確保將解密數(shù)據(jù)所用的密鑰保存在一個安全的地方,可以考慮使用操作系統(tǒng)的功能實現(xiàn)這一點。還要注意一點,在某些平臺上你的應用程序代碼是可以被閱讀(或反射)的,因此可以考慮對代碼進行混淆。***,但并非無關緊要的是,確保你能夠通過某種機制遠程地消除設備上的數(shù)據(jù)。像移動設備管理(MDM)平臺等工具能夠幫助你實現(xiàn)這一功能,但也可以由應用程序本身完成這一點。
電池使用
如果你計劃使用輪詢機制或是后臺作業(yè)(job),請確保你仔細考慮電池用量的情況。某些操作和網(wǎng)絡功能會很快耗光你的電量,并損害你的用戶體驗。你可以在開始啟動一個耗電量很大的操作之前先檢測電池電量的狀態(tài),以及該設備是否正在充電等等。
數(shù)據(jù)的應用
你或許需要對數(shù)據(jù)進行查詢與操作(新增、修改、刪除),這取決于你的應用程序的需求。在具有一定復雜性的場景中,使用數(shù)據(jù)庫作為持久化機制是一個不錯的選擇。要選擇一個合適的數(shù)據(jù)庫,需要考慮以下一些問題:
- 對平臺的支持:我能夠在應用的每個版本上都使用這個數(shù)據(jù)庫嗎?? (iOS、Android、Web、混合應用等等……)
- 選擇關系型數(shù)據(jù)庫還是NoSQL數(shù)據(jù)庫技術
- 通過ORM的支持,將對象模型方便地映射到數(shù)據(jù)庫中
- 數(shù)據(jù)大小
- 對于同步協(xié)議的支持(例如CouchDB)
下面我們將逐個分析一些類庫及數(shù)據(jù)庫,這對于我們實現(xiàn)離線功能非常實用。
使用類庫及數(shù)據(jù)庫
SQLite
SQLite是一個開源的關系型數(shù)據(jù)庫,非常適合于在移動設備上使用。它使用一個單一的文件用于保存數(shù)據(jù),因此對于持久化的管理非常簡單。對于同步及解決沖突來說,它起不到太大的作用,但對于信息的緩存及隊列操作來說,它是一個簡單易用的選擇。它能夠支持主要的移動平臺,例如iOS、Android、Xamarin和Windows Phone。
SQLCypher
正如上文所說,如果你所緩存或加入隊列中的數(shù)據(jù)十分敏感,那么在保存數(shù)據(jù)的同時需要對其加密。SQLCypher是一種對SQLite數(shù)據(jù)庫進行加密的一種十分健壯的選擇。它支持每種主流的移動平臺,但這個類庫是需要付費的。根據(jù)安全級別和支持功能的不同,它有多個版本可以提供。
Couchbase Mobile
Couchbase最初的名稱是Membase,它是一個開源的分布式NoSQL數(shù)據(jù)庫。它特別適合用于離線應用的場景,因為它能夠通過Couchbase Mobile和一個額外的同步網(wǎng)關對數(shù)據(jù)進行雙向同步。它支持主流的移動平臺,包括Xamarin和PhoneGap,并且提供了本地文件加密的功能。
Meteor
Meteor是一個用于創(chuàng)建web應用的開源平臺,內置了實時更新的能力。Meteor是基于開源的Node.js平臺和MongoDB所創(chuàng)建的,它提供了一種發(fā)布-訂閱機制,能夠將數(shù)據(jù)的變化實時傳遞給每個連接中的客戶端。
它通過PhoneGap和Cordova等混合工具支持所有移動平臺。
結語
一旦用戶開始期望他們的個人應用能夠實現(xiàn)與企業(yè)級應用同等級別的用戶體驗,就無法忽視對離線功能的支持。能夠為用戶提供離線場景的良好支持,將極大地改善移動應用的用戶體驗,對于員工的生產(chǎn)力也是至關重要的。
請留意在設備上進行數(shù)據(jù)本地存儲時的安全問題,并且請盡量不要低估你的應用對于用戶的電池電量消耗可能造成的影響。