diff --git a/package.json b/package.json new file mode 100644 index 0000000..439c4eb --- /dev/null +++ b/package.json @@ -0,0 +1,40 @@ +{ + "name": "cordova-sms-plugin", + "version": "0.1.11", + "description": "Cross-platform plugin for Cordova / PhoneGap to to easily send SMS. Available for Android, iOS and WP.", + "cordova": { + "id": "cordova-sms-plugin", + "platforms": [ + "android", + "wp8", + "ios", + "windows" + ] + }, + "repository": { + "type": "git", + "url": "git+https://github.com/cordova-sms/cordova-sms-plugin.git" + }, + "keywords": [ + "cordova", + "phonegap", + "sms", + "ecosystem:cordova", + "cordova-android", + "cordova-wp8", + "cordova-ios", + "cordova-windows" + ], + "engines": [ + { + "name": "cordova", + "version": ">=3.0.0" + } + ], + "author": "Didier Baquier", + "license": "MIT", + "bugs": { + "url": "https://github.com/cordova-sms/cordova-sms-plugin/issues" + }, + "homepage": "https://github.com/cordova-sms/cordova-sms-plugin#readme" +} diff --git a/plugin.xml b/plugin.xml index b8a0c98..f569f7f 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,8 +1,8 @@ + id="org.apache.cordova.plugin.sms" + version="0.1.2"> Sms Cordova SMS Send Plugin MIT @@ -10,7 +10,7 @@ - + @@ -20,7 +20,7 @@ - + @@ -30,9 +30,10 @@ - + + @@ -54,4 +55,11 @@ + + + + + + + diff --git a/readme.md b/readme.md index e9999fe..b2dbdc2 100644 --- a/readme.md +++ b/readme.md @@ -1,12 +1,14 @@ #Cordova SMS Plugin -Cross-platform plugin for Cordova / PhoneGap to to easily send SMS. Available for **Android**, **iOS**, and **Windows Phone 8**. - -This plugin works with Cordova 3.x and 4.x version. +Cross-platform plugin for Cordova / PhoneGap to to easily send SMS. Available for **Android**, **iOS**, **Windows Phone 8** and **Windows 10 Universal (BETA)**. ##Installing the plugin -Using the Cordova CLI, run: +Using the Cordova CLI and NPM, run: + + cordova plugin add cordova-sms-plugin + +It is also possible to install via repo url directly (unstable), run : cordova plugin add https://github.com/cordova-sms/cordova-sms-plugin.git @@ -23,11 +25,11 @@ Javascript sendSms: function() { var number = document.getElementById('numberTxt').value; var message = document.getElementById('messageTxt').value; - alert(number); - alert(message); + console.log("number=" + number + ", message= " + message); //CONFIGURATION var options = { + replaceLineBreaks: false, // true to replace \n by a new line, false by default android: { intent: 'INTENT' // send SMS with the native android SMS messaging //intent: '' // send SMS without open any other app @@ -40,9 +42,48 @@ Javascript } }; +On Android, an extra function is exposed to know whether or not you have the permission to send a SMS (Android Marshmallow permission). + + var app = { + checkSMSPermission: function() { + var success = function (hasPermission) { + if (hasPermission) { + sms.send(...); + } + else { + // show a helpful message to explain why you need to require the permission to send a SMS + // read http://developer.android.com/training/permissions/requesting.html#explain for more best practices + } + }; + var error = function (e) { alert('Something went wrong:' + e); }; + sms.hasPermission(success, error); + } + }; + ##FAQ +####`sms` is undefined + +Please go through all the [closed issues about this subject](https://github.com/cordova-sms/cordova-sms-plugin/issues?q=is%3Aissue+is%3Aclosed+sms+label%3A%22sms+undefined%22). The issue is mostly coming from the way you installed the plugin, please double check everything before opening another issue. + +####When building my project for android I get the following error: `cannot find symbol: cordova.hasPermission(string)` + +You need to update `cordova-android` to the latest version (recommended), or at least to the version 5.1.1. + +`cordova platform update android` or `cordova platform update android@5.1.1` + +####Is the plugin available on [Adobe PhoneGap Build](https://build.phonegap.com)? + +Yes, the plugin is available, please see instructions here: http://docs.phonegap.com/phonegap-build/configuring/plugins/. Use the npm or github source. + +####How can I receive SMS? + +You can't receive SMS via this plugin. This plugin only sends SMS. + +####Android immediately passes success back to app? + +Please read [#issue 26](https://github.com/cordova-sms/cordova-sms-plugin/issues/26) -###I get this error. What's wrong? +####I get this error. What's wrong? compile: [javac] Compiling 4 source files to /Users/username/MyProject/platforms/android/bin/classes @@ -69,7 +110,7 @@ The problem is that you need to make sure that you set the target to android-19 target=android-19 -#### How can I send an sms in my iOS app without passing control to the native app like it can be done on Android? +##### How can I send an sms in my iOS app without passing control to the native app like it can be done on Android? This isn't possible on iOS. It requires that you show the user the native sms composer, to be able to send an sms. diff --git a/src/android/Sms.java b/src/android/Sms.java index 0f4ae8a..079966e 100644 --- a/src/android/Sms.java +++ b/src/android/Sms.java @@ -1,4 +1,4 @@ -package org.apache.cordova.plugin.sms; +package com.cordova.plugins.sms; import android.annotation.SuppressLint; import android.app.Activity; @@ -20,38 +20,96 @@ import org.json.JSONException; public class Sms extends CordovaPlugin { + public final String ACTION_SEND_SMS = "send"; + + public final String ACTION_HAS_PERMISSION = "has_permission"; + private static final String INTENT_FILTER_SMS_SENT = "SMS_SENT"; - @Override - public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException { + private static final int SEND_SMS_REQ_CODE = 0; - if (action.equals(ACTION_SEND_SMS)) { - try { - String phoneNumber = args.getJSONArray(0).join(";").replace("\"", ""); - String message = args.getString(1); - String method = args.getString(2); - - if (!checkSupport()) { - callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, "SMS not supported on this platform")); - return true; - } + private CallbackContext callbackContext; - if (method.equalsIgnoreCase("INTENT")) { - invokeSMSIntent(phoneNumber, message); - // always passes success back to the app - callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK)); - } else { - send(callbackContext, phoneNumber, message); - } - return true; - } catch (JSONException ex) { - callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION)); + private JSONArray args; + + @Override + public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException { + this.callbackContext = callbackContext; + this.args = args; + if (action.equals(ACTION_SEND_SMS)) { + if (hasPermission()) { + sendSMS(); + } else { + requestPermission(); } + return true; + } + else if (action.equals(ACTION_HAS_PERMISSION)) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, hasPermission())); + return true; } return false; } + private boolean hasPermission() { + return cordova.hasPermission(android.Manifest.permission.SEND_SMS); + } + + private void requestPermission() { + cordova.requestPermission(this, SEND_SMS_REQ_CODE, android.Manifest.permission.SEND_SMS); + } + + public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException { + for (int r : grantResults) { + if (r == PackageManager.PERMISSION_DENIED) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, "User has denied permission")); + return; + } + } + sendSMS(); + } + + private boolean sendSMS() { + cordova.getThreadPool().execute(new Runnable() { + @Override + public void run() { + try { + //parsing arguments + String separator = ";"; + if (android.os.Build.MANUFACTURER.equalsIgnoreCase("Samsung")) { + // See http://stackoverflow.com/questions/18974898/send-sms-through-intent-to-multiple-phone-numbers/18975676#18975676 + separator = ","; + } + String phoneNumber = args.getJSONArray(0).join(separator).replace("\"", ""); + String message = args.getString(1); + String method = args.getString(2); + boolean replaceLineBreaks = Boolean.parseBoolean(args.getString(3)); + + // replacing \n by new line if the parameter replaceLineBreaks is set to true + if (replaceLineBreaks) { + message = message.replace("\\n", System.getProperty("line.separator")); + } + if (!checkSupport()) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, "SMS not supported on this platform")); + return; + } + if (method.equalsIgnoreCase("INTENT")) { + invokeSMSIntent(phoneNumber, message); + // always passes success back to the app + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK)); + } else { + send(callbackContext, phoneNumber, message); + } + return; + } catch (JSONException ex) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION)); + } + } + }); + return true; + } + private boolean checkSupport() { Activity ctx = this.cordova.getActivity(); return ctx.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY); @@ -72,8 +130,10 @@ private void invokeSMSIntent(String phoneNumber, String message) { } } else { sendIntent = new Intent(Intent.ACTION_VIEW); - sendIntent.setData(Uri.parse("smsto:" + Uri.encode(phoneNumber))); 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))); } this.cordova.getActivity().startActivity(sendIntent); } @@ -82,9 +142,9 @@ private void send(final CallbackContext callbackContext, String phoneNumber, Str SmsManager manager = SmsManager.getDefault(); final ArrayList parts = manager.divideMessage(message); - // by creating this broadcast receiver we can check whether or not the SMS was sent + // by creating this broadcast receiver we can check whether or not the SMS was sent final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { - + boolean anyError = false; //use to detect if one of the parts failed int partsCount = parts.size(); //number of parts to send @@ -132,4 +192,4 @@ public void onReceive(Context context, Intent intent) { manager.sendTextMessage(phoneNumber, null, message, sentIntent, null); } } -} \ No newline at end of file +} diff --git a/src/ios/Sms.m b/src/ios/Sms.m index 53b32fc..7328f3e 100644 --- a/src/ios/Sms.m +++ b/src/ios/Sms.m @@ -1,47 +1,50 @@ #import "Sms.h" -#import @implementation Sms @synthesize callbackID; -- (CDVPlugin *)initWithWebView:(UIWebView *)theWebView { - self = (Sms *)[super initWithWebView:theWebView]; - return self; -} - - (void)send:(CDVInvokedUrlCommand*)command { - - self.callbackID = command.callbackId; - - if(![MFMessageComposeViewController canSendText]) { - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Notice" - message:@"SMS Text not available." - delegate:self - cancelButtonTitle:@"OK" - otherButtonTitles:nil - ]; - [alert show]; - return; - } - - MFMessageComposeViewController *composeViewController = [[MFMessageComposeViewController alloc] init]; - composeViewController.messageComposeDelegate = self; - - NSString* body = [command.arguments objectAtIndex:1]; - if (body != nil) { - [composeViewController setBody:body]; - } - - NSMutableArray* recipients = [command.arguments objectAtIndex:0]; - if (recipients != nil) { - if ([recipients.firstObject isEqual: @""]) { - [recipients replaceObjectAtIndex:0 withObject:@"?"]; + [self.commandDelegate runInBackground:^{ + self.callbackID = command.callbackId; + + if(![MFMessageComposeViewController canSendText]) { + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Notice" + message:@"SMS Text not available." + delegate:self + cancelButtonTitle:@"OK" + otherButtonTitles:nil + ]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [alert show]; + }); + return; } - [composeViewController setRecipients:recipients]; - } - - [self.viewController presentViewController:composeViewController animated:YES completion:nil]; + MFMessageComposeViewController *composeViewController = [[MFMessageComposeViewController alloc] init]; + composeViewController.messageComposeDelegate = self; + + NSString* body = [command.arguments objectAtIndex:1]; + if (body != nil) { + BOOL replaceLineBreaks = [[command.arguments objectAtIndex:3] boolValue]; + if (replaceLineBreaks) { + body = [body stringByReplacingOccurrencesOfString: @"\\n" withString: @"\n"]; + } + [composeViewController setBody:body]; + } + + NSMutableArray* recipients = [command.arguments objectAtIndex:0]; + if (recipients != nil) { + if ([recipients.firstObject isEqual: @""]) { + [recipients replaceObjectAtIndex:0 withObject:@"?"]; + } + + [composeViewController setRecipients:recipients]; + } + dispatch_async(dispatch_get_main_queue(), ^{ + [self.viewController presentViewController:composeViewController animated:YES completion:nil]; + }); + }]; } #pragma mark - MFMessageComposeViewControllerDelegate Implementation diff --git a/src/windows/SmsProxy.js b/src/windows/SmsProxy.js new file mode 100644 index 0000000..417dae9 --- /dev/null +++ b/src/windows/SmsProxy.js @@ -0,0 +1,13 @@ +module.exports = { + + send: function (win, fail, args) { + + var chatMessage = new Windows.ApplicationModel.Chat.ChatMessage(); + chatMessage.body = args[1]; + chatMessage.recipients.push(args[0]); + Windows.ApplicationModel.Chat.ChatMessageManager.showComposeSmsMessageAsync(chatMessage).done(win, fail); + + } +}; + +require("cordova/exec/proxy").add("Sms", module.exports); diff --git a/src/wp8/Sms.cs b/src/wp8/Sms.cs index 12b253a..d9065e4 100644 --- a/src/wp8/Sms.cs +++ b/src/wp8/Sms.cs @@ -11,7 +11,8 @@ public class Sms : BaseCommand public void send(string options) { string[] optValues = JsonHelper.Deserialize(options); - String number = optValues[0]; + string[] numValues = JsonHelper.Deserialize(optValues[0]); + String number = String.Join(",", numValues); String message = optValues[1]; SmsComposeTask task = new SmsComposeTask(); @@ -20,4 +21,4 @@ public void send(string options) task.Show(); } } -} \ No newline at end of file +} diff --git a/www/sms.js b/www/sms.js index 59d94e4..af851b0 100644 --- a/www/sms.js +++ b/www/sms.js @@ -20,12 +20,14 @@ sms.send = function(phone, message, options, success, failure) { phone = convertPhoneToArray(phone); // parsing options + var replaceLineBreaks = false; var androidIntent = ''; 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; } else if (typeof options === 'object') { + replaceLineBreaks = options.replaceLineBreaks || false; if (options.android && typeof options.android === 'object') { androidIntent = options.android.intent; } @@ -36,9 +38,18 @@ sms.send = function(phone, message, options, success, failure) { success, failure, 'Sms', - 'send', [phone, message, androidIntent] + 'send', [phone, message, androidIntent, replaceLineBreaks] ); }; +sms.hasPermission = function(success, failure) { + // fire + exec( + success, + failure, + 'Sms', + 'has_permission', [] + ); +}; module.exports = sms; \ No newline at end of file