react-native-mail
react-native-mail copied to clipboard
Android 13 : Unable to launch email window and App "refreshes"
Trying to implement a Support Request by email with some attached files. Everything works perfectly on iOS but I'm stuck with a weird error on Android 13 where the app seems to refresh (there is a visual hickup).
- react-native: 0.67.4
- react-native-mail: 6.1.1
At first I was getting the not_available error and after digging through the issues (mainly found #193) and adding intents to my AndroidManifest.xml file. I'm still stuck with the error below:
2022-10-17 16:31:07.009 2168-3375/? W/PackageManager: Intent does not match component's intent filter: Intent { act=android.intent.action.SEND_MULTIPLE (has extras) sel=act=android.intent.action.SENDTO dat=mailto:} }
2022-10-17 16:31:07.009 2168-3375/? W/PackageManager: Access blocked: ComponentInfo{com.google.android.gm/com.google.android.gm.ComposeActivityGmailExternal}
2022-10-17 16:31:07.012 2168-3375/? W/PackageManager: Intent does not match component's intent filter: Intent { act=android.intent.action.SEND_MULTIPLE flg=0x1 (has extras) sel=act=android.intent.action.SENDTO dat=mailto:} }
2022-10-17 16:31:07.012 2168-3375/? W/PackageManager: Access blocked: ComponentInfo{com.google.android.gm/com.google.android.gm.ComposeActivityGmailExternal}
2022-10-17 16:31:07.013 7547-7749/com.my_org.Myapp W/Bundle: Key android.intent.extra.TEXT expected ArrayList<java.lang.CharSequence> but value was of a different type. The default value <null> was returned.
2022-10-17 16:31:07.013 7547-7749/com.my_org.Myapp W/Bundle: Attempt to cast generated internal exception:
java.lang.ClassCastException: Cannot cast android.text.SpannableStringBuilder to java.util.ArrayList
at java.lang.Class.cast(Class.java:2479)
at android.os.BaseBundle.getValueAt(BaseBundle.java:405)
at android.os.BaseBundle.getValue(BaseBundle.java:374)
at android.os.BaseBundle.getArrayList(BaseBundle.java:1483)
at android.os.BaseBundle.getCharSequenceArrayList(BaseBundle.java:1526)
at android.os.Bundle.getCharSequenceArrayList(Bundle.java:1204)
at android.content.Intent.getCharSequenceArrayListExtra(Intent.java:9053)
at android.content.Intent.migrateExtraStreamToClipData(Intent.java:12089)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1799)
at android.app.ContextImpl.startActivity(ContextImpl.java:1101)
at android.app.ContextImpl.startActivity(ContextImpl.java:1072)
at android.content.ContextWrapper.startActivity(ContextWrapper.java:432)
at android.content.ContextWrapper.startActivity(ContextWrapper.java:432)
at com.chirag.RNMail.RNMailModule.mail(RNMailModule.java:138)
at java.lang.reflect.Method.invoke(Native Method)
at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:188)
at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:226)
at java.lang.Thread.run(Thread.java:1012)
2022-10-17 16:31:07.015 2168-3375/? W/PackageManager: Intent does not match component's intent filter: Intent { act=android.intent.action.SEND_MULTIPLE flg=0x10000001 clip={null {U(content)}} (has extras) sel=act=android.intent.action.SENDTO dat=mailto:} }
2022-10-17 16:31:07.015 2168-3375/? W/PackageManager: Access blocked: ComponentInfo{com.google.android.gm/com.google.android.gm.ComposeActivityGmailExternal}
2022-10-17 16:31:07.016 2168-3375/? I/ActivityTaskManager: START u0 {act=android.intent.action.SEND_MULTIPLE flg=0x10000001 cmp=com.my_org.Myapp/.MainActivity clip={null {U(content)}} (has extras) sel=act=android.intent.action.SENDTO dat=mailto:}} from uid 10469
2022-10-17 16:31:07.016 2168-3375/? D/CompatibilityChangeReporter: Compat change id reported: 194480991; UID 10469; state: ENABLED
2022-10-17 16:31:07.018 2168-3375/? D/CompatibilityChangeReporter: Compat change id reported: 197654537; UID 10469; state: DISABLED
2022-10-17 16:31:07.019 2168-3375/? D/CompatibilityChangeReporter: Compat change id reported: 174042980; UID 10469; state: DISABLED
2022-10-17 16:31:07.019 2168-3375/? D/CompatibilityChangeReporter: Compat change id reported: 184838306; UID 10469; state: DISABLED
2022-10-17 16:31:07.020 2168-3375/? D/CompatibilityChangeReporter: Compat change id reported: 185004937; UID 10469; state: DISABLED
2022-10-17 16:31:07.020 2168-3375/? D/CompatibilityChangeReporter: Compat change id reported: 181136395; UID 10469; state: DISABLED
2022-10-17 16:31:07.020 2168-3375/? D/CompatibilityChangeReporter: Compat change id reported: 174042936; UID 10469; state: DISABLED
2022-10-17 16:31:07.026 2168-3375/? D/CompatibilityChangeReporter: Compat change id reported: 194833441; UID 10469; state: DISABLED
2022-10-17 16:31:07.031 1435-1435/? I/sensors-hal: [hal]batch_physical_sensor:314, android.sensor.accelerometer/11, period=200000000, max_latency=2000000000
2022-10-17 16:31:07.031 1435-1435/? I/sensors-hal: [sensor]set_config:64, sample_period_ns is adjusted to 200000000 based on min/max delay_ns
2022-10-17 16:31:07.031 1435-1435/? I/sensors-hal: [hal]batch_physical_sensor:323, android.sensor.accelerometer/11, period=200000000, max_latency=2000000000 request completed
2022-10-17 16:31:07.032 1435-23065/? I/sensors-hal: [ssc_sensor]ssc_conn_resp_cb:686, resp_value = 0
2022-10-17 16:31:07.033 2168-2833/? W/ActivityTaskManager: Tried to set launchTime (0) < mLastActivityLaunchTime (278676904)
2022-10-17 16:31:07.056 7547-7547/com.my_org.Myapp E/unknown:ReactModalHost: Updating existing dialog with context: com.my_org.Myapp.MainActivity@2b5b8cf@45463759
2022-10-17 16:31:07.061 2168-2833/? D/CoreBackPreview: Window{2bb554f u0 com.my_org.Myapp/com.my_org.Myapp.MainActivity}: Setting back callback OnBackInvokedCallbackInfo{mCallback=android.window.IOnBackInvokedCallback$Stub$Proxy@e0199e5, mPriority=0}
2022-10-17 16:31:07.063 1435-1435/? I/sensors-hal: [hal]batch_physical_sensor:314, android.sensor.accelerometer/11, period=66667000, max_latency=0
2022-10-17 16:31:07.063 1435-1435/? I/sensors-hal: [sensor]set_config:64, sample_period_ns is adjusted to 66667000 based on min/max delay_ns
2022-10-17 16:31:07.063 1435-1435/? I/sensors-hal: [hal]batch_physical_sensor:323, android.sensor.accelerometer/11, period=66667000, max_latency=0 request completed
2022-10-17 16:31:07.064 1435-1435/? I/sensors-hal: [hal]flush_physical_sensor:355, android.sensor.accelerometer/11
2022-10-17 16:31:07.064 1435-1435/? I/sensors-hal: [hal]flush_physical_sensor:361, android.sensor.accelerometer/11 completed
2022-10-17 16:31:07.065 1435-23065/? I/sensors-hal: [ssc_sensor]ssc_conn_resp_cb:686, resp_value = 0
2022-10-17 16:31:07.065 1435-23065/? I/sensors-hal: [ssc_sensor]ssc_conn_resp_cb:686, resp_value = 0
2022-10-17 16:31:07.066 7547-7547/com.my_org.Myapp W/unknown:ReactContext: initializeMessageQueueThreads() is called.
2022-10-17 16:31:07.068 7547-7748/com.my_org.Myapp I/ReactNativeJS: Running "MyApp" with {"rootTag":11}
From what I gather from the logs, there seems to be a problem with :
- intent declarations
-
W/PackageManager: Intent does not match component's intent filter: Intent { act=android.intent.action.SEND_MULTIPLE (has extras) sel=act=android.intent.action.SENDTO dat=mailto:} }
-
- access to GMail
-
W/PackageManager: Access blocked: ComponentInfo{com.google.android.gm/com.google.android.gm.ComposeActivityGmailExternal}
-
- there is an error in the activity launched
-
W/Bundle: Key android.intent.extra.TEXT expected ArrayList<java.lang.CharSequence> but value was of a different type. The default value <null> was returned.
-
W/Bundle: Attempt to cast generated internal exception: java.lang.ClassCastException: Cannot cast android.text.SpannableStringBuilder to java.util.ArrayList
-
All this seems to relaunch MyApp as it seems to be the activity called. Any hint or help is appreciated.
My AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.intent.action.SENDTO"/>
<data android:scheme="mailto"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.SEND"/>
<data android:mimeType="*/*"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.SEND_MULTIPLE"/>
<data android:mimeType="*/*"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:mimeType="*/*" />
</intent>
<intent>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<data android:mimeType="*/*" />
</intent>
</queries>
My JS Code
export async function sendSupportMessage(project?: Project) {
const subject = `Support request for MyApp (${Platform.OS})`
let attachments:MailAttachment[] | undefined = undefined;
await supportMessageAttachments().then((at) => {
attachments = at;
}, (error) => {
Alert.alert("Error", error);
});
if (!attachments) {
return;
}
Mailer.mail({
subject,
recipients: [AppConfig.support_email],
ccRecipients: [],
bccRecipients: [],
customChooserTitle: subject, // Android only (defaults to "Send Mail")
body: supportMessageBody(project),
isHTML: true,
attachments
}, (error, event) => {
if (error) {
let title = "Error";
let text = "Cannot send message";
// iOS errors
if (error.startsWith("attachment file with") || error.startsWith("Mime type")) {
error = 'not_found';
}
switch (error) {
case 'not_found':
text = "Attachment not found";
break;
case 'not_available':
title = "Not available";
text = "Please configure your email application"
break;
case 'failed':
text = "Failed to send message";
break;
}
Alert.alert(title, text);
}
});
}
The same issue
For Android 13 we should patch code of RNMailModule.java to just call
Intent.createChooser - it works without issues
The problem is: PackageManager's queryIntentActivities doesn't find Gmail app at all (AndroidManifest.xml has all required entries as mentioned in Google docs). It seems it is current Android 13 bug or new not documented "security enhancement"
same issue
A few theories as to what might be happening here:
- Gmail may have updated their intent filter in the app manifest to restrict the intent actions or selectors that they receive. This seems unlikely, because the code used to select the email intent reasonably checks for anything that would receive a "SENDTO" intent, and support a "mailto" link, which Gmail most likely would. Unfortunately, they don't publish their intent-filter, naturally, so it's hard to verify this is the case. Still, it's definitely possible, and not the first time Gmail has changed the way they receive communications from other apps.
- Most likely, in Android 13, intent-filters are more restrictive – it's possible that some of the intent matching is now getting applied more strictly from the Gmail side of things. For what it's worth though, we cannot reproduce this issue on an emulator running a May 2022 version of Gmail, but we can on an emulator running a Dec 22 version.
- Lastly, one of the Android APIs used (
PackageManager::queryIntentActivities(Intent, int)
) has been deprecated as of Android API 33. It looks like the flag we are providing it (0
), is non-sensical in this context. It is possible that this is simply returning a defunct return value, and instead we should be using the updated version of this call.
We're going to try out some solutions related to the hypotheses above, but unfortunately we can't imitate this on an emulator because the version of Gmail on the emulator doesn't reproduce the issue :(
same issue here -- hoping for a fix.
I have a solution for it here: https://github.com/chirag04/react-native-mail/issues/196#issuecomment-1455470151