当前位置: 首页 > 科技观察

安卓锁屏APP实现难点总结

时间:2023-03-15 00:57:42 科技观察

定制一款美观实用的锁屏APP。如果能赢得用户的认可,更换系统自带的锁屏,绝对会是一个大的日常入口。这段时间正好总结一下最近调研的Android平台锁屏APP开发难点。一、前言锁屏的大概实现原理很简单。监听系统亮屏广播,在亮屏时显示自己的锁屏界面,用户在锁屏界面上进行一系列操作即可解锁。有的手机在启动锁屏界面的过程中会很卡,所以你会明显看到在亮屏后锁屏界面的启动有延迟,所以你也可以选择监听广播系统的屏幕关闭,屏幕关闭时锁屏也会关闭。界面就绪后,点亮屏幕,直接显示(熄屏后你的app更容易被kill掉,注意保活)。另外需要注意的是,SCREEN_ON/SCREEN_OFF只能在亮屏和灭屏时动态监听,所以需要开启另外一个Service进行注册,同时这个Service的自启动和保活也必须做好。我不会详细介绍基本实现的细节。本文只谈遇到的几个困难。二、锁屏实现的难点1、屏蔽Home键既然是锁屏界面,当然锁屏只能通过界面上的一些滑动或者输入操作来解锁,不能简单的通过直接按主页按钮。从4.0开始,Home在框架层直接由系统响应,被迫退居桌面。第三方应用无法再通过Activity.onKeyDown方法监听拦截Home键,虽然Home键的KeyCode还是象征性的保留了下来。为了向前兼容,但是当Home键被??按下时,这个方法不会被回调。除了onKeyDown,还有没有其他方法可以监听Home键,有。当前台app回到后台时,会广播ACTION_CLOSE_SYSTEM_DIALOGS。收到广播携带的intent后,分析其中的“reason”参数,即可知道退出的原因。home键按下后,原因是“homekey”,最近任务键按下后,原因是“recentapps”。这当然不是最终的解决方案,因为某些三星ROM没有此广播。而广播的意思只是通知你框架层已经把你的应用程序返回到桌面了。可以监听home键,但是没办法拦截home键。可能我想到了,当home键可以被监听到的时候,我就立马重新打开我的Activity来显示。我尝试过这个。home键按下后,startActivity会有3秒左右的延时。这应该是谷歌的想法,我们将要做到这一点,我们制定了这样一个延迟计划。直接拦截不行,想想其他办法。按下Home键是让系统回到Launcher(也就是桌面启动器),所以如果我们的锁屏Activity本身就是Launcher,那么按下Home键并不意味着回到我们的锁屏Activity,而它也可以防止锁屏Activity被关闭。如何将自己的Activity声明为Launcher,为Activity添加intent-filter:这样,新安装的应用程序将是一个可以用作启动器的应用程序,所以当你按下home键第一次使用,会有弹窗提示选择进入哪个launcher,选择我们自己的Activity,这样home键就被我们接管了。但是,这有一个明显的问题。如果在我们的锁屏界面不按Home键,也会进入锁屏Activity。当然,解决方法也很简单。当我们按下Home后,我们进入锁屏Activity的onCreate进行判断。如果前面的前台Activity是锁屏Activity,那么Home键就不用处理了。如果不是锁屏Activity,那么要关闭锁屏Activity,跳到用户的真实桌面启动器。哪个是真正的桌面启动器,我们可以这样找到:ListpkgNamesT=newArrayList();ListactNamesT=newArrayList();ListresolveInfos=context.getPackageManager().queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY);  for(inti=0;i是的在手机设置中,默认没有授权应用使用悬浮窗,所以应用也要考虑引导用户授权使用浮动窗口。另外,对于一些紧急解锁场景,比如接听电话、处理闹钟等,对于Activity实现的锁屏界面,系统会自动隐藏所有前台Activity,让用户直接处理这些场景。但是浮窗会覆盖场景,所以遇到这些场景时,浮窗实现的锁屏界面就得自己处理这些特殊场景的自动解锁。3、禁用系统锁屏自带锁屏界面,同样需要禁用系统锁屏,以免造成用户需要二次解锁的情况。首先,我们需要知道用户是否设置了锁屏,方法如下:对于APILevel16及以上的SDK,可以使用如下方法判断是否有锁:((KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE)).isKeyguardSecure()对于APILevel15及以下SDK,可以使用反射判断:try{Classclazz=Class.forName("com.android.internal.widget.LockPatternUtils");构造函数constructor=clazz.getConstructor(Context.class);constructor.setAccessible(true);Objectutils=constructor.newInstance(this);Methodmethod=clazz.getMethod("isSecure");return(Boolean)method.invoke(utils);}catch(Exceptione){e.printStackTrace();}好的,了解到用户设置了系统锁屏,如何关闭呢?有人建议这个方法keyguardLock.disableKeyguard();需要权限但根据笔者的测试,该方法只能禁用滑动锁,如果用户设置了图案锁或PIN锁,则无法直接取消.禁用密码锁或图案锁是非常危险的行为。基于此,谷歌应该不会向开发者开放,所以目前锁屏应用中禁用锁的方式是直接跳转到系统锁屏设置界面,直接引导用户手动关闭。可以通过以下代码跳转到用户锁屏设置界面:Intentin=newIntent(Settings.ACTION_SECURITY_SETTINGS);startActivity(in);这样也会有一些兼容性问题,比如?手机的ROM没有设置系统锁屏的功能放在安全设置里,所以你找不到取消系统锁的地方打开安全设置界面时的画面。这与许多锁屏应用程序不兼容。3、附加功能难点以上功能直接针对锁屏本身的实现。除了“锁屏”功能外,锁屏应用还应该具备一些其他美观实用的功能。最起码要尽量接近系统锁屏风格,这样才能容易被用户接受。1.获取通知当一个新的Notification到来时,它应该显示在锁屏上,所以我们需要监控通知栏。从Android4.3(api18)开始,Google为我们提供了一个NotificationListenerService类。第三方应用程序可以更容易地获得通知栏的使用权(NotificationAccess)。当然,这样的敏感权限必须由应用自己声明,同时引导用户手动授权。如下,创建一个继承自NotificationListenerService的NotificationMonitor类,并声明权限:.notification.NotificationListenerService"/>然后,就像引导用户关闭系统锁屏一样,引导用户授权通知栏使用权:));可以通过如下代码查看是否已经获取到通知栏的使用权限:TextUtils.isEmpty(flat)){finalString[]names=flat.split(":");for(inti=0;i