【问题标题】:Android: How to set passcode/PIN for my app only?Android:如何仅为我的应用设置密码/PIN?
【发布时间】:2021-03-02 13:23:08
【问题描述】:

我正在开发一个应用程序,我需要通过为用户设置密码/密码/pin 来设置安全功能,以便每当他们从后台打开应用程序时,应用程序都会要求输入密码/密码/pin。我阅读了一些文章/解决方案,例如this,但它们对我没有帮助。我们在普通银行应用程序中发现的相同功能,每当您打开应用程序时,它们都会要求输入密码/指纹。

我已经设置了将密码/pin 保存在共享首选项中的逻辑,但我不确定何时询问。我知道我们不能用密码/pin 活动替换启动屏幕,因为有时从应用程序的 homeScreen/MainActivity 中,用户按下主页按钮,当他们再次从最近的应用程序中打开应用程序时,应用程序应该要求输入密码/pin 以恢复应用程序使用。

任何帮助将不胜感激。

【问题讨论】:

  • 您是否希望 pin 与设备或用户设置相同?
  • @Ferdinand 用户设置密码。我已经提到我在本地存储共享首选项中的密码/pin。
  • 您实现了自己的引脚活动和逻辑来保存/检查输入引脚。您现在需要的只是如何以正确的方式显示它,不是吗?
  • @SonTruong 完全正确。

标签: android security kotlin passcode


【解决方案1】:

这是一个有趣的问题,我将分享我对这个问题的想法并给出解决方案。

术语:

App Lock Type:pin/pincode/password/passcode等的通用名称(下节我会用pin名来演示)

PinActivity:用户输入他们的密码以验证自己的屏幕

故事:

对于需要用户输入密码的应用,他们通常希望确保敏感信息不会被其他人泄露/窃取。因此,我们将应用活动分为 2 组。

  • 普通活动:不包含任何敏感信息,通常在用户登录应用之前,如 SplashActivity、LoginActivity、RegistrationActivity、PinActivity 等。

  • 安全活动:包含敏感信息,通常在用户登录后,如 MainActivity、HomeActivity、UserInfoActivity 等。

条件:

对于安全活动,我们必须确保用户始终在通过显示 PinActivity 查看内容之前输入他们的 pin。此活动将在以下场景中显示:

  • [1]当用户从正常的Activity打开一个安全的Activity时,比如从SplashActivity到MainActivity

  • [2] 当用户通过点击通知打开安全活动时,例如他们点击通知以打开 MainActivity

  • [3] 当用户从“最近”屏幕点击应用时

  • [4] 当应用从其他地方(如服务、广播接收器等)启动安全活动时。

实施:

对于案例 [1] [2] 和 [4],在开始安全活动之前,我们将在原始意图中添加额外内容。我将创建一个名为 IntentUtils.kt 的文件

IntentUtils.kt

const val EXTRA_IS_PIN_REQUIRED = "EXTRA_IS_PIN_REQUIRED"

fun Intent.secured(): Intent {
    return this.apply {
        putExtra(EXTRA_IS_PIN_REQUIRED, true)
    }
}

在正常活动、通知、服务等中使用此类。

startActivity(Intent(this, MainActivity::class.java).secured())

对于案例 [3],我将使用 2 个 API:

首先我创建一个基础活动,所有正常的活动都必须从这个类扩展

BaseActivity.kt

open class BaseActivity : AppCompatActivity() {
    
    // This method indicates that a pin is required if 
    // users want to see the content inside.
    open fun isPinRequired() = false
}

其次我创建了一个安全活动,所有安全活动都必须从这个类扩展

SecuredActivity.kt

open class SecuredActivity : BaseActivity() {
    override fun isPinRequired() = true

    // This is useful when launch a secured activity with 
    // singleTop, singleTask, singleInstance launch mode
    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        setIntent(intent)
    }
}

第三,我创建了一个从应用程序扩展的类,所有逻辑都在这个类中

MyApplication.kt

class MyApplication : Application() {

    private var wasEnterBackground = false

    override fun onCreate() {
        super.onCreate()
        registerActivityLifecycleCallbacks(ActivityLifecycleCallbacksImpl())
        ProcessLifecycleOwner.get().lifecycle.addObserver(LifecycleObserverImpl())
    }

    private fun showPinActivity() {
        startActivity(Intent(this, PinActivity::class.java))
    }

    inner class LifecycleObserverImpl : LifecycleObserver {

        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        fun onEnterBackground() {
            wasEnterBackground = true
        }
    }

    inner class ActivityLifecycleCallbacksImpl : ActivityLifecycleCallbacks {

        override fun onActivityResumed(activity: Activity) {
            val baseActivity = activity as BaseActivity
            if (!wasEnterBackground) {
                // Handle case [1] [2] and [4]
                val removed = removeIsPinRequiredKeyFromActivity(activity)
                if (removed) {
                    showPinActivity()
                }
            } else {
                // Handle case [3]
                wasEnterBackground = false
                if (baseActivity.isPinRequired()) {
                    removeIsPinRequiredKeyFromActivity(activity)
                    showPinActivity()
                }
            }
        }

        private fun removeIsPinRequiredKeyFromActivity(activity: Activity): Boolean {
            val key = EXTRA_IS_PIN_REQUIRED
            if (activity.intent.hasExtra(key)) {
                activity.intent.removeExtra(key)
                return true
            }
            return false
        }

        override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
        override fun onActivityStarted(activity: Activity) {}
        override fun onActivityPaused(activity: Activity) {}
        override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
        override fun onActivityStopped(activity: Activity) {}
        override fun onActivityDestroyed(activity: Activity) {}
    }
}

结论:

此解决方案适用于我之前提到的那些情况,但我还没有测试过以下场景:

  • 启动安全活动时,启动模式为 singleTop|singleTask|singleInstance
  • 当应用程序被内存不足的系统杀死时
  • 其他人可能会遇到的情况(如果是,请在 cmets 部分告诉我)。

【讨论】:

  • Cảmơn chia sẻ từ anh,liệu có thể kết hợp hết 1 2 3 4 không ạ, xin lỗi cho câu hỏi em mới bắt đầu。
  • @hungcuiga1 em thông cảm vì giờ anh mới trả lời được, anh cũng chưa có thời gian để kết hợp nữa。 Em mới bắt đầu có thể tìm hiểu và dựa vào một số gợi ý từ câu trả lời của anh để áp dụng vào ứng dụng em đang làm。 Nếu có gì khó khăn anh có thể giúp thì anh sẵn sàng。
  • Cảmơn anh. Em mới tìm hiểu về android và mục đích của em là xây dựng một ứng dụng đơn giản theo yêu cầu của mình。 Do thời gian hạn chế nên dường như em chỉ cố gắng lắp ráp mọi thứ mà không có kiến thức nhiều :v。 Hiện em có câu hỏi nhỏ nhưng chưa biết cách giải quyết ở đây, có lẽ em diễn tả hơi khó hiểu mong anh thông cảm。 Cảmơn anh rất nhiều.
猜你喜欢
  • 2021-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多