如何通过BroadcastReceiver监听应用启动的Broadcast Intent?
解决Android检测应用启动的问题
你当前的配置完全错误,android.intent.category.LAUNCHER是用于标记应用入口Activity的,和广播接收无关。而且Android早已废弃了通过静态注册广播监听应用启动的方式,API 21及以上系统不再支持这类广播的静态接收,即使动态注册也会因为后台限制导致不可靠。
下面是两种目前可行的实现方案:
方案一:使用UsageStatsManager(需用户授权)
该方案通过系统提供的应用使用统计服务,查询最近活跃的应用,需要用户授予"查看应用使用情况"权限。
1. 配置权限
在AndroidManifest.xml中添加权限:
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />
2. 检查并引导开启权限
// 检查是否已获取权限 fun checkUsageStatsPermission(context: Context): Boolean { val appOps = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager val mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), context.packageName) return mode == AppOpsManager.MODE_ALLOWED } // 跳转到权限设置页面 fun openUsageStatsSettings(context: Context) { val intent = Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS) context.startActivity(intent) }
3. 查询当前活跃应用并监听
通过定时轮询获取当前最活跃的应用包名,判断是否是目标应用:
// 获取当前前台应用包名 fun getTopAppPackageName(context: Context): String? { val usageStatsManager = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager val endTime = System.currentTimeMillis() val startTime = endTime - 1000 * 60 * 10 // 查询最近10分钟的使用记录 val usageStatsList = usageStatsManager.queryUsageStats( UsageStatsManager.INTERVAL_BEST, startTime, endTime ) if (usageStatsList.isEmpty()) return null return usageStatsList.maxByOrNull { it.lastTimeUsed }?.packageName } // 启动轮询检测 private val handler = Handler(Looper.getMainLooper()) private val checkRunnable = object : Runnable { override fun run() { val topPackage = getTopAppPackageName(applicationContext) if ("com.example.targetapp" == topPackage) { // 触发提醒逻辑,比如显示通知 showNotification(applicationContext) } handler.postDelayed(this, 2000) // 每2秒检查一次 } } // 开始检测 handler.post(checkRunnable) // 停止检测 // handler.removeCallbacks(checkRunnable)
方案二:使用AccessibilityService(无障碍服务,需用户授权)
该方案通过无障碍服务监听窗口状态变化,当目标应用启动时会触发事件,可靠性更高,但需要用户开启无障碍权限。
1. 创建无障碍服务类
class AppLaunchDetectionService : AccessibilityService() { override fun onAccessibilityEvent(event: AccessibilityEvent?) { // 监听窗口状态变化事件 if (event?.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { val targetPackage = "com.example.targetapp" val currentPackage = event.packageName?.toString() if (targetPackage == currentPackage) { // 触发提醒逻辑 showNotification(this) } } } override fun onInterrupt() { // 服务中断时的处理 } }
2. 在Manifest中配置服务
<service android:name=".AppLaunchDetectionService" 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_config" /> </service>
3. 创建无障碍服务配置文件
在res/xml目录下创建accessibility_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" android:description="@string/accessibility_service_desc" />
在strings.xml中添加服务描述:
<string name="accessibility_service_desc">检测目标应用启动,为您提供提醒服务</string>
4. 检查并引导开启无障碍权限
// 检查无障碍权限是否开启 fun checkAccessibilityPermission(context: Context): Boolean { val accessibilityManager = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager val enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC) return enabledServices.any { it.id.contains(context.packageName) } } // 跳转到无障碍设置页面 fun openAccessibilitySettings(context: Context) { val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) context.startActivity(intent) }
注意事项
- 两种方案都需要用户手动授权,无法自动获取
- UsageStatsManager的轮询间隔可以根据需求调整,过短会增加功耗
- 无障碍服务会被系统视为敏感权限,应用上架时需要说明用途
内容的提问来源于stack exchange,提问作者Owlon
相关产品推荐
相关产品推荐

