项目中文本链接(包括网址和邮箱)点击以后使用的是Intent.ACTION_VIEW打开,但是有用户反馈在三星Galaxy Tab S7上点击以后无法跳转,于是做了问题的排查,最后确定为Android 11以上软件包可见性未设置。
链接点击跳转代码如下:
public static void openBrowser(Context context, String url) {
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
if (intent.resolveActivity(context.getPackageManager()) != null) {
context.startActivity(intent);
} else {
Toast.makeText(context, "No app available", Toast.LENGTH_SHORT).show();
}
}
在Android 11以上设备点击打开会弹出"No app available",因为软件包可见性未设置。
解决办法
在AndroidManifest.xml的manifest节点下添加如下queries的内容:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xxx.xxx">
<queries>
<intent>
<!--检查是否有可用浏览器-->
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<!--检查是否有可用浏览器-->
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
</intent>
<intent>
<!--打开邮箱发送邮件-->
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="mailto" />
</intent>
<intent>
<!--在自定义标签页中打开网址-->
<action android:name="android.support.customtabs.action.CustomTabsService" />
</intent>
</queries>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
总结
系统会自动让部分应用可见,以便应用可以与其交互,而无需声明元素。
注意:如果应用以Android 10(API 29)或更低版本为targetSdk,那么全部应用均会自动对应用可见
即使应用以Android 11(API 30)或更高版本为targetSdk,以下类型的应用也始终可见:
- 当前应用
- 实现Android核心功能的某些系统软件包,如媒体提供程序
- 安装了当前应用的应用
- 使用startActivityForResult()方法在当前应用中启动activity的任何应用
- 启动或绑定到当前应用中的某项Service的任何应用
- 访问当前应用中的ContentProvider的任何应用
- 具有ContentProvider的任何应用,其中当前应用已被授予URI权限来访问该ContentProvider
- 接收当前应用输入的任何应用。这种情况仅适用于当前应用作为输入法应用提供输入
此外,可以使用隐式或显式Intent来启动另一应用的activity,无论这个应用是否可见。
如果应用以Android 11(API 30)或更高版本为targetSdk,并且需要与其他应用(自动可见的应用除外)交互,则需要在应用的清单文件中添加元素。在 元素中,按应用包名、按intent签名或按提供程序授权指定其他应用。
包名指定
如果要查询其他应用或者与其他应用进行交互,需要将其他应用的包名添加到元素内元素中:
<manifest package="com.xxx.xxx">
<queries>
<package android:name="包名" />
<package android:name="包名" />
</queries>
...
</manifest>
Intent过滤器指定
如果需要查询其他有特殊用途的应用或者与其进行交互,但又不知道应用的包名,则可以在元素中列出Intent过滤器。这样具有匹配的元素的应用就可以被发现或者交互。
<manifest package="com.xxx.xxx">
<queries>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="image/jpeg" />
</intent>
</queries>
...
</manifest>
授权指定
如果需要查询ContentProvider但不知道具体的应用包名,可以在元素中声明该提供程序授权,如以下代码段所示:
<manifest package="com.xxx.xxx">
<queries>
<provider android:authorities="授权字符串" />
</queries>
...
</manifest>
感谢大家的支持,如有错误请指正,如需转载请标明原文出处!