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
?
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.
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.
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.
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 }
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 asqueryIntentActivities()
, 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.
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" />
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With