-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
refactor: Use AndroidX Photo Picker for selecting media #2304
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: Use AndroidX Photo Picker for selecting media #2304
Conversation
Thanks for submitting @hubatruck. We can confirm that the update works well for our use case, and means all permission checks can be removed once targeting SDK 34. We haven't tested this update when targeting versions prior 34 though. |
@hubatruck Am I doing something wrong? I have errors:
I have target SDK 34 and I added to app/build.gradle
|
Hi @Darex1991 Could you please give a bit more information about your issue? I have ran the project with the example application which also uses Kotlin, and it was not throwing me this kind of error. So it seems like react-native has For easier debugging, the best would be a minimal project that reproduces the issue you mentioned. |
@Darex1991 try adding these to
|
@hubatruck First of all, thank you for this fix! It's been a lifesaver. I'm having an issue on Android 11/12 where the |
@janithl this helped me! Thanks. |
@Darex1991 I'm glad I could help. I'm not 100% sure about the usage of The Photo Picker also falls back to opening documents on older versions of Android if the modular component is not available, which seems to require some sort of read permission:
|
@Darex1991 I hope this post from the Android Developers blog is helpful: https://medium.com/androiddevelopers/permissionless-is-the-future-of-storage-on-android-3fbceeb3d70a |
@janithl I only noticed adding |
Are you using AAB or APK distribution? |
@Johan-dutoit is there any chance that this PR can get reviewed and merged before October 31'st? 🤞 Otherwise, we will no longer be able to publish updates to our app (as we don't really have good reasons for having the |
@Johan-dutoit @marcshilling (I know its been a long time since you contributed to this lib) @brentvatne: Desperate times call for desperate tags <3 I'm sure you have a lot of other important stuff but the change in this PR is becoming more and more critical. If it is not merged and released before end of October it will block people from releasing updates to their apps in Google Play Store and will force people to look for other similar libs (not that I've been able to find good alternatives), write their own lib or try out the risky pursuit of applying this PR as a patch or fork. |
@jenskuhrjorgensen I can get this merged and a new version released but I don't have capacity to review/test this at the moment. Can you confirm/approve this PR is good as-is? Is this a breaking change that warrants a new major version? |
@marcshilling thanks a lot for your quick reply 🤗 I will try to find time to review and test it asap! In the meantime: @janithl you also wrote:
Did you come to a conclusion on this? Is it an issue? Thanks all for testing and discussing on this - it all helps in getting it merged and released <3 |
@jenskuhrjorgensen we added a check for Not 100% sure if it will run afoul of Google's policies, but that was the only way we found to make it work on older versions of Android where the new photo picker wasn't available. |
I have forked this and tested on android Api level 34, 30, 29. Works fine. |
Same as @SMPinCode, but still double size of my apk. |
Hmm, well I just realized I don't have any permissions on this repo anymore 😞. If someone can bring me back into the fold, I'll get this merged and a new version released. Until then though I can't help. |
</activity> | ||
|
||
<!-- Trigger Google Play services to install the backported photo picker module. --> | ||
<service android:name="com.google.android.gms.metadata.ModuleDependencies" android:enabled="false" android:exported="false"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I open this file in Android Studio I get this warning:
It looks like you missed the tools:ignore="MissingClass"
property from the official documentation:
https://developer.android.com/training/data-storage/shared/photopicker
For that to work you also need to add the tools
namespace in the top of this file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
README.md
Outdated
|
||
#### Targeting below Android API v30 | ||
|
||
Check if your application meets the requirement for AndroidX Photo Picker, otherwise add the entry to your `AndroidManifest.xml`: <https://developer.android.com/training/data-storage/shared/photopicker#device-availability> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I understand it this is only required if you want to add backwards compatibility, i.e. be able to use the photo picker on older Android versions https://developer.android.com/training/data-storage/shared/photopicker#device-availability.
And I also believe that for it to work, you need androidx.activity:activity:1.7.+
installed (either directly in your app or transitively via another dependency https://developer.android.com/jetpack/androidx/releases/activity#1.7.0. React Native currently depends on androidx.appcompat:appcompat:1.6.1
which in turn depends on androidx.activity:activity:1.6.0
. I think you should add something about this to both the example app and the README. @hubatruck Did the photo picker actually work for you in the example app on Android <30?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest this backwards compatibility part for me is not exactly clear from the docs on how it should work. On the compatible Android APIs it works as expected, and the Photo Picker is showing up.
Did the photo picker actually work for you in the example app on Android <30?
For my Android 8 Samsung device, the fallback documents picker showed up, instead of the new Photo Picker :/
I tried with your suggested changes, but on an Android API 30 emulator, still the system documents picker was showing up.
I honestly have no idea how this backwards compatibility should be configured to work correctly, the Android docs seem too vague.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I managed to get the backported version to work on older Android versions 🎊
What (primarily) did the trick for me was to test on physical devices (via BrowserStack App Live). I don't know where the limitation in the emulators is. Maybe it has to do with Google Play Services not being updated/installed 🤷
Once, I got this on one of my physical devices (Samsung Galaxy S20 Ultra, Android 10) and I believe this is where it downloads/installs the backported version of the photo picker:
Here is proof that the new photo picker works on a Samsung Galaxy S10, Android 9 device:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition to testing on a physical device, I also had to add this to example/android/app/build.gradle
(due to reasons stated earlier in this thread):
...
implementation("com.facebook.react:flipper-integration")
// androidx.activity:activity >= 1.7.0 is required for the backported photo picker to work on Android < 30 https://developer.android.com/jetpack/androidx/releases/activity#1.7.0.
// This dependency can be removed from here once the react-native library updates androidx.appcompat:appcompat to >= 1.7.0
// https://github.com/facebook/react-native/blob/3dfe22bd27429a43b4648c597b71f7965f31ca65/packages/react-native/gradle/libs.versions.toml#L11
// because androidx.appcompat:appcompat:1.7.0 depends on androidx.activity:activity:1.7.0 https://developer.android.com/jetpack/androidx/releases/appcompat#1.7.0
implementation("androidx.activity:activity:1.7.+")
if (hermesEnabled.toBoolean()) {
...
As this only fixes the example app, I think we should also add a comment about this to the README under the new Targeting below Android API v30
section.
People can test what version of androidx.activity:activity
their app depends on with ./gradlew app:dependencies
and then look for the first occurrence of androidx.activity:activity
. Without implementation("androidx.activity:activity:1.7.+")
it looks like this for the example app:
+--- com.facebook.react:react-android -> 0.73.6
| +--- androidx.appcompat:appcompat:1.6.1
| | +--- androidx.activity:activity:1.6.0
With implementation("androidx.activity:activity:1.7.+")
it looks like this:
+--- com.facebook.react:react-android -> 0.73.6
| +--- androidx.appcompat:appcompat:1.6.1
| | +--- androidx.activity:activity:1.6.0 -> 1.7.2
In the README, I don't know if we should go this much into details about how to find out about your current version of androidx.activity:activity
or if it is enough to say something like:
If your
minSdkVersion
is < 30 and your app doesn't already depend on/includeandroidx.activity:activity:1.7.+
then you need to addimplementation("androidx.activity:activity:1.7.+")
in thedependencies
block of yourapp/build.gradle
file in order to support the backported photo picker on Android < 30.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can confirm that on both my Android API <30 shows the backported Photo Picker with the implementation("androidx.activity:activity:1.7.+")
line added 🎊
Samsung Galaxy A7 2018 - API 29 "Q"
Manually dragged the Picker a bit down so the app is visible. Otherwise it fills the whole screen.
Samsung Galaxy A5 2017 - API 26 "Oreo"
Manually dragged the Picker a bit down so the app is visible. Otherwise it fills the whole screen.
If I do not add the line, the fallback documents selector shows up.
I have updated the readme to show the tricks needed. Also added your suggested comment in the example app's build.gradle
.
@janithl, @SMPinCode and others: Were you actually able to get the new photo picker to work on Android < 30? I've tried to install @marcshilling that's a bummer :( But thanks for your good intentions! <3 |
@jenskuhrjorgensen I was not getting new photo picker on Android < 30. My mistake i have not mentioned it. I was focused of getting rid of |
@jenskuhrjorgensen no, I wasn't able to get the new photo picker on the older versions of Android. The document picker was shown instead: |
From my part, the backwards compatibility of the Photo Picker is still a big question. On my API <30 devices & emulators, the documents picker was showing up with the example app. I don't understand what else would be needed for it to work on older APIs. |
README.md
Outdated
|
||
#### Targeting below Android API v30 | ||
|
||
Check if your application meets the requirement for AndroidX Photo Picker, otherwise add the entry to your `AndroidManifest.xml`: <https://developer.android.com/training/data-storage/shared/photopicker#device-availability> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I managed to get the backported version to work on older Android versions 🎊
What (primarily) did the trick for me was to test on physical devices (via BrowserStack App Live). I don't know where the limitation in the emulators is. Maybe it has to do with Google Play Services not being updated/installed 🤷
Once, I got this on one of my physical devices (Samsung Galaxy S20 Ultra, Android 10) and I believe this is where it downloads/installs the backported version of the photo picker:
Here is proof that the new photo picker works on a Samsung Galaxy S10, Android 9 device:
README.md
Outdated
|
||
#### Targeting below Android API v30 | ||
|
||
Check if your application meets the requirement for AndroidX Photo Picker, otherwise add the entry to your `AndroidManifest.xml`: <https://developer.android.com/training/data-storage/shared/photopicker#device-availability> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition to testing on a physical device, I also had to add this to example/android/app/build.gradle
(due to reasons stated earlier in this thread):
...
implementation("com.facebook.react:flipper-integration")
// androidx.activity:activity >= 1.7.0 is required for the backported photo picker to work on Android < 30 https://developer.android.com/jetpack/androidx/releases/activity#1.7.0.
// This dependency can be removed from here once the react-native library updates androidx.appcompat:appcompat to >= 1.7.0
// https://github.com/facebook/react-native/blob/3dfe22bd27429a43b4648c597b71f7965f31ca65/packages/react-native/gradle/libs.versions.toml#L11
// because androidx.appcompat:appcompat:1.7.0 depends on androidx.activity:activity:1.7.0 https://developer.android.com/jetpack/androidx/releases/appcompat#1.7.0
implementation("androidx.activity:activity:1.7.+")
if (hermesEnabled.toBoolean()) {
...
As this only fixes the example app, I think we should also add a comment about this to the README under the new Targeting below Android API v30
section.
People can test what version of androidx.activity:activity
their app depends on with ./gradlew app:dependencies
and then look for the first occurrence of androidx.activity:activity
. Without implementation("androidx.activity:activity:1.7.+")
it looks like this for the example app:
+--- com.facebook.react:react-android -> 0.73.6
| +--- androidx.appcompat:appcompat:1.6.1
| | +--- androidx.activity:activity:1.6.0
With implementation("androidx.activity:activity:1.7.+")
it looks like this:
+--- com.facebook.react:react-android -> 0.73.6
| +--- androidx.appcompat:appcompat:1.6.1
| | +--- androidx.activity:activity:1.6.0 -> 1.7.2
In the README, I don't know if we should go this much into details about how to find out about your current version of androidx.activity:activity
or if it is enough to say something like:
If your
minSdkVersion
is < 30 and your app doesn't already depend on/includeandroidx.activity:activity:1.7.+
then you need to addimplementation("androidx.activity:activity:1.7.+")
in thedependencies
block of yourapp/build.gradle
file in order to support the backported photo picker on Android < 30.
@SMPinCode @janithl I haven't been able to reproduce any issues without the During testing I also removed |
@jenskuhrjorgensen I have tried removing |
@SMPinCode I believe you can explicitly remove permissions with
|
And I don't believe this is a breaking change. The API didn't change, no dependencies changed, and if you are running Android < 30, you will just fallback to the old document picker. Newer OS'es will get the new photo picker. If you are running Android < 30 and you would like the new backported photo picker you have to add a few additional lines. This will be described in the README. |
- update permission - update docs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @jenskuhrjorgensen for your support and debugging efforts 🙏
README.md
Outdated
|
||
#### Targeting below Android API v30 | ||
|
||
Check if your application meets the requirement for AndroidX Photo Picker, otherwise add the entry to your `AndroidManifest.xml`: <https://developer.android.com/training/data-storage/shared/photopicker#device-availability> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can confirm that on both my Android API <30 shows the backported Photo Picker with the implementation("androidx.activity:activity:1.7.+")
line added 🎊
Samsung Galaxy A7 2018 - API 29 "Q"
Manually dragged the Picker a bit down so the app is visible. Otherwise it fills the whole screen.
Samsung Galaxy A5 2017 - API 26 "Oreo"
Manually dragged the Picker a bit down so the app is visible. Otherwise it fills the whole screen.
If I do not add the line, the fallback documents selector shows up.
I have updated the readme to show the tricks needed. Also added your suggested comment in the example app's build.gradle
.
@jenskuhrjorgensen |
the selectionLimit > 1 will always be true if !isSingleSelect, so there is no point in conditional. |
@chr4ss12 I think |
ignore what i said, was too early in the morning, but i am about to test the whole PR in production to see if there are any problems! October deadline is getting close. |
@brentvatne and @Johan-dutoit please please please give this PR a short review or even just an approval 🙏🙏🙏 It is crucial that we get this merged and released before Google will prevent ALL OF US from releasing updates next week (October 31'st). Otherwise, people will have to start using forks of this PR 😭 For me that is not even an option, because our build servers are behind a company proxy, so I will not be able to use a fork directly from GitHub. |
example/android/app/build.gradle
Outdated
* https://github.com/facebook/react-native/blob/3dfe22bd27429a43b4648c597b71f7965f31ca65/packages/react-native/gradle/libs.versions.toml#L11 | ||
* because androidx.appcompat:appcompat:1.7.0 depends on androidx.activity:activity:1.7.0 https://developer.android.com/jetpack/androidx/releases/appcompat#1.7.0 | ||
*/ | ||
implementation("androidx.activity:activity:1.7.+") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @hubatruck
I actually just discovered that the multi select is not working on older Android devices. It looks like there has been several fixes to the photo picker since v1.7, and specifically v1.8.2 fixed the multi select on older Android devices:
https://developer.android.com/jetpack/androidx/releases/activity#1.8.2
So I think we should change
implementation("androidx.activity:activity:1.7.+")
to
implementation("androidx.activity:activity:1.9.+")
And then update the comment section here as well as the README. (there is not yet a version of androidx.appcompat:appcompat
that depends on androidx.activity:activity:1.9.+
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have updated the docs, and upon testing, seems like it works with the new version too, and fixes the multiple selection bug
i have not heard much feedback from users since releasing to production, thats always good sign. one feedback from an user: ""In this screenshot, you should see an additional "Browse..." option if you've enabled it properly in Android Media Picker code. Since you decided to switch to the media picker before it was ready to be used, you must manually enable this option. Otherwise, we as users are forced to scroll through however many photos are on our device in reverse date order or copy the desired photo to the very few albums media picker can actually see"" does anyone know what option he is referring to? |
@chr4ss12 can you share the screenshot too? What version of androidx.activity:activity did you use? |
@chr4ss12 I tried to spin up the photo picker in a vanilla native Android app as per the official documentation and this is what the photo picker looks like: However, if I change the test app a bit to use And when I press "browse" I end up here and it looks like I can pick whatever file(s) I want here: If I go into the Gmail app on my personal device (Pixel 8, Android 14) and try to attach an image, the picker looks exactly like the one your user complained about ("..." menu with a "Cloud media app" button), so I'm not sure there is anything wrong with this implementation. Also, I'm not sure what your user means by "Since you decided to switch to the media picker before it was ready to be used", since I cannot see anything about the photo picker being experimental or in pilot. |
🎉 This PR is included in version 7.1.4 🎉 The release is available on: Your semantic-release bot 📦🚀 |
@Johan-dutoit hi, this is not included in the release notes, just fyi |
Thanks @efstathiosntonas , semantic release didn't like the "refactor" for some reason. |
Thanks for submitting a PR! Please read these instructions carefully:
main
branch, NOT a "stable" branch.Motivation (required)
What existing problem does the pull request solve?
For a more privacy preserving experience for users, we’re introducing the Photo and Video Permissions policy to reduce the number of apps permitted to request broad photo/video permissions (READ_MEDIA_IMAGES and READ_MEDIA_VIDEO). Apps may only access photos and videos for purposes directly related to app functionality. Apps that have a one-time or infrequent need to access these files are requested to use a system picker, such as the Android photo picker. (effective August 31, 2024)
Reference: https://support.google.com/googleplay/android-developer/answer/13986130
Converted the
launchImageLibrary
Android function to use the native AndroidX Photo Picker: https://developer.android.com/training/data-storage/shared/photopickerTest Plan (required)
Tested out on multiple devices, both with the example app, and on my own project.
Devices used:
Relevant issue: #2146