0

I'm getting following error on some devices while opening url. I don't get any error on my devices but many devices are.

Fatal Exception: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=https://google.com/... }
   at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2076)
   at android.app.Instrumentation.execStartActivity(Instrumentation.java:1720)
   at android.app.Activity.startActivityForResult(Activity.java:5258)
   at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:574)
   at android.app.Activity.startActivityForResult(Activity.java:5203)
   at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:560)
   at android.app.Activity.startActivity(Activity.java:5587)
   at android.app.Activity.startActivity(Activity.java:5555)

The code where error occurs is pretty straight-forward.

Uri uri = Uri.parse("https://google.com");

try {
     CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
     builder.setShowTitle(true);
     CustomTabsIntent customTabsIntent = builder.build();
     Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://"));

     ResolveInfo resolveInfo = getPackageManager().resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY);
     if (resolveInfo != null && resolveInfo.activityInfo.packageName.length() > 0) {
         customTabsIntent.intent.setPackage(resolveInfo.activityInfo.packageName);
     }

     customTabsIntent.launchUrl(this, uri);
} catch (ActivityNotFoundException e) {
          // Do nothing
}

In some devices (not old devices, mostly newest device), exception triggered but how can it be possible? This means devices has 0 browser? If so, my question is how can I open url even user disabled all browsers? Thanks in advance.

Note: Before I upgraded to custom-tabs in the live version, I used following code to open url but I always get the ActivityNotFoundException:

Intent browserIntent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(browserIntent);

It is the simplest code the open any url but without usage of try/catch causes crashes. It doesn't matter to use normal way or custom-tabs, it always causes ActivityNotFoundException. I'm looking a solution which opening url whatever happens. I'm not sure whether it is possible or not.

Note2: MinApi is Android 5.0 (Lollipop)

enter image description here

Aykut Uludağ
  • 1,876
  • 5
  • 18
  • 34
  • 2
    Does this answer your question? [Chrome Custom Tabs throwing an error when chrome is not installed : No Activity found to handle Intent](https://stackoverflow.com/questions/34823420/chrome-custom-tabs-throwing-an-error-when-chrome-is-not-installed-no-activity) – javdromero May 10 '21 at 19:56
  • 2
    There's nothing stopping a user from disabling all browser apps and you must handle that, yes. What exactly is your question? – ianhanniballake May 10 '21 at 19:57
  • @javdromero No it's not a chrome issue. I just try to open url with customtabs but it doesn't have to be chrome-custom-tabs. I just looking any app to open http but no app found because exception triggered. – Aykut Uludağ May 10 '21 at 19:58
  • @ianhanniballake How can I open url even user disabled all browsers? I have to open link in one way or another. – Aykut Uludağ May 10 '21 at 19:58
  • https://developers.google.com/web/updates/2020/07/custom-tabs-android-11 – javdromero May 10 '21 at 20:13
  • @javdromero Also if I know correctly, if the browser doesn't support custom-tabs, it have to open in normal browser. I checked it on Tor browser and url opened without custom-tabs in Tor. – Aykut Uludağ May 10 '21 at 20:17

3 Answers3

3

A few notes on this issue:

Detecting non-browser apps as browsers

They query for browsers can detect non-browser applications, which will lead the an ActivityNotFoundException when launching the Custom Tab. See this issue for an example.

When querying for packages that can handle browser intents, I recommend using the below:


Intent browserIntent = new Intent()
        .setAction(Intent.ACTION_VIEW)
        .addCategory(Intent.CATEGORY_BROWSABLE)
        .setData(Uri.fromParts("http", "", null));

This is also how the Android framework itself detects browsers.

The following shouldn't be a problem as the the Custom Tab will still work, but the behaviour of PackageManager.MATCH_DEFAULT_ONLY changed on Android M and only the default browser is returned - I'm not sure what happens if a default browser is not set, but this may mean the returned list will be empty instead. This will mean users will get the disambiguation dialog when a default browser is not set. From Android M and above you may also want additionally query the package manager using PackageManager.MATCH_ALL if you want to get all browsers avoid the disambiguation dialog.

Check out this snippet in the android-browser-helper library for detecting Custom Tabs and Trusted Web Activity.

Preparing for Android 11

Android 11 introduced package visibility and applications must now declare which packages they are querying for. If your application is not implementing this, the list returned when querying the package manage will be empty, even with a browser installed.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    possibleProviders.addAll(pm.queryIntentActivities(queryBrowsersIntent,
                    PackageManager.MATCH_ALL));
}

Again, this shouldn't cause an ActivityNotFoundException as it would just cause the Custom Tab to launch without a package set.

Disabled browsers

Note: Before I upgraded to custom-tabs in the live version, I used following code to open url but I always get the ActivityNotFoundException:

Intent browserIntent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(browserIntent);

It is possible for users to disable all browser applications, but I wouldn't expect this to be common.

Another thing to be aware of is that Android TV and Android Auto devices don't have a browser installed. If your application is targeting those devices you won't be able to open these URLs. But this is only a problem if your app is targeting these platforms.

andreban
  • 4,621
  • 1
  • 20
  • 49
  • I will try with PackageManager.MATCH_ALL options. I hope it works. Thanks! – Aykut Uludağ May 11 '21 at 17:51
  • 1
    PackageManager.MATCH_ALL requires Android 6.0 so I implemented as following: ResolveInfo resolveInfo; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { resolveInfo = getPackageManager().resolveActivity(browserIntent, PackageManager.MATCH_ALL); } else { resolveInfo = getPackageManager().resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY); } – Aykut Uludağ May 11 '21 at 17:53
  • Remember to change how you are building the browser Intent. That's the most likely thing to be causing problems (I've had that in the past). – andreban May 11 '21 at 19:47
3

I create a method which based on @andreban's answer. I believe it will open url %99.99 times.

public static void openURL(Context mContext, Uri uri) {
    CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
    builder.setShowTitle(true);
    CustomTabsIntent customTabsIntent = builder.build();
    Intent browserIntent = new Intent()
            .setAction(Intent.ACTION_VIEW)
            .addCategory(Intent.CATEGORY_BROWSABLE)
            .setType("text/plain")
            .setData(Uri.fromParts("http", "", null));

    List<ResolveInfo> possibleBrowsers;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
        possibleBrowsers = mContext.getPackageManager().queryIntentActivities(browserIntent, PackageManager.MATCH_DEFAULT_ONLY);
        if (possibleBrowsers.size() == 0) {
            possibleBrowsers = mContext.getPackageManager().queryIntentActivities(browserIntent, PackageManager.MATCH_ALL);
        }
    } else {
        possibleBrowsers = mContext.getPackageManager().queryIntentActivities(browserIntent, PackageManager.MATCH_DEFAULT_ONLY);
    }

    if (possibleBrowsers.size() > 0) {
        customTabsIntent.intent.setPackage(possibleBrowsers.get(0).activityInfo.packageName);
        customTabsIntent.launchUrl(mContext, uri);
    } else {
        Intent browserIntent2 = new Intent(Intent.ACTION_VIEW, uri);
        mContext.startActivity(browserIntent2);
    }
}
Aykut Uludağ
  • 1,876
  • 5
  • 18
  • 34
  • If the only browser Google Chrome is disabled, this will throw android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW at the last line mContext.startActivity(browserIntent2); – Sudheesh Mohan Dec 12 '22 at 06:21
0

I also create a method which based on @andreban's answer, but I had a problem with url because it contained a query parameter.

ActivityNotFoundException when:

val url = "https://somesite.com/page?num=4"
val uri = Uri.parse(url)

Custom Tabs opened when:

val uri = Uri.Builder()
        .scheme("https")
        .authority("somesite.com")
        .appendPath("page")
        .appendQueryParameter("num", 4)
        .build()

This discussion helped create a uri