You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 21:28:21