为移动应用提供离线支持
对移动应用的离线支持可以理解为应用在网络连接不稳定的情况下能够做出优雅的反应的能力。在移动设备这一相对较新的技术背景中,新的问题也随之产生,例如网络连接的正常或异常、高延迟以及低带宽等情况。这些问题出现的时间并不算长,刚刚上手进行移动开发的工程师对此并不十分了解。除此之外,创建一个能够适应不同网络情况的移动应用可能还包括以下需求:
- 在网络调用失败的情况下显示适当的错误信息。
- 允许在“访客模式”下使用该应用,而某些特性只在用户登录之后才可以使用。
- 在 UI 上明确地显示出网络连接断开的信息(连接模式 / 离线模式)。
- 在网络连接断开的情况下禁用某些控件。
- 在没有网络连接的情况下也允许用户进行数据查询与操作(离线数据访问)。
- 在不同的网络连接条件下对应用进行测试!
虽然以上这几点从使用性的角度来看都是非常重要的,但其中某一点的复杂性尤为突出,即“离线数据访问”。应用程序或许需要支持多种不同的离线数据访问场景或是级别,在下文中我将一一进行讲解。
本地缓存
应用程序在没有网络连接的情况下依然能够显示信息,而在连上网络的情况下需要刷新数据。要实现这一点,需要在移动设备上对数据进行一定程度的持久化,并且通常需要保留一段时间。
对缓存中的数据进行刷新有三种不同的“策略”,接下来我将逐一进行分析。
网络优先
总是尝试从服务器上获取数据,如果无法从服务器上获取,再转而从本地缓存中获取数据。如果你特别希望总是显示最近的、经过更新的信息,那么这种策略对你非常有帮助。
本地优先
在一段指定的时间之内完全不会从网络上获取数据,而是通过本地缓存进行获取。如果你的应用能够接受显示被缓存的数据而不存在什么风险,那么这种方式非常适合你。另一方面,这种方式的用户体验更好,因为通常来说不会产生任何延迟。
混合 / 智能
这种方式在从服务端获取数据之前先从本地缓存中返回结果。可以选择等待服务端的通知,或是在后台对服务进行轮询的方式,对本地的缓存数据进行刷新。这种机制能够在性能与用户体验之间取得一种良好的平衡,而它仍然会对本地缓存进行定期刷新,避免了为用户显示“过期”数据的风险。
此外,通过某种服务端缓存的支持,可以有效地弥补本地缓存的不足之处。正如 HTTP 缓存一样,当需要从服务器获取数据的时候,客户端可以通过发送一个“修订号”以确认该数据是否已经被更新了。服务端将检查客户端所发送的修订号是否与服务器上的数据一致,根据结果不同,或者通知客户端不必更新数据,或者将最新的数据返回。
示例场景
对于性能与用户体验的改进使得本地缓存在许多场景中非常实用,这种实用性的关键条件在于数据无需进行实时显示。能够将数据在本地缓存中保留的时间越长,这种方式的优点就越突出。
这方面的例子包括用户所感兴趣的地区或联系人,这种信息具有很高的实用性,同时又不太会非常频繁地更新,因此是使用本地缓存理想的应用场景。
本地队列
一旦应用程序失去了网络连接,可以将服务器请求放入本地队列,以便之后的处理。这种方式让用户能够发起即发即弃(fire and forget)的操作,等到这些操作由服务器成功处理之后(如果确实经过处理的话)收到操作完成的通知信息。
在本地队列处理多个操作时,你需要考虑以下问题:
- 用户应当收到该操作已加入队列的通知。
- 用户很可能想要了解队列的实际状态,哪些操作已经完成了,还有哪些操作还在等待中?
- 对于仍处于队列中的操作来说,手动撤消或重试的能力或许是十分重要的。
- 一旦这些操作被发送到服务器,用户希望了解最终的处理结果(成功或失败)。
- 当操作进入队列之后,用户有可能需要重新启动整个流程,因而需要中断这个操作。
在使用者进行审核或测量等现场工作,以及发送报告时,本地队列是一个很好的主意。如果这些操作不需要更新记录,只是插入新记录而已,那么整个实现会变得更加简单,无需进行并发管理或冲突处理。
示例场景
本地队列能够帮助你在进行操作时无需等待其结果,这对于库存检查或审核等操作来说是非常重要的,让使用者无需等待网络连接也能够使用该应用,或发送报告 。
数据同步
通过使用本地缓存与队列,你就能够保持设备与服务器数据的更新,这就是我们熟知的“同步”。有以下几种方式可以实现数据同步。
保持移动端数据的更新
在这种场景下,你需要让你的移动应用数据保持同步。有两种方式可以实现这一需求:如上文所描述的方式一样使用本地缓存、或者向服务器请求最新的变更。这些最新的变更也被称为“增量”,能够让移动应用对服务器的当前状态进行重建。为了能够对最新的更新进行查询,你需要使用一些审核字段,例如‘UpdatedOn’、 ‘CreatedOn’和‘DeletedOn’。
在第二种场景中,数据在设备中并未修改,因此也无需处理任何冲突,因此服务器上的数据总是正确的。
保持服务器数据的更新
这一点可以通过使用本地队列实现,但仅仅使用队列本身是不够的。如果在我的请求发送到服务器时,服务器上的数据状态与我尝试进行修改的时候已经有所变化,这时该如何处理?如果请求的执行被延迟,例如出现网络连接断开的情况,就有可能造成并发冲突的增长。在这种情况下,开发者(或用户)必须决定如何对服务器与应用中的变更进行“合并”。对于每一次数据冲突来说,有以下几种合并方式:
- 保留设备上的版本
- 保留服务器上的版本
- 同时保留两个版本
合并记录的操作往往是由移动开发者通过自动化实现的。至于具体使用哪一种算法,要由应用程序的业务规则来确定。一旦出现无法完全自动化的情况,将提示用户做出决定。
同时保持移动端与服务器的数据更新
这种方式也被称为双向同步。你很可能已经猜到了,这种策略是对以上两种技术的一个结合,它是目前所描述的场景中最完整,也是最强大的。但请注意,虽然创建一种可以支持双向同步的应用很有诱惑性,但它也是目前为止最为复杂的一种场景。而且问题不仅仅在于它的复杂性,正如我在本文中已经提到的,双向同步并不总是必要的。
示例场景
双向同步为移动应用带来了一个全新级别的用户体验,而必须使用双向同步方式的关键条件之一是让一个团队或小组里的所有用户都能够及时了解其它人的活动情况。这方面的一个例子是协作应用,需要显示更新、注释或状态变更的最新状态。可以想象如果有一个协作式的地址簿,那么团队中的每位成员都能够在任何时间更新其中的联系人信息。
思考
为你创建的移动应用加入对离线场景的支持能够极大地提高用户体验,但如何选择合适的支持级别,并随后实现这一功能,这并不是一件简单的任务。我在下文中列举了一些当你计划为应用加入离线功能时应当考虑的问题。
数据大小
在进行数据本地缓存时,对于存储的数据大小要有所警觉。尽量争取在缓存的数据量与得到的用户体验改善之间达到一种良好的平衡,这一点十分重要。如果数据量十分庞大(例如保存一个完整的 Sharepoint 网站内容),你可能必须考虑为用户提供一个选项,让他选择要将哪些数据进行缓存,以用于离线阅读。
数据存储
一定要对于如何进行数据存储,以及存储在何处作出明智的抉择。这些数据是否包含敏感信息?如果是的话,就需要在保存数据时进行加密。而一旦你选择了对数据进行加密,请确保将解密数据所用的密钥保存在一个安全的地方,可以考虑使用操作系统的功能实现这一点。还要注意一点,在某些平台上你的应用程序代码是可以被阅读(或反射)的,因此可以考虑对代码进行混淆。最后,但并非无关紧要的是,确保你能够通过某种机制远程地消除设备上的数据。像移动设备管理(MDM)平台等工具能够帮助你实现这一功能,但也可以由应用程序本身完成这一点。
电池使用
如果你计划使用轮询机制或是后台作业(job),请确保你仔细考虑电池用量的情况。某些操作和网络功能会很快耗光你的电量,并损害你的用户体验。你可以在开始启动一个耗电量很大的操作之前先检测电池电量的状态,以及该设备是否正在充电等等。
数据的应用
你或许需要对数据进行查询与操作(新增、修改、删除),这取决于你的应用程序的需求。在具有一定复杂性的场景中,使用数据库作为持久化机制是一个不错的选择。要选择一个合适的数据库,需要考虑以下一些问题:
- 对平台的支持:我能够在应用的每个版本上都使用这个数据库吗?? (iOS、Android、Web、混合应用等等……)
- 选择关系型数据库还是 NoSQL 数据库技术
- 通过 ORM 的支持,将对象模型方便地映射到数据库中
- 数据大小
- 对于同步协议的支持(例如 CouchDB)
下面我们将逐个分析一些类库及数据库,这对于我们实现离线功能非常实用。
使用类库及数据库
SQLite
SQLite 是一个开源的关系型数据库,非常适合于在移动设备上使用。它使用一个单一的文件用于保存数据,因此对于持久化的管理非常简单。对于同步及解决冲突来说,它起不到太大的作用,但对于信息的缓存及队列操作来说,它是一个简单易用的选择。它能够支持主要的移动平台,例如 iOS、Android、Xamarin 和 Windows Phone。
SQLCypher
正如上文所说,如果你所缓存或加入队列中的数据十分敏感,那么在保存数据的同时需要对其加密。 SQLCypher 是一种对 SQLite 数据库进行加密的一种十分健壮的选择。它支持每种主流的移动平台,但这个类库是需要付费的。根据安全级别和支持功能的不同,它有多个版本可以提供。
Couchbase Mobile
Couchbase 最初的名称是 Membase,它是一个开源的分布式 NoSQL 数据库。它特别适合用于离线应用的场景,因为它能够通过 Couchbase Mobile 和一个额外的同步网关对数据进行双向同步。它支持主流的移动平台,包括 Xamarin 和 PhoneGap,并且提供了本地文件加密的功能。
Meteor
Meteor 是一个用于创建 web 应用的开源平台,内置了实时更新的能力。Meteor 是基于开源的 Node.js 平台和 MongoDB 所创建的,它提供了一种发布 - 订阅机制,能够将数据的变化实时传递给每个连接中的客户端。
它通过 PhoneGap 和 Cordova 等混合工具支持所有移动平台。
结语
一旦用户开始期望他们的个人应用能够实现与企业级应用同等级别的用户体验,就无法忽视对离线功能的支持。能够为用户提供离线场景的良好支持,将极大地改善移动应用的用户体验,对于员工的生产力也是至关重要的。
请留意在设备上进行数据本地存储时的安全问题,并且请尽量不要低估你的应用对于用户的电池电量消耗可能造成的影响。
关于作者
Gustavo Machado是 KidoZen 的工程部门的副总裁,负责牵头公司的下一代企业移动平台的执行。他对于使用不同技术以及敏捷实践开发高度分布式的系统具有丰富的经验。他也是一个活跃的博客撰写人,twitter 帐号是@machadogj。
查看英文原文: Mobile Apps Offline Support
评论