cordova-plugin-camera: Camera plugin crashes app on some android phones when an image is taken

So the plugin works on most of the devices, it works on IOS perfectly. But on android it works on some devices and on some devices once the picture is taken the user is send back to app, app crashes. Now the only thing that I am doing is storing this image in an array. Now one more thing is that if I take a picture and click on retake and then submit the second image the app does not crashes but if I submit the first image it crashes.

Here is my function:

uploadImage() {
    this.actionCtrl.create({
      title:  'Upload Image',
      buttons: [
        {
          icon: 'camera',
          text: 'Open Camera',
          handler: () => {
            const options: CameraOptions = {
              quality: 100,
              destinationType: this.camera.DestinationType.DATA_URL,
              encodingType: this.camera.EncodingType.JPEG,
              mediaType: this.camera.MediaType.PICTURE,
              sourceType: 1
            }

            this.camera.getPicture(options).then((imageData) => {
              let base64Image = 'data:image/jpeg;base64,' + imageData;
              this.images.push(base64Image);
              console.log(base64Image);
            }, (err) => {
              console.log('Error Uploading File')
            });
          }
        },
        {
          icon: 'image',
          text:  'Open Gallery',
          handler: () => {
            const options: CameraOptions = {
              quality: 100,
              destinationType: this.camera.DestinationType.DATA_URL,
              encodingType: this.camera.EncodingType.JPEG,
              mediaType: this.camera.MediaType.PICTURE,
              sourceType: 0
            }

            this.camera.getPicture(options).then((imageData) => {
              let base64Image = 'data:image/jpeg;base64,' + imageData;
              this.images.push(base64Image);
            }, (err) => {
              console.log('Error Uploading File')
            });
          }
        }
      ]
    }).present();
  }

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 3
  • Comments: 86 (7 by maintainers)

Most upvoted comments

Update Camera Plugin and Cordova-android version it will fix this issue

Using cordova-plugin-background-mode. Enable before camera and then disable after camera is back. It fixed the problem.

It seems Android worked on the issue which made it necessary to implement the background plugin. I deactivated the background plugin for devices older than Android 8 and now it worked. I don’t know if there is a generally issue with the Background Plugin and Android 8.

if (device.platform.toLowerCase() == 'android' && parseInt( device.version, 10 ) < 8){
	cordova.plugins.backgroundMode.enable();
}

It’s only an issue if using DATA_URL destination. DATA_URL is useful for representing small binary data, it’s not reasonable to use it to represent large binary. And that will only get worse as phones support larger resolutions which will only make the data larger. I can also make an educated guess to say that’s why videos never supported DATA_URL destination at all.

Using the FILE_URI destination type will save/stream the data to a temporary location, where you can read a file into a blob, which is the proper way of handling binary data in javascript. Using blobs will also keep the binary data allocated outside of the JS virtual machine (similar to how Buffers work in NodeJS), which helps JS performance by not requiring frequent garbage collections.

To resolve the issues that multiple users have reported. I had to implement my cordova-camera plugin and I was successful. In my tests there were no more errors with mobiles with low memory, because now the call is being made directly to the camera and no longer to a third camera application.

  1. In the ionic application I sent the code “uuid” + .jpg and the application folder where the photo will be saved.

  2. In the PluginResult object: setKeepCallback (true);

  3. In the onActivityResult method, I check if the file was saved and return the request status to the front end.

I would really like to understand why cordova-camera-plugin does not call the api directly.

I would like to suggest that the developer also has the option of using the direct call to the camera

Privacy issues can be included in the app’s privacy policy and that’s it.

Do you agree with my point of view?

It seems Android worked on the issue which made it necessary to implement the background plugin. I deactivated the background plugin for devices older than Android 8 and now it worked. I don’t know if there is a generally issue with the Background Plugin and Android 8.

if (device.platform.toLowerCase() == 'android' && parseInt( device.version, 10 ) < 8){
	cordova.plugins.backgroundMode.enable();
}

Thanks for the input, will try this ASAP !

It’s probably a memory problem and it’s how Android behave

I faced that problem too and built a workaround in my Ionic app using the provided Cordova lifecycle, I documented everything in https://forum.ionicframework.com/t/solved-camera-plugin-restart-app-on-android-8-1 if interested

Which version of Android? We are seeing similar issues with an Android 8 device. We are thinking it may be related to the device having an app called Moto Camera installed on it.

@mcrio memory does not have anything to do with this issue, it is the way background tasks are dealt with in some roms. A more aggressive approach like on Xiaomi (but also the latest Samsung, Huawei etc…) kills the app when it goes to the background. It is not limited to photo taking, any background task can be killed at random if it is not a system app or a popular app the manufacturer decided to whitelist. More info https://dontkillmyapp.com/

@mcrio we have positive results with this foreground plugin, which we forked due to some crashes. It helps mitigate the issue, however not perfect. A lot of work is going towards other approaches like Camera Preview but unfortunately, it is too buggy for the time being.

On modern devices, this can be a problem when using the DATA_URL destination. This is because it needs to encode an already large image binary into a base64 encoded string, which expands the data by about 40%. This can be a problem for devices that have low memory limits.

This is noted in the documentation:

NOTE: Photo resolution on newer devices is quite good. Photos selected from the device’s gallery are not downscaled to a lower quality, even if a quality parameter is specified. To avoid common memory problems, set Camera.destinationType to FILE_URI rather than DATA_URL.

Using a FILE_URI will give you a url that can be read into a blob, which is far more efficient for representing binary data. You can also use blobs to create an object url to use in html tags like <img> tags, or send to a remote server using XMLHttpRequest.

I am facing same issue. I am using FILE_URI as destinationType. My phone contains lot of free memory, still app crashes when i try to take pictures.

Many phones imposes a memory quota, so having lots of free money doesn’t mean all that memory is available for any individual app. You could also be experiencing another android quirk, also documented below:

Android uses intents to launch the camera activity on the device to capture images, and on phones with low memory, the Cordova activity may be killed. In this scenario, the result from the plugin call will be delivered via the resume event. See the Android Lifecycle guide for more information. The pendingResult.result value will contain the value that would be passed to the callbacks (either the URI/URL or an error message). Check the pendingResult.pluginStatus to determine whether or not the call was successful.

@sithwarrior We upgraded to cordova-plugin-camera@4.0.3, cordova-android@7.1.4 and cordova@8.1.2 and it seemed to fix most issues with users and the camera. We had to get rid of the backgroundMode plugin as it was causing problems with ios 12.2 so that fix option was not an issue.

@sithwarrior try to take like 50 photos in a row, it should crash at some point. It could happen after the first one, or after 50, it is completely random.

To resolve the issues that multiple users have reported. I had to implement my cordova-camera plugin and I was successful. In my tests there were no more errors with mobiles with low memory, because now the call is being made directly to the camera and no longer to a third camera application.

  1. In the ionic application I sent the code “uuid” + .jpg and the application folder where the photo will be saved.
  2. In the PluginResult object: setKeepCallback (true);
  3. In the onActivityResult method, I check if the file was saved and return the request status to the front end.

I would really like to understand why cordova-camera-plugin does not call the api directly.

I would like to suggest that the developer also has the option of using the direct call to the camera

Privacy issues can be included in the app’s privacy policy and that’s it.

Do you agree with my point of view?

Is your custom plugin a public repo? I’d like to have a look.

My investigations suggest that the use of applicationId is the problem. If the activity has been destroyed and is recreated then applicationId will not be set because it gets set in the execute() method. If I fiddle with the code locally and ensure it gets set within onActivityResult then that problem goes away.

You can recreate this 100% is you set allowEdit to true and on the device change the developer settings to destroy activities.

But this referer to the “allowEdit” branch of the if. If not in allowEdit applicationId is not used. With allowEdit the app crash ( maybe for the applicationId as you reporti ) but without the app restart anyway.

I’m reaching a bit here - but I see that the error reported in issue #554 is on line 803 of CameraLauncher. I have been trying to debug a problem with resuming after the activity has been destroyed and hit the same error on that line.

My investigations suggest that the use of applicationId is the problem. If the activity has been destroyed and is recreated then applicationId will not be set because it gets set in the execute() method. If I fiddle with the code locally and ensure it gets set within onActivityResult then that problem goes away.

You can recreate this 100% is you set allowEdit to true and on the device change the developer settings to destroy activities.

I am using FILE_URI destination type still facing the issue with front camera and when I click on retake and then submit the second image the app does not crash

If someone can provide a sample reproduction app that produces this issue, it will help move this ticket along.

https://github.com/apache/cordova-contribute/blob/master/create-reproduction.md

You are not right about the FILE_URI. The app can crash even when using FILE_URI! It’s a matter of memory management from Android. This behavior can easily be simulated in the following way: “It’s easy to reproduce/simulate the problem. To do so, you have to set “always destroy activities” to true in the developer settings of your Android phone. Doing so, each time you gonna take a photo, your app in the background gonna be killed and recreated (as cordova does when an Android phone is running on low memory)” On one of our test devices(Samsung Galaxy S5) this is also easily reproducible(without this setup) when taking photo in some kind of night portrait mode - while taking photo without light it uses some special mode which takes more time to shoot and obviously more memory. Screenshot_2020-01-19-13-33-22 1

@tenglandct we never managed to find a proper solution. IOS will always kill app to save memory. So i doubt there is a good way to prevent the crash beside limiting the memory consumption of your app. To reproduce, i guess you just need to run a lot of background apps, and then take high quality pictures (with Iphone x max). My advice is to do a fail safe check which make sure that app can restore to previous state the app crashed and reloaded

It’s probably a memory problem and it’s how Android behave I faced that problem too and built a workaround in my Ionic app using the provided Cordova lifecycle, I documented everything in https://forum.ionicframework.com/t/solved-camera-plugin-restart-app-on-android-8-1 if interested

the link is not founded, i have the same issue with a moto g4 plus, i have a feeling that it has to do with the memory. if anyone knows any other solution please share

@yaksneumann @thesheikhwasim here is the new link: https://forum.ionicframework.com/t/solved-camera-plugin-restart-app-on-android/117828

It’s probably a memory problem and it’s how Android behave

I faced that problem too and built a workaround in my Ionic app using the provided Cordova lifecycle, I documented everything in https://forum.ionicframework.com/t/solved-camera-plugin-restart-app-on-android-8-1 if interested

Its 404, the link provided. Can you elaborate

@sithwarrior Well, i’ve managed to get it working with background mode but im not 100% it was caused by this as other users seem to have it working without it,

imho for me it was more a problem on the system ram for the device i was testing on.

My conclusion on this would be to try without it in the first place and make sure you have tons of ram on your android simulator or test on a real device.