前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >项目需求讨论- 手机锁屏及APP退到后台后自动锁定功能

项目需求讨论- 手机锁屏及APP退到后台后自动锁定功能

作者头像
青蛙要fly
发布2018-08-29 14:59:14
8630
发布2018-08-29 14:59:14
举报
文章被收录于专栏:青蛙要fly的专栏

大家好,又到了新一期的项目需求讨论,很多APP都有安全的意识,比如一些银行的APP,你登录后,看一些东西,然后这时候锁屏了。或者是按了Home键退到了后台,这时候,再启动这个App,可能就会又到了这个APP的解锁的界面。或者重新登录的界面。防止安全。


在前面的文章中我介绍过APP第一次打开登录进去时候的解锁功能: 项目需求讨论-APP手势解锁及指纹解锁 假设我们我们这里APP的登录用的是手势解锁,那么我们的APP在使用过程中,退到后台或者锁屏后,就应该再次出现这个手势解锁的界面。也就是:

手势解锁

还是老话,我写的方法可能不是最佳的,希望大家轻点喷,哈哈。

我们分情况来看:

1.用户按了Home键或者启动其他APP等导致当前APP居于后台:

因为用户是在操作过程中,把APP退到了后台,所以我们不可能在特定的某个Activity中去监听这些用户退出后台等操作。所以我们想到了在BaseActivity中做处理。

我们假设用户在操作我们APP的A界面,A界面调用onStop方法有二种情况,一种是你开启了APP中的其他界面,还有一种就是比如按了Home键退到了后台,所以当onStop调用的时候,我们来判断下,我们的APP当前是不是在还处于前台,如果还在前台,就说明只是APP内部开启了另外一个Activity而已。不然就是处于了后台。

判断我们的APP是处于前台还是后台有很多介绍,网上也有很多。但是我这里还是要说一点: 网上很多代码都是这样的:

代码语言:javascript
复制
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningProcesses = am.getRunningAppProcesses();  
    for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {  

       if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {  
           for (String activeProcess : processInfo.pkgList) {  
               if (activeProcess.equals(context.getPackageName())) {  
                   isInBackground = false;  
               }  
           }  
       }  
   }复制代码

我们可以看到网上很多介绍ActivityManager.getRunningAppProcessed方法说是返回了系统中正在运行的APP的进程,所有拿到的是List,所以然后遍历一遍,判断哪个进程处于前端,然后再判断这个处于前端的进程的包名是不是我们这个APP的名字。网上清一色的介绍也都是这样,但是在我实际开发中,我发现runningProcess的size一直返回为1。直接就返回了我们的APP的进程,还不是像网上所说的那样。就算我额外开了好几个其他APP也还是一样,返回的size为1,后来查了其他的资料发现了原因:

在Android 5.0+的系统上,getRunningTasks方法和getRunningAppProcess方法返回的都是你的application process。我在测试时候也都验证了(Android 6.0),的确这二个方法都返回的size都为1。这里大家可以留个心。说不定以后就碰到这方面问题。

最后我们的代码如下所示:

代码语言:javascript
复制
public boolean isApplicationBroughtToBackground(final Context context) {

   ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
   if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) {
       List<ActivityManager.RunningAppProcessInfo> runningProcesses = am.getRunningAppProcesses();
       if(runningProcesses != null && !runningProcesses.isEmpty()){
           if(runningProcesses.get(0).importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND){
               return true;
           }
       }

    }else{
        List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
        if (tasks != null && !tasks.isEmpty()) {
            ComponentName topActivity = tasks.get(0).topActivity;
            if (!topActivity.getPackageName().equals(context.getPackageName())) {
                return true;
            }
        }
    }
    return false;
}复制代码

然后我们在onRestart方法中进行判断来决定是否启动我们的手势锁界面:

代码语言:javascript
复制
@Override
protected void onRestart() {
    super.onRestart();

    if (isBackground) {
        isBackground = false;
        Intent intent = new Intent();
        intent.putExtra("isReLock", true);
        intent.setClass(aty, PatternLockActivity.class);
        startActivity(intent);
    }
}复制代码

细心的读者发现,我们这里intent里面传了个参数intent.putExtra("isReLock", true);,为什么要传这个值,是这样的:

  1. 如果你是第一次打开这个APP。启动这个手势界面的时候,你不想进去了。你可以按返回键,然后退出了这个APP,但是如果是你在操作我们的APP过程中,因为退到了后台后再次被锁定,这时候出来的手势锁就不能有响应返回键的功能了。除非你重新解锁,不然按了返回键,手势界面被关闭,岂不是里面的内容又被看到了。再次启动的手势界面也毫无保密功能可言。
  2. 第一次打开APP的显示的手势锁解锁成功的时候,是会进行其他登录的代码,然后跳到主页面,而后面再次锁上的手势锁,解锁成功后,我们只是把它给finish掉而已。所以我们这里要传这么个参数来进行标记。

我们来看下相关的代码:

代码语言:javascript
复制
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (!isReLock && keyCode == KeyEvent.KEYCODE_BACK) {
        finish();
    }
    return true;
}复制代码

2. 用户对手机进行了锁屏操作:

我们一般在APP登录成功后,进入到主界面MainActivity,然后通过MainActivity进行相关界面的跳转及操作,所以一般来说,这个MainActivity是一直存在的。不会说被关闭等,所以我们只需要在主界面处动态注册广播,来监听相关的锁屏界面即可。

自定义广播LockStateReceiver.java:

代码语言:javascript
复制
public class LockStateReceiver extends BroadcastReceiver{

    private StateListener listener;

    public LockStateReceiver(StateListener listener) {
        this.listener = listener;
    }

    @Override
    public void onReceive(Context context, Intent intent) {

       if(Intent.ACTION_USER_PRESENT.equals(intent.getAction())){
            if(!App.getBackgroundApp()){
                listener.stateScreenOff();
            }
        }
    }

    public interface StateListener{
        void stateScreenOff();
    }
}复制代码

MainActivity.java:

代码语言:javascript
复制
receiver = new LockStateReceiver(this);
if (receiver != null) {
    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_USER_PRESENT);
    registerReceiver(receiver, filter);
}复制代码

记得在MainActivity.java销毁时候取消注册的广播:

代码语言:javascript
复制
if (receiver != null) {
    unregisterReceiver(receiver);
}复制代码
这里大家可能会问,你不是说好的监听锁屏的吗,怎么现在监听的是用户解锁的Action了。

是这样的,我解释下:

在我的上一篇文章中,我们的用户可能用的是指纹解锁的功能, 项目需求讨论-APP手势解锁及指纹解锁 如果你在监听用户锁屏动作,然后在接受到锁屏的广播时候就去把我们APP的指纹锁屏界面给调出来,这时候你会发现,你去解锁手机自带的锁屏界面时候,用指纹解锁无效,因为指纹解锁的功能已经被我们的APP给挟持过去了。所以反而手机的锁屏无法用指纹解锁了。所以我们思路换一下,既然有手机要锁定,肯定有解锁的时候,我们只需要监听手机解锁动作,然后把我们的APP给锁定起来即可。

所以我们只需要在接受到Intent.ACTION_USER_PRESENT的广播后,判断下当前是不是处于后台,如果是处于后台,我们就不需要做处理,为什么,因为我们的APP处于后台后,本身就已经有一套机制去调用APP锁定界面,如果我们的APP处于前端,然后手机解锁后,我们才会去启动APP的锁定界面。 所以代码才会反过来:

代码语言:javascript
复制
if(!App.getBackgroundApp()){
    listener.stateScreenOff();
}复制代码

同样的,stateScreenOff方法也就是启动我们的APP的手势锁定界面:

代码语言:javascript
复制
public void stateScreenOff() {

    Intent intent = new Intent();
    intent.putExtra("isReLock", true);
    intent.setClass(aty, PatternLockActivity.class);
    startActivity(intent);

}复制代码

好了。基本的实现就是这样。希望大家多提意见。哈哈。。

PS:感谢大家留言,下面也有人说了可以使用ActivityLifecycleCallbacks来执行。。大家也可以参考。o( ̄︶ ̄)o

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017年07月28日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 还是老话,我写的方法可能不是最佳的,希望大家轻点喷,哈哈。
  • 1.用户按了Home键或者启动其他APP等导致当前APP居于后台:
  • 2. 用户对手机进行了锁屏操作:
    • 这里大家可能会问,你不是说好的监听锁屏的吗,怎么现在监听的是用户解锁的Action了。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档