Android运行时如何获取前台应用?能否监听前台应用切换及所需权限?
如何在Android中检测前台应用及接收切换事件?
嘿,关于这个问题我刚好有不少实践经验,给你梳理得明明白白:
一、怎么获取当前前台的应用?
不同Android版本的API限制不一样,毕竟Google一直在收紧隐私权限:
- Android 5.0(API21)到Android10(API29):可以用
UsageStatsManager来查询应用使用记录,或者老的ActivityManager.getRunningAppProcesses()(不过后者在API22后就被标记为废弃了,返回的结果也不一定准确,不推荐用)。 - Android11+(API30及以上):
UsageStatsManager是唯一可靠的途径,而且需要额外的权限才能用。
给你贴个UsageStatsManager的简单实现代码(Kotlin版):
val usageStatsManager = getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager val endTime = System.currentTimeMillis() val startTime = endTime - 1000 * 60 // 查询最近1分钟的应用使用记录 val stats = usageStatsManager.queryUsageStats( UsageStatsManager.INTERVAL_DAILY, startTime, endTime ) var foregroundPackage: String? = null var lastUsedTime = 0L // 遍历找到最后使用的应用,也就是当前前台的 for (stat in stats) { if (stat.lastTimeUsed > lastUsedTime) { lastUsedTime = stat.lastTimeUsed foregroundPackage = stat.packageName } } // 拿到的foregroundPackage就是当前前台应用的包名啦
二、能在应用切换前台时收到事件通知吗?
当然可以,主要有两种方式,各有优劣:
- 定时轮询:用
Handler或者WorkManager定期调用上面的查询方法,对比上次的结果,如果包名变了就触发你的记录逻辑。这种方式简单易实现,但不够实时,而且会消耗一点系统资源。 - 辅助服务(AccessibilityService):这是更实时的方案,通过辅助服务监听窗口状态变化。当有应用切换到前台时,会收到
TYPE_WINDOW_STATE_CHANGED事件,直接就能拿到当前应用的包名。
给你说下辅助服务的实现步骤:
- 写一个继承
AccessibilityService的类,重写事件处理方法:
class AppSwitchMonitorService : AccessibilityService() { override fun onAccessibilityEvent(event: AccessibilityEvent?) { // 监听窗口状态变化事件 if (event?.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { val currentPackage = event.packageName?.toString() currentPackage?.let { // 这里处理应用切换的逻辑,比如把它添加到你的使用列表里 } } } override fun onInterrupt() { // 服务被中断时的处理,一般空实现就行 } }
- 在
AndroidManifest.xml里注册这个服务:
<service android:name=".AppSwitchMonitorService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config" /> </service>
- 创建
res/xml/accessibility_service_config.xml配置文件,指定要监听的事件:
<?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeWindowStateChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" />
⚠️ 注意:辅助服务需要用户手动在系统设置里开启,你得做个引导页面告诉用户怎么操作,没法自动申请权限。
三、需要哪些权限?
分两种情况来说:
- 用UsageStatsManager的情况:需要
android.permission.PACKAGE_USAGE_STATS权限。这个权限没法通过代码里的requestPermissions()申请,必须引导用户去系统设置的「应用使用权限」页面开启(一般路径是:设置 → 应用 → 你的应用 → 权限 → 应用使用情况)。 - 用AccessibilityService的情况:需要
android.permission.BIND_ACCESSIBILITY_SERVICE权限,这个权限在注册服务的时候声明就行,用户开启辅助服务后自动获取。 - 还有个老权限
android.permission.GET_TASKS,在API21之前能用,但现在已经被废弃了,高版本系统普通应用根本拿不到,别用了。
四、普通应用能实现吗?还是只能系统应用?
- 普通应用:完全可以实现,但有两个小限制:
- 必须引导用户手动开启对应的权限(应用使用权限或辅助服务),没法静默获取。
- 在Android12+(API31)里,
UsageStatsManager的查询结果可能会有一点延迟,而且某些系统应用的记录会被隐藏。
- 系统应用:如果你的应用是预装在系统里、有系统签名的,那就能跳过一些权限申请步骤,比如直接拿到
PACKAGE_USAGE_STATS权限,而且获取前台应用的信息更稳定,没有普通应用的那些限制。
内容的提问来源于stack exchange,提问作者The Matrix




