├── .gitignore ├── README.md ├── android ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── rhaker │ └── reactnativesmsandroid │ ├── RNSmsAndroidModule.java │ └── RNSmsAndroidPackage.java ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## react-native-sms-android 2 | 3 | This is a react native module that sends a sms message to a phone number. There are two options for sending a sms: 1) directly inside the app or 2) outside the app by launching the default sms application. This is for android only. 4 | 5 | For ios, you can use the LinkingIOS component which is part of the core. 6 | 7 | To get a contact's phone number, you can use my react-native-select-contact-android module. 8 | 9 | ## Installation 10 | 11 | ```js 12 | npm install react-native-sms-android --save 13 | ``` 14 | 15 | ## Usage Example 16 | 17 | ```js 18 | var SmsAndroid = require('react-native-sms-android'); 19 | 20 | SmsAndroid.sms( 21 | '123456789', // phone number to send sms to 22 | 'This is the sms text', // sms body 23 | 'sendDirect', // sendDirect or sendIndirect 24 | (err, message) => { 25 | if (err){ 26 | console.log("error"); 27 | } else { 28 | console.log(message); // callback message 29 | } 30 | } 31 | ); 32 | 33 | /* List SMS messages matching the filter */ 34 | var filter = { 35 | box: 'inbox', // 'inbox' (default), 'sent', 'draft', 'outbox', 'failed', 'queued', and '' for all 36 | // the next 4 filters should NOT be used together, they are OR-ed so pick one 37 | read: 0, // 0 for unread SMS, 1 for SMS already read 38 | _id: 1234, // specify the msg id 39 | address: '+97433------', // sender's phone number 40 | body: 'Hello', // content to match 41 | // the next 2 filters can be used for pagination 42 | indexFrom: 0, // start from index 0 43 | maxCount: 10, // count of SMS to return each time 44 | }; 45 | 46 | SmsAndroid.list(JSON.stringify(filter), (fail) => { 47 | console.log("OH Snap: " + fail) 48 | }, 49 | (count, smsList) => { 50 | console.log('Count: ', count); 51 | console.log('List: ', smsList); 52 | var arr = JSON.parse(smsList); 53 | for (var i = 0; i < arr.length; i++) { 54 | var obj = arr[i]; 55 | console.log("Index: " + i); 56 | console.log("-->" + obj.date); 57 | console.log("-->" + obj.body); 58 | } 59 | }); 60 | 61 | ``` 62 | 63 | ## Getting Started - Android 64 | * In `android/setting.gradle` 65 | ```gradle 66 | ... 67 | include ':react-native-sms-android' 68 | project(':react-native-sms-android').projectDir = new File(settingsDir, '../node_modules/react-native-sms-android/android') 69 | ``` 70 | 71 | * In `android/app/build.gradle` 72 | ```gradle 73 | ... 74 | dependencies { 75 | ... 76 | compile project(':react-native-sms-android') 77 | } 78 | ``` 79 | 80 | * If using RN < 0.29, register module (in android/app/src/main/java/[your-app-namespace]/MainActivity.java) 81 | ```java 82 | import com.rhaker.reactnativesmsandroid.RNSmsAndroidPackage; // <------ add import 83 | 84 | public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { 85 | ...... 86 | 87 | private ReactRootView mReactRootView; 88 | private RNSmsAndroidPackage mRNSmsAndroidPackage; // <------ add package 89 | ...... 90 | 91 | mRNSmsAndroidPackage = new RNSmsAndroidPackage(this); // <------ add package 92 | mReactRootView = new ReactRootView(this); 93 | 94 | mReactInstanceManager = ReactInstanceManager.builder() 95 | .setApplication(getApplication()) 96 | .setBundleAssetName("index.android.bundle") 97 | .setJSMainModuleName("index.android") 98 | .addPackage(new MainReactPackage()) 99 | .addPackage(mRNSmsAndroidPackage) // <------ add package 100 | .setUseDeveloperSupport(BuildConfig.DEBUG) 101 | .setInitialLifecycleState(LifecycleState.RESUMED) 102 | .build(); 103 | ...... 104 | 105 | mReactInstanceManager.onResume(this); 106 | } 107 | } 108 | 109 | } 110 | ``` 111 | 112 | If using RN 0.29+, register module (in android/app/src/main/java/[your-app-namespace]/MainApplication.java) 113 | ``` java 114 | // ... 115 | import com.rhaker.reactnativesmsandroid.RNSmsAndroidPackage; // <-- 116 | 117 | public class MainApplication extends Application implements ReactApplication { 118 | 119 | private final ReactNativeHost reactNativeHost = new ReactNativeHost(this) { 120 | 121 | // ... 122 | 123 | @Override 124 | protected List getPackages() { 125 | return Arrays.asList( 126 | new RNSmsAndroidPackage(), // <-- 127 | // ... 128 | ); 129 | } 130 | }; 131 | } 132 | 133 | // ... 134 | } 135 | ``` 136 | 137 | * add Sms permission if you're sending SMS using the ```sendDirect``` method (in android/app/src/main/AndroidManifest.xml) 138 | ```xml 139 | ... 140 | 141 | 142 | ... 143 | ``` 144 | ## Additional Notes 145 | 146 | You should parse the phone number for digits only for best results. And the text message should be kept as short as possible to prevent truncation. 147 | 148 | The sendDirect option sends the text message silently from within your app. This requires android version 4.4 or higher. You must also specify a body message. If you provide invalid data, the module will default to the sendIndirect method. 149 | 150 | The sendIndirect option launches either the default sms application or the chooser. From here, the data is pre-populated in the sms message to the recipient. The user still needs to hit the send button for the sms to be sent. This occurs outside of your app. 151 | 152 | ## Acknowledgements and Special Notes 153 | 154 | - This module owes a special thanks to @lucasferreira for his react-native-send-intent module. 155 | - This module was updated for RN v0.29+ by @sharafat. 156 | - This module was updated to include a list feature by @DarrylID. 157 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:1.1.3' 8 | } 9 | } 10 | 11 | apply plugin: 'com.android.library' 12 | 13 | android { 14 | compileSdkVersion 23 15 | buildToolsVersion "23.0.1" 16 | 17 | defaultConfig { 18 | minSdkVersion 16 19 | targetSdkVersion 22 20 | versionCode 1 21 | versionName "1.0" 22 | } 23 | lintOptions { 24 | abortOnError false 25 | } 26 | } 27 | 28 | repositories { 29 | mavenCentral() 30 | } 31 | 32 | dependencies { 33 | compile 'com.facebook.react:react-native:0.19.+' 34 | } 35 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /android/src/main/java/com/rhaker/reactnativesmsandroid/RNSmsAndroidModule.java: -------------------------------------------------------------------------------- 1 | package com.rhaker.reactnativesmsandroid; 2 | 3 | import android.app.Activity; 4 | import android.app.PendingIntent; 5 | import android.content.BroadcastReceiver; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.content.IntentFilter; 9 | import android.content.pm.PackageManager; 10 | import android.net.Uri; 11 | import android.os.Build; 12 | import android.provider.Telephony; 13 | import android.telephony.SmsManager; 14 | import android.util.Log; 15 | import android.database.Cursor; 16 | 17 | import java.util.Map; 18 | import java.util.HashMap; 19 | import java.lang.SecurityException; 20 | import java.lang.String; 21 | 22 | import com.facebook.react.bridge.Callback; 23 | import com.facebook.react.bridge.NativeModule; 24 | import com.facebook.react.bridge.ReactApplicationContext; 25 | import com.facebook.react.bridge.ReactContext; 26 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 27 | import com.facebook.react.bridge.ReactMethod; 28 | 29 | import org.json.JSONArray; 30 | import org.json.JSONException; 31 | import org.json.JSONObject; 32 | 33 | public class RNSmsAndroidModule extends ReactContextBaseJavaModule { 34 | 35 | private static final String TAG = RNSmsAndroidModule.class.getSimpleName(); 36 | 37 | private ReactApplicationContext reactContext; 38 | 39 | // set the activity - pulled in from Main 40 | public RNSmsAndroidModule(ReactApplicationContext reactContext) { 41 | super(reactContext); 42 | this.reactContext = reactContext; 43 | } 44 | 45 | @Override 46 | public String getName() { 47 | return "SmsAndroid"; 48 | } 49 | 50 | @ReactMethod 51 | public void sms(String phoneNumberString, String body, String sendType, Callback callback) { 52 | 53 | // send directly if user requests and android greater than 4.4 54 | if ((sendType.equals("sendDirect")) && (body != null) && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)) { 55 | 56 | try { 57 | SmsManager smsManager = SmsManager.getDefault(); 58 | smsManager.sendTextMessage(phoneNumberString,null,body,null,null); 59 | callback.invoke(null,"success"); 60 | } 61 | 62 | catch (Exception e) { 63 | callback.invoke(null,"error"); 64 | e.printStackTrace(); 65 | } 66 | 67 | } else { 68 | 69 | // launch default sms package, user hits send 70 | Intent sendIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("sms:" + phoneNumberString.trim())); 71 | sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 72 | 73 | if (body != null) { 74 | sendIntent.putExtra("sms_body", body); 75 | } 76 | 77 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 78 | String defaultSmsPackageName = Telephony.Sms.getDefaultSmsPackage(getCurrentActivity()); 79 | if (defaultSmsPackageName != null) { 80 | sendIntent.setPackage(defaultSmsPackageName); 81 | } 82 | } 83 | 84 | try { 85 | this.reactContext.startActivity(sendIntent); 86 | callback.invoke(null,"success"); 87 | } 88 | 89 | catch (Exception e) { 90 | callback.invoke(null,"error"); 91 | e.printStackTrace(); 92 | } 93 | 94 | } 95 | 96 | } 97 | 98 | @ReactMethod 99 | public void list(String filter, final Callback errorCallback, final Callback successCallback) { 100 | try{ 101 | JSONObject filterJ = new JSONObject(filter); 102 | String uri_filter = filterJ.has("box") ? filterJ.optString("box") : "inbox"; 103 | int fread = filterJ.has("read") ? filterJ.optInt("read") : -1; 104 | int fid = filterJ.has("_id") ? filterJ.optInt("_id") : -1; 105 | String faddress = filterJ.optString("address"); 106 | String fcontent = filterJ.optString("body"); 107 | int indexFrom = filterJ.has("indexFrom") ? filterJ.optInt("indexFrom") : 0; 108 | int maxCount = filterJ.has("maxCount") ? filterJ.optInt("maxCount") : -1; 109 | Cursor cursor = getCurrentActivity().getContentResolver().query(Uri.parse("content://sms/"+uri_filter), null, "", null, null); 110 | int c = 0; 111 | JSONArray jsons = new JSONArray(); 112 | while (cursor.moveToNext()) { 113 | boolean matchFilter = false; 114 | if (fid > -1) 115 | matchFilter = fid == cursor.getInt(cursor.getColumnIndex("_id")); 116 | else if (fread > -1) 117 | matchFilter = fread == cursor.getInt(cursor.getColumnIndex("read")); 118 | else if (faddress.length() > 0) 119 | matchFilter = faddress.equals(cursor.getString(cursor.getColumnIndex("address")).trim()); 120 | else if (fcontent.length() > 0) 121 | matchFilter = fcontent.equals(cursor.getString(cursor.getColumnIndex("body")).trim()); 122 | else { 123 | matchFilter = true; 124 | } 125 | if (matchFilter) 126 | { 127 | if (c >= indexFrom) { 128 | if (maxCount>0 && c >= indexFrom + maxCount) break; 129 | c++; 130 | // Long dateTime = Long.parseLong(cursor.getString(cursor.getColumnIndex("date"))); 131 | // String message = cursor.getString(cursor.getColumnIndex("body")); 132 | JSONObject json; 133 | json = getJsonFromCursor(cursor); 134 | jsons.put(json); 135 | 136 | } 137 | } 138 | 139 | } 140 | cursor.close(); 141 | try { 142 | successCallback.invoke(c, jsons.toString()); 143 | } catch (Exception e) { 144 | errorCallback.invoke(e.getMessage()); 145 | } 146 | } catch (JSONException e) 147 | { 148 | errorCallback.invoke(e.getMessage()); 149 | return; 150 | } 151 | } 152 | 153 | private JSONObject getJsonFromCursor(Cursor cur) { 154 | JSONObject json = new JSONObject(); 155 | 156 | int nCol = cur.getColumnCount(); 157 | String[] keys = cur.getColumnNames(); 158 | try 159 | { 160 | for (int j = 0; j < nCol; j++) 161 | switch (cur.getType(j)) { 162 | case 0: 163 | json.put(keys[j], null); 164 | break; 165 | case 1: 166 | json.put(keys[j], cur.getLong(j)); 167 | break; 168 | case 2: 169 | json.put(keys[j], cur.getFloat(j)); 170 | break; 171 | case 3: 172 | json.put(keys[j], cur.getString(j)); 173 | break; 174 | case 4: 175 | json.put(keys[j], cur.getBlob(j)); 176 | } 177 | } 178 | catch (Exception e) 179 | { 180 | return null; 181 | } 182 | 183 | return json; 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /android/src/main/java/com/rhaker/reactnativesmsandroid/RNSmsAndroidPackage.java: -------------------------------------------------------------------------------- 1 | package com.rhaker.reactnativesmsandroid; 2 | 3 | import android.app.Activity; 4 | 5 | import java.util.*; 6 | 7 | import com.facebook.react.ReactPackage; 8 | import com.facebook.react.bridge.JavaScriptModule; 9 | import com.facebook.react.bridge.NativeModule; 10 | import com.facebook.react.bridge.ReactApplicationContext; 11 | import com.facebook.react.uimanager.ViewManager; 12 | 13 | public class RNSmsAndroidPackage implements ReactPackage { 14 | private RNSmsAndroidModule mModuleInstance; 15 | 16 | @Override 17 | public List createNativeModules(ReactApplicationContext reactContext) { 18 | mModuleInstance = new RNSmsAndroidModule(reactContext); 19 | return Arrays.asList(mModuleInstance); 20 | } 21 | 22 | @Override 23 | public List> createJSModules() { 24 | return Collections.emptyList(); 25 | } 26 | 27 | @Override 28 | public List createViewManagers(ReactApplicationContext reactContext) { 29 | return Collections.emptyList(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var ReactNative = require('react-native') 2 | module.exports = ReactNative.NativeModules.SmsAndroid 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-sms-android", 3 | "version": "0.4.1", 4 | "description": "A react-native module for sending a sms message to a phone number.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "react-component", 11 | "react-native", 12 | "android", 13 | "contact", 14 | "addressbook", 15 | "sms" 16 | ], 17 | "repository": { 18 | "type": "git", 19 | "url": "github.com:rhaker/react-native-sms-android.git" 20 | }, 21 | "author": "rhaker (http://github.com/rhaker)", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/rhaker/react-native-sms-android/issues" 25 | }, 26 | "homepage": "https://github.com/rhaker/react-native-sms-android", 27 | "peerDependencies": { 28 | "react-native": ">=0.19.0" 29 | }, 30 | "devDependencies": {} 31 | } 32 | --------------------------------------------------------------------------------