Android两种方式监听短信内容---BroadcastReceiver和ContentObserver
16lz
2021-01-22
监听短信:
ContentObserver:监听短信数据库的变化
BroadCastReceiver:通过广播接收器来实现监听
拦截垃圾短信:用广播,如果用ContentObserver,垃圾短信已经存到收件箱了 用广播要考虑优先级不如第三方软件会被拦截
监 听 短 信:用ContentObserver,用广播如果短信长会被切割成多条
第一种方式:广播
SMSBroadcastReceiver:
package com.ddgl.ddlx.BroadcastReceiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.telephony.SmsMessage; import android.util.Log; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by 27c1 on 2016/12/27. */ public class SMSBroadcastReceiver extends BroadcastReceiver { private static final String TAG = "smsreceiver"; private String ss; private static MessageListener mMessageListener; @Override public void onReceive(Context context, Intent intent) { Log.i(TAG, "onReceive: " + "收到短信广播"); Bundle bundle = intent.getExtras(); SmsMessage msg = null; if (null != bundle) { Object[] smsObj = (Object[]) bundle.get("pdus"); for (Object object : smsObj) { msg = SmsMessage.createFromPdu((byte[]) object); Date date = new Date(msg.getTimestampMillis());//时间 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String receiveTime = format.format(date); Log.i(TAG, "onReceive:===="+"number:" + msg.getOriginatingAddress() + " body:" + msg.getDisplayMessageBody() + " time:" + msg.getTimestampMillis()); if (msg.getDisplayMessageBody().substring(0,9).equals("【丁丁旅行】验证码")){ ss = msg.getDisplayMessageBody().substring(9, 15); Log.i(TAG, "onReceive: 截取的为==="+ ss); if (ss.length()==6){ mMessageListener.onReceived(ss); abortBroadcast(); } } } } } //回调接口 public interface MessageListener { public void onReceived(String message); } public void setOnReceivedMessageListener(MessageListener messageListener) { this.mMessageListener = messageListener; } }MainActiivty:动态注册广播并修改edittext内容
@Override public void onStart() { super.onStart(); receiver = new SMSBroadcastReceiver(); IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED"); filter.setPriority(Integer.MAX_VALUE); getActivity().registerReceiver(receiver, filter); receiver.setOnReceivedMessageListener(new SMSBroadcastReceiver.MessageListener() { @Override public void onReceived(String message) { etLoginName.setText(message); } }); } //注销短信监听广播 @Override public void onDestroy() { super.onDestroy(); getActivity().unregisterReceiver(receiver); }短信权限:
<!--短信权限--> <uses-permission android:name="android.permission.RECEIVE_SMS"/> <uses-permission android:name="android.permission.SEND_SMS"/> <uses-permission android:name="android.permission.READ_SMS" />但是这个方法Android 5.1系统魅族手机可以 Android4.3系统oppo手机不可以
第二种方法:数据库读取短信记录:
MainActivity:
private SMSObserver observer; //点击完获取验证码就开始读取数据库 observer = new SMSObserver(getActivity(), smsHandler); getActivity().getContentResolver().registerContentObserver(SMS_INBOX, true, observer); //读取短信内容handler private Handler smsHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); Log.i(TAG, "handleMessage: msg===" + msg.obj); String autoCode = (String) msg.obj; etLoginName.setText(autoCode); } }; @Override public void onDestroy() { super.onDestroy(); getActivity().getContentResolver().unregisterContentObserver(observer); }SMSObserver:
package com.ddgl.ddlx.ContentObserver; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.Handler; import android.os.Message; import android.util.Log; import java.util.regex.Matcher; import java.util.regex.Pattern; import static com.ddgl.ddlx.fragment.LoginNoPassFragment.getCodeTime; /** * Created by 27c1 on 2016/12/29. */ public class SMSObserver extends ContentObserver { private static final String TAG = "smsobserver"; private Context context; public static Uri SMS_INBOX = Uri.parse("content://sms/"); private Handler handler = new Handler(); /** * Creates a content observer. * * @param handler The handler to run {@link #onChange} on, or null if none. */ public SMSObserver(Context context, Handler handler) { super(handler); this.context = context; this.handler = handler; } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); //每当有新短信到来时,使用我们获取短消息的方法 getSmsFromPhone(); } private void getSmsFromPhone() { ContentResolver cr = context.getContentResolver(); String[] projection = new String[]{"body"};//"_id", "address", "person",, "date", "type String where = " date > " + getCodeTime; Cursor cursor = cr.query(SMS_INBOX, projection, where, null, "date desc"); if (cursor != null) { if (cursor.moveToNext()) { String body = cursor.getString(cursor.getColumnIndex("body")); Log.i(TAG, "getSmsFromPhone:短信内容===" + body); if (body.contains("XXX验证码")) { //这里我是要获取自己短信服务号码中的验证码~~ String regEx = "[^0-9]"; Pattern p = Pattern.compile(regEx); Matcher m = p.matcher(body); String num = m.replaceAll("").trim().toString(); Log.i(TAG, "getSmsFromPhone: num===" + num); if (num != null) { Message message = new Message(); message.obj = num; handler.sendMessage(message); } } else { Log.i(TAG, "getSmsFromPhone: " + "没有收到XXX的短信"); } } } else { return; } } }
动态注册广播:写一个SMSBroadcastReceiver类
SMSBroadcastReceiver receiver = new SMSBroadcastReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction("android.provider.Telephony.SMS_RECEIVED"); filter.setPriority(Integer.MAX_VALUE); getActivity().registerReceiver(receiver, filter);静态注册广播:
<receiver android:name=".BroadcastReceiver.SMSBroadcastReceiver" android:enabled="true" android:exported="true"> <intent-filter android:priority="1000"> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver>数据库读取短信:
用ManageQuery还是不行 Android5.1系统魅族手机通知类短信读不到验证码
Android 6.0小米系统所有通知类短信都读不到
代码:
package com.miapsoft.intercept_mmsdemo.activity; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.example.intercept_mmsdemo.R; import android.app.Activity; import android.content.ContentValues; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.widget.EditText; public class MainActivity extends Activity{ EditText ed_mmscode; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ed_mmscode=(EditText) findViewById(R.id.ed_mms); SmsContent content = new SmsContent(new Handler()); //注册短信变化监听 this.getContentResolver().registerContentObserver(Uri.parse("content://sms/"), true, content); } /** * 监听短信数据库 */ class SmsContent extends ContentObserver { private Cursor cursor = null; public SmsContent(Handler handler) { super(handler); } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); //读取收件箱中指定号码的短信 cursor = managedQuery(Uri.parse("content://sms/inbox"), new String[]{"_id", "address", "read", "body"}, " address=? and read=?", new String[]{"10658464", "0"}, "_id desc");//按id排序,如果按date排序的话,修改手机时间后,读取的短信就不准了 if (cursor != null && cursor.getCount() > 0) { ContentValues values = new ContentValues(); values.put("read", "1"); //修改短信为已读模式 cursor.moveToNext(); int smsbodyColumn = cursor.getColumnIndex("body"); String smsBody = cursor.getString(smsbodyColumn); ed_mmscode.setText(getDynamicPassword(smsBody)); } //在用managedQuery的时候,不能主动调用close()方法, 否则在Android 4.0+的系统上, 会发生崩溃 if(Build.VERSION.SDK_INT < 14) { cursor.close(); } } } /** * 从字符串中截取连续6位数字 * 用于从短信中获取动态密码 * @param str 短信内容 * @return 截取得到的6位动态密码 */ public static String getDynamicPassword(String str) { Pattern continuousNumberPattern = Pattern.compile("[0-9\\.]+"); Matcher m = continuousNumberPattern.matcher(str); String dynamicPassword = ""; while(m.find()){ if(m.group().length() == 6) { System.out.print(m.group()); dynamicPassword = m.group(); } } return dynamicPassword; } }