“这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战”
问题定位
因为做的是海外项目,早上问题反馈群里出现了twitter 点击登录时候提示: 未安装。 在项目本地查了下是提示文案, 是因为调用了
//根据包名 获取应用信息,如果不抛异常就是已经安装app
context.getPackageManager().getApplicationInfo("com.twitter.android",
PackageManager.MATCH_UNINSTALLED_PACKAGES);
ps:代码是为了方便演示简化后的代码。实际是封装在公共库里面的代码。 看代码没有啥问题,况且三方登录这块儿好久没有修改了 理论不应该出现问题。
- 怀疑用户网络下载的apk 是被第三方市场或者灰产处理过的,所以包名不是官方的包名称 这个时候让QA去复现一下,好家伙,好几个手机都不可以了。 找他们要到twitter.apk 然后通过命令查看了下apk信息,确实发现包名不是 com.twitter.android ,本来以为事情到这里应该结束了,然后并没有。。。 先用aapt查看拿到的apk信息: 在终端输入:
aapt dump badging Twitter_Rev_ali213.apk
然后输入了Twitter_Rev_ali213.apk 的所有信息
//重点信息: 包名
package: name='com.fengyintime.rongshu' versionCode='104' versionName='1.0.4' compileSdkVersion='23' compileSdkVersionCodename='6.0-2438415'
install-location:'internalOnly'
sdkVersion:'21'
targetSdkVersion:'30'
uses-permission: name='com.twitter.android.permission.RESTRICTED'
uses-permission: name='android.permission.MODIFY_AUDIO_SETTINGS'
uses-permission: name='android.permission.INTERNET'
...
...
...
uses-permission: name='android.permission.INTERNET'
uses-permission: name='android.permission.READ_EXTERNAL_STORAGE'
application-label:'Twitter'
application-label-ar:'تويتر'
application-label-bg:'Twitter'
...
...
locales: '--_--' 'ar' 'bg' 'bn' 'ca' 'cs' 'da' 'de' 'el' 'en-GB' 'es' 'fa' 'fi' 'fr' 'gu' 'hi' 'hr' 'hu' 'in' 'it' 'iw' 'ja' 'kn' 'ko' 'mr' 'ms' 'nb' 'nl' 'pl' 'pt' 'ro' 'ru' 'sk' 'sr' 'sv' 'ta' 'th' 'tl' 'tr' 'uk' 'vi' 'zh-CN' 'zh-HK' 'zh-TW'
densities: '120' '160' '240' '320' '480' '640' '65534' '65535'
native-code: 'arm64-v8a' 'armeabi-v7a' 'x86'
- 然后在让从google play市场下载apk,发现一个神奇的事情,就是Android 11 系统不可以, 低于11的系统可以正常登录。
这个时候才去插上USB数据线,然后看下是不是有什么日志输出。点击时候直接看到
android.content.pm.PackageManager$NameNotFoundException: com.twitter.android 异常, 这个时候我知道,一定是代码出问题了,或者我们apk的问题,一定不是用户的问题。
然后查了下为啥11系统会报着个错误,接着就发现问题了。
然后看了下我们 项目targetSdkVersion 版本修改记录是最近一个版本从29升级到30 ,这块儿被忽视了 没有测试到。
问题解决方案
方案一
找到了官方文档,在Android 11系统,项目targetSdkVersion =30 的时候 对安装app列表做了限制,就是你不能直接向开始那样读取安装列表,或者查询某个app信息。需要单独配置,或者给配置权限,不然读取不到。 直呼好家伙。差点就。。。。。
google官网给我们解决方案了:如果知道要查询或与之交互的一组特定应用(例如,与您的应用集成的应用或您使用其服务的应用),请将其软件包名称添加到 <queries> 元素内的一组 <package> 元素中:
<manifest package="com.example.app">
<queries>
<package android:name="com.twitter.android" />
<package android:name="com.tencent.mm" />
...
...
</queries>
...
</manifest>
如果我们需要和多个app做交互,直接向<queries> 标签中添加我们要交互的app 包名就可以了。
这个时候你是不是又想说,如果我不知道那个apk包名 但是我想找到对应的apk怎么办呢? 别着急,google粑粑 给我们解决方案了,直接拿过来用。
在给定 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>
<intent> 元素有一些限制:
-
您必须只添加一个
<action>元素。 -
您不能在
<data>元素中使用path、pathPrefix、pathPattern或port属性。系统的行为就像您将每个属性的值都设为通用通配符 (*) 一样。 -
您不能使用
<data>元素的mimeGroup属性。 -
在单个
<intent>元素的<data>元素中,您可以使用以下每个属性最多一次:mimeTypeschemehost
您可以在多个
<data>元素之间分配这些属性,也可以在单个<data>元素中使用这些属性。
<intent> 元素支持通用通配符 (*) 作为一些属性的值:
<action>元素的name属性。<data>元素的mimeType属性的子类型 (image/*)。<data>元素的mimeType属性的类型和子类型 (*/*)。<data>元素的scheme属性。<data>元素的host属性。
除非前面列表中另有说明,否则系统不支持混合使用文本和通配符,如 prefix*。
注意:如果您在应用的清单中声明了 <package> 元素,则与该软件包名称关联的应用会出现在对 PackageManager 进行的任何与该应用的组件匹配的查询的结果中。
方案二
直接增加权限.
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
这种直接增加权限面临的问题:
- 但是可能会存在问题, 比如后续权限继续收紧,不及时适配可能出现新的问题。
- 还有可能会在市场标记我们的应用会读取手机安装app列表的提示,国外用户可能会比较介意。
所以直接增加权限的方案pass了。
总结
以上就是线上问题排查已经处理的全部过程,记录下来方便后边有兄弟遇到同样的问题。
- 遇到问题一定要刨根问底 不要放过任何细节,因为既然出现了就证明一定有问题
- 找不到问题直接debug 看代码,总会找到问题的