23

我希望能够使用以下 ADB 命令从我的 Android 手机连接到我的计算机时发送短信

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

我已经完成了这项工作,但是在电话上,这将向收件人弹出一条短信,并填写正文,然后单击发送按钮并返回到您所在的位置。有没有办法在后台完全做到这一点,这样它就不会干扰手机上发生的任何事情?

4

6 回答 6

35

精简版 :

Android 5 及更早版本(此处为 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 及更高版本(此处为 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 方法编号(上面的 5 和 7)可能会随着 android 版本的变化而变化。阅读完整的解释以理解它。


所有安卓版本的完整解释:

是的,它存在!但不使用此命令,因为这些输入事件在睡眠模式下被阻止。此解决方案取决于您的 android 版本,因此我将为您解释几乎所有版本...

1st,通过运行检查您是否有服务isms:

adb shell service check isms
Service isms: found

答案找到了,很好,继续前进。服务主义有各种“选项”,语法是:

service call name_service option args

可以通过键入以下内容找到服务名称:

adb shell service list

它将显示很多可用的服务,但有趣的是:

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

您可以看到 com.android.internal.telephony.Isms,因此在此链接上选择您的 android 版本(通过更改分支),然后导航到:telephony/java/com/android/internal/telephony并打开Isms.aidl

剩下的我将使用 android Pie (android 9) 文件(链接)。

在第185行,我们有:

无效 sendTextForSubscriberWithSelfPermissions(...)

注意:在 android 5 之前,该方法被命名sendText(...)

它是接口 ISMS 中的第 7 个声明。所以我们发送短信的选项是数字 7。在声明的顶部有参数的解释。这是一个简短的版本:

  • subId :在 android 5 之后,您要使用的 SIM 卡 0、1 或 2 取决于您的 android 版本(例如 android 9 的 0-1 和 android 8 的 1-2)
  • callPkg : 将发送您的短信的包的名称(我稍后会解释如何找到它)
  • destinationAdress : 消息接收者的电话号码
  • scAddress :您的 smsc 仅在 android 5 及更低版本中需要(稍后解释)
  • 零件:您的留言!
  • sendIntends 和 deliveryIntents :你不在乎

-> 查找您的包名称: 浏览您的应用文件或在 google play 上下载包名称查看器,找到您的消息应用程序并复制名称(com.android...)

-> 找到您的短信: 在您的应用程序 -> 设置 -> SMSC 或服务中心或消息中心等,复制号码显示(不要更改)

就在完成之前,在服务中,字符串由s16和整数和 PendingIntent 与 i32 声明

所以对于我的例子,我们有:

  • 子标识符:0
  • 调用包:com.android.mms
  • 目标号码:+01234567890
  • 短信中心:+01000000000
  • 我的文字:世界你好!
  • sendIntends 和 deliveryIntents 我们不关心,所以我们把 0 设置为默认值。

最后 :

Android 5 及更早版本(此处为 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 及更高版本(此处为 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"

-> 批处理文件中的示例:

android 4 的 send.bat :

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

运行:

send.bat +01234567890 Hey you !

现在告诉我它是否适用于您的 android 版本:)

编辑:Alex P提供的信息更正。 编辑 2:Neil提供的信息更正

于 2015-05-13T19:57:05.127 回答
4

取而代之的是,编写您自己的意图服务,如下所示。在清单中为以下 IntentService 创建一个条目。

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);
        }
    }
}
于 2013-07-11T00:11:39.947 回答
2

我花了很多时间试图用 SlimKat 来为我的 HTC Desire 做好这个。现在我使用这个脚本,它允许我用我的 PC 键盘几乎立即发送 SMS(yad GUI 非常快)。我只需选择一个手机号码(例如 00165826453)并按 WinKey+S 即可打开:

使用 yad 的 Linux 短信应用

这是我为此开发的 BASH 脚本:

#!/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\""

它在语音上非常有用且快速。对我来说唯一的缺点是发送的 SMS 消息不会出现在我 SlimKat 的默认 SMS 应用程序中。

为了让它在您的 Debian 衍生产品上工作,您必须:

aptDistro> sudo apt install yad bash

或您的发行版的等价物。

这适用于我的机器,因为我已经在我的 SlimKat 安装上设置了一个带有密钥身份验证的 SSH 服务器。您可以稍微修改它以通过 ADB 无线工作。

于 2020-02-04T20:40:33.553 回答
1

下面的答案对我很有用!在 Android 5.02 中,选项是 12,我发现您可以发送 null 作为 SMSC 以使用默认值,因此发送 SMS 可以使用:

adb shell service call isms 12 s16 "com.android.mms" s16 "+01234567890" s16 "null" s16 "Hello world" i32 0 i32 0
于 2015-06-26T19:22:19.167 回答
1

谢谢你,Taknok,一个很好的答案。

我使用的是带有 Android 版本 6.0.1 的三星 Galaxy S5。在我的手机上,SIM 卡 subId 实际上是 3(不是您的答案中建议的 0、1 或 2)。我花了一段时间才弄清楚,所以我在这里发帖以防其他人对此感到疑惑。该命令有效:

adb shell service call isms 7 i32 3 s16 "com.android.mms" s16 "+123456789" s16 "+100000000" s16 "'Hello world'" i32 0 i32 0
于 2019-10-15T11:15:45.583 回答
0

对于 android 版本 8,我使用了以下代码:

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(); 

但有时取决于手机,我使用相同的代码三星 j5 版本 8 但在这里我使用isms 7 i32 8.

对于 android 版本 9,我使用了以下代码:

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(); 

对于 android 版本 6,我使用了以下代码:

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(); 

但是我卡在了android 11版。我习惯了很多条件,但没有来正确的地方。

于 2021-12-02T15:22:22.820 回答