├── .gitignore ├── .npmignore ├── CancellableSubscription.js ├── LICENSE ├── README.md ├── ReceivedSmsMessage.js ├── android ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── centaurwarchief │ └── smslistener │ ├── SmsListenerModule.java │ ├── SmsListenerPackage.java │ └── SmsReceiver.java ├── build.gradle ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | gradlew 9 | gradlew.bat 10 | gradle.properties 11 | *.iml 12 | .idea 13 | ./build.gradle 14 | settings.gradle 15 | gradle/ 16 | build/ 17 | gen/ 18 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | gradle.properties 2 | gradlew 3 | local.properties 4 | react-native-android-sms-listener.iml 5 | settings.gradle 6 | android/build 7 | README.md 8 | gen/ 9 | -------------------------------------------------------------------------------- /CancellableSubscription.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | export type CancellableSubscription = { 3 | remove(): void; 4 | }; 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Andrey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## `react-native-android-sms-listener` [![react-native-android-sms-listener](https://badge.fury.io/js/react-native-android-sms-listener.svg)](https://badge.fury.io/js/react-native-android-sms-listener) 2 | 3 | A utility that allows you to listen for incoming SMS messages. 4 | 5 | ### Example 6 | 7 | ```JS 8 | import SmsListener from 'react-native-android-sms-listener' 9 | 10 | SmsListener.addListener(message => { 11 | console.info(message) 12 | }) 13 | ``` 14 | 15 | The contents of `message` object will be: 16 | 17 | ```JS 18 | { 19 | originatingAddress: string, 20 | body: string, 21 | timestamp: number 22 | } 23 | ``` 24 | 25 | `SmsListener#addListener` returns a `CancellableSubscription` so if you want to stop listening for incoming SMS messages you can simply `.remove` it: 26 | 27 | ```JS 28 | let subscription = SmsListener.addListener(...) 29 | 30 | subscription.remove() 31 | ``` 32 | 33 | In recent versions of Android you might also have to ask for permissions: 34 | 35 | ```JS 36 | async function requestReadSmsPermission() { 37 | try { 38 | await PermissionsAndroid.request( 39 | PermissionsAndroid.PERMISSIONS.READ_SMS, 40 | { 41 | title: "(...)", 42 | message: "Why you're asking for..." 43 | } 44 | ); 45 | } catch (err) {} 46 | } 47 | 48 | class MyComponent extends Component { 49 | // ... 50 | 51 | componentDidMount() { 52 | requestReadSmsPermission(); 53 | } 54 | 55 | // ... 56 | } 57 | ``` 58 | 59 | ### Example of using it for verification purposes: 60 | 61 | ...and if in your sign up process you have the phone number verification step which is done by sending a code via SMS to the specified phone, you might want to verify it automatically when the user receive it — pretty much like what Telegram or WhatsApp does: 62 | 63 | ```JS 64 | let subscription = SmsListener.addListener(message => { 65 | let verificationCodeRegex = /Your verification code: ([\d]{6})/ 66 | 67 | if (verificationCodeRegex.test(message.body)) { 68 | let verificationCode = message.body.match(verificationCodeRegex)[1] 69 | 70 | YourPhoneVerificationApi.verifyPhoneNumber( 71 | message.originatingAddress, 72 | verificationCode 73 | ).then(verifiedSuccessfully => { 74 | if (verifiedSuccessfully) { 75 | subscription.remove() 76 | return 77 | } 78 | 79 | if (__DEV__) { 80 | console.info( 81 | 'Failed to verify phone `%s` using code `%s`', 82 | message.originatingAddress, 83 | verificationCode 84 | ) 85 | } 86 | }) 87 | } 88 | }) 89 | ``` 90 | 91 | If you're using Twilio or a similar third-party messaging service which you have a fixed phone number to deliver messages you might want to ensure that the message comes from your service by checking `message.originatingAddress`. 92 | 93 | ### Installation 94 | 95 | ```SH 96 | $ npm install --save react-native-android-sms-listener 97 | $ react-native link react-native-android-sms-listener 98 | ``` 99 | 100 | ### Manual Installation 101 | 102 | For a manual installation, all you need to do to use this so-called utility is: 103 | 104 | _android/settings.gradle_ 105 | 106 | ```Gradle 107 | include ':react-native-android-sms-listener' 108 | project(':react-native-android-sms-listener').projectDir = new File(rootProject.projectDir,'../node_modules/react-native-android-sms-listener/android') 109 | ``` 110 | 111 | _android/app/build.gradle_ 112 | 113 | ```Gradle 114 | dependencies { 115 | compile project(':react-native-android-sms-listener') 116 | // (...) 117 | } 118 | ``` 119 | 120 | _MainApplication.java_ 121 | 122 | ```Java 123 | import com.centaurwarchief.smslistener.SmsListenerPackage; 124 | ``` 125 | 126 | ```Java 127 | @Override 128 | protected List getPackages() { 129 | return Arrays.asList( 130 | new MainReactPackage(), 131 | new SmsListenerPackage() 132 | // (...) 133 | ); 134 | } 135 | ``` 136 | -------------------------------------------------------------------------------- /ReceivedSmsMessage.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | export type ReceivedSmsMessage = { 3 | originatingAddress: string; 4 | body: string; 5 | }; 6 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | def safeExtGet(prop, fallback) { 2 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback 3 | } 4 | 5 | apply plugin: 'com.android.library' 6 | 7 | android { 8 | compileSdkVersion safeExtGet('compileSdkVersion', 26) 9 | buildToolsVersion safeExtGet('buildToolsVersion', '26.0.3') 10 | 11 | defaultConfig { 12 | minSdkVersion safeExtGet('minSdkVersion', 16) 13 | targetSdkVersion safeExtGet('targetSdkVersion', 26) 14 | } 15 | } 16 | 17 | dependencies { 18 | implementation 'com.facebook.react:react-native:+' 19 | } 20 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/src/main/java/com/centaurwarchief/smslistener/SmsListenerModule.java: -------------------------------------------------------------------------------- 1 | package com.centaurwarchief.smslistener; 2 | 3 | import android.app.Activity; 4 | import android.content.BroadcastReceiver; 5 | import android.content.IntentFilter; 6 | import android.os.Build; 7 | import android.provider.Telephony; 8 | 9 | import com.facebook.react.bridge.LifecycleEventListener; 10 | import com.facebook.react.bridge.ReactApplicationContext; 11 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 12 | 13 | public class SmsListenerModule extends ReactContextBaseJavaModule implements LifecycleEventListener { 14 | private BroadcastReceiver mReceiver; 15 | private boolean isReceiverRegistered = false; 16 | 17 | public SmsListenerModule(ReactApplicationContext context) { 18 | super(context); 19 | 20 | mReceiver = new SmsReceiver(context); 21 | getReactApplicationContext().addLifecycleEventListener(this); 22 | registerReceiverIfNecessary(mReceiver); 23 | } 24 | 25 | private void registerReceiverIfNecessary(BroadcastReceiver receiver) { 26 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && getCurrentActivity() != null) { 27 | getCurrentActivity().registerReceiver( 28 | receiver, 29 | new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION) 30 | ); 31 | isReceiverRegistered = true; 32 | return; 33 | } 34 | 35 | if (getCurrentActivity() != null) { 36 | getCurrentActivity().registerReceiver( 37 | receiver, 38 | new IntentFilter("android.provider.Telephony.SMS_RECEIVED") 39 | ); 40 | isReceiverRegistered = true; 41 | } 42 | } 43 | 44 | private void unregisterReceiver(BroadcastReceiver receiver) { 45 | if (isReceiverRegistered && getCurrentActivity() != null) { 46 | getCurrentActivity().unregisterReceiver(receiver); 47 | isReceiverRegistered = false; 48 | } 49 | } 50 | 51 | @Override 52 | public void onHostResume() { 53 | registerReceiverIfNecessary(mReceiver); 54 | } 55 | 56 | @Override 57 | public void onHostPause() { 58 | unregisterReceiver(mReceiver); 59 | } 60 | 61 | @Override 62 | public void onHostDestroy() { 63 | unregisterReceiver(mReceiver); 64 | } 65 | 66 | @Override 67 | public String getName() { 68 | return "SmsListenerPackage"; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /android/src/main/java/com/centaurwarchief/smslistener/SmsListenerPackage.java: -------------------------------------------------------------------------------- 1 | package com.centaurwarchief.smslistener; 2 | 3 | import android.app.Activity; 4 | 5 | import com.facebook.react.ReactPackage; 6 | import com.facebook.react.bridge.JavaScriptModule; 7 | import com.facebook.react.bridge.NativeModule; 8 | import com.facebook.react.bridge.ReactApplicationContext; 9 | import com.facebook.react.uimanager.ViewManager; 10 | 11 | import java.util.Arrays; 12 | import java.util.Collections; 13 | import java.util.List; 14 | 15 | public class SmsListenerPackage implements ReactPackage { 16 | static final String TAG = "SmsListenerPackage"; 17 | 18 | @Override 19 | public List createNativeModules(ReactApplicationContext context) { 20 | return Collections.singletonList( 21 | new SmsListenerModule(context) 22 | ); 23 | } 24 | 25 | // @Override deprecated in RN 0.47 26 | public List> createJSModules() { 27 | return Collections.emptyList(); 28 | } 29 | 30 | @Override 31 | public List createViewManagers(ReactApplicationContext context) { 32 | return Collections.emptyList(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /android/src/main/java/com/centaurwarchief/smslistener/SmsReceiver.java: -------------------------------------------------------------------------------- 1 | package com.centaurwarchief.smslistener; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Build; 7 | import android.os.Bundle; 8 | import android.provider.Telephony; 9 | import android.telephony.SmsMessage; 10 | import android.util.Log; 11 | 12 | import com.facebook.react.bridge.ReactApplicationContext; 13 | import com.facebook.react.bridge.WritableNativeMap; 14 | import com.facebook.react.modules.core.DeviceEventManagerModule; 15 | 16 | public class SmsReceiver extends BroadcastReceiver { 17 | private ReactApplicationContext mContext; 18 | 19 | private static final String EVENT = "com.centaurwarchief.smslistener:smsReceived"; 20 | 21 | public SmsReceiver() { 22 | super(); 23 | } 24 | 25 | public SmsReceiver(ReactApplicationContext context) { 26 | mContext = context; 27 | } 28 | 29 | private void receiveMessage(SmsMessage message, String body) { 30 | if (mContext == null) { 31 | return; 32 | } 33 | 34 | if (! mContext.hasActiveCatalystInstance()) { 35 | return; 36 | } 37 | 38 | Log.d( 39 | SmsListenerPackage.TAG, 40 | String.format("%s: %s", message.getOriginatingAddress(), message.getMessageBody()) 41 | ); 42 | 43 | WritableNativeMap receivedMessage = new WritableNativeMap(); 44 | 45 | receivedMessage.putString("originatingAddress", message.getOriginatingAddress()); 46 | receivedMessage.putString("body", body.length() > 0 ? body : message.getMessageBody()); 47 | receivedMessage.putDouble("timestamp", message.getTimestampMillis()); 48 | 49 | mContext 50 | .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) 51 | .emit(EVENT, receivedMessage); 52 | } 53 | 54 | private void receiveMultipartMessage(SmsMessage[] messages) { 55 | SmsMessage sms = messages[0]; 56 | String body; 57 | 58 | if (messages.length == 1 || sms.isReplace()) { 59 | body = sms.getDisplayMessageBody(); 60 | } else { 61 | StringBuilder bodyText = new StringBuilder(); 62 | 63 | for (SmsMessage message : messages) { 64 | bodyText.append(message.getMessageBody()); 65 | } 66 | 67 | body = bodyText.toString(); 68 | } 69 | 70 | receiveMessage(sms, body); 71 | } 72 | 73 | @Override 74 | public void onReceive(Context context, Intent intent) { 75 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 76 | receiveMultipartMessage(Telephony.Sms.Intents.getMessagesFromIntent(intent)); 77 | 78 | return; 79 | } 80 | 81 | try { 82 | final Bundle bundle = intent.getExtras(); 83 | 84 | if (bundle == null || ! bundle.containsKey("pdus")) { 85 | return; 86 | } 87 | 88 | final Object[] pdus = (Object[]) bundle.get("pdus"); 89 | final SmsMessage[] messages = new SmsMessage[pdus.length]; 90 | 91 | for (int i = 0; i < pdus.length; i++) { 92 | messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]); 93 | } 94 | 95 | receiveMultipartMessage(messages); 96 | } catch (Exception e) { 97 | Log.e(SmsListenerPackage.TAG, e.getMessage()); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:1.3.0' 8 | } 9 | } 10 | 11 | allprojects { 12 | repositories { 13 | jcenter() 14 | } 15 | } 16 | 17 | task clean(type: Delete) { 18 | delete rootProject.buildDir 19 | } 20 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | import type CancellableSubscription from './CancellableSubscription' 3 | import type ReceivedSmsMessage from './ReceivedSmsMessage' 4 | import { DeviceEventEmitter } from 'react-native' 5 | 6 | const SMS_RECEIVED_EVENT = 'com.centaurwarchief.smslistener:smsReceived' 7 | 8 | export default { 9 | addListener( 10 | listener: (message: ReceivedSmsMessage) => void 11 | ): CancellableSubscription { 12 | return DeviceEventEmitter.addListener( 13 | SMS_RECEIVED_EVENT, 14 | listener 15 | ) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-android-sms-listener", 3 | "version": "0.8.0", 4 | "description": "Allows you to listen for incoming SMS messages", 5 | "license": "MIT", 6 | "main": "index.js", 7 | "author": { 8 | "name": "Andrey K. Vital", 9 | "email": "andreykvital@gmail.com", 10 | "url": "https://github.com/CentaurWarchief" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/CentaurWarchief/react-native-android-sms-listener.git" 15 | }, 16 | "keywords": [ 17 | "react", 18 | "native", 19 | "react-native", 20 | "android", 21 | "sms", 22 | "listener", 23 | "sms-listener" 24 | ] 25 | } 26 | --------------------------------------------------------------------------------