Intent.ACTION_VIEW无法跳转问题排查

项目中文本链接(包括网址和邮箱)点击以后使用的是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"
        
            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>

感谢大家的支持,如有错误请指正,如需转载请标明原文出处!

你可能感兴趣的:(Android,android)