Android监听系统短信数据库变化-提取短信内容

由于监听系统短信广播受到权限的限制,所以很多手机可能使用这种方式没法监听广播,从而没办法获取到系统短信,所以又重新开辟一条路。

Android监听系统短信数据库内容变化使用场景:

1、监听短信数据库的变化,添加删除修改,变化的时候会回调onChange方法

2、提取刚刚变化的那条短信的内容

备注:

1、这种方式虽然一开始能够监听到数据变化,但是要判断是刚刚接手到的短信,还需要做一些处理,具体看代码

2、这种方式需要从数据库里面去读取刚刚加入的那条短信,所以需要读取数据库权限,会弹出系统的权限申请框,所以注意使用时机

import android.content.ContentResolver;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.text.TextUtils;

/**
 * 数据库观察者
 */
public class SmsDatabaseChaneObserver extends ContentObserver {
    // 只检查收件箱
    public static final Uri MMSSMS_ALL_MESSAGE_URI = Uri.parse("content://sms/inbox");
    public static final String SORT_FIELD_STRING = "_id asc";  // 排序
    public static final String DB_FIELD_ID = "_id";
    public static final String DB_FIELD_ADDRESS = "address";
    public static final String DB_FIELD_PERSON = "person";
    public static final String DB_FIELD_BODY = "body";
    public static final String DB_FIELD_DATE = "date";
    public static final String DB_FIELD_TYPE = "type";
    public static final String DB_FIELD_THREAD_ID = "thread_id";
    public static final String[] ALL_DB_FIELD_NAME = {
            DB_FIELD_ID, DB_FIELD_ADDRESS, DB_FIELD_PERSON, DB_FIELD_BODY,
            DB_FIELD_DATE, DB_FIELD_TYPE, DB_FIELD_THREAD_ID };
    public static int mMessageCount = -1;
    
    private static final long DELTA_TIME = 60 * 1000;
    private ContentResolver mResolver;

    public SmsDatabaseChaneObserver(ContentResolver resolver, Handler handler) {
        super(handler);
        mResolver = resolver;
    }

    @Override
    public void onChange(boolean selfChange) {
        onReceiveSms();
    }

    private void onReceiveSms() {
        Cursor cursor = null;
        // 添加异常捕捉
        try {
            cursor = mResolver.query(MMSSMS_ALL_MESSAGE_URI, ALL_DB_FIELD_NAME,
                    null, null, SORT_FIELD_STRING);
            final int count = cursor.getCount();
            if (count <= mMessageCount) {
                mMessageCount = count;
                return;
            }
            // 发现收件箱的短信总数目比之前大就认为是刚接收到新短信---如果出现意外,请神保佑
            // 同时认为id最大的那条记录为刚刚新加入的短信的id---这个大多数是这样的,发现不一样的情况的时候可能也要求神保佑了
            mMessageCount = count;
            if (cursor != null) {
                cursor.moveToLast();
                final long smsdate = Long.parseLong(cursor.getString(cursor.getColumnIndex(DB_FIELD_DATE)));
                final long nowdate = System.currentTimeMillis();
                // 如果当前时间和短信时间间隔超过60秒,认为这条短信无效
                if (nowdate - smsdate > DELTA_TIME) {
                    return;
                }
                final String strAddress = cursor.getString(cursor.getColumnIndex(DB_FIELD_ADDRESS));    // 短信号码
                final String strbody = cursor.getString(cursor.getColumnIndex(DB_FIELD_BODY));          // 在这里获取短信信息
                final int smsid = cursor.getInt(cursor.getColumnIndex(DB_FIELD_ID));
                if (TextUtils.isEmpty(strAddress) || TextUtils.isEmpty(strbody)) {
                    return;
                }
                // 得到短信号码和内容之后进行相关处理
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                try {  // 有可能cursor都没有创建成功
                    cursor.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

下面是对数据库观察者的注册,使用方式与广播类似,生命周期也需要自己控制,结合自己使用的Activity或者Service的生命周期来进行控制。

public static final Uri SMS_MESSAGE_URI = Uri.parse("content://sms");
private static SmsDatabaseChaneObserver mSmsDBChangeObserver;
private static void registerSmsDatabaseChangeObserver(ContextWrapper contextWrapper) {
    //因为,某些机型修改rom导致没有getContentResolver
    try {
        SmsDatabaseChaneObserver = new SmsDatabaseChaneObserver(contextWrapper.getContentResolver(), new Handler());
        contextWrapper.getContentResolver().registerContentObserver(SMS_MESSAGE_URI, true, mSmsDBChangeObserver);
    } catch (Throwable b) {
    }
}

private static void unregisterSmsDatabaseChangeObserver(ContextWrapper contextWrapper) {
    try {
        contextWrapper.getContentResolver().unregisterContentObserver(SmsDatabaseChaneObserver);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

监听一般放在Service中,所以需要在Service时创建时注册监听,Service销毁时取消监听

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菩提树下的杨过

jQuery扩展以及gzip压缩测试

<!doctype html> <html> <head> <meta http-equiv="content-type" content="text/h...

2315
来自专栏Android 研究

APK安装流程详解15——PMS中的新安装流程下(装载)补充

代码位置在PackageManagerService的installPackageLI方法里面会调用到,代码如下: PackageManagerService...

1921
来自专栏Hongten

Java Web 文件上传

 在我们的web开发中,很多的时候都需要把本机的一些文件上传到web服务器上面去

2343
来自专栏后台开发+音视频+ffmpeg

dpvs源码分析(续)

在上一篇https://cloud.tencent.com/developer/article/1180256?s=original-sharing,我们已经介...

3621
来自专栏Java架构师学习

分布式消息队列Apache RocketMQ源码剖析-Producer分析正文总结

正文 首先我们看一下Producer的继承结构: ? image.png MQAdmin主要包含一些管理性的接口,比如创建topic、查询某个特定消息以方便排查...

3837
来自专栏俞其荣的博客

Android Architecture Component之LiveData解析HeaderLiveDataFooter

Android Architecture Component 是 Google 在 2017 年推出的一套帮助开发者解决 Android 架构设计的方案。里面有...

983
来自专栏Jack的Android之旅

刨解OkHttp框架

继AsyncTask,又把手术刀指向OkHttp,有时候解析源码会上瘾。因为源码里包含的东西仿佛就是组成计算机世界的砖头,水分,只要有这些东西,就可以保罗万物,...

1132
来自专栏IT开发技术与工作效率

VBA非登陆下载Excel文件并处理例子

1234
来自专栏西二旗一哥

iOS - autoreleasepool and @autoreleasepool

+ 在一个自动引用计数的环境中(并不是垃圾回收机制),一个包含了多个对象的 NSAutoreleasePool 对象能够接收 autorelease 消息并且...

1264
来自专栏Android 研究

Android Handler机制6之MessageQueue简介

我们知道MessageQueue就一个构造函数 代码在MessageQueue.java 68行

1062

扫码关注云+社区