Android-收听收到的短信

我试图创建一个应用程序来监测收到的短信,并启动一个程序通过收到的短信,也应该从短信的内容。

工作流程:

  • 发送到 Android 设备的短信
  • 自执行应用程序
  • 阅读短信信息
184585 次浏览
public class SmsListener extends BroadcastReceiver{


private SharedPreferences preferences;


@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub


if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){
Bundle bundle = intent.getExtras();           //---get the SMS message passed in---
SmsMessage[] msgs = null;
String msg_from;
if (bundle != null){
//---retrieve the SMS message received---
try{
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
for(int i=0; i<msgs.length; i++){
msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
msg_from = msgs[i].getOriginatingAddress();
String msgBody = msgs[i].getMessageBody();
}
}catch(Exception e){
//                            Log.d("Exception caught",e.getMessage());
}
}
}
}
}

注意: 在清单文件中添加 BroadcastReceiver-

<receiver android:name=".listener.SmsListener">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>

添加此权限:

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

注意,在一些设备上,如果意图过滤器中没有 机器人: 优先级 = “1000”,代码就无法工作:

<receiver android:name=".listener.SmsListener">
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>

以下是一些优化措施:

public class SmsListener extends BroadcastReceiver{


@Override
public void onReceive(Context context, Intent intent) {
if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(intent.getAction())) {
for (SmsMessage smsMessage : Telephony.Sms.Intents.getMessagesFromIntent(intent)) {
String messageBody = smsMessage.getMessageBody();
}
}
}
}

注意 :
该值必须是一个整数,如“100”。数字越大优先级越高。默认值为0。该值必须大于 -1000且小于1000。

这里有个链接。

@ Mike M 和我发现了一个问题:

基本上,如果我们不每次连接多部分消息,那么通过 for 循环是没有意义的:

for (int i = 0; i < msgs.length; i++) {
msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
msg_from = msgs[i].getOriginatingAddress();
String msgBody = msgs[i].getMessageBody();
}

请注意,无论我们处于哪个索引上,我们都只是将 msgBody设置为消息各部分的字符串值,这使得遍历 SMS 消息不同部分的整个循环过程毫无意义,因为它将被设置为最后一个索引值。相反,我们应该使用 +=,或者正如迈克指出的,StringBuilder:

总而言之,我的短信接收代码是这样的:

if (myBundle != null) {
Object[] pdus = (Object[]) myBundle.get("pdus"); // pdus is key for SMS in bundle


//Object [] pdus now contains array of bytes
messages = new SmsMessage[pdus.length];
for (int i = 0; i < messages.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]); //Returns one message, in array because multipart message due to sms max char
Message += messages[i].getMessageBody(); // Using +=, because need to add multipart from before also
}


contactNumber = messages[0].getOriginatingAddress(); //This could also be inside the loop, but there is no need
}

我只是提供这个答案以防其他人也有同样的困惑。

如果您想处理打开的活动的意图,可以使用 PendintInent (完成下面的步骤) :

public class SMSReciver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final Bundle bundle = intent.getExtras();
try {
if (bundle != null) {
final Object[] pdusObj = (Object[]) bundle.get("pdus");
for (int i = 0; i < pdusObj.length; i++) {
SmsMessage currentMessage = SmsMessage.createFromPdu((byte[]) pdusObj[i]);
String phoneNumber = currentMessage.getDisplayOriginatingAddress();
String senderNum = phoneNumber;
String message = currentMessage.getDisplayMessageBody();
try {
if (senderNum.contains("MOB_NUMBER")) {
Toast.makeText(context,"",Toast.LENGTH_SHORT).show();


Intent intentCall = new Intent(context, MainActivity.class);
intentCall.putExtra("message", currentMessage.getMessageBody());


PendingIntent pendingIntent= PendingIntent.getActivity(context, 0, intentCall, PendingIntent.FLAG_UPDATE_CURRENT);
pendingIntent.send();
}
} catch (Exception e) {
}
}
}
} catch (Exception e) {
}
}
}

舱单:

<activity android:name=".MainActivity"
android:launchMode="singleTask"/>
<receiver android:name=".SMSReciver">
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>

返回文章页面新意图:

 @Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Toast.makeText(this, "onNewIntent", Toast.LENGTH_SHORT).show();


onSMSReceived(intent.getStringExtra("message"));


}

权限:

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

如果有人提到如何在 Xamarin Android 上做同样的功能(使用接收到的短信阅读 OTP) ,比如我:

  1. 将这段代码添加到 AndroidManifest.xml 文件:

    <receiver android:name=".listener.BroadcastReveiverOTP">
    <intent-filter>
    <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
    </receiver>
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.BROADCAST_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />
    
  2. Then create your BroadcastReveiver class in your Android Project.

    [BroadcastReceiver(Enabled = true)] [IntentFilter(new[] { "android.provider.Telephony.SMS_RECEIVED" }, Priority = (int)IntentFilterPriority.HighPriority)]
    public class BroadcastReveiverOTP : BroadcastReceiver {
    public static readonly string INTENT_ACTION = "android.provider.Telephony.SMS_RECEIVED";
    
    
    protected string message, address = string.Empty;
    
    
    public override void OnReceive(Context context, Intent intent)
    {
    if (intent.HasExtra("pdus"))
    {
    var smsArray = (Java.Lang.Object[])intent.Extras.Get("pdus");
    foreach (var item in smsArray)
    {
    var sms = SmsMessage.CreateFromPdu((byte[])item);
    address = sms.OriginatingAddress;
    if (address.Equals("NotifyDEMO"))
    {
    message = sms.MessageBody;
    string[] pin = message.Split(' ');
    if (!string.IsNullOrWhiteSpace(pin[0]))
    {
    // NOTE : Here I'm passing received OTP to Portable Project using MessagingCenter. So I can display the OTP in the relevant entry field.
    MessagingCenter.Send<object, string>(this,MessengerKeys.OnBroadcastReceived, pin[0]);
    }
    }
    }
    }
    }
    }
    
  3. Register this BroadcastReceiver class in your MainActivity class on Android Project:

    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity {
    
    
    // Initialize your class
    private BroadcastReveiverOTP _receiver = new BroadcastReveiverOTP ();
    
    
    protected override void OnCreate(Bundle bundle) {
    base.OnCreate(bundle);
    
    
    global::Xamarin.Forms.Forms.Init(this, bundle);
    LoadApplication(new App());
    
    
    // Register your receiver :  RegisterReceiver(_receiver, new IntentFilter("android.provider.Telephony.SMS_RECEIVED"));
    
    
    }
    }
    

广播科特林的实施情况:

 private class SmsListener : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d(TAG, "SMS Received!")


val txt = getTextFromSms(intent?.extras)
Log.d(TAG, "message=" + txt)
}


private fun getTextFromSms(extras: Bundle?): String {
val pdus = extras?.get("pdus") as Array<*>
val format = extras.getString("format")
var txt = ""
for (pdu in pdus) {
val smsmsg = getSmsMsg(pdu as ByteArray?, format)
val submsg = smsmsg?.displayMessageBody
submsg?.let { txt = "$txt$it" }
}
return txt
}


private fun getSmsMsg(pdu: ByteArray?, format: String?): SmsMessage? {
return when {
SDK_INT >= Build.VERSION_CODES.M -> SmsMessage.createFromPdu(pdu, format)
else -> SmsMessage.createFromPdu(pdu)
}
}


companion object {
private val TAG = SmsListener::class.java.simpleName
}
}

注意: 在清单文件中添加 BroadcastReceiver-

<receiver android:name=".listener.SmsListener">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>

添加此权限:

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

感谢@Vineet Shukla (公认答案)和@Ruchir Baronia (在公认答案中发现问题) ,以下是 Kotlin版本:

添加权限:

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

在 Android 清单中注册 BroadcastReceiver:

<receiver
android:name=".receiver.SmsReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="2332412">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>

为 BroadcastReceiver 添加实现:

class SmsReceiver : BroadcastReceiver() {
private var mLastTimeReceived = System.currentTimeMillis()


override fun onReceive(p0: Context?, intent: Intent?) {
val currentTimeMillis = System.currentTimeMillis()
if (currentTimeMillis - mLastTimeReceived > 200) {
mLastTimeReceived = currentTimeMillis


val pdus: Array<*>
val msgs: Array<SmsMessage?>
var msgFrom: String?
var msgText: String?
val strBuilder = StringBuilder()
intent?.extras?.let {
try {
pdus = it.get("pdus") as Array<*>
msgs = arrayOfNulls(pdus.size)
for (i in msgs.indices) {
msgs[i] = SmsMessage.createFromPdu(pdus[i] as ByteArray)
strBuilder.append(msgs[i]?.messageBody)
}


msgText = strBuilder.toString()
msgFrom = msgs[0]?.originatingAddress


if (!msgFrom.isNullOrBlank() && !msgText.isNullOrBlank()) {
//
// Do some thing here
//
}
} catch (e: Exception) {
}
}
}
}
}

有时事件触发两次,所以我添加 mLastTimeReceived = System.currentTimeMillis()

接受的答案是正确的,可以在老版本的安卓系统上运行,安卓系统在安装应用程序时会请求许可。但是在新版本的安卓系统上,它不能立即运行,因为新版本的安卓系统会在运行时请求许可,当应用程序需要这个功能时。因此,为了在 Android 的新版本上接收短信,使用公认答案中提到的技术,程序员还必须实现在运行时检查和请求用户权限的代码。在这种情况下,权限检查功能/代码可以在应用程序的第一个活动的 onCreate ()中实现。只需在第一个活动中复制并粘贴以下两个方法,并在 onCreate ()的末尾调用 checkForSmsReceivePermission ()方法。

    void checkForSmsReceivePermissions(){
// Check if App already has permissions for receiving SMS
if(ContextCompat.checkSelfPermission(getBaseContext(), "android.permission.RECEIVE_SMS") == PackageManager.PERMISSION_GRANTED) {
// App has permissions to listen incoming SMS messages
Log.d("adnan", "checkForSmsReceivePermissions: Allowed");
} else {
// App don't have permissions to listen incoming SMS messages
Log.d("adnan", "checkForSmsReceivePermissions: Denied");


// Request permissions from user
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.RECEIVE_SMS}, 43391);
}
}


@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == 43391){
if(grantResults.length>0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
Log.d("adnan", "Sms Receive Permissions granted");
} else {
Log.d("adnan", "Sms Receive Permissions denied");
}
}
}

从现在开始,如果你不是一个默认的短信应用程序,那么发布一个具有 android.permission. RECEIVE _ SMS 权限的应用程序几乎是不可能的。Google 为短信捕捉提供了一个新的工具