简体   繁体   English

广播接收器 + SMS_RECEIVED

[英]BroadcastReceiver + SMS_RECEIVED

I'd like my app to catch incoming SMS messages.我希望我的应用能够接收收到的 SMS 消息。 There are a few examples of this around.有几个这样的例子。 Looks like we just need to do this:看起来我们只需要这样做:

// AndroidManifest.xml
<receiver android:name=".SMSReceiver"> 
  <intent-filter> 
    <action android:name="android.provider.Telephony.SMS_RECEIVED" /> 
  </intent-filter> 
</receiver>        

// SMSReceiver.java
public class SMSReceiver extends BroadcastReceiver 
{ 
    @Override 
    public void onReceive(Context context, Intent intent) { 
        Log.i(TAG, "SMS received.");
        ....
    }
}

is this correct?这样对吗? I'm sending my phone some sms messages, but the log statement never gets printed.我正在向我的手机发送一些短信,但日志语句从未被打印出来。 I do have some other SMS applications installed on the phone, which display a popup when the sms is received - are they somehow blocking the intent from getting passed down to my app, they are just consuming it completely?我确实在手机上安装了一些其他 SMS 应用程序,它们在收到短信时显示一个弹出窗口 - 它们是否以某种方式阻止了将意图传递给我的应用程序,他们只是完全使用它?

Thanks谢谢

You would also need to specify a uses-permission in your manifest file:您还需要在清单文件中指定使用权限:

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

The following tutorials should help:以下教程应该会有所帮助:

React on incoming SMS 对收到的短信做出反应
SMS messaging in Android Android中的短信

There are a few gotchas on the way.途中有一些陷阱。 You can find all the needed info on stackoverflow.你可以在 stackoverflow 上找到所有需要的信息。 I have gathered all the info in this answer, for convenience.为方便起见,我收集了此答案中的所有信息。

Things to be noticed需要注意的事项

  1. I assume android kitkat and above.我假设 android kitkat 及更高版本。
  2. The intent for incomming sms is "android.provider.Telephony.SMS_RECEIVED"传入短信的意图是"android.provider.Telephony.SMS_RECEIVED"
  3. You can change the priority of the intent filter, but it's not necessary.您可以更改意图过滤器的优先级,但这不是必需的。
  4. You need this permission "android.permission.RECEIVE_SMS" in manifest xml, in order to receive sms messages.您需要清单 xml 中的"android.permission.RECEIVE_SMS"权限才能接收短信。 In android 6 and above, you additionally need to ask for the permission in runtime.在 android 6 及更高版本中,您还需要在运行时请求权限。
  5. You do not need to set the MIME type of data in the intent filter.您不需要在意图过滤器中设置 MIME 类型的数据。 Intent filter should pass only on empty data if no MIME type is set, but fortunately it will still work without MIME.如果没有设置 MIME 类型,意图过滤器应该只传递空数据,但幸运的是它在没有 MIME 的情况下仍然可以工作。
  6. adb shell am broadcast will not work. adb shell am broadcast将不起作用。 Use telnet connection to simulator to test sms receiving.使用 telnet 连接到模拟器来测试短信接收。
  7. Long sms messages are divided into small sms chunks.长短信被分成小短信块。 We need to concatenate them.我们需要连接它们。

How to send a sms message to the emulator如何向模拟器发送短信

The most important thing is to have the possibility to send fake sms messages to the device, so we can test the code.最重要的是有可能向设备发送假短信,以便我们测试代码。

For this we will use a virtual device and a telnet connection to it.为此,我们将使用一个虚拟设备和一个到它的 telnet 连接。

  1. Create a virtual device in android studio and run the simulator在android studio中创建一个虚拟设备并运行模拟器
  2. Look at the title bar in the simulator window.查看模拟器窗口中的标题栏。 There is the device name and a port number .有设备名称和端口号 We need to know this port number in the next steps.我们需要在接下来的步骤中知道这个端口号。
  3. Now connect to the port number shown in the simulator title bar with telnet现在使用 telnet 连接到模拟器标题栏中显示的端口号

     $ telnet localhost 5554
  4. If you see this: Android Console: Authentication required , then you need to authenticate the connection with this command:如果您看到: Android Console: Authentication required ,那么您需要使用以下命令验证连接:

     auth xxxxxx

    Replace the xxxxxx above with the token read from ~/.emulator_console_auth_token file.将上面的xxxxxx替换为从~/.emulator_console_auth_token文件中读取的令牌。

  5. Now you should be able to run all the commands.现在您应该能够运行所有命令。 To send a sms message, type this command:要发送短信,请输入以下命令:

     sms send 555 "This is a message"

    Where you can replace 555 with the sender telephone number and a message of your own.您可以在其中用发件人电话号码和您自己的消息替换 555。

How to listen to SMS_RECEIVED broadcasts如何收听 SMS_RECEIVED 广播

To get the broadcasts, you need to register a BroadcastReceiver object.要获取广播,您需要注册一个BroadcastReceiver对象。 You can do this in the manifest.xml OR just call registerReceiver function.您可以在 manifest.xml 中执行此操作,或者只需调用registerReceiver函数。 I will show you the latter, as it is easier to reason about and yet more flexible.我将向您展示后者,因为它更容易推理且更灵活。

Connecting the broadcast receiver with the main activity将广播接收器与主要活动连接起来

The data flow is one way.数据流是一种方式。 From broadcast receiver to the main activity.从广播接收器到主要活动。 So the simplest way to get them to talk is to use a function interface.所以让他们说话的最简单的方法是使用函数接口。 The activity will implement such a function and the broadcast receiver will have the activity instance passed as a parameter in the constructor.活动将实现这样的功能,广播接收器将活动实例作为构造函数中的参数传递。

File SmsHandler.java:文件 SmsHandler.java:

package ...

interface SmsHandler {
    void handleSms(String sender, String message);
}

Implementing the broadcast receiver实现广播接收器

The broadcast receiver will get the intent in a callback.广播接收器将在回调中获得意图。 We will use the function Telephony.Sms.Intents.getMessagesFromIntent(intent) to get the sms messages.我们将使用函数Telephony.Sms.Intents.getMessagesFromIntent(intent)来获取短信。 Notice the SmsHandler parameter in the constructor.注意构造函数中的 SmsHandler 参数。 It will be the activity to which we will send the received sms.这将是我们将收到的短信发送到的活动。

File SmsInterceptor.java:文件 SmsInterceptor.java:

package ...

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.provider.Telephony;
import android.telephony.SmsMessage;

public class SmsInterceptor extends BroadcastReceiver {

    private SmsHandler handler;

    /* Constructor. Handler is the activity  *
     * which will show the messages to user. */
    public SmsInterceptor(SmsHandler handler) {
        this.handler = handler;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        /* Retrieve the sms message chunks from the intent */
        SmsMessage[] rawSmsChunks;
        try {
            rawSmsChunks = Telephony.Sms.Intents.getMessagesFromIntent(intent);
        } catch (NullPointerException ignored) { return; }

        /* Gather all sms chunks for each sender separately */
        Map<String, StringBuilder> sendersMap = new HashMap<>();
        for (SmsMessage rawSmsChunk : rawSmsChunks) {
            if (rawSmsChunk != null) {
                String sender = rawSmsChunk.getDisplayOriginatingAddress();
                String smsChunk = rawSmsChunk.getDisplayMessageBody();
                StringBuilder smsBuilder;
                if ( ! sendersMap.containsKey(sender) ) {
                    /* For each new sender create a separate StringBuilder */
                    smsBuilder = new StringBuilder();
                    sendersMap.put(sender, smsBuilder);
                } else {
                    /* Sender already in map. Retrieve the StringBuilder */
                    smsBuilder = sendersMap.get(sender);
                }
                /* Add the sms chunk to the string builder */
                smsBuilder.append(smsChunk);
            }
        }

        /* Loop over every sms thread and concatenate the sms chunks to one piece */
        for ( Map.Entry<String, StringBuilder> smsThread : sendersMap.entrySet() ) {
            String sender  = smsThread.getKey();
            StringBuilder smsBuilder = smsThread.getValue();
            String message = smsBuilder.toString();
            handler.handleSms(sender, message);
        }
    }
}

The main activity主要活动

Finally we need to implement SmsHandler interface into the main activity and add registering the broadcast receiver and permission check to the onCreate function.最后,我们需要在主活动中实现 SmsHandler 接口,并在onCreate函数中添加注册广播接收器和权限检查。

File MainActivity.java:文件 MainActivity.java:

package ...

import ...

public class MainActivity extends AppCompatActivity implements SmsHandler {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /* Register the broadcast receiver */
        registerSmsListener();

        /* Make sure, we have the permissions */
        requestSmsPermission();
    }

    /* This function will be called by the broadcast receiver */
    @Override
    public void handleSms(String sender, String message) {
        /* Here you can display the message to the user */
    }

    private void registerSmsListener() {
        IntentFilter filter = new IntentFilter();
        filter.addAction("android.provider.Telephony.SMS_RECEIVED");
        /* filter.setPriority(999); This is optional. */
        SmsInterceptor receiver = new SmsInterceptor(this);
        registerReceiver(receiver, filter);
    }

    private void requestSmsPermission() {
        String permission = Manifest.permission.RECEIVE_SMS;
        int grant = ContextCompat.checkSelfPermission(this, permission);
        if ( grant != PackageManager.PERMISSION_GRANTED) {
            String[] permission_list = new String[1];
            permission_list[0] = permission;
            ActivityCompat.requestPermissions(this, permission_list, 1);
        }
    }
}

Finally remember to add RECEIVE_SMS permission to your manifest xml最后记得在清单 xml 中添加 RECEIVE_SMS 权限

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    <uses-permission android:name="android.permission.RECEIVE_SMS"/>
    <application>
        ...
    </application>
</manifest>

One more thing that these answers haven't mentioned - you should require the permission android.permission.BROADCAST_SMS.这些答案还没有提到的另一件事 - 您应该需要权限 android.permission.BROADCAST_SMS。 If you don't do this, any application can spoof messages in your app.如果您不这样做,任何应用程序都可以在您的应用程序中欺骗消息。

<receiver android:name=".SMSReceiver"
              android:exported="true"
              android:permission="android.permission.BROADCAST_SMS">
             <intent-filter>
                 <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
             </intent-filter>
 </receiver>

Also note that the Hangouts application will currently block my BroadcastReceiver from receiving SMS messages.另请注意,环聊应用程序当前将阻止我的 BroadcastReceiver 接收 SMS 消息。 I had to disable SMS functionality in the Hangouts application (Settings->SMS->Turn on SMS), before my SMS BroadcastReceived started getting fired.在我的 SMS BroadcastReceived 开始被解雇之前,我必须在环聊应用程序中禁用 SMS 功能(设置->短信->打开短信)。

Edit: It appears as though some applications will abortBroadcast() on the intent which will prevent other applications from receiving the intent.编辑:似乎某些应用程序会在意图上 abortBroadcast() ,这将阻止其他应用程序接收意图。 The solution is to increase the android:priority attribute in the intent-filter tag:解决办法是在intent-filter标签中增加android:priority属性:

    <receiver android:name="com.company.application.SMSBroadcastReceiver" >
        <intent-filter android:priority="500">
            <action android:name="android.provider.Telephony.SMS_RECEIVED" />
        </intent-filter>
    </receiver>

See more details here: Enabling SMS support in Hangouts 2.0 breaks the BroadcastReceiver of SMS_RECEIVED in my app在此处查看更多详细信息: 在 Hangouts 2.0 中启用 SMS 支持会破坏我的应用中 SMS_RECEIVED 的 BroadcastReceiver

Did you try with the emulator ?你用模拟器试过吗?

After deploying your application in the emulator, you can send events like SMS via the DDMS or via the command line by connecting with telnet :在模拟器中部署您的应用程序后,您可以通过 DDMS 或通过与 telnet 连接的命令行发送诸如 SMS 之类的事件:

telnet localhost <port_emulator>
send sms <incoming_tel_number> <sms_content>

port_emulator is usually 5554 port_emulator 通常是5554

You should read this acticle about send and receive sms programmatically.你应该阅读这篇关于以编程方式发送和接收短信的文章。 http://mobiforge.com/developing/story/sms-messaging-android http://mobiforge.com/developing/story/sms-messaging-android

Android Messenger (the SMS client) has a "Chat" feature which transmits messages over WiFi instead of SMS. Android Messenger( SMS客户端)具有“聊天”功能,可通过 WiFi 而不是 SMS 传输消息。

If the person you are testing with uses Messenger as well, you'll need to disable this feature on one or both of your devices otherwise there is no SMS message actually being received:如果您正在测试的人也使用 Messenger,则您需要在您的一台或两台设备上禁用此功能,否则实际上不会收到 SMS 消息:

To turn chat features off:要关闭聊天功能:

  1. Open Messages Messages Logo Round.打开消息消息标志圆形。
  2. Tap More More and then Settings.点击更多,然后点击设置。
  3. Tap Advanced and then Chat features.点击高级,然后点击聊天功能。
  4. Turn Enable chat features on or off.打开或关闭启用聊天功能。

https://support.google.com/messages/answer/7189714?hl=en https://support.google.com/messages/answer/7189714?hl=en

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM