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

大家好,又到了新一期的项目需求讨论,很多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是处于前台还是后台有很多介绍,网上也有很多。但是我这里还是要说一点: 网上很多代码都是这样的:

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。这里大家可以留个心。说不定以后就碰到这方面问题。

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

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方法中进行判断来决定是否启动我们的手势锁界面:

@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掉而已。所以我们这里要传这么个参数来进行标记。

我们来看下相关的代码:

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

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

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

自定义广播LockStateReceiver.java:

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:

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

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

if (receiver != null) {
    unregisterReceiver(receiver);
}复制代码

这里大家可能会问,你不是说好的监听锁屏的吗,怎么现在监听的是用户解锁的Action了。

是这样的,我解释下:

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

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

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

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

public void stateScreenOff() {

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

}复制代码

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏格子的个人博客

Jenkins系列一:安装和简单配置Jenkins简单介绍Jenkins安装

Jenkins是一个开源软件项目,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。

27510
来自专栏Java职业技术分享

Java异步NIO框架Netty实现高性能高并发

最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调...

92110
来自专栏人工智能LeadAI

译文 | 怎样用 JRebel for Android

只要你的项目相对较小,开发Android应用的用户体验还是很棒的。然而随着项目功能的增加,你会发现构建项目的时间也会随着增长。这种情况会导致你的大部分时间都花在...

42540
来自专栏Web项目聚集地

微信扫码登录实战(附代码)

导读: 由于微信端流量比较足,所以扫码登录系统功能也受到了很多系统的青睐,本文就来详细的解开该技术的面纱。 优质内容请关注微信公众号“Web项目聚集地”

4.2K20
来自专栏玄魂工作室

实战-如何获取安卓iOS上的微信聊天记录、通过Metasploit控制安卓

在这篇文章中我们将讨论如何获取安卓、苹果设备中的微信聊天记录,并演示如何利用后门通过Metasploit对安卓设备进行控制。文章比较基础、可动手性强,有设备的童...

89890
来自专栏cs

kali入侵windows

因为我是一个爱好和平的人(捂嘴笑),所以就在虚拟机中,创建二个系统,一个kali,一个windows xp,来进行这次入侵实验,以此迈入hacke的大门。 -...

700110
来自专栏架构师之旅

《Spring敲门砖之基础教程第一季》 第一章(2)解读Spring Framework

系统架构 一个成功的项目离不开一个好的架构,一个好的架构自然需要一位好的设计师, Rod Johnson正是Spring的前生总架构设计师,那...

21060
来自专栏Netkiller

SOA 面向服务框架设计与实现

文章节选自 《Netkiller Architect 手札》 由于Java 语言的编译与重启不可抗拒缺陷,所选择使用PHP弥补这个缺陷。 在合适的场景中使用PH...

35950
来自专栏令仔很忙

新手学JAVA(九)----Model1 And Model2

Java Web应用结构的发展和MVC的发展非常类似,Java Web编程的发展则经历了三个阶段,下面就来说说有哪三个阶段。

8010
来自专栏数据和云

颜值实力派—打造MySQL运行监控环境

作者 | 陈龙,云和恩墨西区工程师,一线服务过金融等行业,精通 oracle 性能优化,故障诊断,特殊恢复领域 。

14020

扫码关注云+社区

领取腾讯云代金券