katzer / cordova-plugin-email-composer

Edit and send email messages
Apache License 2.0
344 stars 333 forks source link

Calling .open() crushes the app with targetSdk set to 30 on Android #372

Closed MishaMashinaMM closed 2 years ago

MishaMashinaMM commented 2 years ago

Used the plugin for a while and everything worked alright on Android. However, after setting 'targetSdkVersion = 30' instead of 29 (due to changes in Google Playstore rules), the plugin no longer opens the email client but crushes the app - moves it to the background and bringing it to foreground restarts the app. Any known solution to this? Thanks!

ThorvaldAagaard commented 2 years ago

My app used targetSdkVersion = 31 and it worked fine on my Note 9

But after installing the app on a Android 12 it started crashing.

I did some experiments, and switching back to targetSdkVersion=29 is working on Android 12.

I made a trace in the debugger, and found this expecion

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
    at java.util.ArrayList.remove(ArrayList.java:503)
    at de.appplant.cordova.emailcomposer.Impl.getDraft(Impl.java:90)
    at de.appplant.cordova.emailcomposer.EmailComposer$4.run(EmailComposer.java:173)

so it looks like it needs a rework in android 12

Looking at the code

        List<Intent> targets = new ArrayList<>();

        for (String clientId : getEmailClientIds()) {
            Intent target = (Intent) draft.clone();
            targets.add(target.setPackage(clientId));
        }

        return Intent.createChooser(targets.remove(0), header)
                .putExtra(EXTRA_INITIAL_INTENTS, targets.toArray(new Parcelable[0]));

it can be seen that the exception is becuase targets is empty.

Browsing around to see how this is done I found this

To be able to check for email clients when targeting api 30, add "queries" to the Manifest:
<queries>
    <intent>
        <action android:name="android.intent.action.SENDTO" />
        <data android:scheme="*" />
    </intent>
</queries>

But this requires newer version of Gradle

jfoclpf commented 2 years ago

Thank you @ThorvaldAagaard

Please submit a PR if you find a solid solution that I accept it.

ThorvaldAagaard commented 2 years ago

I upgraded to

'com.android.tools.build:gradle:4.0.1'

as that would allow queries in the AndroidManifest.xml

That required a Gradle version 6.1.1

So I upgraded

distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip

in gradle-wrapper.properties

The proper way of doing this is to set an environment variable

CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL=https://services.gradle.org/distributions/gradle-6.1.1-all.zip

and perhaps removing and adding the android platform (probably best to stick with android@8.1.0)

And unless you have figured out to add the queries using config.xml you will have to add it again in the AndroidManifest.xml

Now when building with API 31 you might have a look at https://stackoverflow.com/questions/68387270/android-studio-error-installed-build-tools-revision-31-0-0-is-corrupted

Finally I had to add

android:exported="true"

on the activity in AndroidManifest.xml

I got a security exception, but the application worked - probably someting with my attachment

E/DatabaseUtils: Writing exception to parcel
    java.lang.SecurityException: Permission Denial: reading de.appplant.cordova.emailcomposer.Provider uri content://com.mekbas.handitime.emailcomposer.provider/files/handitime-Ulf%20Aagaard%20Skalkam-Januar%202022.xlsx from pid=5322, uid=1000 requires the provider be exported, or grantUriPermission()
MishaMashinaMM commented 2 years ago

@ThorvaldAagaard I've tried your suggestions while looking for minimal changes in the code to make it work.

And - it works! :D

So:

  1. Installed a 6.1.1 gradle version and in Android Studio > Gradle Settings pointed the Gradle to installation folder.
  2. Added distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip to gradle-wrapper.properties.
  3. Added
    <queries>
      <intent>
            <action android:name="android.intent.action.SENDTO" />
            <data android:scheme="*" />
      </intent>
    </queries>

    inside of AndroidManifest.xml

  4. Finally set targetSdkVersion = 30 in variables.gradle.

I have yet to test it on devices with Android 12, but it works on Android 11 for sure.

Thanks a lot - you helped keep the app working for several hundreds of teachers that use my app :)

marshall86 commented 2 years ago

the easiest solution is to replace in the Impl.java file

Intent.createChooser(targets.remove(0), header) ===> Intent.createChooser(draft, header)

jfoclpf commented 2 years ago

the easiest solution is to replace in the Impl.java file

Intent.createChooser(targets.remove(0), header) ===> Intent.createChooser(draft, header)

@marshall86 If that solves this problem, could you kindly make a PR here in the repo? https://github.com/katzer/cordova-plugin-email-composer/blob/master/src/android/Impl.java

jfoclpf commented 2 years ago

@ThorvaldAagaard and @MishaMashinaMM

Could you kindly confirm if simply replacing Intent.createChooser(targets.remove(0), header) to Intent.createChooser(draft, header) in Impl.java exactly here solves the problem as @marshall86 suggested?

I would then make a PR and commit that change

Thank you

ahmad-alk commented 2 years ago

I'm still facing the issue! I don't think the PR solved it.

jfoclpf commented 2 years ago

I'm still facing the issue! I don't think the PR solved it.

@ahmad-alkhatib which PR do you refer to? Did you manually amend Intent.createChooser(targets.remove(0), header) to Intent.createChooser(draft, header) in Impl.java?

ahmad-alk commented 2 years ago

I'm still facing the issue! I don't think the PR solved it.

@ahmad-alkhatib which PR do you refer to? Did you manually amend Intent.createChooser(targets.remove(0), header) to Intent.createChooser(draft, header) in Impl.java?

My bad, I thought the PR was already merged.

jfoclpf commented 2 years ago

I'm still facing the issue! I don't think the PR solved it.

@ahmad-alkhatib which PR do you refer to? Did you manually amend Intent.createChooser(targets.remove(0), header) to Intent.createChooser(draft, header) in Impl.java?

My bad, I thought the PR was already merged.

@ahmad-alkhatib does it work now? Now it's merged. It's not yet in NPM, thus you have to install using this repo as source. Check installation instructions in main readme docs.

jfoclpf commented 2 years ago

Solution with #374

jfoclpf commented 2 years ago

@ahmad-alkhatib if the problem persists, please tell me that I reopen the issue.

ahmad-alk commented 2 years ago

thus you have to install using this repo as source. Check installation instructions in main readme docs.

I'm actually using capacitor and I'm following the installation instructions here, would you help me to understand more on how to "install using this repo as source"?

jfoclpf commented 2 years ago

@ahmad-alkhatib I would say either

npm install https://github.com/katzer/cordova-plugin-email-composer.git

or

ionic cordova plugin add https://github.com/katzer/cordova-plugin-email-composer.git
ahmad-alk commented 2 years ago

It's working for me now. @jfoclpf

jfoclpf commented 2 years ago

great @ahmad-alkhatib