From ae2e30a3dd2c6a4306270d17b377eaac628b79c2 Mon Sep 17 00:00:00 2001 From: Martin Puza Date: Fri, 6 Oct 2017 19:39:25 +0200 Subject: [PATCH 01/24] added "url" parameter for ios - add file path as attachments --- ios/RNMailCompose/RNMailCompose.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ios/RNMailCompose/RNMailCompose.swift b/ios/RNMailCompose/RNMailCompose.swift index 5bc690a..dde58ae 100644 --- a/ios/RNMailCompose/RNMailCompose.swift +++ b/ios/RNMailCompose/RNMailCompose.swift @@ -74,6 +74,13 @@ class RNMailCompose: NSObject, MFMailComposeViewControllerDelegate { if let data = textToData(utf8: dict["text"], base64: dict["data"]), let mimeType = dict["mimeType"], let filename = toFilename(filename: dict["filename"], ext: dict["ext"]) { vc.addAttachmentData(data, mimeType: mimeType, fileName: filename) } + if let url = dict["url"], let mimeType = dict["mimeType"], let filename = toFilename(filename: dict["filename"], ext: dict["ext"]) { + do { + try vc.addAttachmentData(Data(contentsOf: URL(fileURLWithPath: url)), mimeType: mimeType, fileName: filename) + } catch let error { + reject("fileNotFound", "File not found", error) + } + } } } From 5d719640f657559de1bdce5b2d1d8a8da3637e3f Mon Sep 17 00:00:00 2001 From: Martin Puza Date: Wed, 15 Nov 2017 19:55:05 +0100 Subject: [PATCH 02/24] added url share via fileprovider --- .../mailcompose/RNMailComposeModule.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index f0f2bd0..524d35a 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -8,6 +8,7 @@ import android.text.Html; import android.text.Spanned; import android.util.Base64; +import android.support.v4.content.FileProvider; import com.facebook.react.bridge.ActivityEventListener; import com.facebook.react.bridge.BaseActivityEventListener; @@ -35,6 +36,7 @@ public class RNMailComposeModule extends ReactContextBaseJavaModule { + private final ReactApplicationContext reactContext; private static final int ACTIVITY_SEND = 129382; private Promise mPromise; @@ -59,6 +61,7 @@ public void onActivityResult(Activity activity, int requestCode, int resultCode, public RNMailComposeModule(final ReactApplicationContext reactContext) { super(reactContext); reactContext.addActivityEventListener(mActivityEventListener); + this.reactContext = reactContext; } @Override @@ -97,7 +100,7 @@ private void putExtra(Intent intent, String key, ArrayList value) { } } - private void addAttachments(Intent intent, ReadableArray attachments) { + private void addAttachments(Intent intent, ReadableArray attachments, String fileProviderUri) { if (attachments == null) return; ArrayList uris = new ArrayList<>(); @@ -105,7 +108,14 @@ private void addAttachments(Intent intent, ReadableArray attachments) { if (attachments.getType(i) == ReadableType.Map) { ReadableMap attachment = attachments.getMap(i); if (attachment != null) { - byte[] blob = getBlob(attachment, "data"); + Uri contentUri = null; + byte[] blob = null; + if (attachment.hasKey("url") && attachment.getType("url") == ReadableType.String && fileProviderUri != null) { + contentUri = FileProvider.getUriForFile(this.reactContext, fileProviderUri, new File(attachment.getString("url"))); + } else { + blob = getBlob(attachment, "data"); + } + String text = getString(attachment, "text"); // String mimeType = getString(attachment, "mimeType"); String filename = getString(attachment, "filename"); @@ -114,12 +124,16 @@ private void addAttachments(Intent intent, ReadableArray attachments) { } String ext = getString(attachment, "ext"); - File tempFile = createTempFile(filename, ext); + File tempFile = null; if (blob != null) { + createTempFile(filename, ext); tempFile = writeBlob(tempFile, blob); } else if (text != null) { + createTempFile(filename, ext); tempFile = writeText(tempFile, text); + } else if (contentUri != null) { + uris.add(contentUri); } if (tempFile != null) { @@ -309,7 +323,7 @@ public void send(ReadableMap data, Promise promise) throws IOException { putExtra(intent, Intent.EXTRA_EMAIL, getStringArray(data, "toRecipients")); putExtra(intent, Intent.EXTRA_CC, getStringArray(data, "ccRecipients")); putExtra(intent, Intent.EXTRA_BCC, getStringArray(data, "bccRecipients")); - addAttachments(intent, getArray(data, "attachments")); + addAttachments(intent, getArray(data, "attachments"), getString(data, "fileProviderUri")); intent.putExtra("exit_on_sent", true); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); From e492c721a29826e333548afa0e8c5fd19ce6ef48 Mon Sep 17 00:00:00 2001 From: Martin Puza Date: Wed, 15 Nov 2017 19:55:24 +0100 Subject: [PATCH 03/24] changed type from text/plain to message/rfc822 (for plain text only for now) --- .../com/reactlibrary/mailcompose/RNMailComposeModule.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index 524d35a..ea36fcf 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -313,7 +313,9 @@ public void send(ReadableMap data, Promise promise) throws IOException { putExtra(intent, Intent.EXTRA_TEXT, Html.fromHtml(html)); putExtra(intent, Intent.EXTRA_HTML_TEXT, Html.fromHtml(html)); } else { - intent.setType("text/plain"); + // intent.setType("text/plain"); + intent.setType("message/rfc822"); + if (!isEmpty(text)) { putExtra(intent, Intent.EXTRA_TEXT, text); } From 5b0ecbf3b8be5b2d6ac0515174068f473f832857 Mon Sep 17 00:00:00 2001 From: Martin Puza Date: Fri, 17 Nov 2017 13:52:35 +0100 Subject: [PATCH 04/24] this would be very nice, but doesn't seem to work on every platform; successfully sent mails often return as cancelled. --- .../com/reactlibrary/mailcompose/RNMailComposeModule.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index ea36fcf..3e51ce1 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -47,11 +47,13 @@ public class RNMailComposeModule extends ReactContextBaseJavaModule { public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent intent) { if (requestCode == ACTIVITY_SEND) { if (mPromise != null) { - if (resultCode == Activity.RESULT_CANCELED) { + /*if (resultCode == Activity.RESULT_CANCELED) { mPromise.reject("cancelled", "Operation has been cancelled"); } else { mPromise.resolve("sent"); } + mPromise = null;*/ + mPromise.resolve("unknown"); mPromise = null; } } From 5f0de0edc4535e16faecbd9274f13ce113059bb5 Mon Sep 17 00:00:00 2001 From: Florian Renner Date: Thu, 3 May 2018 09:42:08 +0200 Subject: [PATCH 05/24] Filter chooser apps to show Mail apps only for selection --- .../mailcompose/RNMailComposeModule.java | 109 ++++++++++++------ 1 file changed, 75 insertions(+), 34 deletions(-) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index 3e51ce1..dfa195b 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -1,14 +1,23 @@ package com.reactlibrary.mailcompose; import android.app.Activity; +import android.app.PendingIntent; import android.content.ActivityNotFoundException; +import android.content.ComponentName; import android.content.Intent; +import android.content.IntentSender; +import android.content.pm.LabeledIntent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; import android.net.Uri; import android.os.Bundle; +import android.os.Parcelable; import android.text.Html; import android.text.Spanned; import android.util.Base64; import android.support.v4.content.FileProvider; +import android.util.Log; import com.facebook.react.bridge.ActivityEventListener; import com.facebook.react.bridge.BaseActivityEventListener; @@ -27,14 +36,15 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Array; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; - public class RNMailComposeModule extends ReactContextBaseJavaModule { private final ReactApplicationContext reactContext; private static final int ACTIVITY_SEND = 129382; @@ -301,46 +311,77 @@ private File writeBlob(File file, byte[] blob) { @ReactMethod public void send(ReadableMap data, Promise promise) throws IOException { - if (mPromise != null) { - mPromise.reject("timeout", "Operation has timed out"); - mPromise = null; - } + if (mPromise != null) { + mPromise.reject("timeout", "Operation has timed out"); + mPromise = null; + } Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); - String text = getString(data, "body"); - String html = getString(data, "html"); - if (!isEmpty(html)) { - intent.setType("text/html"); - putExtra(intent, Intent.EXTRA_TEXT, Html.fromHtml(html)); - putExtra(intent, Intent.EXTRA_HTML_TEXT, Html.fromHtml(html)); - } else { - // intent.setType("text/plain"); - intent.setType("message/rfc822"); - - if (!isEmpty(text)) { - putExtra(intent, Intent.EXTRA_TEXT, text); - } - } + String text = getString(data, "body"); + String html = getString(data, "html"); + if (!isEmpty(html)) { + intent.setType("text/html"); + putExtra(intent, Intent.EXTRA_TEXT, Html.fromHtml(html)); + putExtra(intent, Intent.EXTRA_HTML_TEXT, Html.fromHtml(html)); + } else { + // intent.setType("text/plain"); + intent.setType("message/rfc822"); + + if (!isEmpty(text)) { + putExtra(intent, Intent.EXTRA_TEXT, text); + } + } + putExtra(intent, Intent.EXTRA_SUBJECT, getString(data, "subject")); + putExtra(intent, Intent.EXTRA_EMAIL, getStringArray(data, "toRecipients")); + putExtra(intent, Intent.EXTRA_CC, getStringArray(data, "ccRecipients")); + putExtra(intent, Intent.EXTRA_BCC, getStringArray(data, "bccRecipients")); + addAttachments(intent, getArray(data, "attachments"), getString(data, "fileProviderUri")); + + intent.putExtra("exit_on_sent", true); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + try { - putExtra(intent, Intent.EXTRA_SUBJECT, getString(data, "subject")); - putExtra(intent, Intent.EXTRA_EMAIL, getStringArray(data, "toRecipients")); - putExtra(intent, Intent.EXTRA_CC, getStringArray(data, "ccRecipients")); - putExtra(intent, Intent.EXTRA_BCC, getStringArray(data, "bccRecipients")); - addAttachments(intent, getArray(data, "attachments"), getString(data, "fileProviderUri")); + ArrayList mailIntents = getEmailAppLauncherIntents(intent); + // PendingIntent pendingIntent = PendingIntent.getActivities(this.reactContext, ACTIVITY_SEND, mailIntents.toArray( new Intent[mailIntents.size()] ), PendingIntent.FLAG_IMMUTABLE); - intent.putExtra("exit_on_sent", true); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + //Create chooser + Intent chooserIntent = Intent.createChooser(new Intent(), "Select email app:"); // , pendingIntent.getIntentSender()); - try { - getCurrentActivity().startActivityForResult(Intent.createChooser(intent, "Send Mail"), ACTIVITY_SEND); - mPromise = promise; - } catch (ActivityNotFoundException e) { - promise.reject("failed", "Activity Not Found"); - } catch (Exception e) { - promise.reject("failed", "Unknown Error"); + chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, mailIntents.toArray( new Parcelable[mailIntents.size()] )); + getCurrentActivity().startActivityForResult(chooserIntent, ACTIVITY_SEND); + mPromise = promise; + } catch (ActivityNotFoundException e) { + promise.reject("failed", "Activity Not Found"); + } catch (Exception e) { + promise.reject("failed", "Unknown Error"); + } + } + + // Get E-Mail App intents only for share picker (filtered for duplicates) + private ArrayList getEmailAppLauncherIntents (Intent intent) { + ArrayList emailAppLauncherIntents = new ArrayList<>(); + + // Intent that only email apps can handle: + Intent emailAppIntent = new Intent(Intent.ACTION_SENDTO); + emailAppIntent.setData(Uri.parse("mailto:")); + emailAppIntent.putExtra(Intent.EXTRA_EMAIL, ""); + emailAppIntent.putExtra(Intent.EXTRA_SUBJECT, ""); + + PackageManager packageManager = getCurrentActivity().getPackageManager(); + // All installed apps that can handle email intent: + List emailApps = packageManager.queryIntentActivities(emailAppIntent, PackageManager.MATCH_ALL); + ArrayList addedPackages = new ArrayList<>(); + for (int i = 0; i < emailApps.size(); i++) { + String packageName = emailApps.get(i).activityInfo.packageName; + if (addedPackages.indexOf(packageName) == -1) { + addedPackages.add(packageName); + emailAppLauncherIntents.add(((Intent) intent.clone()).setPackage(packageName)); + } } + return emailAppLauncherIntents; } } From ee696c2e440389099890a48a4d05d8f75ea38c33 Mon Sep 17 00:00:00 2001 From: Florian Renner Date: Thu, 3 May 2018 10:45:12 +0200 Subject: [PATCH 06/24] handle/ prevent errors --- .../mailcompose/RNMailComposeModule.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index dfa195b..46e5a99 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -18,6 +18,7 @@ import android.util.Base64; import android.support.v4.content.FileProvider; import android.util.Log; +import android.widget.Toast; import com.facebook.react.bridge.ActivityEventListener; import com.facebook.react.bridge.BaseActivityEventListener; @@ -45,6 +46,8 @@ import java.util.Map; import java.util.UUID; + + public class RNMailComposeModule extends ReactContextBaseJavaModule { private final ReactApplicationContext reactContext; private static final int ACTIVITY_SEND = 129382; @@ -347,16 +350,24 @@ public void send(ReadableMap data, Promise promise) throws IOException { ArrayList mailIntents = getEmailAppLauncherIntents(intent); // PendingIntent pendingIntent = PendingIntent.getActivities(this.reactContext, ACTIVITY_SEND, mailIntents.toArray( new Intent[mailIntents.size()] ), PendingIntent.FLAG_IMMUTABLE); + if (mailIntents == null || mailIntents.size() == 0) { + Toast.makeText(getCurrentActivity(), "No matching app found", Toast.LENGTH_LONG).show(); + return; + } //Create chooser Intent chooserIntent = Intent.createChooser(new Intent(), "Select email app:"); // , pendingIntent.getIntentSender()); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, mailIntents.toArray( new Parcelable[mailIntents.size()] )); getCurrentActivity().startActivityForResult(chooserIntent, ACTIVITY_SEND); mPromise = promise; + } catch (NullPointerException e) { + promise.reject("failed", "StartActivityForResult failed"); } catch (ActivityNotFoundException e) { - promise.reject("failed", "Activity Not Found"); + promise.reject("failed", "Activity Not Found"); + } catch (RuntimeException e) { + promise.reject("failed", "External App Probably Cannot Handle Parcelable"); } catch (Exception e) { - promise.reject("failed", "Unknown Error"); + promise.reject("failed", "Unknown Error"); } } From 870f66130bf72cf88e13a17898920a8ba620a353 Mon Sep 17 00:00:00 2001 From: Florian Renner Date: Mon, 7 May 2018 16:16:11 +0200 Subject: [PATCH 07/24] Get selected Mail app name --- .../mailcompose/RNMailComposeModule.java | 188 ++++++++++-------- 1 file changed, 105 insertions(+), 83 deletions(-) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index 46e5a99..9825f4a 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -3,15 +3,13 @@ import android.app.Activity; import android.app.PendingIntent; import android.content.ActivityNotFoundException; -import android.content.ComponentName; +import android.content.BroadcastReceiver; +import android.content.Context; import android.content.Intent; import android.content.IntentSender; -import android.content.pm.LabeledIntent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.res.Resources; import android.net.Uri; -import android.os.Bundle; import android.os.Parcelable; import android.text.Html; import android.text.Spanned; @@ -21,7 +19,6 @@ import android.widget.Toast; import com.facebook.react.bridge.ActivityEventListener; -import com.facebook.react.bridge.BaseActivityEventListener; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; @@ -29,6 +26,7 @@ import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableType; +import com.facebook.react.bridge.Callback; import java.io.ByteArrayOutputStream; import java.io.File; @@ -37,7 +35,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.lang.reflect.Array; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; @@ -46,36 +43,14 @@ import java.util.Map; import java.util.UUID; - - -public class RNMailComposeModule extends ReactContextBaseJavaModule { +public class RNMailComposeModule extends ReactContextBaseJavaModule implements ActivityEventListener { private final ReactApplicationContext reactContext; private static final int ACTIVITY_SEND = 129382; - private Promise mPromise; - private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() { - - @Override - public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent intent) { - if (requestCode == ACTIVITY_SEND) { - if (mPromise != null) { - /*if (resultCode == Activity.RESULT_CANCELED) { - mPromise.reject("cancelled", "Operation has been cancelled"); - } else { - mPromise.resolve("sent"); - } - mPromise = null;*/ - mPromise.resolve("unknown"); - mPromise = null; - } - } - } - }; - public RNMailComposeModule(final ReactApplicationContext reactContext) { super(reactContext); - reactContext.addActivityEventListener(mActivityEventListener); + reactContext.addActivityEventListener(this); this.reactContext = reactContext; } @@ -126,9 +101,9 @@ private void addAttachments(Intent intent, ReadableArray attachments, String fil Uri contentUri = null; byte[] blob = null; if (attachment.hasKey("url") && attachment.getType("url") == ReadableType.String && fileProviderUri != null) { - contentUri = FileProvider.getUriForFile(this.reactContext, fileProviderUri, new File(attachment.getString("url"))); + contentUri = FileProvider.getUriForFile(this.reactContext, fileProviderUri, new File(attachment.getString("url"))); } else { - blob = getBlob(attachment, "data"); + blob = getBlob(attachment, "data"); } String text = getString(attachment, "text"); @@ -312,87 +287,134 @@ private File writeBlob(File file, byte[] blob) { return null; } - @ReactMethod - public void send(ReadableMap data, Promise promise) throws IOException { - if (mPromise != null) { - mPromise.reject("timeout", "Operation has timed out"); - mPromise = null; - } + public static class ChooserBroadcast extends BroadcastReceiver { + private static Callback chosenCallback = null; - Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); + public static void setChosenCallback (Callback c) { + chosenCallback = c; + } - String text = getString(data, "body"); - String html = getString(data, "html"); - if (!isEmpty(html)) { - intent.setType("text/html"); - putExtra(intent, Intent.EXTRA_TEXT, Html.fromHtml(html)); - putExtra(intent, Intent.EXTRA_HTML_TEXT, Html.fromHtml(html)); - } else { - // intent.setType("text/plain"); - intent.setType("message/rfc822"); - - if (!isEmpty(text)) { - putExtra(intent, Intent.EXTRA_TEXT, text); - } - } - putExtra(intent, Intent.EXTRA_SUBJECT, getString(data, "subject")); - putExtra(intent, Intent.EXTRA_EMAIL, getStringArray(data, "toRecipients")); - putExtra(intent, Intent.EXTRA_CC, getStringArray(data, "ccRecipients")); - putExtra(intent, Intent.EXTRA_BCC, getStringArray(data, "bccRecipients")); - addAttachments(intent, getArray(data, "attachments"), getString(data, "fileProviderUri")); - - intent.putExtra("exit_on_sent", true); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + @Override + public void onReceive(Context context, Intent intent) { + String result = String.valueOf(intent.getExtras().get(Intent.EXTRA_CHOSEN_COMPONENT)); + String chosenComponent = result.substring(result.indexOf("{") + 1, result.indexOf("/")); - try { + if (chosenCallback != null) { + chosenCallback.invoke(chosenComponent); + } + } + } - ArrayList mailIntents = getEmailAppLauncherIntents(intent); - // PendingIntent pendingIntent = PendingIntent.getActivities(this.reactContext, ACTIVITY_SEND, mailIntents.toArray( new Intent[mailIntents.size()] ), PendingIntent.FLAG_IMMUTABLE); + @ReactMethod + public void send(ReadableMap data, Promise promise) { + if (mPromise != null) { + mPromise.reject("timeout", "Operation has timed out"); + mPromise = null; + } + try { + // Check if Mail App exists + ArrayList mailIntents = getEmailAppLauncherIntentsWithData(data); if (mailIntents == null || mailIntents.size() == 0) { Toast.makeText(getCurrentActivity(), "No matching app found", Toast.LENGTH_LONG).show(); return; } - //Create chooser - Intent chooserIntent = Intent.createChooser(new Intent(), "Select email app:"); // , pendingIntent.getIntentSender()); - chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, mailIntents.toArray( new Parcelable[mailIntents.size()] )); - getCurrentActivity().startActivityForResult(chooserIntent, ACTIVITY_SEND); - mPromise = promise; - } catch (NullPointerException e) { + // Create chooser + Intent chooserIntent = Intent.createChooser(new Intent(), "Select email app:", getIntentSender()); //TODO: handle <22 API devices + chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, mailIntents.toArray( new Parcelable[mailIntents.size()] )); + getCurrentActivity().startActivityForResult(chooserIntent, ACTIVITY_SEND); + mPromise = promise; + } catch (NullPointerException e) { promise.reject("failed", "StartActivityForResult failed"); - } catch (ActivityNotFoundException e) { + } catch (ActivityNotFoundException e) { promise.reject("failed", "Activity Not Found"); - } catch (RuntimeException e) { + } catch (RuntimeException e) { promise.reject("failed", "External App Probably Cannot Handle Parcelable"); - } catch (Exception e) { + } catch (Exception e) { promise.reject("failed", "Unknown Error"); - } + } } - // Get E-Mail App intents only for share picker (filtered for duplicates) - private ArrayList getEmailAppLauncherIntents (Intent intent) { - ArrayList emailAppLauncherIntents = new ArrayList<>(); + // Create intent for data share + private Intent getDataIntent (ReadableMap data) { + Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); + String text = getString(data, "body"); + String html = getString(data, "html"); + if (!isEmpty(html)) { + intent.setType("text/html"); + putExtra(intent, Intent.EXTRA_TEXT, Html.fromHtml(html)); + putExtra(intent, Intent.EXTRA_HTML_TEXT, Html.fromHtml(html)); + } else { + // intent.setType("text/plain"); + intent.setType("message/rfc822"); + + if (!isEmpty(text)) { + putExtra(intent, Intent.EXTRA_TEXT, text); + } + } + putExtra(intent, Intent.EXTRA_SUBJECT, getString(data, "subject")); + putExtra(intent, Intent.EXTRA_EMAIL, getStringArray(data, "toRecipients")); + putExtra(intent, Intent.EXTRA_CC, getStringArray(data, "ccRecipients")); + putExtra(intent, Intent.EXTRA_BCC, getStringArray(data, "bccRecipients")); + addAttachments(intent, getArray(data, "attachments"), getString(data, "fileProviderUri")); + intent.putExtra("exit_on_sent", true); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + return intent; + } - // Intent that only email apps can handle: + // Intent that only email apps can handle + private Intent getEmailAppIntent() { Intent emailAppIntent = new Intent(Intent.ACTION_SENDTO); emailAppIntent.setData(Uri.parse("mailto:")); emailAppIntent.putExtra(Intent.EXTRA_EMAIL, ""); emailAppIntent.putExtra(Intent.EXTRA_SUBJECT, ""); + return emailAppIntent; + } + + // Get E-Mail App intents only for share picker (filtered for duplicates) + private ArrayList getEmailAppLauncherIntentsWithData (ReadableMap data) { + ArrayList emailAppLauncherIntentsWithData = new ArrayList<>(); + Intent dataIntent = getDataIntent(data); + Intent emailAppIntent = getEmailAppIntent(); + + // Get All installed apps that can handle email intent PackageManager packageManager = getCurrentActivity().getPackageManager(); - // All installed apps that can handle email intent: List emailApps = packageManager.queryIntentActivities(emailAppIntent, PackageManager.MATCH_ALL); ArrayList addedPackages = new ArrayList<>(); for (int i = 0; i < emailApps.size(); i++) { String packageName = emailApps.get(i).activityInfo.packageName; if (addedPackages.indexOf(packageName) == -1) { addedPackages.add(packageName); - emailAppLauncherIntents.add(((Intent) intent.clone()).setPackage(packageName)); + emailAppLauncherIntentsWithData.add(((Intent) dataIntent.clone()).setPackage(packageName)); } } - return emailAppLauncherIntents; + + return emailAppLauncherIntentsWithData; } -} + private IntentSender getIntentSender () { + Intent receiverIntent = new Intent(reactContext, ChooserBroadcast.class); + PendingIntent pendingIntent = PendingIntent.getBroadcast(reactContext, ACTIVITY_SEND, receiverIntent, PendingIntent.FLAG_UPDATE_CURRENT); + return pendingIntent.getIntentSender(); + } + + @Override + public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { + if (requestCode == ACTIVITY_SEND) { + + if (mPromise != null) { + mPromise.resolve("unknown"); + mPromise = null; + } + } + } + + @Override + public void onNewIntent(Intent intent) { + } +} From d02cd6039d16bc3dc1edc6c06e7f4b25fed3516f Mon Sep 17 00:00:00 2001 From: Florian Renner Date: Mon, 7 May 2018 17:48:44 +0200 Subject: [PATCH 08/24] Pass lastSelection to js over bridge --- .../mailcompose/RNMailComposeModule.java | 17 +++++++---------- js/RNMailCompose.android.js | 8 +++++--- js/RNMailCompose.ios.js | 4 +--- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index 9825f4a..a84be85 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -26,7 +26,6 @@ import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableType; -import com.facebook.react.bridge.Callback; import java.io.ByteArrayOutputStream; import java.io.File; @@ -46,6 +45,7 @@ public class RNMailComposeModule extends ReactContextBaseJavaModule implements ActivityEventListener { private final ReactApplicationContext reactContext; private static final int ACTIVITY_SEND = 129382; + public static String lastSelection = null; private Promise mPromise; public RNMailComposeModule(final ReactApplicationContext reactContext) { @@ -288,23 +288,20 @@ private File writeBlob(File file, byte[] blob) { } public static class ChooserBroadcast extends BroadcastReceiver { - private static Callback chosenCallback = null; - - public static void setChosenCallback (Callback c) { - chosenCallback = c; - } - @Override public void onReceive(Context context, Intent intent) { String result = String.valueOf(intent.getExtras().get(Intent.EXTRA_CHOSEN_COMPONENT)); String chosenComponent = result.substring(result.indexOf("{") + 1, result.indexOf("/")); - if (chosenCallback != null) { - chosenCallback.invoke(chosenComponent); - } + RNMailComposeModule.lastSelection = chosenComponent; } } + @ReactMethod + public void getLastSelection(Promise promise) { + promise.resolve(lastSelection); + } + @ReactMethod public void send(ReadableMap data, Promise promise) { if (mPromise != null) { diff --git a/js/RNMailCompose.android.js b/js/RNMailCompose.android.js index 1476c94..cddf316 100644 --- a/js/RNMailCompose.android.js +++ b/js/RNMailCompose.android.js @@ -6,8 +6,10 @@ const {RNMailCompose} = NativeModules; export default { name: RNMailCompose.name, - - send(data) { - return RNMailCompose.send(data); + getLastSelection() { + return RNMailCompose.getLastSelection() }, + send(data) { + return RNMailCompose.send(data) + } }; diff --git a/js/RNMailCompose.ios.js b/js/RNMailCompose.ios.js index 774bb3d..5e34557 100644 --- a/js/RNMailCompose.ios.js +++ b/js/RNMailCompose.ios.js @@ -6,12 +6,10 @@ const {RNMailCompose} = NativeModules; export default { name: RNMailCompose.name, - canSendMail() { return RNMailCompose.canSendMail(); }, - send(data) { return RNMailCompose.send(data); - }, + } }; From 799a202e192eead4c8a0f1209fc7c7dca7d597b1 Mon Sep 17 00:00:00 2001 From: Florian Renner Date: Mon, 7 May 2018 18:00:26 +0200 Subject: [PATCH 09/24] support direct app selection parameter --- .../mailcompose/RNMailComposeModule.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index a84be85..41ff244 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -379,18 +379,24 @@ private ArrayList getEmailAppLauncherIntentsWithData (ReadableMap data) Intent dataIntent = getDataIntent(data); Intent emailAppIntent = getEmailAppIntent(); - // Get All installed apps that can handle email intent - PackageManager packageManager = getCurrentActivity().getPackageManager(); - List emailApps = packageManager.queryIntentActivities(emailAppIntent, PackageManager.MATCH_ALL); - ArrayList addedPackages = new ArrayList<>(); - for (int i = 0; i < emailApps.size(); i++) { - String packageName = emailApps.get(i).activityInfo.packageName; - if (addedPackages.indexOf(packageName) == -1) { - addedPackages.add(packageName); - emailAppLauncherIntentsWithData.add(((Intent) dataIntent.clone()).setPackage(packageName)); + String selectedApp = getString(data, "selectedApp"); + + if (selectedApp != null) { + // Set selected mail app + emailAppLauncherIntentsWithData.add(((Intent) dataIntent.clone()).setPackage(selectedApp)); + } else { + // Get All installed apps that can handle email intent + PackageManager packageManager = getCurrentActivity().getPackageManager(); + List emailApps = packageManager.queryIntentActivities(emailAppIntent, PackageManager.MATCH_ALL); + ArrayList addedPackages = new ArrayList<>(); + for (int i = 0; i < emailApps.size(); i++) { + String packageName = emailApps.get(i).activityInfo.packageName; + if (addedPackages.indexOf(packageName) == -1) { + addedPackages.add(packageName); + emailAppLauncherIntentsWithData.add(((Intent) dataIntent.clone()).setPackage(packageName)); + } } } - return emailAppLauncherIntentsWithData; } From f0b564b029303f8a21053d0806955b677d32ef1a Mon Sep 17 00:00:00 2001 From: Florian Renner Date: Tue, 8 May 2018 11:48:15 +0200 Subject: [PATCH 10/24] Support getMailAppData which passes Share apps data array from NATIVE to JS --- .../mailcompose/RNMailComposeModule.java | 59 ++++++++++++++++++- js/RNMailCompose.android.js | 3 + 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index 41ff244..70ddd07 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -7,8 +7,13 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Parcelable; import android.text.Html; @@ -25,7 +30,12 @@ import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.ReadableNativeArray; import com.facebook.react.bridge.ReadableType; +import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.WritableNativeArray; +import com.facebook.react.bridge.WritableNativeMap; import java.io.ByteArrayOutputStream; import java.io.File; @@ -297,9 +307,54 @@ public void onReceive(Context context, Intent intent) { } } + @ReactMethod + public void getMailAppData(Promise promise) { + + WritableArray emailAppArray = new WritableNativeArray(); + + // Get App infos + Intent emailAppIntent = getEmailAppIntent(); + PackageManager packageManager = getCurrentActivity().getPackageManager(); + List emailAppInfos = packageManager.queryIntentActivities(emailAppIntent, PackageManager.MATCH_ALL); + + ArrayList addedPackages = new ArrayList<>(); + for (int i = 0; i < emailAppInfos.size(); i++) { + ActivityInfo activityInfo = emailAppInfos.get(i).activityInfo; + // Prevent Duplicated + if (addedPackages.indexOf(activityInfo.packageName) == -1) { + addedPackages.add(activityInfo.packageName); + + // Build Map with app data + WritableMap emailAppData = new WritableNativeMap(); + emailAppData.putString("id", activityInfo.packageName); + emailAppData.putString("name", packageManager.getApplicationLabel(activityInfo.applicationInfo).toString()); + Drawable icon = packageManager.getApplicationLogo(activityInfo.applicationInfo); + emailAppData.putString("icon", getBase64(icon != null ? icon : packageManager.getDefaultActivityIcon())); + + // Add to array + emailAppArray.pushMap(emailAppData); + } + } + promise.resolve(emailAppArray); + } + + private String getBase64(Drawable icon) { + BitmapDrawable drawable = (BitmapDrawable) icon; + Bitmap bitmap = drawable.getBitmap(); + return encodeToBase64(bitmap, Bitmap.CompressFormat.JPEG, 100); + } + + private String encodeToBase64(Bitmap image, Bitmap.CompressFormat compressFormat, int quality) { + ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream(); + image.compress(compressFormat, quality, byteArrayOS); + return Base64.encodeToString(byteArrayOS.toByteArray(), Base64.DEFAULT); + } + @ReactMethod public void getLastSelection(Promise promise) { - promise.resolve(lastSelection); + String selected = lastSelection; + lastSelection = null; + promise.resolve(selected); } @ReactMethod @@ -387,7 +442,7 @@ private ArrayList getEmailAppLauncherIntentsWithData (ReadableMap data) } else { // Get All installed apps that can handle email intent PackageManager packageManager = getCurrentActivity().getPackageManager(); - List emailApps = packageManager.queryIntentActivities(emailAppIntent, PackageManager.MATCH_ALL); + List emailApps = packageManager.queryIntentActivities(emailAppIntent, PackageManager.GET_META_DATA); ArrayList addedPackages = new ArrayList<>(); for (int i = 0; i < emailApps.size(); i++) { String packageName = emailApps.get(i).activityInfo.packageName; diff --git a/js/RNMailCompose.android.js b/js/RNMailCompose.android.js index cddf316..ac39da2 100644 --- a/js/RNMailCompose.android.js +++ b/js/RNMailCompose.android.js @@ -6,6 +6,9 @@ const {RNMailCompose} = NativeModules; export default { name: RNMailCompose.name, + getMailAppData() { + return RNMailCompose.getMailAppData() + }, getLastSelection() { return RNMailCompose.getLastSelection() }, From 87295ed2ddcfd4fcd7bb2634986e99e98b945b41 Mon Sep 17 00:00:00 2001 From: Florian Renner Date: Tue, 8 May 2018 15:06:30 +0200 Subject: [PATCH 11/24] Change data keys to use directly with RN components --- .../com/reactlibrary/mailcompose/RNMailComposeModule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index 70ddd07..a269218 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -326,8 +326,8 @@ public void getMailAppData(Promise promise) { // Build Map with app data WritableMap emailAppData = new WritableNativeMap(); - emailAppData.putString("id", activityInfo.packageName); - emailAppData.putString("name", packageManager.getApplicationLabel(activityInfo.applicationInfo).toString()); + emailAppData.putString("name", activityInfo.packageName); + emailAppData.putString("raw", packageManager.getApplicationLabel(activityInfo.applicationInfo).toString()); Drawable icon = packageManager.getApplicationLogo(activityInfo.applicationInfo); emailAppData.putString("icon", getBase64(icon != null ? icon : packageManager.getDefaultActivityIcon())); From 9e98fc2243d039346bae0cdd8616c1bc48839ab8 Mon Sep 17 00:00:00 2001 From: Florian Renner Date: Tue, 8 May 2018 18:08:39 +0200 Subject: [PATCH 12/24] get correct image and convert it into correct format (that supports transparency) --- .../com/reactlibrary/mailcompose/RNMailComposeModule.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index a269218..2d131ea 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -328,7 +328,8 @@ public void getMailAppData(Promise promise) { WritableMap emailAppData = new WritableNativeMap(); emailAppData.putString("name", activityInfo.packageName); emailAppData.putString("raw", packageManager.getApplicationLabel(activityInfo.applicationInfo).toString()); - Drawable icon = packageManager.getApplicationLogo(activityInfo.applicationInfo); + + Drawable icon = packageManager.getApplicationIcon(activityInfo.applicationInfo); emailAppData.putString("icon", getBase64(icon != null ? icon : packageManager.getDefaultActivityIcon())); // Add to array @@ -341,7 +342,7 @@ public void getMailAppData(Promise promise) { private String getBase64(Drawable icon) { BitmapDrawable drawable = (BitmapDrawable) icon; Bitmap bitmap = drawable.getBitmap(); - return encodeToBase64(bitmap, Bitmap.CompressFormat.JPEG, 100); + return encodeToBase64(bitmap, Bitmap.CompressFormat.PNG, 100); } private String encodeToBase64(Bitmap image, Bitmap.CompressFormat compressFormat, int quality) { From 7850cbf61e3e4a18bfeebe1565025984393a2e11 Mon Sep 17 00:00:00 2001 From: Florian Renner Date: Tue, 8 May 2018 19:31:07 +0200 Subject: [PATCH 13/24] Check if mail app with packageName exists on device --- .../mailcompose/RNMailComposeModule.java | 17 +++++++++++++++++ js/RNMailCompose.android.js | 3 +++ 2 files changed, 20 insertions(+) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index 2d131ea..1574583 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -307,6 +307,23 @@ public void onReceive(Context context, Intent intent) { } } + @ReactMethod + public void hasMailApp(String appName, Promise promise) { + + // Get App infos + Intent emailAppIntent = getEmailAppIntent(); + List emailAppInfos = getCurrentActivity().getPackageManager().queryIntentActivities(emailAppIntent, PackageManager.MATCH_ALL); + + for (int i = 0; i < emailAppInfos.size(); i++) { + String packageName = emailAppInfos.get(i).activityInfo.packageName; + if (packageName.equals(appName)) { + promise.resolve(true); + return; + } + } + promise.resolve(false); + } + @ReactMethod public void getMailAppData(Promise promise) { diff --git a/js/RNMailCompose.android.js b/js/RNMailCompose.android.js index ac39da2..de6f4eb 100644 --- a/js/RNMailCompose.android.js +++ b/js/RNMailCompose.android.js @@ -6,6 +6,9 @@ const {RNMailCompose} = NativeModules; export default { name: RNMailCompose.name, + hasMailApp(appName) { + return RNMailCompose.hasMailApp(appName) + }, getMailAppData() { return RNMailCompose.getMailAppData() }, From c2e4f4e13bbb5b80b43df31731c3af185180d826 Mon Sep 17 00:00:00 2001 From: Florian Renner Date: Fri, 15 Jun 2018 11:15:15 +0200 Subject: [PATCH 14/24] Fix for pre LOLLYPOP devices --- .../com/reactlibrary/mailcompose/RNMailComposeModule.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index 1574583..0160a83 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -391,7 +391,12 @@ public void send(ReadableMap data, Promise promise) { } // Create chooser - Intent chooserIntent = Intent.createChooser(new Intent(), "Select email app:", getIntentSender()); //TODO: handle <22 API devices + Intent chooserIntent; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { + chooserIntent = Intent.createChooser(new Intent(), "Select email app:", getIntentSender()); + } else { + chooserIntent = Intent.createChooser(new Intent(), "Select email app:"); + } chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, mailIntents.toArray( new Parcelable[mailIntents.size()] )); getCurrentActivity().startActivityForResult(chooserIntent, ACTIVITY_SEND); From fb96fb169bb3b68296e9c88a37aebdba9288bfa1 Mon Sep 17 00:00:00 2001 From: csae0 Date: Fri, 15 Jun 2018 12:03:24 +0200 Subject: [PATCH 15/24] add missing import --- .../java/com/reactlibrary/mailcompose/RNMailComposeModule.java | 1 + 1 file changed, 1 insertion(+) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index 0160a83..0cbe9e2 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -22,6 +22,7 @@ import android.support.v4.content.FileProvider; import android.util.Log; import android.widget.Toast; +import android.os.Build; import com.facebook.react.bridge.ActivityEventListener; import com.facebook.react.bridge.Promise; From 2ae6522d59d12f36f95e14cc9d71167cf522f012 Mon Sep 17 00:00:00 2001 From: Martin Puza Date: Fri, 2 Nov 2018 18:36:33 +0100 Subject: [PATCH 16/24] mainqueue --- ios/RNMailCompose/RNMailCompose.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ios/RNMailCompose/RNMailCompose.swift b/ios/RNMailCompose/RNMailCompose.swift index dde58ae..f8e3202 100644 --- a/ios/RNMailCompose/RNMailCompose.swift +++ b/ios/RNMailCompose/RNMailCompose.swift @@ -116,4 +116,9 @@ class RNMailCompose: NSObject, MFMailComposeViewControllerDelegate { controller.dismiss(animated: true, completion: nil) } + + @objc + static func requiresMainQueueSetup() -> Bool { + return false + } } From 63150a172e42693e480db846446341be3a3499f9 Mon Sep 17 00:00:00 2001 From: Florian Renner Date: Thu, 24 Jan 2019 13:52:02 +0100 Subject: [PATCH 17/24] Fix bug (caused of android 8) --- ExampleApp/android/.project | 17 +++++++++++++++++ .../.settings/org.eclipse.buildship.core.prefs | 2 ++ android/.project | 17 +++++++++++++++++ .../.settings/org.eclipse.buildship.core.prefs | 2 ++ .../mailcompose/RNMailComposeModule.java | 12 ++++++++++-- 5 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 ExampleApp/android/.project create mode 100644 ExampleApp/android/.settings/org.eclipse.buildship.core.prefs create mode 100644 android/.project create mode 100644 android/.settings/org.eclipse.buildship.core.prefs diff --git a/ExampleApp/android/.project b/ExampleApp/android/.project new file mode 100644 index 0000000..0e0a1ba --- /dev/null +++ b/ExampleApp/android/.project @@ -0,0 +1,17 @@ + + + android_ + Project android_ created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/ExampleApp/android/.settings/org.eclipse.buildship.core.prefs b/ExampleApp/android/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 0000000..e889521 --- /dev/null +++ b/ExampleApp/android/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +connection.project.dir= +eclipse.preferences.version=1 diff --git a/android/.project b/android/.project new file mode 100644 index 0000000..3964dd3 --- /dev/null +++ b/android/.project @@ -0,0 +1,17 @@ + + + android + Project android created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 0000000..e889521 --- /dev/null +++ b/android/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +connection.project.dir= +eclipse.preferences.version=1 diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index 1574583..6b4a4fc 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -356,9 +356,17 @@ public void getMailAppData(Promise promise) { promise.resolve(emailAppArray); } + @NonNull + static private Bitmap getBitmapFromDrawable(@NonNull Drawable drawable) { + final Bitmap bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + final Canvas canvas = new Canvas(bmp); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + return bmp; + } + private String getBase64(Drawable icon) { - BitmapDrawable drawable = (BitmapDrawable) icon; - Bitmap bitmap = drawable.getBitmap(); + Bitmap bitmap = getBitmapFromDrawable(icon); return encodeToBase64(bitmap, Bitmap.CompressFormat.PNG, 100); } From 3cee357180e74e8ee31a0869416c9047c1831cae Mon Sep 17 00:00:00 2001 From: csae0 Date: Thu, 24 Jan 2019 14:02:08 +0100 Subject: [PATCH 18/24] add import --- .../java/com/reactlibrary/mailcompose/RNMailComposeModule.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index 1b55990..9c51731 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -53,6 +53,8 @@ import java.util.Map; import java.util.UUID; +import android.support.annotation.NonNull; + public class RNMailComposeModule extends ReactContextBaseJavaModule implements ActivityEventListener { private final ReactApplicationContext reactContext; private static final int ACTIVITY_SEND = 129382; From 73e4000204353abde51fc296e5232002127bf127 Mon Sep 17 00:00:00 2001 From: csae0 Date: Thu, 2 May 2019 15:53:40 +0200 Subject: [PATCH 19/24] change ACTIVITY_SEND to 16bit integer --- .../java/com/reactlibrary/mailcompose/RNMailComposeModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java index 9c51731..acffcc9 100644 --- a/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java +++ b/android/src/main/java/com/reactlibrary/mailcompose/RNMailComposeModule.java @@ -57,7 +57,7 @@ public class RNMailComposeModule extends ReactContextBaseJavaModule implements ActivityEventListener { private final ReactApplicationContext reactContext; - private static final int ACTIVITY_SEND = 129382; + private static final int ACTIVITY_SEND = 12938; public static String lastSelection = null; private Promise mPromise; From 84468cd7b1c267fa8cfbd586a7790787127c738e Mon Sep 17 00:00:00 2001 From: csae0 Date: Thu, 6 Feb 2020 14:59:56 +0100 Subject: [PATCH 20/24] Update react-native-mail-compose.podspec --- react-native-mail-compose.podspec | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/react-native-mail-compose.podspec b/react-native-mail-compose.podspec index 4d5be68..799ff7b 100644 --- a/react-native-mail-compose.podspec +++ b/react-native-mail-compose.podspec @@ -1,13 +1,13 @@ Pod::Spec.new do |s| - s.name = "react-native-mail-compose" - s.version = "0.0.3" - s.summary = "React Native library for composing email. Wraps MFMailComposeViewController for iOS and Intent for Android." + s.name = 'react-native-mail-compose' + s.version = '0.0.3' + s.summary = 'React Native library for composing email. Wraps MFMailComposeViewController for iOS and Intent for Android.' s.requires_arc = true s.license = 'MIT' s.homepage = 'https://github.com/joonhocho/react-native-mail-compose' - s.author = "Joon Ho Cho" - s.source = { :git => "https://github.com/joonhocho/react-native-mail-compose.git" } + s.author = 'Joon Ho Cho' + s.source = { :git => 'https://github.com/joonhocho/react-native-mail-compose.git' } s.source_files = 'ios/**/*.{h,m,swift}' - s.platform = :ios, "8.0" - s.dependency 'React/Core' + s.platform = :ios, '8.0' + s.dependency 'React' end From 60fc3946b26f2c2eb9a3a384e7baa9b1dd70d0e5 Mon Sep 17 00:00:00 2001 From: Florian Renner Date: Mon, 2 Mar 2020 16:03:02 +0100 Subject: [PATCH 21/24] fix warning --- ios/RNMailCompose/RNMailComposeBridge.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ios/RNMailCompose/RNMailComposeBridge.m b/ios/RNMailCompose/RNMailComposeBridge.m index f174ff1..2c5be95 100644 --- a/ios/RNMailCompose/RNMailComposeBridge.m +++ b/ios/RNMailCompose/RNMailComposeBridge.m @@ -21,4 +21,9 @@ @interface RCT_EXTERN_MODULE(RNMailCompose, NSObject) resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + @end From 592091182fc7dca2eea9d6432a4231cd82086848 Mon Sep 17 00:00:00 2001 From: Martin Puza Date: Tue, 2 Aug 2022 14:13:18 +0200 Subject: [PATCH 22/24] should fix crash --- ios/RNMailCompose/RNMailCompose.swift | 90 ++++++++++++++------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/ios/RNMailCompose/RNMailCompose.swift b/ios/RNMailCompose/RNMailCompose.swift index f8e3202..20f8db8 100644 --- a/ios/RNMailCompose/RNMailCompose.swift +++ b/ios/RNMailCompose/RNMailCompose.swift @@ -48,52 +48,54 @@ class RNMailCompose: NSObject, MFMailComposeViewControllerDelegate { return } - let vc = MFMailComposeViewController() - - if let value = data["subject"] as? String { - vc.setSubject(value) - } - if let value = data["toRecipients"] as? [String] { - vc.setToRecipients(value) - } - if let value = data["ccRecipients"] as? [String] { - vc.setCcRecipients(value) - } - if let value = data["bccRecipients"] as? [String] { - vc.setBccRecipients(value) - } - if let value = data["body"] as? String { - vc.setMessageBody(value, isHTML: false) - } - if let value = data["html"] as? String { - vc.setMessageBody(value, isHTML: true) - } - - if let value = data["attachments"] as? [[String: String]] { - for dict in value { - if let data = textToData(utf8: dict["text"], base64: dict["data"]), let mimeType = dict["mimeType"], let filename = toFilename(filename: dict["filename"], ext: dict["ext"]) { - vc.addAttachmentData(data, mimeType: mimeType, fileName: filename) - } - if let url = dict["url"], let mimeType = dict["mimeType"], let filename = toFilename(filename: dict["filename"], ext: dict["ext"]) { - do { - try vc.addAttachmentData(Data(contentsOf: URL(fileURLWithPath: url)), mimeType: mimeType, fileName: filename) - } catch let error { - reject("fileNotFound", "File not found", error) - } + DispatchQueue.main.async { + let vc = MFMailComposeViewController() + + if let value = data["subject"] as? String { + vc.setSubject(value) + } + if let value = data["toRecipients"] as? [String] { + vc.setToRecipients(value) + } + if let value = data["ccRecipients"] as? [String] { + vc.setCcRecipients(value) + } + if let value = data["bccRecipients"] as? [String] { + vc.setBccRecipients(value) + } + if let value = data["body"] as? String { + vc.setMessageBody(value, isHTML: false) + } + if let value = data["html"] as? String { + vc.setMessageBody(value, isHTML: true) + } + + if let value = data["attachments"] as? [[String: String]] { + for dict in value { + if let data = textToData(utf8: dict["text"], base64: dict["data"]), let mimeType = dict["mimeType"], let filename = toFilename(filename: dict["filename"], ext: dict["ext"]) { + vc.addAttachmentData(data, mimeType: mimeType, fileName: filename) + } + if let url = dict["url"], let mimeType = dict["mimeType"], let filename = toFilename(filename: dict["filename"], ext: dict["ext"]) { + do { + try vc.addAttachmentData(Data(contentsOf: URL(fileURLWithPath: url)), mimeType: mimeType, fileName: filename) + } catch let error { + reject("fileNotFound", "File not found", error) + } + } } } + + vc.mailComposeDelegate = self + + self.resolve = resolve + self.reject = reject + + var rootVC = UIApplication.shared.keyWindow?.rootViewController; + while (rootVC?.presentedViewController != nil) { + rootVC = rootVC?.presentedViewController; + } + rootVC?.present(vc, animated: true, completion: nil) } - - vc.mailComposeDelegate = self - - self.resolve = resolve - self.reject = reject - - var rootVC = UIApplication.shared.keyWindow?.rootViewController; - while (rootVC?.presentedViewController != nil) { - rootVC = rootVC?.presentedViewController; - } - rootVC?.present(vc, animated: true, completion: nil) } func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { @@ -119,6 +121,6 @@ class RNMailCompose: NSObject, MFMailComposeViewControllerDelegate { @objc static func requiresMainQueueSetup() -> Bool { - return false + return true } } From 857fbd74cde7178b6231ec31782d65a709317ec6 Mon Sep 17 00:00:00 2001 From: Martin Puza Date: Tue, 2 Aug 2022 14:58:35 +0200 Subject: [PATCH 23/24] added self. reference --- ios/RNMailCompose/RNMailCompose.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/RNMailCompose/RNMailCompose.swift b/ios/RNMailCompose/RNMailCompose.swift index 20f8db8..6008ae2 100644 --- a/ios/RNMailCompose/RNMailCompose.swift +++ b/ios/RNMailCompose/RNMailCompose.swift @@ -72,10 +72,10 @@ class RNMailCompose: NSObject, MFMailComposeViewControllerDelegate { if let value = data["attachments"] as? [[String: String]] { for dict in value { - if let data = textToData(utf8: dict["text"], base64: dict["data"]), let mimeType = dict["mimeType"], let filename = toFilename(filename: dict["filename"], ext: dict["ext"]) { + if let data = self.textToData(utf8: dict["text"], base64: dict["data"]), let mimeType = dict["mimeType"], let filename = toFilename(filename: dict["filename"], ext: dict["ext"]) { vc.addAttachmentData(data, mimeType: mimeType, fileName: filename) } - if let url = dict["url"], let mimeType = dict["mimeType"], let filename = toFilename(filename: dict["filename"], ext: dict["ext"]) { + if let url = dict["url"], let mimeType = dict["mimeType"], let filename = self.toFilename(filename: dict["filename"], ext: dict["ext"]) { do { try vc.addAttachmentData(Data(contentsOf: URL(fileURLWithPath: url)), mimeType: mimeType, fileName: filename) } catch let error { From 41e239fc615b8989c021961957044a110eb21ff8 Mon Sep 17 00:00:00 2001 From: Martin Puza Date: Tue, 2 Aug 2022 14:59:19 +0200 Subject: [PATCH 24/24] added self. reference 2 --- ios/RNMailCompose/RNMailCompose.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RNMailCompose/RNMailCompose.swift b/ios/RNMailCompose/RNMailCompose.swift index 6008ae2..2aa36c6 100644 --- a/ios/RNMailCompose/RNMailCompose.swift +++ b/ios/RNMailCompose/RNMailCompose.swift @@ -72,7 +72,7 @@ class RNMailCompose: NSObject, MFMailComposeViewControllerDelegate { if let value = data["attachments"] as? [[String: String]] { for dict in value { - if let data = self.textToData(utf8: dict["text"], base64: dict["data"]), let mimeType = dict["mimeType"], let filename = toFilename(filename: dict["filename"], ext: dict["ext"]) { + if let data = self.textToData(utf8: dict["text"], base64: dict["data"]), let mimeType = dict["mimeType"], let filename = self.toFilename(filename: dict["filename"], ext: dict["ext"]) { vc.addAttachmentData(data, mimeType: mimeType, fileName: filename) } if let url = dict["url"], let mimeType = dict["mimeType"], let filename = self.toFilename(filename: dict["filename"], ext: dict["ext"]) {