测试的系统为MIUI10和模拟器(Pixel 2 API 26)
应用场景:短信验证码自动填写等
方法1为监听系统短信数据库,但是存在一个问题,就是收到短信之后需要
点击短信进入短信详情页面,才会触发广播
。
方法2通过监听通知栏,根据发通知的应用包名锁定对应的短信应用,从而可以在收到短信的同时获取短信内容
两种方法在获取短信的时候都是只获取收到回调时最新的一条短信,因此不推荐方法1。
首先需要获取对应的权限,高版本的系统需要写代码动态获取权限
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
-
使用ContentObserver监听系统短信数据库更新
1.1 实现代码- 监听短信数据库变化
class SmsObserver extends ContentObserver { private Context context; public SmsObserver(Context context, Handler handler) { super(handler); this.context = context; } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); //每当有新短信到来时,获取短消息的方法 getSmsFromPhone(); } private void getSmsFromPhone() { ContentResolver cr = context.getContentResolver(); String[] projection = new String[]{"_id", "body", "address"};//"_id", "address", "person",, "date", "type String where = " date > " + (System.currentTimeMillis() - 10 * 60 * 1000);//10分钟之内的短信 Cursor cur = cr.query(Uri.parse("content://sms/inbox"), projection, where, null, "date desc"); if (null == cur) return; try { if (cur.moveToFirst()) { String number = cur.getString(cur.getColumnIndex("address"));//手机号 String body = cur.getString(cur.getColumnIndex("body"));//内容 } } finally { cur.close(); } } }
- 初始化监听
val smsHandler: Handler = @SuppressLint("HandlerLeak") object : Handler() { //这里可以进行回调的操作 //TODO } smsObserver = SmsObserver(this, smsHandler) //监听短信 applicationContext.contentResolver.registerContentObserver( Uri.parse("content://sms/inbox"), true, smsObserver!! )
- 监听短信数据库变化
-
使用NotificationListenerService监听系统通知栏数据更新
2.1 实现代码-
继承NotificationListenerService(高版本的安卓系统需要在Service里面调用函数
startForeground
设置通知栏,否则会报错)class NotificationMonitor : NotificationListenerService() { private val match = arrayOf("com.android.mms", "com.google.android.apps.messaging") //暂时只有小米短信和谷歌短信的包名 // 有新的通知 override fun onNotificationPosted(sbn: StatusBarNotification) { super.onNotificationPosted(sbn) Log.i(getString(R.string.app_name), sbn.packageName) if (sbn.packageName in match) { Log.i(getString(R.string.app_name), "有新的短信") getSmsFromPhone() } } private fun getSmsFromPhone() { val cr: ContentResolver = contentResolver val projection = arrayOf("_id", "body", "address") //"_id", "address", "person",, "date", "type val where = (" date > " + (System.currentTimeMillis() - 10 * 60 * 1000)) val cur = cr.query(Uri.parse("content://sms"), projection, where, null, "date desc") ?: return cur.use { cur -> if (cur.moveToFirst()) { val number = cur.getString(cur.getColumnIndex("address")) //手机号 val body = cur.getString(cur.getColumnIndex("body")) //内容 } } } override fun onCreate() { super.onCreate() //设置通知栏 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channelId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { createNotificationChannel( "message_deliver_notification_service", "MessageDeliver Background Service" ) } else { // If earlier version channel ID is not used // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context) "" } val notificationBuilder = NotificationCompat.Builder(this, channelId) val notification = notificationBuilder.setOngoing(true) .setSmallIcon(R.mipmap.ic_launcher) .setPriority(NotificationCompat.PRIORITY_MIN) .setCategory(Notification.CATEGORY_SERVICE) .build() startForeground(1, notification) } } @RequiresApi(Build.VERSION_CODES.O) private fun createNotificationChannel(channelId: String, channelName: String): String { val chan = NotificationChannel( channelId, channelName, NotificationManager.IMPORTANCE_NONE ) chan.lightColor = Color.BLUE chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager service.createNotificationChannel(chan) return channelId } }
-
在AndroidManifest.xml的
application
标签里面注册Service<service android:name=".NotificationMonitor" android:label="@string/app_name" android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"> <intent-filter> <action android:name="android.service.notification.NotificationListenerService" /> </intent-filter> </service>
-
启动Service(这里由于安卓版本的不同,启动后台服务可以选择调用不同的函数)
val notification = Intent(this, NotificationMonitor::class.java) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { this.startForegroundService(notification) } else { this.startService(notification) }
-