2025-09-08升级问题记录:Android11以上判断是否已安装指定APP的权限

Bug排查日记 9.5w人浏览 171人参与

一:问题

        以下代码为判断是否已安装某指定app,在工程升级到Android11后无法正确运行,都是未安装。

private static boolean isInstallApp(Context context, String packageName) {
        PackageInfo packageInfo;
        try {
            packageInfo = context.getPackageManager().getPackageInfo(packageName, 0);
        } catch (Exception e) {
            packageInfo = null;
            e.printStackTrace();
            Log.e("判断是否安装导航软件时出错,",e.getMessage());
        }
        return packageInfo != null;
    }

二:原因

        Android 目标 SDK 版本(targetSdkVersion)升级到 30 后,无法检测应用安装问题,主要是由于 Android 11(API 级别 30)引入了包可见性(Package Visibility)限制来提高用户隐私和安全性。

        在 Android 11 及更高版本中,你的应用默认只能看到有限的包集合。getPackageInfo(packageName, 0) 方法在查询不在这个“可见集合”内的应用时,即使应用已安装,也可能抛出 NameNotFoundException 或返回 null,导致判断失效。

默认情况下,你的应用只能看到以下应用

  • 自己的应用

  • 实现了 Android 核心功能的某些系统包(如媒体提供程序)

  • 安装了你应用的应用(通常应用商店或安装器)

  • 使用 startActivityForResult() 在你应用中启动了某个 activity 的任何应用

  • 启动或绑定到你应用中某项服务任何应用

  • 访问你应用中 Content Provider 的任何应用

  • 具有 Content Provider 且你应用已被授予 URI 权限来访问的任何应用

  • 作为输入法向你应用提供输入任何应用

三:解决方法

1、声明权限需要查询所有包

在 AndroidManifest.xml 中添加权限声明(本文用该方法解决)

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.your.packagename">

    <!-- 添加查询所有包的权限 -->
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />

    <application ...>
        ...
    </application>

</manifest>
2、声明特定的包名

        如果你的应用只需要查询少数几个特定的应用(例如高德地图、百度地图),这是最推荐的做法,因为它遵循了最小权限原则。

        在你的 AndroidManifest.xml 文件中的 <manifest> 标签内,添加 <queries> 元素:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.your.packagename">

    <!-- 添加 queries 声明 -->
    <queries>
        <!-- 指定你需要查询的单个包名 -->
        <package android:name="com.autonavi.minimap" /> <!-- 高德地图 -->
        <package android:name="com.baidu.BaiduMap" /> <!-- 百度地图 -->
        <!-- 添加其他你需要检测的导航软件包名 -->
    </queries>

    <application ...>
        ...
    </application>

</manifest>
     3、通过intent filter查询

        如果你不知道应用的包名,只是想查询具有某种功能的应用,那么可以使用以下的方式

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.blowing.demo"
    <queries>
        <intent>
             <action android:name="android.intent.action.SEND"/>
             <data android:mimeType="image/png"/>
        </intent>
    </queries>
</manifest>

        如果我们使用android.intent.action.MAIN 作为action元素,那么不添加权限,也是可以绕过去的,因为几乎所有应用都会有这个action。

        那么,完整的就是:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.your.packagename">

    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />

    <queries>
        <!-- 这是一个非常广泛的查询,声明你的应用需要与具有 MAIN Action 的应用交互 -->
        <intent>
            <action android:name="android.intent.action.MAIN" />
        </intent>
    </queries>

    <application ...>
        ...
    </application>

</manifest>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值