• Android 11判断应用已安装坑点



    一个很久没有大更新的app,接用户反馈购买课程微信支付不了,通过app、后端的日志查看,确实有多次选择微信下单却未支付的操作。后来在一同事手机上复现,(app提示微信未安装,事实上已经安装)经过很久的折腾,得到结论。app调用的 wxApi.isWXAppInstalled() 来判断微信是否安装。最终在腾讯文档中找到了说明,原因是Android 应用可见性,要求做适配。

    Android 11 wxApi.isWXAppInstalled() 返回false


    解决办法

    以下方法任意一种都可以解决问题

    1、在清单文件的添加queries标签

    manifest节点添加如下内容:

       <queries>
             <package android:name="com.tencent.mm" />
       </queries>
    
    • 1
    • 2
    • 3

    具体位置如下所示

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="...">
        <queries>
           <package android:name="com.tencent.mm" />
       </queries>
       .....
    </manifest>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    由于是新的标签,因此需要升级开发工具,否则会出现编译错误:

    1)Android Studio 需要升级至 3.3 及以上,建议升级至 4.0 及以上版本;

    2)Android SDK Build-Tools 需要升级至 30 及以上版本;

    3)com.android.tools.build:gradle 需要升级至 3.6.0 版本,建议升级至最新的 3.6.4 版本。

    原因与说明

    主要原因是因为Android 11加强了应用可见性,原来的调用方式没有变,但系统内部是做了更苛刻的条件进行判断。什么是可见性?,在这里可见性指其他应用是否能被当前应用检测到(是否已经安装了某个app,一般这种需求不多或特定应用才会检测是否已经安装某个app)。
    微信SDK内部是封装了对微信应用的检测,源码:

    public final boolean isWXAppInstalled() {
            if (this.detached) {
                throw new IllegalStateException("isWXAppInstalled fail, WXMsgImpl has been detached");
            } else {
                try {
                    PackageInfo var1;
                    return (var1 = this.context.getPackageManager().getPackageInfo("com.tencent.mm", 64)) == null ? false : WXApiImplComm.validateAppSignature(this.context, var1.signatures, this.checkSignature);
                } catch (NameNotFoundException var2) {
                    return false;
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    其中就获取”com.tencent.mm“ 的packageInfo,在Android 11上,代码执行是异常的,所以返回的一致是false。
    Android 11 系统策略更新,请开发者及时适配

    <manifest package=“com.example.app”>

    // 在应用的AndroidManifest.xml添加如下标签

    // 指定微信包名


    </manifest>

    添加以上标签之后,需要开发者升级编译工具,否则会出现编译错误。

    1)Android Studio 需要升级至 3.3 及以上,建议升级至 4.0 及以上版本;

    2)Android SDK Build-Tools 需要升级至 30 及以上版本;

    3)com.android.tools.build:gradle 需要升级至 3.6.0 版本,建议升级至最新的 3.6.4 版本。

    2、增加权限

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

    Android 11 获取已安装app列表问题

    其实还是来自第一个问题,既然指定单个包名获取不到packgeinfo,那么获取所有的应用之后,进行匹配会如何,答案是否定的。

    var pkgs = packageManager.getInstalledPackages(0)
    var apps = packageManager.getInstalledApplications(0);
    
    • 1
    • 2

    getInstalledApplications 是新的接口。如上两个接口返回的列表,在Android 11上,正常情况下返回了系统预装的app和当前app的packageinfo,不会返回其他已安装应用,因此替代单一包名的检测是行不通的。重要的是那些管理手机应用的app此时就需要采用上面第二种方法了,否则获取不到其他app。

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

    Android 11 应用可见性官方说明

    Android 11可见性官方说明

    您的App运行在Android 11(API 级别 30)或更高版本系统,默认情况下,系统会自动让部分应用对您的app可见,但会过滤掉其他应用。本指南将介绍如何让上述其他应用对您的app可见。

    如果您的应用以 Android 11 或更高版本为目标平台,并且需要与应用(自动可见的应用除外)交互,请在您应用的清单文件中添加 <queries> 元素。在<queries> 元素中,按软件包名称、按 intent 签名或按 Provider 授权指定其他应用,如以下部分所述。

    特定软件包名称

    如果您知道要查询或与之交互的一组特定应用(例如,与您的应用集成的应用或您使用其服务的应用),请将其包名添加到 <queries> 元素内的一组 <package> 元素中:

    <manifest package="com.example.game">
        <queries>
            <package android:name="com.example.store" />
            <package android:name="com.example.services" />
        </queries>
        ...
    </manifest>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注意:如果在应用的清单中声明了 <package> 元素,则与该软件包名称关联的应用会出现在对 PackageManager 进行的任何与该应用的组件匹配的查询的结果中。

    在库中与托管应用通信

    如果要开发 Android 库,可以通过在 AAR 清单文件中添加 <queries> 元素来声明软件包可见性需求。此 <queries> 元素与应用可在自己的清单中声明的元素功能相同。

    如果您的库涉及与“托管”应用通信(例如使用绑定服务),请添加用于指定托管应用的软件包名称的 <package> 元素:

    <!-- Place inside the <queries> element. -->
    <package android:name=PACKAGE_NAME />
    
    • 1
    • 2

    通过添加此声明,可以检查是否已安装托管应用并与之交互,例如通过调用 bindService() 来完成。此交互的结果是,使用这个库的调用方应用会自动对托管应用可见。

    与 intent 过滤器签名匹配的软件包

    您的应用可能需要查询一组具有特定用途的应用或与之交互,但您可能不知道要添加的具体软件包名称。在这种情况下,您可以在<queries> 元素中列出 intent 过滤器签名。然后,您的应用就可以发现具有匹配的 <intent-filter> 元素的应用。

    以下示例允许您的应用看到支持 JPEG 图片共享功能的已安装应用:

    <manifest package="com.example.game">
        <queries>
            <intent>
                <action android:name="android.intent.action.SEND" />
                <data android:mimeType="image/jpeg" />
            </intent>
        </queries>
        ...
    </manifest>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    <intent> 元素有一些限制:

    • 必须只添加一个 <action> 元素。
    • 不能在 <data> 元素中使用 path、pathPrefix、pathPattern 或 port 属性。系统的行为就像您将每个属性的值都设为通用通配符 (*) 一样。
    • 不能使用 元素的 mimeGroup 属性。
    • 在单个 元素的 元素中,以下每个属性最多使用一次:
      • mimeType
      • scheme
      • host
        可以在多个 <data> 元素之间分配这些属性,也可以在单个 <data> 元素中使用这些属性。

    <intent> 元素支持通用通配符 (*) 作为一些属性的值:

    • <action> 元素的 name 属性。
    • <data> 元素的 mimeType 属性的子类型 (image/*)。
    • <data> 元素的 mimeType 属性的类型和子类型 (/)。
    • <data> 元素的 scheme 属性。
    • <data> 元素的 host 属性。
      除非前面列表中另有说明,否则系统不支持混合使用文本和通配符,如 prefix*。

    使用特定授权的软件包

    如果您需要查询 Content Provider 但不知道具体的软件包名称,您可以在 <provider> 元素中声明该提供程序授权,如以下代码段所示:

    <manifest package="com.example.suite.enterprise">
        <queries>
            <provider android:authorities="com.example.settings.files" />
        </queries>
        ...
    </manifest>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注意:如果 元素包含 元素,您可能会在 Android Studio 中看到与 <provider> 元素相关的编辑器警告。只要您使用的是 Android Gradle 插件的最新“点”版本,您的 build 就不受影响,因此您可以忽略该警告。如需了解详情,请参阅有关为 Android 11 中的软件包可见性准备 Gradle build 的博文。

    可以在单个 <queries> 元素中声明所有提供程序授权。此格式取决于您声明提供程序授权的数量:

    • 单个 <provider> 元素
      在元素中,声明以英文分号分隔的授权列表。
    • 多个 <provider> 元素
      在每个元素中,声明单项授权或以英文分号分隔的授权列表。

    所有应用(不推荐)

    在极少数情况下,可能需要查询设备上的所有已安装应用或与之交互,不管这些应用包含哪些组件。为了允许您的应用看到其他所有已安装应用,系统会提供 QUERY_ALL_PACKAGES 权限。

    下面列出了适合添加 QUERY_ALL_PACKAGES 权限的用例的一些示例:

    • 无障碍应用
    • 浏览器
    • 设备管理应用
    • 安全应用
    • 防病毒应用

    不过,在绝大多数情况下,可以通过以下方式实现您应用的用例:与一组自动可见的应用交互,并在您的清单文件中声明您的应用需要访问的其他应用。为了尊重用户隐私,您的应用应请求应用正常工作所需的最小软件包可见性。

    这项来自 Google Play 的政策更新为需要 QUERY_ALL_PACKAGES 权限的应用提供了相关准则。

  • 相关阅读:
    C++实现类似QT中的计时器QTime类(CQTime)
    海关外贸企业大数据风控平台产品应用
    golang获取操作系统信息:CPU,内存,网络,磁盘,进程管理,传感器(温度,风扇,电池)
    谷歌开发者社区推荐:《Jetpack Compose 从入门到实战》新书上架,带你踏上 Compose 开发之旅~
    C++--哈希表的实现及unorder_set和unorder_map的封装
    《深度学习进阶 自然语言处理》第五章:RNN通俗介绍
    Visual Studio Code(vs code) 安装c# .net环境 solution
    VR头显Unity下如何实现毫秒级延迟的RTMP或RTSP播放?
    编写一个会导致死锁的程序,将怎么解决?
    【Python】Python常用的日期时间函数
  • 原文地址:https://blog.csdn.net/lanlangaogao/article/details/125624162