cordova-plugin-media-capture icon indicating copy to clipboard operation
cordova-plugin-media-capture copied to clipboard

[Android] Store image/audio/video in FileProvider due to Android 11 updates

Open chriskhongqarma opened this issue 3 years ago • 14 comments

Android

Motivation and Context

Since the Storage updates in Android 11, it would be impossible for app to get access to files (image, audio, video) saved into MediaStore external storage, as how it is implemented now. Starting from 2021 August, Android apps are required to target Android API level 30 (Android 11), which means it is critical that we need a new way to store files for media-capture plugin. More details are included in the issue #210. Here is a suggested implementation for the above issue.

Description

The idea is to use a ContentProvider (a FileProvider, in this case) as a common database to store files, so that both our app and other apps can get access to. An empty file (audio, image, video) with unique file name (which is generated using current timestamp) and corresponding file format will be created before capturing. Unique file name prevents the file from being duplicated. We use FileProvider to create a Uri for the file, and send it through capturing intents as EXTRA_OUTPUT, so that the created file will be saved with the above Uri. Meanwhile, we store the file absolute path as a global variable, so that it can be used when the intent returns results. As the file is saved into FileProvider, the app will get access and have control over the created file.

Testing

captureAudio, captureImage, captureVideo features are tested over various Android devices (from Android 7 to Android 11 are covered) using browserstack app live. The app then has full access over the generated media file (move, delete, transcode, etc).

Checklist

  • [x] I've run the tests to see all new and existing tests pass
  • [x] I added automated test coverage as appropriate for this change
  • [x] Commit is prefixed with (platform) if this change only applies to one platform (e.g. (android))
  • [x] If this Pull Request resolves an issue, I linked to the issue in the text above (and used the correct keyword to close issues using keywords)
  • [x] I've updated the documentation if necessary

chriskhongqarma avatar Apr 13 '21 10:04 chriskhongqarma

Cordova-android AndroidX reference: https://github.com/apache/cordova-android/pull/1052

breautek avatar Apr 14 '21 13:04 breautek

Does this fix this issue? I can't play the recorded video on my WebView.

Cordova: 8.1.2 Cordova-Android: 9.0.0 cordova-plugin-media-capture: 1.4.3

image

andreycruz16 avatar Apr 20 '21 08:04 andreycruz16

@andreycruz16 I can see that the recorded video is still saved in external storage. Could you make sure that you pulled the code from this PR? It should save the video into a FileProvider, and the video uri should look like this. file:///data/user/0/{applicationID}/cache/VID_20210420130001621.avi

chriskhongqarma avatar Apr 20 '21 11:04 chriskhongqarma

@andreycruz16 , @chriskhongqarma On android 11, Lineage OS 18.1, the video gets saved at path:

fullPath: "file:///data/user/0/{applicationID}/cache/Capture.avi"

but I cannot find any file there (using a root explorer), therefore I am getting error 1 (not found) when trying to play it or copy it.

Works fine in older Android versions

Any suggestions?

mirko77 avatar Apr 26 '21 16:04 mirko77

@mirko77 As I explained in this PR, Since the Storage updates in Android 11, it would be impossible for app to get access to files (image, audio, video) saved into MediaStore external storage, as how it is implemented now.. I suggested a solution with this PR and have been waiting for it to be merged. You can pull the code from this PR and try to see if it works. The file recorded should be saved into a path like this: file:///data/user/0/{applicationID}/cache/VID_20210420130001621.avi, with 20210420130001621 as the current timestamp. Since it is saved into a FileProvider, your app will have full access to the file.

chriskhongqarma avatar Apr 26 '21 17:04 chriskhongqarma

I suggested a solution with this PR and have been waiting for it to be merged.

Just FYI: this PR isn't being ignored, just busy preparing cordova-android@10 for API 30 support. I'm personally spending time on weekends trying to get cordova-plugin-file working with raw file paths (so usage stays pretty much the same). Then I'll be focusing on the media/media-capture plugins.

It's my goal to have all of these plugins ready to be released at the same time, or shortly after cordova-android@10 is released... (But I can't make any promises...)

breautek avatar Apr 26 '21 18:04 breautek

@breautek any updates?

victorvhpg avatar Jun 16 '21 19:06 victorvhpg

Would it be possible to add search terms / more text to this issue? I spent the better part of a day tracking down an error that appears to be directly addressed by this PR (thank you by the way!!)

In the 3.0.3 code, within createMediaFile(Uri data) after a video capture on Galaxy Tab A7 on Android 11, this line File fp = webView.getResourceApi().mapUriToFile(data); yields null (as the uri is NOT in the local system on this device as you noted in your issue).

Then, later in createMediaFile(Uri data) this line is run LocalFilesystemURL url = filePlugin.filesystemURLforLocalPath(fp.getAbsolutePath()); and since the variable fp is null, you get this error in logcat...

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.io.File.getAbsolutePath()' on a null object reference

and the plugin crashes, along with our app.

Request: Could some portion of the logcat error be added to the search terms on this page/issue? Maybe I'm wrong, but this might be a nice way for others who might see this connect that error, with this issue / PR.

Sorry if this is a dumb question. Thank you so much again for this PR!!

PabbleDabble avatar Jul 27 '21 12:07 PabbleDabble

Hey folks, now that cordova-android@10 has been out for a few months, are there any updates on this? Google's deadline for existing apps to target API 30 is approaching (November), so this fix is becoming more important.

I gave this a test on a couple Android 10-12 devices and it seemed to work, though I see this isn't using AndroidX yet. Let me know if there's anything I can do to help move this along.

davidofwatkins avatar Oct 14 '21 20:10 davidofwatkins

@chriskhongqarma should be rebased to resolve conflicts since #192 has been merged into master branch yesterday

ath0mas avatar Nov 06 '21 10:11 ath0mas

I tested the 4.0 release, and it still has an error for recording a video. Taking a picture still works. The fork works for both video and pictures.

chrisjdev avatar Jun 16 '22 17:06 chrisjdev

@chriskhongqarma On Android 13 and API 33 (Gradle 8), now that fork throws an error Couldn't find meta-data for provider with authority null.cordova.plugin.mediacapture.provider

because this.applicationID is null in Capture.java (line 134/135)


this.applicationId = (String) BuildHelper.getBuildConfigValue(this.cordova.getActivity(), "APPLICATION_ID");
this.applicationId = preferences.getString("applicationId", this.applicationId);

this is fixed by using this.applicationId = cordova.getContext().getPackageName();

which is what the camera plugin is doing as well (@breautek)-> https://github.com/apache/cordova-plugin-camera/pull/827#pullrequestreview-1341542741

mirko77 avatar Jun 13 '23 15:06 mirko77

Can this branch use for android 12 13 issue?

shivamsharmanps avatar Jul 13 '23 15:07 shivamsharmanps

@shivamsharmanps yes but you need to apply the changes I mentioned, or use this fork https://github.com/epicollect5/cordova-plugin-media-capture

mirko77 avatar Jul 13 '23 16:07 mirko77