android实现获取短信验证码并自动填充-kb88凯时官网登录

来自:网络
时间:2023-06-14
阅读:
目录

前言

最近弄了个短信自动填充功能,一开始觉得很简单,不就是动态注册个广播接收器去监听短信消息不就可以了吗?结果没这么简单,问题就出在机型的适配上。小米的短信权限、荣耀、oppo的短信监听都是坑,暂时就用这三个手机测了,其他的遇到了再补充。

下面简单讲讲:

权限

申请权限

短信属于隐私权限,android 6.0后需要动态申请权限。首先在manifest里面注册权限:



在需要用的地方,动态申请下:

string[] smspermission = {manifest.permission.read_sms, manifest.permission.receive_sms};

小米短信权限问题

本来这样权限问题就搞定了,但是在小米手机上就不行。小米手机会把短信归类到通知类权限里:

在 contextcompat.checkselfpermission 的时候会直接返回true,并且不会弹出权限对话框,而是在实际使用的时候才会咨询用户,按理说好像和我们逻辑没有冲突,但是在使用receiver进行监听前,不是得确保有权限么?实际效果也是,在没有权限时,不能获取到短信的广播。

小米短信权限解决

在网上找了找办法,好像也没多少博文,但是大致有了思路:不是用的时候才申请么?那我就先用一下,再去用receiver监听。下面是方法:

// 读取一下试试,能读取到就有权限
boolean flag = false;
try {
    uri uri = uri.parse("content://sms/inbox");
    contentresolver cr = context.getcontentresolver();
    string[] projection = new string[]{"_id"};
    cursor cur = cr.query(uri, projection, null, null, "date desc");
    if (null != cur) {
        cur.close();
    }
    lag = true;
}catch (exception e) {
    e.printstacktrace();
}

这里仅针对小米手机啊,对小米手机的判断我只是用 android.os.build.manufacturer 简单判断了下,如果有更高要求请查找资料。

使用receiver进行监听

编写smsreceiver

这里也是网上随便找了个代码,能用,但是在荣耀手机上却是偶尔能收到一次,后面几次就收不到了,打了log也没进入到onreceive中,这就很离奇了,排查了很久。同样的代码,在小米手机上是没问题的,那就只可能是适配问题了。

import android.content.broadcastreceiver;
import android.content.context;
import android.content.intent;
import android.os.bundle;
import android.telephony.smsmessage;
import android.util.log;
public class smsreceiver extends broadcastreceiver {
    @override
    public void onreceive(context context, intent intent) {
        //toast.maketext(context, "收到信息", toast.length_long).show();
        log.d("smsreceiver", "onreceive: "   intent.getaction());
        if(intent.getaction().equals("android.provider.telephony.sms_received")){
            //intent.getextras()方法就是从过滤后的意图中获取携带的数据,
            // 这里携带的是以“pdus”为key、短信内容为value的键值对
            // android设备接收到的sms是pdu形式的
            bundle bundle = intent.getextras();
            smsmessage msg;
            if (null != bundle){
                //生成一个数组,将短信内容赋值进去
                object[] smsobg = (object[]) bundle.get("pdus");
                //遍历pdus数组,将每一次访问得到的数据方法object中
                for (object object:smsobg){
                    //获取短信
                    msg = smsmessage.createfrompdu((byte[])object);
                    //获取短信内容
                    string content = msg.getdisplaymessagebody();
                    log.d("smsreceiver", "onreceive: content = "   content);
                    //获取短信发送方地址
                    string from = msg.getoriginatingaddress();
                    log.d("smsreceiver", "onreceive: from = "   from);
                    // todo ...
                }
            }
        }
    }
}

使用方法:

// 使用广播进行监听
intentfilter smsfilter = new intentfilter();
smsfilter.addaction("android.provider.telephony.sms_received");
smsfilter.addaction("android.provider.telephony.sms_deliver");
if (smsreceiver == null) {
    smsreceiver = new smsreceiver();
}
smsreceiver.setcallbackcontext(callbackcontext);
context.registerreceiver(smsreceiver, smsfilter);

接触监听,最好在收到短信的时候就取消注册广播:

context.unregisterreceiver(smsreceiver);

解决oppo手机无法接收短信广播问题

本来小米荣耀都搞定了,给测试一测,结果又不行了。收不到广播,用下面的contentobserver还总拿不到对的数据。找了下资料,发现oppo手机需要在短信app进行设置。

ps. 后面发现华为、荣耀都是这样,会对验证码进行保护。可以使用contentobserver 监听,能触发onchange,但是拿不到uri,不过可以使用查询,拿到倒叙的第一条数据,取出其中的date属性,比对监听时的时间,如果短信两分钟有效,那就看看第一条数据是不是在两分钟内,如果不是,那就是没拿到,问题就出在用户开启了短信验证码保护,可以提示用户自行输入验证码(毕竟这个不是我们的锅)。

解决方法: 在短信 -> 短信设置里面 -> 打开禁止后台应用读取验证码

解决荣耀无法连续监听短信的问题

既然上面的方法没用了,只能找新的办法喽,网上很多提供了两种办法,第二种就是通过contentresolver去监听短信添加的更新动作,其实也和广播类似,代码如下:

import android.content.context;
import android.database.contentobserver;
import android.database.cursor;
import android.net.uri;
import android.os.build;
import android.os.handler;
import android.provider.telephony;
import android.util.log;
import androidx.annotation.requiresapi;
@requiresapi(api = build.version_codes.kitkat)
public class readsmsobserver extends contentobserver {
    private final context context;
    public readsmsobserver(handler handler, context context) {
        super(handler);
        this.context = context;
    }
    private static final string sms_inbox_uri = "content://sms/inbox";//api level>=23,可直接使用telephony.sms.inbox.content_uri,用于获取cusor
    // private static final string sms_uri = "content://sms";//api level>=23,可直接使用telephony.sms.content_uri,用于注册内容观察者
    private static final string[] projection = new string[]{
            telephony.sms._id,
            telephony.sms.address,
            telephony.sms.body,
            telephony.sms.date
    };
    @override
    public void onchange(boolean selfchange, uri uri) {
        super.onchange(selfchange);
        log.d("readsmsobserver", "onchange: ");
        // 当收到短信时调用一次,当短信显示到屏幕上时又调用一次,所以需要return掉一次调用
        if(uri.tostring().equals("content://sms/raw")){
            return;
        }
        // 读取短信收件箱,只读取未读短信,即read=0,并按照默认排序
        cursor cursor = context.getcontentresolver().query(uri.parse(sms_inbox_uri), projection,
                telephony.sms.read   "=?", new string[]{"0"}, telephony.sms.inbox.default_sort_order);
        if (cursor == null) return;
        // 获取倒序的第一条短信
        if (cursor.movetofirst()) {
            // 读取短信发送人
            string address = cursor.getstring(cursor.getcolumnindex(telephony.sms.address));
            log.d("readsmsobserver", "onchange: address = "   address);
            // 读取短息内容
            string smsbody = cursor.getstring(cursor.getcolumnindex(telephony.sms.body));
            log.d("readsmsobserver", "onchange: smsbody = "   smsbody);
            
            // todo 传递出去,最好切下线程
        }
        // 关闭cursor的方法
        cursor.close();
    }
}

用的时候要注册和取消注册:

// 使用contentresolver进行监听
if (build.version.sdk_int >= build.version_codes.kitkat) {
    if (smsobserver == null) {
        smsobserver = new readsmsobserver(new smshandler(), context);
    }
    smsobserver.setcallbackcontext(callbackcontext);
    context.getcontentresolver().registercontentobserver(
        uri.parse("content://sms/"), true, smsobserver);
}

取消注册:

context.getcontentresolver().unregistercontentobserver(smsobserver);

解决oppo手机无法拿到最新短信问题

很神奇啊,每次使用contentobserver去监听短信变化,明明onchange触发了,但是去拿短信就是拿不到最新的,开了上面的设置也不行,弄了好久。

最后想的解决办法是,两种方式同时监听,在onchange触发后等待三秒钟(开始试了1s还不行),看看有没有onreceive,如果有就直接使用onreceive的短信,如果没有再验证onchange内拿到的短信,看看是不是有效时间内的,连倒叙第一个都在有效时间外,那就是没拿到了,直接舍弃了。

ps. 后续更新,感觉这些问题都可能是手机系统开了短信验证码保护。

思路是这样,做起来不麻烦,用个handler就可以解决,读者自行处理吧。

以上就是android实现获取短信验证码并自动填充的详细内容,更多关于android获取短信验证码的资料请关注其它相关文章!

返回顶部
顶部
网站地图