5

From the Chrome docs, I understand apps can be opened with the following URI

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

I was wondering if I could open this URI from my app.

Example 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

Since it look like a normal URI I thought I could open it like this:

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

That gives me an ActivityNotFoundException. What am I missing?

Caused by: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=intent://qr/json/{"u":"https://privacybydesign.foundation/backend/irma/session/vsRjkZF2B2H17sBWmVZe","irmaqr":"disclosing"} pkg=org.irmacard.cardemu (has extras) }

Robin Dijkhof
  • 18,665
  • 11
  • 65
  • 116

2 Answers2

1

The "intent:" syntax described in the Chrome docs is used to launch apps from a web page, Chrome will handle the href and retrieve the params to launch apps via the Android Intent.

The scheme of the example URI you provided is intent://, it is not handled by default.

if you want to handle the intent:// URI, you need to create a deep link

If you want to open a web page from your Android app, you can use the ACTION_VIEW action and specify the web URL in the intent data.

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")

more info about Intents and Intent Filters

Rahul
  • 3,293
  • 2
  • 31
  • 43
iamwent
  • 111
  • 4
0

Here are several things you could try:

1. Make sure the application that you want to start has implemented the right intent.

<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. Always use a new intent and never reuse the old one.

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

3. Set everything else right.

// 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. Set or add flags might help

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. Now you can safely start the activity.

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

EDIT

* 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;
    }
Darkman
  • 2,941
  • 2
  • 9
  • 14
  • I am pretty sure Chrome has not declared every possible activity out there. – Robin Dijkhof May 22 '21 at 09:14
  • It's not about Chrome but the app itself. Does the app has `android.intent.action.VIEW` as activity in its `Manifest.xml`? Make sure to pass the right mime type as well. I've noticed if the mime: `*/*`, android package installer might be called. – Darkman May 22 '21 at 09:53