Sending a SMS on Android through ADB
Asked Answered
C

8

30

I would like to be able to send a SMS from my Android phone while it's connected to my computer using the following ADB commands

adb shell am start -a android.intent.action.SENDTO -d sms:CCXXXXXXXXXX --es sms_body "SMS BODY GOES HERE" --ez exit_on_sent true
adb shell input keyevent 22
adb shell input keyevent 66

I've got this working however on the phone this will pop up a text message to the recipient with the body filled in and then click the send button and return to where you were. Is there any way to do this completely in the background so it would not interfere with anything happening on the phone?

Chobot answered 10/7, 2013 at 20:22 Comment(2)
For new Android phones you better do tabbing two times so, it would be: adb shell input keyevent 22 adb shell input keyevent 22 adb shell input keyevent 66Ronni
On Android 8, I had to send keyevent 61 twice, followed by keyevent 66.Sybaris
P
45

Short version :

Android 5 and older (here android 4):

adb shell service call isms 5 s16 "com.android.mms" s16 "+01234567890" s16 "+01SMSCNUMBER" s16 "Hello world !" i32 0 i32 0

Android 5 and later (here android 9):

adb shell service call isms 7 i32 0 s16 "com.android.mms.service" s16 "+1234567890" s16 "null" s16 "Hey\ you\ !" s16 "null" s16 "null"

Isms method number (5 and 7 above) may change with the android version . Read full explanation to understand it.


Full explanation for all android version :

Yes it exists ! but not with this command, because these input events are blocked in sleep mode. This solution depends on your android version, so I'm going to explain you for almost all version ...

1st, check if you have the service isms by running :

adb shell service check isms
Service isms: found

The answer is found, good, keep moving. The service isms have various "options" the syntax is :

service call name_service option args

The service name can be found by typing :

adb shell service list

It will display a lot of services avaible, but the interesting line is :

5       isms: [com.android.internal.telephony.ISms]

You can see com.android.internal.telephony.Isms, so on this link choose your android version (by changing branch), then navigate to : telephony/java/com/android/internal/telephony and open Isms.aidl

For the rest I will take the android Pie (android 9) file (link).

On the line 185 we have :

void sendTextForSubscriberWithSelfPermissions(...)

Note : before android 5 the method is named sendText(...).

It is the 7th declaration in the interface ISMS . So our option to send a sms is the number 7. On the top of the declaration there is the explanation of the arguments. Here a short version:

  • subId : after android 5, the SIM card you want to use 0, 1 or 2 depending of your android version (ex 0-1 for android 9 and 1-2 for android 8)
  • callingPkg : the name of the package that will send your sms (I explain how to find it later)
  • destinationAdress : the phone number of the message recipient
  • scAddress : your smsc is only need in android 5 and lower (explained after)
  • parts : your message !
  • sendIntends and deliveryIntents : you don't care

-> Find your package name : Explore your app file or download Package Name Viewer on google play, find your message application and copy the name (com.android...)

-> Find your smsc : In your application -> settings -> SMSC or Service Center or Message Center etc, copy the number display (DON'T CHANGE IT)

Just before finishing, in services the strings are declared by s16 and integers and PendingIntent with i32.

So for my example we have :

  • subId : 0
  • callingPkg : com.android.mms
  • target number : +01234567890
  • SMSC : +01000000000
  • My text : Hello world !
  • sendIntends and deliveryIntents we don't care so we put 0 to set it to default value.

Finally :

Android 5 and older (here android 4):

adb shell service call isms 5 s16 "com.android.mms" s16 "+01234567890" s16 "+01000000000" s16 "Hello world !" i32 0 i32 0

Android 5 and later (here android 9):

adb shell service call isms 7 i32 0 s16 "com.android.mms.service" s16 "+1234567890" s16 "null" s16 "'Hey you !'" s16 "null" s16 "null"

-> An example in a batch file :

The send.bat for android 4 :

echo off
set num=%1
shift
for /f "tokens=1,* delims= " %%a in ("%*") do set ALL_BUT_FIRST=%%b
echo %ALL_BUT_FIRST%
adb shell service call isms 5 s16 "com.android.mms" s16 "%num%" s16 "+01000000000" s16 "%ALL_BUT_FIRST%" i32 0 i32 0

run with :

send.bat +01234567890 Hey you !

Now tell me if it works with your android version :)

Edit : Corrected with information given by Alex P. Edit 2: Corrected with information given by Neil

Predominance answered 13/5, 2015 at 19:57 Comment(8)
The value of FIRST_CALL_TRANSACTION is 1, so the proper code for sendMultipartText in Android 4.4.x would be 6, not 5. For easier way to get the transaction codes read ktnr74.blogspot.com/2014/09/…Scabrous
The command is right though, the explanation is wrong. You are using transaction code 5 and all other parameters for the sendText() command - the proper one to use for sending simple texts like yours.Scabrous
Android evolved quite a lot since my answer, I will update it later, try adb shell service call isms 7 i32 0 s16 "com.android.mms.service" s16 "+1234567890" s16 "null" s16 "Hey\ you\ !" s16 "null" s16 "null" for android 9. Android 7 try with ...isms 7 i32 1 s16 "com.android.mms" s16...Predominance
Man, I would upvote this a hundred times if it was possible! You're a lifesaver! Probably you should add the Android 7 command to the original answer as well; where the subId and "com.android.mms.service" should be changed to 1 or 2 and "com.android.mms", as you had mentioned in the comment.Blackett
This "'Hey you !'" is better than "Hey\ you\ !" you don't have to put / every time there is a space in the text.Yoicks
Is 7th declaration is the number that receive as transport_id with command adb devices -l?Grimaldo
I do not understand your question @Grimaldo sorry.Predominance
In Android 13 I use this command line: > adb shell service call isms 5 i32 0 s16 "com.android.mms.service" s16 "null" s16 "number_to_receive" s16 "null" s16 "'Message'" s16 "null" s16 "null" i32 0 i64 0Twinkle
F
6

Instead of this , write your own intentservice like the following. Create a entry for the following IntentService in your manifest.

String targetPhoneNumber = "XX-XXXXXXX-XXXXXX-XXXX";
SmsToSend targetSms = new SmsToSend();
String urlText = url;
targetSms.setPhoneNumbers(new String[]{targetPhoneNumber});
targetSms.setSmsBody("Help me");
Intent smsIntent = targetSms.convertToIntent(context);
        startService(smsIntent);


        import java.util.ArrayList;
        import android.app.IntentService;
        import android.app.PendingIntent;
        import android.content.Intent;

        public class SendStreamMessage extends IntentService {

        public SendStreamMessage() {
            super("Sms Sender Intent Service");
        }

        @Override
        protected void onHandleIntent(Intent intent) {
            sendSms(intent);
        }

        private void sendSms(Intent intent) {
            try {
                SmsToSend smsSend = (SmsToSend) intent
                        .getParcelableExtra("SMSMessage");
                Intent sentIntent = new Intent(SmsDeliveryHandlers.SENT_SMS_ACTION);

                PendingIntent sentPI = PendingIntent.getBroadcast(
                        SendStreamMessage.this, 0, sentIntent, 0);
                Intent deliveryIntent = new Intent(
                        SmsDeliveryHandlers.DELIVERED_SMS_ACTION);
                PendingIntent deliverPI = PendingIntent.getBroadcast(
                        SendStreamMessage.this, 0, deliveryIntent, 0);
                android.telephony.SmsManager smsManager = android.telephony.SmsManager
                        .getDefault();

                ArrayList<String> messages = smsManager.divideMessage(smsSend
                        .getSmsBody());

                int smsSize = messages.size();

                ArrayList<PendingIntent> sentPiList = new ArrayList<PendingIntent>(
                        smsSize);
                ArrayList<PendingIntent> deliverPiList = new ArrayList<PendingIntent>(
                        smsSize);

                for (int i = 0; i < smsSize; i++) {
                    sentPiList.add(sentPI);
                    deliverPiList.add(deliverPI);
                }

                if (smsSize > 1) {
                    for (int i = 0; i < smsSend.getPhoneNumbers().length; i++) {
                        String targetPhoneNumber = smsSend.getPhoneNumbers()[i];
                        SmsDeliveryHandlers handler = new SmsDeliveryHandlers(
                                targetPhoneNumber, smsSend.getSmsBody());
                        try {
                            smsManager.sendMultipartTextMessage(targetPhoneNumber,
                                    null, messages, sentPiList, deliverPiList);
                        } catch (Exception ex) {
                            handler.cleanReceiver();
                        }
                    }
                } else {
                    SmsDeliveryHandlers handler;
                    for (int i = 0; i < smsSend.getPhoneNumbers().length; i++) {
                        String targetPhoneNumber = smsSend.getPhoneNumbers()[i];
                        handler = new SmsDeliveryHandlers(targetPhoneNumber,
                                smsSend.getSmsBody());
                        try {
                            smsManager.sendTextMessage(targetPhoneNumber, null,
                                    smsSend.getSmsBody(), sentPI, deliverPI);
                        } catch (Exception ex) {
                            handler.cleanReceiver();
                        }
                    }
                }
            } finally {
            }
        }
    }

    import android.app.Activity;
    import android.content.BroadcastReceiver;
    import android.content.ContentResolver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.net.Uri;

    public final class SmsDeliveryHandlers extends BroadcastReceiver {
        public static final String SENT_SMS_ACTION = "SENT_SMS_ACTION";
        public static final String DELIVERED_SMS_ACTION = "DELIVERED_SMS_ACTION";
        private SmsToSend send;
        private Context context;
        private Uri sendboxUri;

        public SmsDeliveryHandlers(String phoneNumber, String message) {
            this(new SmsToSend(message, phoneNumber));
        }

        public SmsDeliveryHandlers(SmsToSend send) {
            this.send = send;
            IntentFilter targetFilter = new IntentFilter();
            targetFilter.addAction(SENT_SMS_ACTION);
            targetFilter.addAction(DELIVERED_SMS_ACTION); 
            context = MmsLiveApplication.getInstance().getTargetContext();
            context.registerReceiver(this, targetFilter);
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            if (SENT_SMS_ACTION.equals(intent.getAction())) {
                handleSend();
            } else if (DELIVERED_SMS_ACTION.equals(intent.getAction())) {
                handleDelivery();
            }
        }
        private synchronized void handleSend() {
            String address = send.getPhoneNumbers()[0];
            ContentResolver contentResolver = context.getContentResolver();
            int resultCode = getResultCode();
            if(resultCode != Activity.RESULT_OK)
            {           
                cleanReceiver();
            }
        }

        public void cleanReceiver() {
            context.unregisterReceiver(this); 
        }

        private void handleDelivery() {
            switch (getResultCode()) {
            case Activity.RESULT_OK:
                // HACK This is a hack to insert the send sms result to the real
                // message send table ;)
                break;
            case Activity.RESULT_CANCELED:
                break;
            }
            cleanReceiver();
        }
    }

package com.ttech.mmslive.contacts;


import android.content.Context;
import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;

public class SmsToSend implements Parcelable{
    public static final Parcelable.Creator<SmsToSend> CREATOR = new Parcelable.Creator<SmsToSend>() {
        public SmsToSend createFromParcel(Parcel in) {
            return new SmsToSend(in);
        }
        public SmsToSend[] newArray(int size) {
            return new SmsToSend[size];
        }
    };
    public SmsToSend()
    {       
    }
    public SmsToSend(Parcel in) {
        readFromParcel(in);
    }   
    public SmsToSend(String smsBody,String phoneNumber)
    {
        this.smsBody = smsBody;
        phoneNumbers = new String[]{phoneNumber};
    }   
    public Intent convertToIntent(Context targetContext)
    {
        Intent targetIntent = new Intent(targetContext,SendStreamMessage.class);
        targetIntent.putExtra("SMSMessage", this);
        return targetIntent;
    }
    @Override
    public int describeContents() {
        return 0;
    }
    private String[] phoneNumbers; 
    private String smsBody;
    public String[] getPhoneNumbers() {
        return phoneNumbers;
    }
    public String getSmsBody() {
        return smsBody;
    }
    public void readFromParcel(Parcel in) {
        smsBody = in.readString();
        int length = in.readInt();
        if(length > 0)
        {
            phoneNumbers = new String[length];
            in.readStringArray(phoneNumbers);
        }
    }
    public void setPhoneNumbers(String[] phoneNumbers) {
        this.phoneNumbers = phoneNumbers;
    }
    public void setSmsBody(String smsBody) {
        this.smsBody = smsBody;
    }
    @Override
    public void writeToParcel(Parcel parcel, int params) {
        parcel.writeString(smsBody);
        if(phoneNumbers != null && phoneNumbers.length > 0)
        {
            parcel.writeInt(phoneNumbers.length);
            parcel.writeStringArray(phoneNumbers);
        }
        else{
            parcel.writeInt(0);
        }
    }
}
Favour answered 11/7, 2013 at 0:11 Comment(1)
Sorry I know this is a long time after the fact, but I understand how to accomplish this through intents etc. The goal here was to accomplish everything through ADB, thereby eliminating the need to install anything on the phoneChobot
J
4

I've spent a LOT of time trying to get this right for my HTC Desire with SlimKat. Now I use this script that allows me to send an SMS almost instantly (yad GUI is extremely fast) with my PC keyboard. I just select a cellphone number (let's say 00165826453) and press WinKey+S and this opens up:

SMS app for Linux using yad

This is the BASH script that I developed for this:

#!/usr/bin/env bash

if [ $# -eq 1 ]; then
    phoneNumber=${1//[^0-9\+]/}
else
    phoneNumber=`xsel | sed 's/[^0-9\+]//g'`
fi

if [ -z "$phoneNumber" ]; then
    yadText=`yad --form --field="Phone number" --field="Multiline text:TXT" --width=400 --height=320 --title="Send SMS" --focus-field=1 --button="Send SMS:0"`
else
    yadText=`yad --form --field="Phone number" "$phoneNumber" --field="SMS text:TXT" --width=400 --height=320 --title="Send SMS" --focus-field=2 --button="Send SMS:0"`
fi

phoneNumber=${yadText//\|*/}
smsText=${yadText#*|}
smsText=${smsText%|*}

ssh root@noa "su shell service call isms 5 s16 \"com.android.mms\" s16 \"$phoneNumber\" s16 \"null\" s16 \"$smsText\" s16 \"null\" s16 \"null\""

It is phonomenaly useful and quick. The only drawback for me is that the sent SMS messages do not appear in the default SMS app on my SlimKat.

In order for this to work on your Debian derivative you have to:

aptDistro> sudo apt install yad bash

or the equivalent for your distro.

This works on my machine because I have setup an SSH server on my SlimKat install with key authentication. You could slightly modify it to work via ADB wirelessly.

Jefferson answered 4/2, 2020 at 20:40 Comment(0)
L
3

For Android 12 (sdk 31), please find the latest solution:

adb shell service call isms 5 i32 0 s16 "com.android.mms.service" s16 "null" s16 '+0123456789' s16 "null" s16 "text message body here" s16 "null" s16 "null" s16 "null" s16 "null"

This is based on the following function as found in the source code in case you'd like to change the "null" values:

void sendTextForSubscriber(
  in int subId, 
  String callingPkg, 
  String callingAttributionTag, 
  in String destAddr, 
  in String scAddr, 
  in String text, 
  in PendingIntent sentIntent,
  in PendingIntent deliveryIntent, 
  in boolean persistMessageForNonDefaultSmsApp,
  in long messageId);

This was tested successfully using Samsung Galaxy S21 and Motorola (new flagship) on T-Mobile network.

**note previous issue (reason for downvoted) was due to "services" instead of "service" in the package name. Uncertain why GS21 unaffected by these changes.

Laird answered 6/5, 2022 at 17:19 Comment(2)
Is it supposed to return Result: Parcel(00000000 '....')?Ghent
Also, the question is asking for SMS, so you should change com.android.mms.service to com.android.sms.service.Ghent
C
2

The answer below worked great for me ! In Android 5.02 the option is 12 and I figured out you could send null as the SMSC to use the default, so sending a SMS worked with :

adb shell service call isms 12 s16 "com.android.mms" s16 "+01234567890" s16 "null" s16 "Hello world" i32 0 i32 0
Coan answered 26/6, 2015 at 19:22 Comment(1)
I get Result: Parcel(00000000 '....') but nothing happens on android 7.1.1Entoderm
S
2

Thank you, Taknok, for a great answer.

I'm using a Samsung Galaxy S5 with Android version 6.0.1. On my phone, the SIM card subId is actually 3 (not 0, 1 or 2 as suggested in your answer). Took me I while to figure out, so I'm posting here in case others wonder about the same. This command worked:

adb shell service call isms 7 i32 3 s16 "com.android.mms" s16 "+123456789" s16 "+100000000" s16 "'Hello world'" i32 0 i32 0
Sensualism answered 15/10, 2019 at 11:15 Comment(0)
R
1

For android version 8, I used this code:

Process process = new Process();
process.StartInfo.FileName = "adb.exe";
process.StartInfo.Arguments = "shell service call isms 7 i32 2  s16 'com.android.mms.service' s16 '" + 03001111111 + "' s16 'null' s16 '" + textBox1.Text + "' i32 0 i32 0";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.Start(); 

But sometime depend upon mobile phone in I use same code Samsung j5 version 8 but here I use isms 7 i32 8.

For android version 9, I used this code:

Process process = new Process();
process.StartInfo.FileName = "adb.exe";
process.StartInfo.Arguments = "shell service call isms 7 i32 2 s16 'com.android.mms.service' s16 '" + 03001111111 + "' s16 'null' s16 '" + textBox1.Text + "' i32 0 i32 0";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.Start(); 

For android version 6, I used this code:

Process process = new Process();
process.StartInfo.FileName = "adb.exe";
process.StartInfo.Arguments = "shell service call isms 7 i32 1 s16 'com.android.mms.service' s16 '" + 03001111111 + "' s16 'null' s16 '" + textBox1.Text + "' i32 0 i32 0";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.Start(); 

But I stuck in android version 11. I used to many conditions but not come to correct place.

Rosenwald answered 2/12, 2021 at 15:22 Comment(1)
Fomatting needs improvement. Code formatters can be used while adding code to question or answerEvocation
T
0

Android 13 function signature hasn't changed, but adb command fails when trying previous answers here with weird response.

void sendTextForSubscriber(in int subId, String callingPkg, String callingAttributionTag,
            in String destAddr, in String scAddr, in String text, in PendingIntent sentIntent,
            in PendingIntent deliveryIntent, in boolean persistMessageForNonDefaultSmsApp,
            in long messageId);

Unix shell alias in e.g. .bash_profile

alias sms='adb shell service call isms 5 i32 0 s16 "com.android.mms.service" s16 "null" s16 "$1" s16 "null" s16 "$2" s16 "null" s16 "null" i32 0 i64 0'

Usage: sms "+372xxxxxx" "Your message"


Windows CMD alias:

DOSKEY sms=adb shell service call isms 5 i32 0 s16 "com.android.mms.service" s16 "null" s16 "$1" s16 "null" s16 "'$*'" s16 "null" s16 "null" i32 0 i64 0

Add a *.bat/cmd file path to AutoRun value in HKLM\Software\Microsoft\Command Processor

Usage: sms +372xxxxxx Your message

Trichloroethylene answered 5/2, 2023 at 18:18 Comment(2)
Is it supposed to return Result: Parcel(00000000 '....')?Ghent
Also, the question is asking for SMS, so you should change com.android.mms.service to com.android.sms.service.Ghent

© 2022 - 2025 — McMap. All rights reserved.