Android 高仿支付宝手势密码
前言
支付宝的手势密码 支持两种方式,第一种是进入app 时启动,第二种是进入理财时启动。
实现
1,我们先来分析下第一种方式,进入APP 时启动手势密码
进入app 时启动手势密码,有一个关键的知识点,前后台切换,如何判断app 应用做了前后台切换了呢?
(1) 使用ProcessLifecycleOmner
ProcessLifecycleOwner
该类提供了整个 app 进程的 lifecycle。
可以将其视为所有 activity 的 LifecycleOwner ,其中 Lifecycle.Event.ON_START 代表app 进入前台,而 Lifecycle.Event.ON_STOP 代表app 进入后台。当然(Lifecycle.Event.On_RESUME 和 Lifecycle.Event.ON_PAUSE 也可以分别代表进入前台和后台)。
ProcessLifecycleOwner.get().lifecycle.addObserver(object:LifecycleObserver{
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onForeground(){
EasyLog.e(TAG,"== onForeground==")
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onBackground(){
EasyLog.e(TAG,"== onBackground==")
}
});
ProcessLifecycle 能很好的监听前后台切换,但是 不太适合做手势密码的前后台切换,首先首页和登录页是不需要弹出手势密码的,这些页面要过滤,ProcessLifecycle 不好做到这一点。下面看第二种方法。
(2)使用 lifecycleCallbacks接口:
通过这个接口,我们对onActivityStart回调方法里记录启动的次数 mActivityCount++,onActivityStop 回调里对 mActivityCount-- ,当mActivityCount == 1 时认为在前台,mActivityCount ==0 在后台。代码如下:
/**
* 监听 前后台启动
* 自定义 可以很容易过滤一些不需要跳出手势密码的特殊的场景,比如 登录页
*/
class GestureLifecycleHandler constructor(context:Context): Application.ActivityLifecycleCallbacks {
companion object{
private const val TAG = "GestureLifecycleHandler"
}
private val uiScope = CoroutineScope(Dispatchers.Main)
private var isOpenHandLock = false
init {
}
/**
* 记录 activity 前后台情况
*/
private var mActivityCount: Int = 0
override fun onActivityPaused(activity: Activity?) {
}
override fun onActivityResumed(activity: Activity?) {
}
override fun onActivityStarted(activity: Activity?) {
if(activityFilter(activity)){
return
}
mActivityCount ++
EasyLog.e(TAG,"onForeground = $mActivityCount")
uiScope.launch {
withContext(Dispatchers.IO){
isOpenHandLock = GestureManager.getAppGestureState()
if(isOpenHandLock && mActivityCount == 1){
GestureActivity.actionStart(activity!!,GestureActivity.GestureState.Verify)
}
}
}
}
override fun onActivityDestroyed(activity: Activity?) {
}
override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {
}
override fun onActivityStopped(activity: Activity?) {
if(activityFilter(activity)){
return
}
mActivityCount--
EasyLog.e(TAG,"onBackground = $mActivityCount")
}
override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
}
private fun activityFilter(activity: Activity?):Boolean{
return activity is SplashActivity
}
}
2,我们分析第二种方式,进入理财时弹出手势密码
理财模块是个fragment ,也就是说要对财富fragment 监听前后台的变化,这个时候可以使用ProcessLifecycleOwner 对Fragment监听,代码如下:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
ProcessLifecycleOwner.get().lifecycle.addObserver(GestureLife(this))
}
private const val TAG = "GestureLife"
open class GestureLife(val fragment: GestureLockFragment) :LifecycleObserver{
private val uiScope = CoroutineScope(Dispatchers.Main)
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onVisible() {
EasyLog.e(TAG,"==ON_RESUME==")
if(fragment.isHidden){
EasyLog.e(TAG,"等待台跳出手势密码")
fragment.waitingGesture = true
}
if(!fragment.isHidden||fragment.isVisible){
EasyLog.e(TAG,"==isVisible==")
uiScope.launch {
withContext(Dispatchers.IO){
val isOpenHandLock = GestureManager.getFragmentGestureState()
if(isOpenHandLock && !GestureLockFragment.showGesture){
GestureLockFragment.showGesture = true
GestureActivity.actionStart(ActivityUtils.getTopActivity(),GestureActivity.GestureState.Verify)
}
}
}
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onBackground(){
EasyLog.e(TAG,"==onBackground==")
GestureLockFragment.showGesture = false
}
}
这里要处理两种情况,第一种财富这个fragment 前后台切换后,fragment 是可见的,那么久直接弹出手势,如果不可见要等待可见的时再次弹出,所以还要处理onHidden,
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
EasyLog.e(TAG,"onHiddenChanged")
if(!hidden){
if(waitingGesture && !showGesture){
waitingGesture = false
showGesture = true
GestureActivity.actionStart(activity!!, GestureActivity.GestureState.Verify)
}
}
}