【问题标题】:Android how is a Chrome intent-based URI openedAndroid 如何打开一个基于 Intent 的 URI
【发布时间】:2021-08-03 17:59:32
【问题描述】:

Chrome docs,我了解到可以使用以下 URI 打开应用程序

intent:  
   HOST/URI-path // Optional host  
   #Intent;  
      package=\[string\];  
      action=\[string\];  
      category=\[string\];  
      component=\[string\];  
      scheme=\[string\];  
   end;

我想知道是否可以从我的应用程序中打开此 URI。

示例 URI

intent:
    //qr/json/%7B%22u%22%3A%22https%3A%2F%2Fprivacybydesign.foundation%2Fbackend%2Firma%2Fsession%2FvsRjkZF2B2H17sBWmVZe%22%2C%22irmaqr%22%3A%22disclosing%22%7D
    #Intent;
        package=org.irmacard.cardemu;
        scheme=cardemu;
        l.timestamp=1620907855707;
        S.browser_fallback_url=https%3A%2F%2Fplay.google.com%2Fstore%2Fapps%2Fdetails%3Fid%3Dorg.irmacard.cardemu
    ;end

因为它看起来像一个普通的 URI,我想我可以这样打开它:

Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("%EXAMPLE_URI%"));
startActivity(intent);

这给了我一个ActivityNotFoundException。我错过了什么?

原因:android.content.ActivityNotFoundException:未找到处理 Intent 的 Activity { act=android.intent.action.VIEW dat=intent://qr/json/{"u":"https://privacybydesign.基础/后端/irma/session/vsRjkZF2B2H17sBWmVZe","irmaqr":"disclosure"} pkg=org.irmacard.cardemu(有附加功能)}

【问题讨论】:

  • 从哪里调用 startActivity(intent); ?
  • 来自我的主要活动
  • chrome 将使用 Intent 来识别您的应用并在安装时启动该应用。在内部,您不能使用它来启动活动。
  • 如果chrome能做到,我应该也能做到吧?
  • 我不这么认为。根据您所期望的结果,也许有不同的方法来处理它。你能告诉我更多关于你如何以及为什么使用它的背景信息吗?

标签: android uri deep-linking


【解决方案1】:

Chrome docs 中描述的“intent:”语法用于从网页启动应用程序,Chrome 将处理 href 并检索参数以通过 Android Intent 启动应用程序.

您提供的示例URI的方案是intent://,默认不处理。

如果要处理intent:// URI,则需要create a deep link

如果您想从 Android 应用打开网页,可以使用 ACTION_VIEW 操作并在 Intent 数据中指定网页 URL。

public void openWebPage(String url) {
    Uri webpage = Uri.parse(url);
    Intent intent = new Intent(Intent.ACTION_VIEW, webpage);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
}

// example
// openWebPage("https://privacybydesign.foundation/backend/irma/session/vsRjkZF2B2H17sBWmVZe")

更多关于Intents and Intent Filters 的信息

【讨论】:

【解决方案2】:

您可以尝试以下几种方法:

1.确保您要启动的应用程序实现了正确的意图。

<application android:label="@string/app_name">
...
    <activity android:name=".PleaseStartThisActivity" android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.VIEW"/>
        </intent-filter>
    </activity>
...
</application>

2。始终使用新意图,切勿重复使用旧意图。

Intent intent = new Intent(android.content.Intent.ACTION_VIEW); //OK.
// Intent intent = getIntent(); //Not OK.

3.把其他一切都设置好。

// If package name and activity are known.
intent.setComponent(new ComponentName("org.irmacard.cardemu", "org.irmacard.cardemu.PleaseStartThisActivity"));
// Else
// intent = new Intent(android.content.Intent.ACTION_GET_CONTENT);
// intent.setDataAndType(Uri.parse("file://" + filePath), "text/plain");

4.设置或添加标志可能会有所帮助

intent.setFlags(
    android.content.Intent.FLAG_ACTIVITY_FORWARD_RESULT |
    android.content.Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP |
    android.content.Intent.FLAG_INCLUDE_STOPPED_PACKAGES |
    android.content.Intent.FLAG_RECEIVER_FOREGROUND |
    android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION |
    android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION |
    android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION |
    android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION |
    android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

5.现在您可以安全地开始活动了。

startActivity(intent);
// Or this:
// startActivity(android.content.Intent.createChooser(intent, null));

编辑

* intent.getDataString() - To get intent data (You may have to parse it to get the package name).
* getPackageManager().queryIntentActivities() - To check available activities for that package like the following example:
private final String getActivity(final String packageName, final Intent intent, final Bundle bundle, final String mimeType) {
        final String activity;
        int activityLen = 0;
        final int packageLen = packageName.length();
        
        if(bundle != null && (activity = bundle.getString("activity")) != null) {
            activityLen = activity.length();
        } else {
            activity = null;
        }

        final List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent, PackageManager.GET_RESOLVED_FILTER);
        
        for(ResolveInfo ri : list) {        
            final IntentFilter filter = ri.filter;  

            final String activityName = ri.activityInfo.name;
            //Make sure the activity is valid and exist for the package.
            //Tolerate with case insensitive
            if(activity != null && activity.regionMatches(true, 0, activityName, 0, activityLen)
               && packageName.regionMatches(true, 0, ri.activityInfo.packageName, 0, packageLen)) {
                return activityName;
            } else if(filter == null) {
                Toast.makeText(this, "ERROR: No available ACTIONS to handle this file", 1).show();
                return null;
                //Auto search only if user hasn't specified the activity, else return null. Tolerate with case insensitive
            } else if(activity == null && filter.hasAction(intent.getAction()) && filter.hasDataType(mimeType)) {
                if(ri.activityInfo.packageName.regionMatches(true, 0, packageName, 0, packageLen)) {
                    return ri.activityInfo.name;
                }
            } // Else keep validating next activities
        }
        
        if(activity == null) {
            Toast.makeText(this, "ERROR: No available ACTIVITIES to open this file", 1).show();
        } else {
            Toast.makeText(this, "ERROR: No such activity found", 1).show();
        }
        return null;
    }

【讨论】:

  • 我很确定 Chrome 并没有声明所有可能的活动。
  • 这不是关于 Chrome 而是关于应用程序本身。该应用程序的Manifest.xml 中是否有android.intent.action.VIEW 作为活动?确保也传递正确的 mime 类型。我注意到如果 mime:*/*, android package installer 可能被调用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多