在进行程序锁开发的时候,我们会发现程序锁实现的核心难点是如何监视应用程序的启动,于是我们主要着手实现如何对应用程序的启动进行监测,这个功能的实现经历了三种方案的尝试,也符合我们实际开发中的思路,具体的实现过程如下:
- 尝试方案一
设想每个应用在启动的时候会发送一个广播,那么我们就能通过广播接收者来订阅这个广播从而达到监视应用程序启动的目的,于是我们在广播接收者的动作名称中去寻找这样的广播动作,但是很可惜系统并没有为我们提供这样一种广播。
- 尝试方案二
设想系统自身是否有一个服务对应用程序的启动做监视,如果这个服务里面的一个方法能够得到前台应用任务栈最顶端的 Activity,那么我们也能够达到监视应用程序启动的目的;一般情况下,系统的服务都是以 aidl 的形式出现的,这是因为系统底层的服务都封装在 Application Framework 层,而开发者的调用是在 Applications 层,这种调用属跨进程的调用,所以 Applications 层和 Application Framework 层的交互需要通过 aidl 来实现,于是我们就可以在系统源码中查找与之相关的 aidl 文件,但是同样系统也没有提供这样的一种服务。
- 尝试方案三
设想应用程序在启动过程中 LogCat 是否会对 Activity 的启动进行记录,于是我们尝试启动安卓手机上的系统应用计算器来观察 LogCat 的日志,通过对日志的观察我们发现 ActivityManager 可以检测到应用的 Activity 的启动,如下图:
有了上面的信息,我们就可以从 ActivityManager 入手来实现监视应用程序的启动,经过尝试 ActivityManager 的 API 可以通过如下代码来实现对应用程序启动的监视了。
package cn.sunzn.activitymonitor; import java.util.List; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.content.ComponentName; import android.os.Bundle; import android.os.SystemClock; import android.util.Log; import android.view.Menu; /** * 程序运行需要在清单文件中添加 <uses-permission android:name="android.permission.GET_TASKS"/> */ public class MainActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /** 获取系统服务 ActivityManager */ ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); while (true) { /** 获取当前正在运行的任务栈列表, 越是靠近当前运行的任务栈会被排在第一位,之后的以此类推 */ List<RunningTaskInfo> runningTasks = manager.getRunningTasks(1); /** 获得当前最顶端的任务栈,即前台任务栈 */ RunningTaskInfo runningTaskInfo = runningTasks.get(0); /** 获取前台任务栈的最顶端 Activity */ ComponentName topActivity = runningTaskInfo.topActivity; /** 获取应用的包名 */ String packageName = topActivity.getPackageName(); /** 输出检测到的启动应用信息 */ Log.i("sunzn", packageName); /** 为了便于观察信息的输出,程序休眠2秒 */ SystemClock.sleep(2000); } } public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }
实现以上的代码后,我们将该程序部署到模拟器进行测试,通过测试我们会发现被启动的应用程序的包名都会被输出到 LogCat 界面,这也就证明程序成功的检测到了应用程序的启动,所以程序锁的实现即可以此为基础将得到的包名与加锁应用数据库中的数据进行比对来实现应用程序启动时 是否进行密码验证的功能。最后的测试图如下,在下面的测试结果中我们可以发现程序成功的检测到了浏览器和计算器的启动。