Development of functionality for sending short messages is one of the basic tasks when creating Android applications. Whether it's an authorization system by phone number, notifications about order status, or just a messenger, understanding how to work with SMS is critical for anyone Android developer. In an environment Android Studio this process requires not only writing code, but also correctly setting access rights, as well as understanding the limitations of a modern operating system.

Many beginners are faced with the fact that the code is written correctly, but the message does not go away. Often the problem lies in the lack of permissions in the manifest file or in incorrect work with SmsManager. Unlike simple interface elements, working with telecom requires special attention to security details and compatibility with different versions of Android. We will analyze all the stages: from connecting libraries to testing on virtual devices.

It is worth noting right away that modern versions of Android (starting from 6.0 and higher) introduce strict rules for working with dangerous permissions. Simply writing a line in the configuration file is no longer enough - it is necessary to request confirmation from the user during app execution. This makes the process of sending SMS more complex, but significantly increases the security of the end user.

Preparing the project and setting permissions

The first step before writing any logic for sending messages is to declare the necessary rights in the file AndroidManifest.xml. Without this step, Android security will block any attempt by your application to access the communication module. You need to add two main lines inside the tag <manifest>but before the tag <application>.

The main permission SEND_SMS gives the application the right to initiate sending the message. However, if you plan to also read incoming messages or track delivery status, additional permission RECEIVE_SMSwill be required. It is important to understand the difference: the first is responsible for outgoing traffic, the second for incoming traffic. For the basic task of sending, only the first option is sufficient.

โš ๏ธ Attention: Starting with Android 10, Google has tightened its SMS access policy. Applications that are not the default messaging client may be restricted from sending or reading SMS in the background. Always check the latest Google Play Console requirements before publishing.

After adding the lines to the manifest, the code should look like this. This is the foundation without which further work is impossible. Don't forget to synchronize the project after making changes to the configuration file so that the IDE picks up the new settings.

<uses-permission android:name="android.permission.SEND_SMS" />

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

๐Ÿ’ก

Use the comment next to permission to understand in six months why exactly you needed this permission. For example: .

Implementation of sending logic via SmsManager

To directly send messages to the Android SDK, the class SmsManageris used. This is the main tool provided by the system to interact with the SIM card. You can get an instance of this class through the static method getDefault.

The process of sending text is divided into several stages. First you get the manager, then you call the method sendTextMessage. This method takes five arguments: the recipient's address, the sender's address (usually null), the message body itself, a PendingIntent to track the sending, and a PendingIntent to track the delivery. The last parameter is especially important if you need to know whether the message has reached the subscriber.

  • ๐Ÿ“ฑ Addresser: phone number in international format or local, depending on the operator.
  • ๐Ÿ“ Text: the contents of the message, which must be in the encoding supported by GSM (usually UTF-16 for Cyrillic).
  • ๐Ÿ”„ Status: PendingIntent allows you to process the result of the operation (success or error) in real time.

Processing long messages requires special attention. If the text exceeds 160 characters (for Latin) or 70 characters (for Cyrillic), the standard method sendTextMessage may not work correctly or break the message into parts without guaranteeing sequential delivery. In such cases, you should use the method sendMultipartTextMessagethat accepts a list of strings ArrayList<String>.

โ˜‘๏ธ Check before sending

Done: 0 / 4

Dynamic permission request at runtime

Starting with Android version 6.0 (API level 23), the permission model has changed. Setting permissions in the manifest now only declares intent, but does not provide actual access. The user must explicitly confirm the permission in a dialog box that appears while the application is running. Ignoring this step will cause the application to crash with an error SecurityException at the time of the attempt to send.

Checking the availability of rights is carried out through the method ContextCompat.checkSelfPermission. If the result is not equal PackageManager.PERMISSION_GRANTED, you must call ActivityCompat.requestPermissions. This call will show the system window to the user. Your code should be prepared for the user to click "Reject", in which case the SMS sending functionality should be blocked or hidden.

Use a callback method to process the user's response onRequestPermissionsResult. This is where you analyze whether permission has been granted. If yes, you can safely call the submit method. If not, itโ€™s worth showing the user an explanation of why this feature is important for the application to work, perhaps through Snackbar or dialogue.

โš ๏ธ Warning: Never try to bypass the permission request programmatically or use hidden APIs. This will result in your app being banned from the Google Play Store and potentially deleting your developer account.

๐Ÿ“Š How do you prefer to request permissions?
Via the PermissionsDispatcher library
Manually in an Activity
Use Jetpack Activity Result API
I donโ€™t use SMS

Working with the emulator and testing

One of the most common problems during development is the inability to test sending SMS on the emulator Android Studio. By default, the virtual device does not have a physical SIM card and is not connected to the operator's cellular network. An attempt to send a real SMS from an emulator to a real phone will not work without special configuration of the emulator console.

To simulate incoming messages or check sending within the emulator, you can use console commands through adb or the built-in Extended Controls panel. You can send a message from one emulator to another, knowing their numbers (usually 5554, 5556, etc.). This allows you to test the logic of receiving and processing messages without the expense of real communication.

If you need to test real sending, the only reliable way is to use a physical device with an active SIM card. Connect your smartphone via USB, enable USB debugging and run the application on it. The emulator is great for testing the interface and response processing logic, but not for testing signal passage through cell towers.

Testing method SIM required Cost Complexity
Emulator (internal) No Free Low
Physical device Yes At tariff Average
Cloud Device Farm Yes (virtually) Paid High
Mock objects (Unit tests) No Free High
How to find the emulator number?

Open the emulator console (telnet) or look in the device window title. The number is usually even, for example 5554. To send an SMS to it, use the command: adb emu sms send 5554 "Message text."

Handling errors and exceptions

Working with telecommunication modules is always associated with the risk of failures. The network may be lost, the balance may be zero, and the recipient's number may be incorrect. Therefore, the SMS sending code must be wrapped in a block try-catch. The main exception class you will encounter is SmsException, but general runtime errors are also possible.

It is important to distinguish between system-level errors (for example, lack of rights) and network-level errors (message not delivered). To track the delivery status, a mechanism BroadcastReceiveris used. You register the receiver for actions such as SmsManager.RESULT_ERROR_GENERIC_FAILURE or RESULT_OK. This allows you to respond to failure programmatically: prompt the user to try later or send a message via the Internet.

Error logging is a critical part of debugging. Use Log.e to record a stack trace when exceptions occur. This will help you quickly understand the cause of the failure when analyzing crash reports from users. Do not leave empty catch blocks, always record the cause of the error.

๐Ÿ’ก

Always assume that the network is unstable. Implement a retry logic mechanism with an exponential delay if the message is not sent the first time.

Alternative methods and modern APIs

Direct sending of SMS via SmsManager is not the only way. In some cases, it is more appropriate to use an implicit intent (Intent.ACTION_VIEW or ACTION_SENDTO). This method opens the default messaging app on the user's device with the To and Text fields already populated. The user only has to click the "Submit" button.

This approach has a number of advantages. First, you don't need to ask for dangerous permissions to send SMS since the action is performed by the system app and not yours. Secondly, the user can see exactly what is being sent, which increases trust. Third, it bypasses many of the restrictions introduced in new versions of Android for third-party applications.

However, this method also has a drawback: you cannot guarantee that the message will be sent. The user can open the window, change the text and click "Send", or can simply close the window. You will not receive confirmation of the fact of sending through your code. The choice between direct sending and intent depends on the business logic of your application.

Intent smsIntent = new Intent(Intent.ACTION_SENDTO);

smsIntent.setData(Uri.parse("smsto:" + phoneNumber));

smsIntent.putExtra("sms_body", messageText);

startActivity(smsIntent);

What is the difference between direct sending and Intent?

Direct sending through SmsManager occurs in the background, without user intervention, but requires permissions and complex error handling. Intent transfers control to the system application, requires fewer rights, but does not guarantee automatic sending and does not give full control over the process.

Why is the message not sent on Android 11?

In Android 11, restrictions have been introduced on access to the list of all SMS. If your app is not the default SMS client, it can only send messages to numbers that the user has previously interacted with, or use the SMS app role. Check the role settings in the system.

How to send an SMS without a SIM card?

Technically, it is impossible to send a classic SMS without a SIM card, since this requires registration in the operatorโ€™s network. However, you can use VoIP technologies or Internet instant messengers (WhatsApp, Telegram), which emulate sending messages via an Internet connection (Wi-Fi or mobile data).

Do you need to pay to use SmsManager?

Using the SmsManager API is free for the developer. However, sending SMS consumes the user's data plan (or enterprise plan if using a gateway). Make sure the user is aware of possible communication costs before initiating sending.

Is it possible to send pictures via SmsManager?

Classic SmsManager is for text (SMS) only. Sending images (MMS) requires the use of other classes and methods, such as creating an MMS message with an attachment, which is much more complex and requires additional permissions to read the storage.