为安卓应用添加手势密码功能,遇到的一些问题以及解决方法

公司的APP有个需求为他添加类似于支付宝的手势密码验证功能效果图如下
这里写图片描述
首先我们要分析三个问题:
1.手势密码的作用是什么?
2.在什么时候启动?
3.启动之后干什么?


1.手势密码的作用是什么?
这里很容易解答,为了APP二次启动进入进行验证是否正常授权的用户。
2.在什么时候启动?
如果是对安全性比较高的应用这里推荐应用处于后台运行状态下马上进入安全验证状态(也就是需要输入手势密码才能回到之前的Activity
另一种安全性能要求是不那么高的用户在锁屏之后再次回到应用启动验证即可。
3.启动之后干什么?
手势验证成功就进入打开APP,验证失败就不让动~
关于手势验证代码网上一大堆,我这里主要讲解如何集成到我们的app中,毕竟在app开发中会用就行:orz

首先我们要获取APP的状态是否进入后台等,这里有几种思路:
1.监听HOME键power键跟返回键操作
2.监听锁屏解锁广播
3.自定义广播实现监听
由于软件需求的安全性不高,我选择了第二种:监听解锁广播
android.intent.action.USER_PRESENT 用户操作进行解锁时会触发
我们首先编写一个CustomReceiver代码如下

public class CustomReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("android.intent.action.USER_PRESENT") && SPUtils.getGestureCode(context) == HAS_GESTURE) {
            Logger.e("存在锁屏密码");
            SPUtils.put(context, "isLock", true);
            Intent intent1 = new Intent(context, SignUserGestureActivity.class);
            intent1.setFlags(FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent1);
        } else {
            Logger.e("不存在锁屏密码" + SPUtils.getGestureCode(context));
            SPUtils.put(context, "isLock", false);
        }
}

然后在清单文件申明

 <receiver android:name=".broadcast.CustomReceiver">
    <intent-filter>
        <action android:name="android.intent.action.USER_PRESENT"/>
    </intent-filter>
</receiver>

监听广播并且判断当前手势密码是否存在,存在跳转到验证Activity。注意这里的setFlags在广播中启动activity必须设置flag为FLAG_ACTIVITY_NEW_TASK
否则报错如下

Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

锁屏后启动验证解决了。现在的问题,启动后干什么?两种情况
1.APP未启动过,处于非运行状态,跳转至启动动画即可
2.运行时,恢复到原来的Activity
第一种情况直接启动Intent的跳转就好了
第二种情况怎么记录处于栈顶的Activity?
我这里提供一个办法在每个activity的onResume方法中添加当前的Activity

    //全局静态集合保留所有的activity
    public static List<Activity> activitys=new ArrayList<>();

当手势密码验证通过取得最后一个activity的名字去启动,代码如下

//程序处于运行状态只要取出最后一个运行的activity就好了
            if(activitys.size()!=0){
                lastactivityname = activitys.get(activitys.size()-1).getComponentName();
                Logger.e(activitys.size()+"");
                Intent intent = new Intent();
                intent.setComponent(lastactivityname);
                intent.setFlags(FLAG_ACTIVITY_CLEAR_TOP);//清除当前activity,让之前启动的Activity处于栈顶
                startActivity(intent);
            }else {
                //程序此时没有运行启动欢迎页面即可
                Intent intent = new Intent(this,ShowFirstActivity.class);
                startActivity(intent);

            }

注意这里的FLAG_ACTIVITY_CLEAR_TOP


这里贴上Intent 的常见Flag

先首先简单介绍下Task和Activity的关系

Task就像一个容器,而Activity就相当与填充这个容器的东西,第一个东西(Activity)则会处于最下面,最后添加的东西(Activity)则会在最上面。从Task中取出东西(Activity)是从最顶端取出,也就是说最先取出的是最后添加的东西(Activity),以此类推,最后取出的是第一次添加的Activity,而Activity在Task中的顺序是可以控制的,在Activity跳转时用到Intent Flag可以设置新建activity的创建方式;

FLAG_ACTIVITY_NEW_TASK

默认的跳转类型,它会重新创建一个新的Activity,不过与这种情况,比如说Task1中有A,B,C三个Activity,此时在C中启动D的话,如果在AndroidManifest.xml文件中给D添加了Affinity的值和Task中的不一样的话,则会在新标记的Affinity所存在的Task中压入这个Activity。如果是默认的或者指定的Affinity和Task一样的话,就和标准模式一样了启动一个新的Activity.

FLAG_ACTIVITY_SINGLE_TOP

这个FLAG就相当于加载模式中的singletop,比如说原来栈中情况是A,B,C,D在D中启动D,栈中的情况还是A,B,C,D

FLAG_ACTIVITY_CLEAR_TOP

这个FLAG就相当于加载模式中的SingleTask,这种FLAG启动的Activity会把要启动的Activity之上的Activity全部弹出栈空间。类如:原来栈中的情况是A,B,C,D这个时候从D中跳转到B,这个时候栈中的情况就是A,B了

FLAG_ACTIVITY_BROUGHT_TO_FRONT

这个网上很多人是这样写的。如果activity在task存在,拿到最顶端,不会启动新的Activity。这个有可能会误导大家! 他这个FLAG其实是这个意思!比如说我现在有A,在A中启动B,此时在A中Intent中加上这个标记。此时B就是以FLAG_ACTIVITY_BROUGHT_TO_FRONT方式启动,此时在B中再启动C,D(正常启动C,D),如果这个时候在D中再启动B,这个时候最后的栈的情况是 A,C,D,B。如果在A,B,C,D正常启动的话,不管B有没有用FLAG_ACTIVITY_BROUGHT_TO_FRONT启动,此时在D中启动B的话,还是会变成A,C,D,B的。

FLAG_ACTIVITY_NO_USER_ACTION

onUserLeaveHint()作为activity周期的一部分,它在activity因为用户要跳转到别的activity而要退到background时使用。比如,在用户按下Home键,它将被调用。比如有电话进来(不属于用户的选择),它就不会被调用。
那么系统如何区分让当前activity退到background时使用是用户的选择?

它是根据促使当前activity退到background的那个新启动的Activity的Intent里是否有FLAG_ACTIVITY_NO_USER_ACTION来确定的。

注意:调用finish()使该activity销毁时不会调用该函数

FLAG_ACTIVITY_NO_HISTORY

意思就是说用这个FLAG启动的Activity,一旦退出,它不会存在于栈中,比方说!原来是A,B,C这个时候再C中以这个FLAG启动D的,D再启动E,这个时候栈中情况为A,B,C,E。

至此为应用添加手势密码功能的逻辑就完成了。欢迎留言更好的方法。

发布了53 篇原创文章 · 获赞 17 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq910689331/article/details/61922250