This commit is contained in:
Siddarth Kumar
2023-02-28 22:00:13 +05:30
11 changed files with 207 additions and 128 deletions
+13 -5
View File
@@ -124,12 +124,20 @@ export default class App extends Component {
ccRecipients: ['supportCC@example.com'],
bccRecipients: ['supportBCC@example.com'],
body: '<b>A Bold Body</b>',
customChooserTitle: 'This is my new title', // Android only (defaults to "Send Mail")
isHTML: true,
attachment: {
path: '', // The absolute path of the file from which to read data.
type: '', // Mime Type: jpg, png, doc, ppt, html, pdf, csv
name: '', // Optional: Custom filename for attachment
}
attachments: [{
// Specify either `path` or `uri` to indicate where to find the file data.
// The API used to create or locate the file will usually indicate which it returns.
// An absolute path will look like: /cacheDir/photos/some image.jpg
// A URI starts with a protocol and looks like: content://appname/cacheDir/photos/some%20image.jpg
path: '', // The absolute path of the file from which to read data.
uri: '', // The uri of the file from which to read the data.
// Specify either `type` or `mimeType` to indicate the type of data.
type: '', // Mime Type: jpg, png, doc, ppt, html, pdf, csv
mimeType: '', // - use only if you want to use custom type
name: '', // Optional: Custom filename for attachment
}]
}, (error, event) => {
Alert.alert(
error,
+89 -76
View File
@@ -36,108 +36,121 @@ RCT_EXPORT_METHOD(mail:(NSDictionary *)options
MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
mail.mailComposeDelegate = self;
_callbacks[RCTKeyForInstance(mail)] = callback;
if (options[@"subject"]){
NSString *subject = [RCTConvert NSString:options[@"subject"]];
[mail setSubject:subject];
}
bool *isHTML = NO;
BOOL isHTML = NO;
if (options[@"isHTML"]){
isHTML = [options[@"isHTML"] boolValue];
}
if (options[@"body"]){
NSString *body = [RCTConvert NSString:options[@"body"]];
[mail setMessageBody:body isHTML:isHTML];
}
if (options[@"recipients"]){
NSArray *recipients = [RCTConvert NSArray:options[@"recipients"]];
[mail setToRecipients:recipients];
}
if (options[@"ccRecipients"]){
NSArray *ccRecipients = [RCTConvert NSArray:options[@"ccRecipients"]];
[mail setCcRecipients:ccRecipients];
}
if (options[@"bccRecipients"]){
NSArray *bccRecipients = [RCTConvert NSArray:options[@"bccRecipients"]];
[mail setBccRecipients:bccRecipients];
}
if (options[@"attachment"] && options[@"attachment"][@"path"] && options[@"attachment"][@"type"]){
NSString *attachmentPath = [RCTConvert NSString:options[@"attachment"][@"path"]];
NSString *attachmentType = [RCTConvert NSString:options[@"attachment"][@"type"]];
NSString *attachmentName = [RCTConvert NSString:options[@"attachment"][@"name"]];
// Set default filename if not specificed
if (!attachmentName) {
attachmentName = [[attachmentPath lastPathComponent] stringByDeletingPathExtension];
if (options[@"attachments"]) {
NSArray *attachments = [RCTConvert NSArray:options[@"attachments"]];
for (NSDictionary *attachment in attachments) {
if ((attachment[@"path"] || attachment[@"uri"]) && (attachment[@"type"] || attachment[@"mimeType"])) {
NSString *attachmentPath = [RCTConvert NSString:attachment[@"path"]];
NSString *attachmentUri = [RCTConvert NSString:attachment[@"uri"]];
NSString *attachmentType = [RCTConvert NSString:attachment[@"type"]];
NSString *attachmentName = [RCTConvert NSString:attachment[@"name"]];
NSString *attachmentMimeType = [RCTConvert NSString:attachment[@"mimeType"]];
// Set default filename if not specificed
if (!attachmentName) {
attachmentName = [[attachmentPath lastPathComponent] stringByDeletingPathExtension];
}
NSData *fileData;
if (attachmentPath) {
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:attachmentPath]){
callback(@[[NSString stringWithFormat: @"attachment file with path '%@' does not exist", attachmentPath]]);
return;
}
// Get the resource path and read the file using NSData
fileData = [NSData dataWithContentsOfFile:attachmentPath];
} else if (attachmentUri) {
// Get the URI and read it using NSData
NSURL *attachmentURL = [[NSURLComponents componentsWithString:attachmentUri] URL];
NSError *error = nil;
fileData = [NSData dataWithContentsOfURL:attachmentURL options:0 error:&error];
if (!fileData) {
callback(@[[NSString stringWithFormat: @"attachment file with uri '%@' does not exist", attachmentUri]]);
return;
}
}
// Determine the MIME type
NSString *mimeType;
if (attachmentType) {
/*
* Add additional mime types and PR if necessary. Find the list
* of supported formats at http://www.iana.org/assignments/media-types/media-types.xhtml
*/
NSDictionary *supportedMimeTypes = @{
@"jpeg" : @"image/jpeg",
@"jpg" : @"image/jpeg",
@"png" : @"image/png",
@"doc" : @"application/msword",
@"docx" : @"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
@"ppt" : @"application/vnd.ms-powerpoint",
@"pptx" : @"application/vnd.openxmlformats-officedocument.presentationml.presentation",
@"html" : @"text/html",
@"csv" : @"text/csv",
@"pdf" : @"application/pdf",
@"vcard" : @"text/vcard",
@"json" : @"application/json",
@"zip" : @"application/zip",
@"text" : @"text/*",
@"mp3" : @"audio/mpeg",
@"wav" : @"audio/wav",
@"aiff" : @"audio/aiff",
@"flac" : @"audio/flac",
@"ogg" : @"audio/ogg",
@"xls" : @"application/vnd.ms-excel",
@"ics" : @"text/calendar",
@"xlsx" : @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
};
if([supportedMimeTypes objectForKey:attachmentType]) {
mimeType = [supportedMimeTypes objectForKey:attachmentType];
} else {
callback(@[[NSString stringWithFormat: @"Mime type '%@' for attachment is not handled", attachmentType]]);
return;
}
} else if (attachmentMimeType) {
mimeType = attachmentMimeType;
}
// Add attachment
[mail addAttachmentData:fileData mimeType:mimeType fileName:attachmentName];
}
}
// Get the resource path and read the file using NSData
NSData *fileData = [NSData dataWithContentsOfFile:attachmentPath];
// Determine the MIME type
NSString *mimeType;
/*
* Add additional mime types and PR if necessary. Find the list
* of supported formats at http://www.iana.org/assignments/media-types/media-types.xhtml
*/
if ([attachmentType isEqualToString:@"jpg"]) {
mimeType = @"image/jpeg";
} else if ([attachmentType isEqualToString:@"png"]) {
mimeType = @"image/png";
} else if ([attachmentType isEqualToString:@"doc"]) {
mimeType = @"application/msword";
} else if ([attachmentType isEqualToString:@"docx"]) {
mimeType = @"application/vnd.openxmlformats-officedocument.wordprocessingml.document";
} else if ([attachmentType isEqualToString:@"ppt"]) {
mimeType = @"application/vnd.ms-powerpoint";
} else if ([attachmentType isEqualToString:@"pptx"]) {
mimeType = @"application/vnd.openxmlformats-officedocument.presentationml.presentation";
} else if ([attachmentType isEqualToString:@"html"]) {
mimeType = @"text/html";
} else if ([attachmentType isEqualToString:@"csv"]) {
mimeType = @"text/csv";
} else if ([attachmentType isEqualToString:@"pdf"]) {
mimeType = @"application/pdf";
} else if ([attachmentType isEqualToString:@"vcard"]) {
mimeType = @"text/vcard";
} else if ([attachmentType isEqualToString:@"json"]) {
mimeType = @"application/json";
} else if ([attachmentType isEqualToString:@"zip"]) {
mimeType = @"application/zip";
} else if ([attachmentType isEqualToString:@"text"]) {
mimeType = @"text/*";
} else if ([attachmentType isEqualToString:@"mp3"]) {
mimeType = @"audio/mpeg";
} else if ([attachmentType isEqualToString:@"wav"]) {
mimeType = @"audio/wav";
} else if ([attachmentType isEqualToString:@"aiff"]) {
mimeType = @"audio/aiff";
} else if ([attachmentType isEqualToString:@"flac"]) {
mimeType = @"audio/flac";
} else if ([attachmentType isEqualToString:@"ogg"]) {
mimeType = @"audio/ogg";
} else if ([attachmentType isEqualToString:@"xls"]) {
mimeType = @"application/vnd.ms-excel";
} else if ([attachmentType isEqualToString:@"ics"]) {
mimeType = @"text/calendar";
} else if ([attachmentType isEqualToString:@"xlsx"]) {
mimeType = @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
}
// Add attachment
[mail addAttachmentData:fileData mimeType:mimeType fileName:attachmentName];
}
UIViewController *root = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
while (root.presentedViewController) {
root = root.presentedViewController;
}
+1 -1
View File
@@ -9,7 +9,7 @@ android {
buildToolsVersion project.hasProperty('buildToolsVersion') ? project.buildToolsVersion : "23.0.1"
defaultConfig {
minSdkVersion 16
minSdkVersion 21
targetSdkVersion project.hasProperty('targetSdkVersion') ? project.targetSdkVersion : 22
versionCode 1
versionName "1.0"
+19 -3
View File
@@ -1,4 +1,20 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.chirag.RNMail">
</manifest>
package="com.chirag.RNMail">
<queries>
<intent>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<data android:mimeType="*/*" />
</intent>
</queries>
<application>
<provider
android:name=".RNMailFileProvider"
android:authorities="${applicationId}.rnmail.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
</application>
</manifest>
@@ -0,0 +1,7 @@
package com.chirag.RNMail;
import androidx.core.content.FileProvider;
public class RNMailFileProvider extends FileProvider {
}
@@ -5,6 +5,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.text.Html;
import androidx.core.content.FileProvider;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
@@ -15,10 +16,8 @@ import com.facebook.react.bridge.Callback;
import java.util.List;
import java.io.File;
import android.app.Activity;
import android.support.v4.content.FileProvider;
import android.os.Build;
import java.net.URI;
import java.util.ArrayList;
/**
* NativeModule that allows JS to open emails sending apps chooser.
@@ -55,37 +54,11 @@ public class RNMailModule extends ReactContextBaseJavaModule {
return strArray;
}
private Intent getIntent() {
Intent i;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// https://stackoverflow.com/a/42856167
Intent emailSelectorIntent = new Intent(Intent.ACTION_SENDTO);
emailSelectorIntent.setData(Uri.parse("mailto:"));
i = new Intent(Intent.ACTION_SEND);
i.setData(Uri.parse("mailto:"));
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
i.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
i.setSelector( emailSelectorIntent );
} else {
i = new Intent(Intent.ACTION_SEND);
i.setPackage("com.google.android.gm");
}
return i;
}
private Uri getFileUri(String path) {
File file = new File(path);
file.setReadable(true, false);
final String providerName = reactContext.getPackageName() + ".provider";
final Activity activity = getCurrentActivity();
return FileProvider.getUriForFile(activity, providerName, file);
}
@ReactMethod
public void mail(ReadableMap options, Callback callback) {
Intent i = getIntent();
Intent i = new Intent(Intent.ACTION_SEND_MULTIPLE);
Intent selectorIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"));
i.setSelector(selectorIntent);
if (options.hasKey("subject") && !options.isNull("subject")) {
i.putExtra(Intent.EXTRA_SUBJECT, options.getString("subject"));
@@ -115,13 +88,40 @@ public class RNMailModule extends ReactContextBaseJavaModule {
i.putExtra(Intent.EXTRA_BCC, readableArrayToStringArray(bccRecipients));
}
if (options.hasKey("attachment") && !options.isNull("attachment")) {
ReadableMap attachment = options.getMap("attachment");
if (attachment.hasKey("path") && !attachment.isNull("path")) {
String path = attachment.getString("path");
final Uri p = getFileUri(path);
i.putExtra(Intent.EXTRA_STREAM, p);
if (options.hasKey("attachments") && !options.isNull("attachments")) {
ReadableArray r = options.getArray("attachments");
int length = r.size();
String provider = reactContext.getApplicationContext().getPackageName() + ".rnmail.provider";
List<ResolveInfo> resolvedIntentActivities = reactContext.getPackageManager().queryIntentActivities(i,
PackageManager.MATCH_DEFAULT_ONLY);
ArrayList<Uri> uris = new ArrayList<Uri>();
for (int keyIndex = 0; keyIndex < length; keyIndex++) {
ReadableMap clip = r.getMap(keyIndex);
Uri uri;
if (clip.hasKey("path") && !clip.isNull("path")) {
String path = clip.getString("path");
File file = new File(path);
uri = FileProvider.getUriForFile(reactContext, provider, file);
} else if (clip.hasKey("uri") && !clip.isNull("uri")) {
String uriPath = clip.getString("uri");
uri = Uri.parse(uriPath);
} else {
callback.invoke("not_found");
return;
}
uris.add(uri);
for (ResolveInfo resolvedIntentInfo : resolvedIntentActivities) {
String packageName = resolvedIntentInfo.activityInfo.packageName;
reactContext.grantUriPermission(packageName, uri,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
}
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
i.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
}
PackageManager manager = reactContext.getPackageManager();
@@ -140,7 +140,13 @@ public class RNMailModule extends ReactContextBaseJavaModule {
callback.invoke("error");
}
} else {
Intent chooser = Intent.createChooser(i, "Send Mail");
String chooserTitle = "Send Mail";
if (options.hasKey("customChooserTitle") && !options.isNull("customChooserTitle")) {
chooserTitle = options.getString("customChooserTitle");
}
Intent chooser = Intent.createChooser(i, chooserTitle);
chooser.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="rnmail_dl" path="Download/" />
<cache-path name="rnmail_cache" path="/" />
<root-path name="rnmail_sdcard" path="." />
</paths>
Vendored
+23
View File
@@ -0,0 +1,23 @@
export namespace Mailer {
function mail(options: {
subject?: string;
recipients?: string[];
ccRecipients?: string[];
bccRecipients?: string[];
body?: string;
customChooserTitle?: string;
isHTML?: boolean;
attachments?: {
path?: string; // Specify either 'path' or 'uri'
uri?: string;
type?: string; // Specify either 'type' or 'mimeType'
mimeType?: string;
name?: string;
}[]
}, callback: (
error: string,
event?: string
) => void): void;
}
export default Mailer;
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "react-native-mail",
"version": "3.0.7",
"version": "6.1.1",
"lockfileVersion": 1
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "react-native-mail",
"version": "3.0.7",
"version": "6.1.1",
"description": "A wrapper on top of MFMailComposeViewController from iOS and Mail Intent on android",
"author": {
"name": "Chirag Jain",
+1 -1
View File
@@ -13,6 +13,6 @@ Pod::Spec.new do |s|
s.source = { :git => "https://github.com/chirag04/react-native-mail", :tag => "v#{s.version}" }
s.source_files = 'RNMail/*.{h,m}'
s.dependency 'React'
s.dependency 'React-Core'
end