Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

intent.resolveActivity returns null in API 30

Looking at intent.resolveActivity != null but launching the intent throws an ActivityNotFound exception I wrote opening a browser or an application with Deep linking:

private fun openUrl(url: String) {     val intent = Intent().apply {         action = Intent.ACTION_VIEW         data = Uri.parse(url) //        setDataAndType(Uri.parse(url), "text/html") //        component = ComponentName("com.android.browser", "com.android.browser.BrowserActivity") //        flags = Intent.FLAG_ACTIVITY_CLEAR_TOP + Intent.FLAG_GRANT_READ_URI_PERMISSION     }     val activityInfo = intent.resolveActivityInfo(packageManager, intent.flags)     if (activityInfo?.exported == true) {         startActivity(intent)     } else {         Toast.makeText(             this,             "No application can handle the link",             Toast.LENGTH_SHORT         ).show()     } } 

It doesn't work. No browser found in API 30 emulator, while a common solution works:

private fun openUrl(url: String) {     val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))     try {         startActivity(intent)     } catch (e: ActivityNotFoundException) {         Toast.makeText(             this,             "No application can handle the link",             Toast.LENGTH_SHORT         ).show()     } } 

The first method doesn't work, because intent.resolveActivityInfo or intent.resolveActivity returns null. But for PDF-viewer it works.

Should we dismiss intent.resolveActivity?

like image 624
CoolMind Avatar asked Jun 23 '20 13:06

CoolMind


People also ask

Why does resolveactivity return NULL in Android 11?

Due to the new limitations when targeting Android 11 the Intent.resolveActivity () call might now return null even though using startActivity () with the intent would work just fine. To make this work you could add a <queries> entry to AndroidManifest.xml as explained in the documentation.

What is the use of resolveactivity?

Of course Intent.resolveActivity () still has its uses. For example, you might want to hide a ‘take picture’ button if no camera app is installed. In that case resolveActivity () comes in handy.

How to find the package of a specific intent action?

Inside queries tag explicitly mention respective package to show up when intent action is required. This method will show the only package which is listed in the <queries> tag. After that, run the application to see changes.

How do I deal with activitynotfoundexception in Android?

Instead of using Intent.resolveActivity () just call startActivity () and deal with ActivityNotFoundException. val intent = … // Some implicit intent try { startActivity(intent) } catch (e: ActivityNotFoundException) { // Display some error message }


2 Answers

This appears to be due to the new restrictions on "package visibility" introduced in Android 11.

Basically, starting with API level 30, if you're targeting that version or higher, your app cannot see, or directly interact with, most external packages without explicitly requesting allowance, either through a blanket QUERY_ALL_PACKAGES permission, or by including an appropriate <queries> element in your manifest.

Indeed, your first snippet works as expected with that permission, or with an appropriate <queries> element in the manifest; for example:

<queries>     <intent>         <action android:name="android.intent.action.VIEW" />         <category android:name="android.intent.category.BROWSABLE" />         <data android:scheme="https" />     </intent> </queries> 

The information currently available isn't terribly specific, but it does state:

The PackageManager methods that return results about other apps, such as queryIntentActivities(), are filtered based on the calling app's <queries> declaration

Though your example is using an Intent method – i.e., resolveActivityInfo() – that's actually calling PackageManager "query" methods internally. An exhaustive list of every method and functionality affected by this change might not be feasible, but it's probably safe to assume that if PackageManager is involved, you might do well to check its behavior with the new restrictions.

like image 135
Mike M. Avatar answered Oct 19 '22 07:10

Mike M.


Thanks to Mike M. I added queries for Browser, Camera and Gallery. Place them inside AndroidManifest in any part of it (before or after <application> tag).

Looking at MediaStore.ACTION_IMAGE_CAPTURE and Intent.ACTION_GET_CONTENT I got both actions.

<queries>     <!-- Browser -->     <intent>         <action android:name="android.intent.action.VIEW" />         <data android:scheme="http" />     </intent>      <!-- Camera -->     <intent>         <action android:name="android.media.action.IMAGE_CAPTURE" />     </intent>      <!-- Gallery -->     <intent>         <action android:name="android.intent.action.GET_CONTENT" />     </intent> </queries> 

Dylan answer was not required to me, so I still have

<uses-feature     android:name="android.hardware.camera"     android:required="false"     /> 
like image 37
CoolMind Avatar answered Oct 19 '22 05:10

CoolMind