Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image attachments support #224

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,27 @@
<param name="android-package" value="com.cordova.plugins.sms.Sms"/>
</feature>
</config-file>


<config-file target="AndroidManifest.xml" parent="/manifest">
<uses-feature android:name="android.hardware.telephony" android:required="false" />
</config-file>
<config-file target="AndroidManifest.xml" parent="application">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.cordova.plugins.sms.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/cordova_sms_filepaths" />
</provider>
</config-file>

<source-file src="src/android/Sms.java" target-dir="src/com/cordova/plugins/sms" />
<source-file
src="src/android/xml/cordova_sms_filepaths.xml"
target-dir="res/xml" />
</platform>

<!-- wp8 -->
Expand Down
94 changes: 87 additions & 7 deletions src/android/Sms.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,26 @@
import android.os.Build;
import android.provider.Telephony;
import android.telephony.SmsManager;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import android.util.Base64;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONException;

import androidx.core.content.FileProvider;

public class Sms extends CordovaPlugin {

public final String ACTION_SEND_SMS = "send";
Expand Down Expand Up @@ -103,6 +116,11 @@ public void run() {
String message = args.getString(1);
String method = args.getString(2);
boolean replaceLineBreaks = Boolean.parseBoolean(args.getString(3));
JSONObject attachments = null;

if (!args.isNull(4)) {
attachments = args.getJSONObject(4);
}

// replacing \n by new line if the parameter replaceLineBreaks is set to true
if (replaceLineBreaks) {
Expand All @@ -113,9 +131,7 @@ public void run() {
return;
}
if (method.equalsIgnoreCase("INTENT")) {
invokeSMSIntent(phoneNumber, message);
// always passes success back to the app
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
invokeSMSIntent(phoneNumber, message, attachments);
} else {
send(callbackContext, phoneNumber, message);
}
Expand All @@ -134,25 +150,89 @@ private boolean checkSupport() {
}

@SuppressLint("NewApi")
private void invokeSMSIntent(String phoneNumber, String message) {
private void invokeSMSIntent(String phoneNumber, String message, JSONObject attachments) {
Intent sendIntent;
if ("".equals(phoneNumber) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
List<File> images = null;

if (attachments != null) {
Iterator<String> keys = attachments.keys();
while(keys.hasNext()) {
String fileName = keys.next();
String base64String;
try {
base64String = attachments.getString(fileName);
} catch (JSONException e) {
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
return;
}
byte[] imgBytes = Base64.decode(base64String, Base64.DEFAULT);

File tmpDir = cordova.getContext().getCacheDir();
File imgFile = new File(tmpDir, fileName);

try {
imgFile.createNewFile();
} catch (IOException e) {
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION));
}

try (OutputStream stream = new FileOutputStream(imgFile)) {
stream.write(imgBytes);
} catch (NullPointerException e) {
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR));
} catch (IOException e) {
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION));
}
if (images == null) {
images = new ArrayList<>();
}
images.add(imgFile);
}
}

final boolean hasImage = images != null;
final boolean hasMultipleImages = hasImage && images.size() > 1;
final boolean emptyPhoneNumber = "".equals(phoneNumber);

if ((emptyPhoneNumber || hasImage) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
String defaultSmsPackageName = Telephony.Sms.getDefaultSmsPackage(this.cordova.getActivity());

sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.setType("text/plain");
sendIntent = new Intent(hasMultipleImages ? Intent.ACTION_SEND_MULTIPLE : Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, message);

if (!emptyPhoneNumber) {
// See http://stackoverflow.com/questions/7242190/sending-sms-using-intent-does-not-add-recipients-on-some-devices
sendIntent.putExtra("address", phoneNumber);
sendIntent.setData(Uri.parse("smsto:" + Uri.encode(phoneNumber)));
}

if (defaultSmsPackageName != null) {
sendIntent.setPackage(defaultSmsPackageName);
}
sendIntent.setType( hasImage ? "image/*" : "text/plain");
} else {
sendIntent = new Intent(Intent.ACTION_VIEW);
sendIntent.putExtra("sms_body", message);
// See http://stackoverflow.com/questions/7242190/sending-sms-using-intent-does-not-add-recipients-on-some-devices
sendIntent.putExtra("address", phoneNumber);
sendIntent.setData(Uri.parse("smsto:" + Uri.encode(phoneNumber)));
}

if (hasImage) {
String FILE_AUTHORITY = cordova.getContext().getPackageName() + ".cordova.plugins.sms.fileprovider";

ArrayList<Uri> imageUris = images.stream()
.map(file -> FileProvider.getUriForFile(cordova.getContext(), FILE_AUTHORITY, file))
.collect(Collectors.toCollection(ArrayList::new));
if (hasMultipleImages) {
sendIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris);
} else {
sendIntent.putExtra(Intent.EXTRA_STREAM, imageUris.get(0));
}
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}

callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
this.cordova.getActivity().startActivity(sendIntent);
}

Expand Down
4 changes: 4 additions & 0 deletions src/android/xml/cordova_sms_filepaths.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="cache_files" path="." />
</paths>
15 changes: 15 additions & 0 deletions src/ios/Sms.m
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@ - (void)send:(CDVInvokedUrlCommand*)command {

[composeViewController setRecipients:recipients];
}

NSMutableDictionary* attachments = [command.arguments objectAtIndex:4];
if (attachments != nil && ![attachments isEqual:[NSNull null]]) {
for (NSString* filename in attachments) {
NSString* imgStr = [attachments objectForKey:filename];
NSData *data = [[NSData alloc] initWithBase64EncodedString:imgStr options:0];
UIImage *image = [UIImage imageWithData:data];
if (image != nil) {
NSData* attachment = UIImageJPEGRepresentation(image, 1.0);
[composeViewController
addAttachmentData:attachment
typeIdentifier:@"public.jpeg" filename:filename];
}
}
}
[self.viewController presentViewController:composeViewController animated:YES completion:nil];
});
}];
Expand Down
6 changes: 5 additions & 1 deletion www/sms.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ sms.send = function(phone, message, options, success, failure) {
// parsing options
var replaceLineBreaks = false;
var androidIntent = '';
var attachments = null;
if (typeof options === 'string') { // ensuring backward compatibility
window.console.warn('[DEPRECATED] Passing a string as a third argument is deprecated. Please refer to the documentation to pass the right parameter: https://github.com/cordova-sms/cordova-sms-plugin.');
androidIntent = options;
Expand All @@ -31,14 +32,17 @@ sms.send = function(phone, message, options, success, failure) {
if (options.android && typeof options.android === 'object') {
androidIntent = options.android.intent;
}
if (options.attachments) {
attachments = options.attachments;
}
}

// fire
exec(
success,
failure,
'Sms',
'send', [phone, message, androidIntent, replaceLineBreaks]
'send', [phone, message, androidIntent, replaceLineBreaks, attachments]
);
};

Expand Down