Skip to content

Commit

Permalink
Add getEmailClients method for iOS and Android, make openComposer
Browse files Browse the repository at this point in the history
with predefined app work on both platforms, update TS declarations
  • Loading branch information
danielmark0116 committed Jan 12, 2024
1 parent 937180a commit a2bf9fa
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableNativeArray;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -27,6 +29,23 @@ public String getName() {
return "Email";
}

@ReactMethod
public void getEmailClients(final Promise promise) {
Intent emailIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("mailto:"));
PackageManager pm = getCurrentActivity().getPackageManager();
List<ResolveInfo> resInfo = pm.queryIntentActivities(emailIntent, 0);
if (resInfo.size() > 0) {
WritableArray emailApps = new WritableNativeArray();
for (ResolveInfo ri : resInfo) {
String packageName = ri.activityInfo.packageName;
emailApps.pushString(packageName);
}
promise.resolve(emailApps);
} else {
promise.reject("NoEmailAppsAvailable", "No email apps available");
}
}

@ReactMethod
public void open(final String title, final boolean newTask, final Promise promise) {
Intent emailIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("mailto:"));
Expand Down Expand Up @@ -68,6 +87,34 @@ public void open(final String title, final boolean newTask, final Promise promis
}
}

@ReactMethod
public void composeWith(String packageName, final String title, final String to, final String subject, final String body, final String cc, final String bcc, final Promise promise) {
Intent launchIntent = new Intent(Intent.ACTION_SENDTO);
launchIntent.setPackage(packageName);

String uriText = "mailto:" + Uri.encode(to) +
"?subject=" + Uri.encode(subject) +
"&body=" + Uri.encode(body);
if(cc != null) {
uriText += "&cc=" + Uri.encode(cc);
}
if(bcc != null) {
uriText += "&bcc=" + Uri.encode(bcc);
}

Uri uri = Uri.parse(uriText);

launchIntent.setData(uri);
launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

if (launchIntent.resolveActivity(getCurrentActivity().getPackageManager()) != null) {
getCurrentActivity().startActivity(launchIntent);
promise.resolve("Success");
} else {
promise.reject("AppNotFound", "Application not found");
}
}

@ReactMethod
public void compose(final String title, final String to, final String subject, final String body, final String cc, final String bcc) {
Intent send = new Intent(Intent.ACTION_SENDTO);
Expand Down
4 changes: 2 additions & 2 deletions index.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This file supports both iOS and Android.
*/

import { openInbox, openComposer } from "./src/android";
import { openInbox, openComposer, getEmailClients } from "./src/android";
import { EmailException } from "./src/email-exception";

export { EmailException, openInbox, openComposer };
export { EmailException, openInbox, openComposer, getEmailClients };
2 changes: 2 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export interface ComposeOptions extends InboxOptions {
body?: string;
}

export function getEmailClients(): Promise<string[]>;

export function openInbox({
app,
title,
Expand Down
4 changes: 2 additions & 2 deletions index.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This file supports both iOS and Android.
*/

import { openInbox, openComposer } from "./src/ios";
import { openInbox, openComposer, getEmailClients } from "./src/ios";
import { EmailException } from "./src/email-exception";

export { EmailException, openInbox, openComposer };
export { EmailException, openInbox, openComposer, getEmailClients };
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Placeholder file so that Expo plugin module resolution works

import { openInbox, openComposer } from "./src/ios";
import { openInbox, openComposer, getEmailClients } from "./src/ios";
import { EmailException } from "./src/email-exception";

export { EmailException, openInbox, openComposer };
export { EmailException, openInbox, openComposer, getEmailClients };
36 changes: 36 additions & 0 deletions src/android.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
import { NativeModules } from "react-native";
import { EmailException } from "./email-exception";

/**
* Get available email clients
* iOS -> returns a list of app names, e.g. ['apple-mail', 'gmail', 'outlook']
* Android -> returns a list of app package names, e.g. ['com.google.android.gm', 'com.microsoft.office.outlook']
* @returns {Promise<string[]>}
*/
export async function getEmailClients() {
if (!("Email" in NativeModules)) {
throw new EmailException(
"NativeModules.Email does not exist. Check if you installed the Android dependencies correctly."
);
}

try {
return NativeModules.Email.getEmailClients();
} catch (error) {
if (error.code === "NoEmailAppsAvailable") {
throw new EmailException("No email apps available");
}
}
}

/**
* Open an email app, or let the user choose what app to open.
*
Expand Down Expand Up @@ -39,6 +61,8 @@ export async function openInbox(options = {}) {

/**
* Open an email app on the compose screen, or let the user choose what app to open on the compose screen.
* Android - app should be a package name, e.g. 'com.google.android.gm' (use getEmailClients() to get a list of available clients)
* iOS - app should be an app name, e.g. 'gmail' (use getEmailClients() to get a list of available clients)
*
* @param {{
* title: string,
Expand All @@ -62,6 +86,18 @@ export async function openComposer(options = {}) {
body = encodeURIComponent(body);
}

if (options.app) {
return NativeModules.Email.composeWith(
options.app,
text,
options.to,
options.subject || "",
body,
options.cc,
options.bcc
);
}

return NativeModules.Email.compose(
text,
options.to,
Expand Down
26 changes: 26 additions & 0 deletions src/ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,30 @@ async function getApp(options, actionType) {
return app;
}

/**
* Get available email clients
* iOS -> returns a list of app names, e.g. ['apple-mail', 'gmail', 'outlook']
* Android -> returns a list of app package names, e.g. ['com.google.android.gm', 'com.microsoft.office.outlook']
* @returns {Promise<string[]>}
*/
export function getEmailClients() {
return new Promise(async (resolve, reject) => {
let availableApps = [];
for (let app in prefixes) {
let avail = await isAppInstalled(app);
if (avail) {
availableApps.push(app);
}
}

if (availableApps.length === 0) {
return reject(new EmailException("No email apps available"));
}

return resolve(availableApps);
});
}

/**
* Open an email app, or let the user choose what app to open.
*
Expand All @@ -300,6 +324,8 @@ export async function openInbox(options = {}) {

/**
* Open an email app on the compose screen, or let the user choose what app to open on the compose screen.
* Android - app should be a package name, e.g. 'com.google.android.gm' (use getEmailClients() to get a list of available clients)
* iOS - app should be an app name, e.g. 'gmail' (use getEmailClients() to get a list of available clients)
*
* @param {{
* app: string | undefined | null,
Expand Down

0 comments on commit a2bf9fa

Please sign in to comment.