TrustedTime API | 让应用时间更可靠

作者 / 软件工程师 Kanyinsola Fapohunda 和技术主管 Geoffrey Boullanger

准确的时间对于各种应用功能而言至关重要,无论是日程安排、事件管理、事务日志记录,还是安全协议。但因为用户可以更改设备的时间设置,所以开发者可能需要一种比设备本地系统时间更准确的时间源。鉴于此,我们推出了 TrustedTime API,它利用 Google 的基础设施提供可信的时间戳,独立于设备上可能被篡改的本地时间设置。

TrustedTime 的

工作原理是什么?

新的 API 利用 Google 的安全基础设施,为您的应用提供可信的时间源。TrustedTime 会定期将其时钟与 Google 的服务器进行同步,这些服务器可以访问高度准确的时间源,因此您无需在每次想要了解当前网络时间时都发出服务器请求。此外,我们还集成了一个独特的模型来计算设备的时钟漂移,这将在网络同步之间的时间可能不准确时通知您。

为什么准确的时间源很重要?

许多应用依赖设备的时钟来实现各种功能。然而,用户可能会有意或无意地更改其设备的时间设置,从而影响应用获取到的时间。这可能导致以下问题:

  • 数据不一致性:如果应用依赖于事件的时间顺序,则用户篡改设备时间可能导致数据损坏。TrustedTime 通过提供一个可信的时间源来降低这种风险。

  • 安全漏洞:基于时间的安全措施,如一次性密码或定时访问控制,需要未经篡改的时间源才能生效。

  • 时间安排失准:依赖于准确时间安排的应用,如日历或提醒事项应用,如果设备时钟 (例如 Unix 时间戳) 不准确,则可能会出现功能异常。

  • 不准确的时间:设备的内部时钟受各种因素 (如温度、低电耗模式、电池电量等) 的影响,可能出现漂移,导致需要更高时间精度的应用出现问题。TrustedTime API 还提供针对时间戳的估计误差,以确保能够正确执行应用中具有严格时间要求的操作。

  • 设备之间缺乏一致性:在多设备场景下,如游戏或协作应用中,设备间的时间差异可能会导致问题。TrustedTime API 有助于确保所有设备的时间保持一致,从而提升用户体验。

  • 不必要的电量和数据消耗:TrustedTime 的设计目的在于,当应用需要获取当前时间时,提供比直接调用 NTP 服务器更加高效的方法。该 API 通过定期将其时钟与时间服务器同步,来避免重复请求网络的消耗。同步后的时间将作为参考,由 TrustedTime API 依据设备的内部时钟计算当前时间。这种方式降低了网络使用量,同时提高了需要频繁检查时间的应用的性能。

TrustedTime 用例

TrustedTime API 为提升应用的可靠性和安全性开辟了更多可能,其用例包括但不限于以下领域:

  • 金融应用:即使设备处于离线状态,也能确保交易时间戳的准确性,防止欺诈和纠纷。

  • 游戏:防止玩家篡改游戏时钟来获得不公平优势,实现公平竞技。

  • 限时优惠:确保促销和优惠活动在正确的时间结束,不受用户设备设置的影响。

  • 电子商务:准确跟踪订单处理和配送时间。

  • 内容许可:对数字内容 (如租赁或订阅) 实施基于时间的限制。

  • IoT 设备:在多个设备之间同步时钟,以实现数据记录和控制的一致性。

  • 工作效率应用:准确记录在离线状态下对云文档进行任何更改的时间。

开始使用 TrustedTime API

TrustedTime API 基于 Google Play 服务而构建,大多数 Android 开发者可以无缝集成。

最简单的集成方式是在应用生命周期的早期初始化 TrustedTimeClient,例如在 Application 类的 onCreate() 方法中进行初始化。以下示例使用 Hilt 进行依赖项注入,使时间客户端在整个应用的组件中可用。

[可选] 设置依赖项注入

// TrustedTimeClientAccessor.ktimport com.google.android.gms.tasks.Taskimport com.google.android.gms.time.TrustedTimeClient
interface TrustedTimeClientAccessor {  fun createClient(): Task<TrustedTimeClient>}
// TrustedTimeModule.kt@Module@InstallIn(SingletonComponent::class)class TrustedTimeModule {  @Provides  fun provideTrustedTimeClientAccessor(    @ApplicationContext context: Context  ): TrustedTimeClientAccessor {    return object : TrustedTimeClientAccessor {      override fun createClient(): Task<TrustedTimeClient> {        return TrustedTime.createClient(context)      }    }  }}

在应用生命周期的早期进行初始化

// TrustedTimeDemoApplication.kt@HiltAndroidAppclass TrustedTimeDemoApplication : Application() {  @Inject  lateinit var trustedTimeClientAccessor: TrustedTimeClientAccessor  var trustedTimeClient: TrustedTimeClient? = null    private set  override fun onCreate() {    super.onCreate()    trustedTimeClientAccessor.createClient().addOnCompleteListener { task ->      if (task.isSuccessful) {        // Stash the client        trustedTimeClient = task.result      } else {        // Handle error, maybe retry later        val exception = task.exception      }    }    // To use Kotlin Coroutine, you can use the await() method,     // see https://developers.google.com/android/guides/tasks#kotlin_coroutine for more info.  }}NOTE: If you don't use dependency injection in your app. You can simply call`TrustedTime.createClient(context)` instead of using a TrustedTimeClientAccessor.

在应用的任何位置使用 TrustedTimeClient

// Retrieve the TrustedTimeClient from your application class  val myApp = applicationContext as TrustedTimeDemoApplication
  // In this example, System.currentTimeMillis() is used as a fallback if the  // client is null (i.e. client creation task failed) or when there is no time  // signal available. You may not want to do this if using the system clock is  // not suitable for your use case.  val currentTimeMillis =    myApp.trustedTimeClient?.computeCurrentUnixEpochMillis()        ?: System.currentTimeMillis()  // trustedTimeClient.computeCurrentInstant() can be used if Instant is  // preferred to long for Unix epoch times and you are able to use the APIs.

在诸如 Activity 之类的短生命周期组件中使用

@AndroidEntryPointclass MainActivity : AppCompatActivity() {  @Inject  lateinit var trustedTimeAccessor: TrustedTimeAccessor
   private var trustedTimeClient: TrustedTimeClient? = null
  override fun onCreate(savedInstanceState: Bundle?) {    super.onCreate(savedInstanceState)    ...    trustedTimeAccessor.createClient().addOnCompleteListener { task ->      if (task.isSuccessful) {          // Stash the client          trustedTimeClient = task.result        } else {         // Handle error, maybe retry later or use another time source.          val exception = task.exception        }    }  }
  private fun getCurrentTimeInMillis() : Long? {    return trustedTimeClient?.computeCurrentUnixEpochMillis()  }}

TrustedTime API 的

可用性和局限性

TrustedTime API 在所有运行 Android 5 (Lollipop) 及以上版本且搭载了 Google Play 服务的设备上均可使用。您需要添加依赖项 com.google.android.gms:play-services-time:16.0.1 (或更高版本) 以访问新的 API。使用此 API 不需要额外的权限。但是,设备启动后 TrustedTime 需要连接互联网才能提供时间戳。如果设备启动后未连接到互联网,TrustedTime API 将无法返回时间戳。

需要注意的是,由于温度、低电耗模式和电池电量等因素的影响,设备的内部时钟可能会出现漂移。TrustedTime 并不能防止这种漂移,但其 API 为每个时间戳提供了一个误差估计。您可以使用这个估计值来判断时间戳的准确性是否符合应用的要求。虽然 TrustedTime 提高了用户篡改应用访问时间的难度,但它并不能完全保证安全性。用户仍有可能通过高级技术来篡改设备的时间。

后续步骤

您可以访问 Android 开发者官方网站了解有关 TrustedTime API 的更多信息。也欢迎您持续关注 "Android 开发者" 微信公众号,及时了解更多开发技术和产品更新等资讯动态!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值