Android 11包可见性:如何查询自有应用是否已安装?
解决方案:在应用A中检测应用B/C是否已安装(无需启动)
由于你可以修改三个应用的代码,以下几种方案可解决你的问题,避免通过启动应用判断:
方案1:使用自定义Content Provider(推荐)
在应用B和C中创建一个仅用于检测存在性的空Content Provider,应用A通过解析该Provider判断应用是否安装。
步骤1:在应用B/C的AndroidManifest.xml中添加Provider
<!-- 以应用B为例,C需替换对应包名和权限名 --> <provider android:name=".DummyDetectionProvider" android:authorities="us.app.B.detection" android:exported="true" android:permission="us.app.B.DETECT_PERMISSION" /> <!-- 声明自定义签名权限,仅允许同签名应用访问 --> <permission android:name="us.app.B.DETECT_PERMISSION" android:protectionLevel="signature" />
步骤2:实现空Content Provider
class DummyDetectionProvider : ContentProvider() { override fun onCreate(): Boolean = true override fun query(uri: Uri, projection: Array<String>?, selection: String?, selectionArgs: Array<String>?, sortOrder: String?): Cursor? = null override fun getType(uri: Uri): String? = null override fun insert(uri: Uri, values: ContentValues?): Uri? = null override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int = 0 override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<String>?): Int = 0 }
步骤3:在应用A中检测
首先在A的Manifest中添加权限:
<uses-permission android:name="us.app.B.DETECT_PERMISSION" /> <uses-permission android:name="us.app.C.DETECT_PERMISSION" />
然后编写检测代码:
fun isAppInstalled(context: Context, authority: String): Boolean { return try { context.packageManager.resolveContentProvider(authority, 0) != null } catch (e: Exception) { false } } // 使用示例 val isBInstalled = isAppInstalled(context, "us.app.B.detection") val isCInstalled = isAppInstalled(context, "us.app.C.detection")
方案2:使用自定义Intent Service
类似方案1,通过解析Service是否存在判断应用状态。
步骤1:在B/C的Manifest中添加Service
<service android:name=".DummyDetectionService" android:exported="true" android:permission="us.app.B.DETECT_PERMISSION" />
步骤2:实现空Service
class DummyDetectionService : Service() { override fun onBind(intent: Intent): IBinder? = null }
步骤3:在应用A中检测
fun isAppInstalled(context: Context, packageName: String, serviceFullName: String): Boolean { val intent = Intent().apply { setClassName(packageName, serviceFullName) } return try { context.packageManager.resolveService(intent, 0) != null } catch (e: Exception) { false } } // 使用示例 val isBInstalled = isAppInstalled(context, "us.app.B", "us.app.B.DummyDetectionService")
方案3:签名验证的广播检测
通过发送自定义广播,监听B/C的响应判断是否安装(异步方式)。
步骤1:在B/C的Manifest中添加Receiver
<receiver android:name=".DetectionReceiver" android:exported="true" android:permission="us.app.B.DETECT_PERMISSION"> <intent-filter> <action android:name="us.app.B.ACTION_DETECT" /> </intent-filter> </receiver>
步骤2:实现Receiver发送响应
class DetectionReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val responseIntent = Intent("us.app.A.ACTION_DETECT_RESPONSE") responseIntent.putExtra("package_name", context.packageName) context.sendBroadcast(responseIntent, "us.app.A.DETECT_RESPONSE_PERMISSION") } }
步骤3:在应用A中发送广播并监听
class AppDetector(private val context: Context) { var isBInstalled = false var isCInstalled = false private val responseReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { when(intent.getStringExtra("package_name")) { "us.app.B" -> isBInstalled = true "us.app.C" -> isCInstalled = true } } } init { val filter = IntentFilter("us.app.A.ACTION_DETECT_RESPONSE") context.registerReceiver(responseReceiver, filter, "us.app.A.DETECT_RESPONSE_PERMISSION", null) } fun startDetection() { // 发送检测广播到B context.sendBroadcast(Intent("us.app.B.ACTION_DETECT"), "us.app.B.DETECT_PERMISSION") // 发送检测广播到C context.sendBroadcast(Intent("us.app.C.ACTION_DETECT"), "us.app.C.DETECT_PERMISSION") } fun cleanup() { context.unregisterReceiver(responseReceiver) } }
为何之前的queries配置未生效?
可能的原因:
- 应用B/C的包名填写错误(注意大小写和完整路径)
- 应用B/C是系统应用或采用特殊安装方式(如工作资料),常规查询无法获取
- 应用B/C的主Activity未设置
android:exported="true"(Android 12+强制要求)
若想继续使用queries方案,建议先核对包名完全匹配,再确认B/C的可导出组件配置。
内容的提问来源于stack exchange,提问作者kristyna
相关产品推荐
相关产品推荐

