Tôi đang cố gắng tạo một ứng dụng để theo dõi các tin nhắn SMS đến và khởi chạy một chương trình thông qua SMS đến, nó cũng nên đọc nội dung từ SMS.
Quy trình làm việc:
- SMS được gửi đến thiết bị Android
- ứng dụng tự thực thi
- Đọc thông tin SMS
Tôi đang cố gắng tạo một ứng dụng để theo dõi các tin nhắn SMS đến và khởi chạy một chương trình thông qua SMS đến, nó cũng nên đọc nội dung từ SMS.
Quy trình làm việc:
Câu trả lời:
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());
}
}
}
}
}
Lưu ý: Trong tệp kê khai của bạn, hãy thêm BroadcastReceiver-
<receiver android:name=".listener.SmsListener">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Thêm quyền này:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
SMS_RECEIVED
phát sóng trong 4.4 trở lên và hiện tại, chương trình phát sóng đó không thể bị hủy bỏ, nó chắc chắn hơn so với các phiên bản trước.
Lưu ý rằng trên một số thiết bị, mã của bạn sẽ không hoạt động mà không có android: ưu tiên = "1000" trong bộ lọc ý định:
<receiver android:name=".listener.SmsListener">
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Và đây là một số tối ưu hóa:
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();
}
}
}
}
Lưu ý :
Giá trị phải là số nguyên, chẳng hạn như "100". Số cao hơn có mức độ ưu tiên cao hơn. Giá trị mặc định là 0. Giá trị phải lớn hơn -1000 và nhỏ hơn 1000.
@Mike M. và tôi đã tìm thấy một vấn đề với câu trả lời được chấp nhận (xem ý kiến của chúng tôi):
Về cơ bản, không có điểm nào đi qua vòng lặp for nếu chúng ta không nối thông điệp nhiều phần mỗi lần:
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();
}
Lưu ý rằng chúng ta chỉ đặt msgBody
giá trị chuỗi của phần tương ứng của tin nhắn cho dù chúng ta đang sử dụng chỉ mục nào, điều này làm cho toàn bộ điểm lặp qua các phần khác nhau của tin nhắn SMS trở nên vô dụng, vì nó sẽ chỉ được đặt thành giá trị chỉ số cuối cùng. Thay vào đó, chúng ta nên sử dụng +=
, hoặc như Mike lưu ý , StringBuilder
:
Nói chung, đây là mã nhận SMS của tôi trông như thế nào:
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
}
Chỉ cần đưa câu trả lời này ra trong trường hợp bất cứ ai khác có cùng một sự nhầm lẫn.
Đây là những gì tôi đã sử dụng!
public class SMSListener extends BroadcastReceiver {
// Get the object of SmsManager
final SmsManager sms = SmsManager.getDefault();
String mobile,body;
public void onReceive(Context context, Intent intent) {
// Retrieves a map of extended data from the 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();
mobile=senderNum.replaceAll("\\s","");
body=message.replaceAll("\\s","+");
Log.i("SmsReceiver", "senderNum: "+ senderNum + "; message: " + body);
// Show Alert
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context,
"senderNum: "+ mobile+ ", message: " + message, duration);
toast.show();
} // end for loop
} // bundle is null
} catch (Exception e) {
Log.e("SmsReceiver", "Exception smsReceiver" +e);
}
}
}
Trong trường hợp bạn muốn xử lý ý định đối với hoạt động đã mở, bạn có thể sử dụng PendintIntent (Hoàn thành các bước bên dưới):
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) {
}
}
}
rõ ràng:
<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>
trên NewIntent:
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Toast.makeText(this, "onNewIntent", Toast.LENGTH_SHORT).show();
onSMSReceived(intent.getStringExtra("message"));
}
quyền:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
Nếu ai đó giới thiệu cách thực hiện tính năng tương tự (đọc OTP bằng SMS đã nhận) trên Xamarin Android như tôi:
Thêm mã này vào tệp AndroidManifest.xml của bạn:
<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" />
Sau đó, tạo lớp BroadcastReveiver trong Dự án Android của bạn.
[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]);
}
}
}
}
}
}
Đăng ký lớp BroadcastReceiver này trong lớp MainActivity của bạn trên Dự án Android:
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"));
}
}
Cảm ơn @Vineet Shukla (câu trả lời được chấp nhận) và @Ruchir Baronia (tìm thấy vấn đề trong câu trả lời được chấp nhận), bên dưới là Kotlin
phiên bản:
Thêm quyền:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
Đăng ký BroadcastReceiver trong AndroidManifest:
<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>
Thêm triển khai cho 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) {
}
}
}
}
}
Đôi khi sự kiện cháy hai lần vì vậy tôi thêm mLastTimeReceived = System.currentTimeMillis()
thực hiện phát sóng trên Kotlin:
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
}
}
Lưu ý: Trong tệp kê khai của bạn, hãy thêm BroadcastReceiver-
<receiver android:name=".listener.SmsListener">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Thêm quyền này:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
Câu trả lời được chấp nhận là chính xác và hoạt động trên các phiên bản Android cũ hơn, nơi HĐH Android yêu cầu quyền khi cài đặt ứng dụng, tuy nhiên trên các phiên bản mới hơn, Android không hoạt động ngay lập tức vì HĐH Android mới hơn yêu cầu quyền trong thời gian chạy khi ứng dụng yêu cầu tính năng đó . Do đó, để nhận SMS trên các phiên bản Android mới hơn bằng kỹ thuật được đề cập trong lập trình câu trả lời được chấp nhận cũng phải triển khai mã sẽ kiểm tra và yêu cầu quyền từ người dùng trong thời gian chạy. Trong trường hợp này, quyền kiểm tra chức năng / mã có thể được triển khai trong onCreate () của hoạt động đầu tiên của ứng dụng. Chỉ cần sao chép và dán theo hai phương thức trong hoạt động đầu tiên của bạn và gọi phương thức checkForSmsReceivePermissions () ở cuối onCreate ().
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");
}
}
}