如何在Ionic 3中开发应用使用时长限制功能并防卸载重装?
实现3小时试用+防卸载重装的最佳方案
嘿,这个需求我之前帮朋友做过类似的,咱们一步步拆解清楚:
一、基础超时功能的实现(无防卸载)
如果只是做最基础的3小时试用,逻辑很简单:
- 首次启动App时,记录首次使用时间戳,存在
SharedPreferences或本地数据库里 - 每次启动App时,读取这个时间戳,和当前时间做差值对比
- 如果时间差超过3小时(10800秒),就触发限制使用的逻辑
代码示例(Kotlin):
// 首次启动时记录时间 val sharedPref = getSharedPreferences("TrialPrefs", Context.MODE_PRIVATE) if (!sharedPref.contains("firstLaunchTime")) { sharedPref.edit().putLong("firstLaunchTime", System.currentTimeMillis()).apply() } // 每次启动检查超时 val firstLaunch = sharedPref.getLong("firstLaunchTime", 0) val currentTime = System.currentTimeMillis() val timeDiff = currentTime - firstLaunch if (timeDiff > 3 * 60 * 60 * 1000) { // 超时,跳转至限制页面 startActivity(Intent(this, TrialExpiredActivity::class.java)) finish() }
但这个方案有个致命漏洞:用户卸载重装App后,SharedPreferences会被完全清空,相当于重新获得3小时试用,轻松绕开限制。
二、防卸载重装的核心思路:找卸载后不消失的存储点
Android系统中,App卸载时会清除自身所有私有存储(包括SharedPreferences、内部数据库、私有文件),所以我们需要找系统级的、App卸载后仍能保留的存储位置,或结合后端验证。这里给你几个可行方案:
1. 服务器验证(最可靠,业界通用)
这是最稳妥的方案,完全从根源上避免卸载重装绕过:
- 首次启动时,获取设备的稳定唯一标识(比如OAID,比Android ID兼容性更强;或者IMEI,但需要
READ_PHONE_STATE权限,Android 10+限制更严) - 将设备标识和首次使用时间发送到你的后端服务器,存储在数据库中
- 每次启动App时,向服务器发送设备标识,由服务器对比首次时间判断是否超时
- 卸载重装后,App读取设备标识再次请求服务器,服务器会返回已超时的结果
优势:完全无法通过卸载重装绕过,还能避免用户篡改本地时间(用服务器时间做对比)。
注意:可以给每个设备标识设置一次试用机会,同时处理设备重置、用户更换设备的特殊场景。
2. 利用系统账户(AccountManager)
Android的AccountManager允许App创建系统级账户,卸载App后账户不会自动删除:
- 首次启动时,创建一个自定义账户,把首次使用时间存在账户的额外数据里
- 重装App后,检查是否存在这个账户,读取里面的时间戳进行验证
代码示例(Kotlin):
// 创建账户 val accountManager = getSystemService(Context.ACCOUNT_SERVICE) as AccountManager val account = Account("TrialAccount", "com.your.app.trial.type") if (accountManager.addAccountExplicitly(account, null, bundleOf("firstLaunchTime" to System.currentTimeMillis()))) { // 账户创建成功 } // 重装后读取账户 val accounts = accountManager.getAccountsByType("com.your.app.trial.type") if (accounts.isNotEmpty()) { val firstLaunch = accountManager.getUserData(accounts[0], "firstLaunchTime")?.toLong() ?: 0 // 超时检查逻辑和之前一致 }
注意:需要添加GET_ACCOUNTS权限,而且用户可以手动在系统设置里删除这个账户,不过门槛比卸载重装高很多。
3. 外部存储隐藏文件(兼容性稍差)
在外部存储创建一个隐藏文件(文件名开头加.),写入首次使用时间和设备标识:
- 但Android 10+的Scoped Storage限制,App只能访问自己的私有外部目录,卸载后这个目录会被删除,所以得用MediaStore的公共目录(比如Download),但用户可能会发现并删除这个文件,可靠性不如前两种方案。
三、关于Android全局变量的疑问
直接说结论:全局变量完全无法解决这个问题。
因为App的全局变量(比如Application类里的静态变量)只存在于App进程的生命周期中,进程被杀就会消失,卸载App后更是彻底清除,根本无法保留任何跨卸载的信息。
额外注意事项
- 防止篡改本地时间:不要只用本地时间做对比,最好每次检查时请求服务器的当前时间,避免用户手动修改系统时间绕过限制
- 权限处理:涉及设备标识、账户、外部存储的方案,都需要注意Android不同版本的权限要求,提前做好权限申请和异常处理
内容的提问来源于stack exchange,提问作者Ronald Araújo
相关产品推荐
相关产品推荐

