天霸动霸tua 发表于 2018-5-23 11:05

[Android]利用Andorid广播实现短信验证码自动填写

本帖最后由 wushaominkk 于 2018-6-5 09:21 编辑

广播

安卓广播BroadCast是安卓四大组件之一,在 Android 开发中,BroadcastReceiver 的应用场景非常多,现在我们用它来做一个简单的短信验证码自动填写
准备
       我们先来理一下思路(思路很重要,大家不要一开始就上来敲代码,一步一步来)
流程大概是这样,我们在第一个app点击获取验证码后,另一个app就发出一条验证码,我们在第一个app中拿到验证码并且自动填到输入框中。

两个app ,一个叫verificationcodedome,接收验证码。另一个 sendSMSdome,发送验证码信息,布局很简单,就几个按钮个几个输入框
verificationcodedome

MainActivity.java
package activitydome.ysl.com.verificationcodedome;

import android.app.PendingIntent;
import android.content.Intent;
import android.os.CountDownTimer;
import android.provider.Telephony;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    Button btn;
    EditText editText;

    private static MainActivity mainActivity;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      mainActivity = this;
      editText = findViewById(R.id.edit);
      btn = findViewById(R.id.btn);
      //点击获取验证码按钮
      btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //启动倒计时
                new MyCountDownTimer(60000,1000).start();
                //发一条短信另一个手机,告诉它我需要一条验证码
                sendSMS();
            }
      });
    }

    public static MainActivity getInstace(){
      return mainActivity;
    }

    public void updateEditText(final String code){
      MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this,"验证码来了:"+code,Toast.LENGTH_SHORT).show();
                editText.setText(code);
            }
      });
    }

    //发送信息的代码
    public void sendSMS(){

      SmsManager manager = SmsManager.getDefault();
      PendingIntent pi = PendingIntent.getActivity(this,0,new Intent(this,Telephony.Sms.class),0);
      //给5556号码发一条短信,内容为2AB25D0130C04299,内容随意,后面我们要在另一个app判断短信内容是否为这个字符串,
      manager.sendTextMessage("5556",null,"2AB25D0130C04299",pi,null);
    }


    //实现点击按钮倒计时效果
    class MyCountDownTimer extends CountDownTimer{

      public MyCountDownTimer(long millisInFuture, long countDownInterval) {
            super(millisInFuture, countDownInterval);
      }

      @Override
      public void onTick(long millisUntilFinished) {
            btn.setClickable(false);
            btn.setText(millisUntilFinished/1000+"s");
      }

      @Override
      public void onFinish() {
            btn.setClickable(true);
            btn.setText("重新获取验证码");
      }
    }
}


新建一个包broadcast,在里面新建一个SMSReceiver广播接收类
SMSReceiver.java
package broadcast;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.SmsMessage;
import android.util.Log;

import activitydome.ysl.com.verificationcodedome.MainActivity;

/**
* Created by 10734 on 2018/5/22 0022.
*/

public class SMSReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
      //拿到短信对象数组
      Object [] objects = (Object[]) intent.getExtras().get("pdus");
      //循环遍历每个短信对象
      for(Object obj : objects){
            byte [] bytes = (byte[]) obj;
            //短信对象转换成SmsMessage
            SmsMessage message = SmsMessage.createFromPdu(bytes);
            //获得发送号码
            String number = message.getOriginatingAddress();
            //获得短信内容
            String msg = message.getMessageBody();
            Log.i("信息内容:" ,number+"_"+ message.getMessageBody());
            //如果号码是验证码发送者的号码,就提取验证码
            if(number.equals("15555215556")){
                //比如短信内容是:(你的验证码为:125314),用substring提取“ :”后面的6个数字
                String code = msg.substring(msg.indexOf(":")+1);
                Log.i("提取的验证码:" , message.getMessageBody());
                //通过MainActivity把验证码更新到EditText中
                MainActivity.getInstace().updateEditText(code);
            }
      }
    }
}


广播和Activity一样,需要在注册 ,注册分动态注册和静态注册,我们使用静态注册,也就是在AndroidManifest.xml中注册
<receiver android:name=".broadcast.SMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
这样只要你手机使用短信,这个类就会拦截它,你可以在里面做你想做的事情

还有权限,在Android6.0之后权限的管理也越加严格,我们需要配置权限
权限
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>

好了,第一个应用就差不多了


sendSMSDome
MainActivity.java

package activitydome.ysl.com.sendmsmdome;

import android.app.PendingIntent;
import android.content.Intent;
import android.provider.Telephony;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    EditText phonenumber_edit,context_edit;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      phonenumber_edit = findViewById(R.id.phonenumber_edit);
      context_edit = findViewById(R.id.context_edit);
      findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String phonenumber = phonenumber_edit.getText().toString();
                String context = context_edit.getText().toString();
                if("".equals(phonenumber) || "".equals(context)){
                  Toast.makeText(MainActivity.this,"号码和内容不能为空",Toast.LENGTH_SHORT).show();
                }else {
                  sendSMS(phonenumber,context);
                }
            }
      });
    }

    //发送验证码
    public void sendSMS(String phonenumber,String context){
      SmsManager manager = SmsManager.getDefault();
      String message = "你的验证码为:"+context;
      PendingIntent pi = PendingIntent.getActivity(this,0,new Intent(this,Telephony.Sms.class),0);
      manager.sendTextMessage(phonenumber,null,message,pi,null);
      Toast.makeText(MainActivity.this,"发送成功",Toast.LENGTH_SHORT).show();
    }
}





SMSReceiver.java
package activitydome.ysl.com.sendmsmdome.broadcast;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.provider.Telephony;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.util.Log;
import android.widget.Toast;

import java.util.Random;


/**
* Created by 10734 on 2018/5/22 0022.
*/

public class SMSReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
      SmsManager manager = SmsManager.getDefault();
      Object [] objects = (Object[]) intent.getExtras().get("pdus");
      for(Object obj : objects){
            byte [] bytes = (byte[]) obj;
            SmsMessage message = SmsMessage.createFromPdu(bytes);
            String str = message.getMessageBody();
            String number = message.getOriginatingAddress();
            Log.i("收到请求号码:" ,number);
            //如果短信内容是2AB25D0130C04299,就给这个号码发一条验证码
            if(str.equals("2AB25D0130C04299")){
                PendingIntent pi = PendingIntent.getActivity(context,0,new Intent(context,Telephony.Sms.class),0);
                Random random= new Random();
                int code = random.nextInt(999999);
                if(code < 100000){
                  code = code + 100000;
                }
                String msg = "您的验证码为:"+code;
                Log.i("sendSMS", "给号码"+number+"发送验证码="+code);
                Toast.makeText(context,"自动发送验证码", Toast.LENGTH_SHORT).show();
                manager.sendTextMessage(number,null,code+msg,pi,null);
            }
      }
    }
}

同样的要注册和配置权限
注册
<receiver android:name=".broadcast.SMSReceiver">
    <intent-filter>
      <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver>

权限
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>



这样第二个应用也OK了


效果




注意
android系统版有可能不弹出授权管理,那我们手动给权限
拖动app,应用信息->权限->允许短信



不怎么会写教程,感觉很啰嗦,大家有什么问题可以问我,也许有个好的代码可以 实现,大家有建议可以一起讨论,最后祝大家好好学习天天向上!!!
我用的AndroidStudio是3.0的,导入的时候修改一下gradle文件Model sendsmsdome是发送短信的APP,verificationcodedome是接收验证码的APP
等我把工程打包好再上传

lan666 发表于 2018-5-29 15:55

学习感谢分享

Hmily 发表于 2018-5-23 14:39

图片不能直接粘贴,需要上传才可以,看这个帮助学习修改下:https://www.52pojie.cn/misc.php?mod=faq&action=faq&id=29&messageid=36

觉对无敌 发表于 2018-6-5 11:53

写得不错,thx:
   总结下,学到的知识点:
   1.如何发送短信。(权限+SmsManager)
   2.倒计时的实现。(CountDownTimer)
   3.如何接受短信并解析内容。(aciton为Telephony.SMS_RECEIVED广播)

天霸动霸tua 发表于 2018-5-24 12:54

Hmily 发表于 2018-5-23 14:39
图片不能直接粘贴,需要上传才可以,看这个帮助学习修改下:https://www.52pojie.cn/misc.php?mod=faq&acti ...

嗯 谢啦。我重新编辑

wangjin52748232 发表于 2018-5-27 04:47

验证码能不能发送文字,求楼主教

天霸动霸tua 发表于 2018-5-28 12:27

wangjin52748232 发表于 2018-5-27 04:47
验证码能不能发送文字,求楼主教

也可以不过你要在代码里修改提取验证码的规则

wangjin52748232 发表于 2018-5-28 14:46

766616786扣

wangjin52748232 发表于 2018-5-28 14:47

你有软件成型的吗?求

天霸动霸tua 发表于 2018-5-28 18:55

wangjin52748232 发表于 2018-5-28 14:47
你有软件成型的吗?求

有 我有源码的 等我打包上传上来

天霸动霸tua 发表于 2018-5-28 19:03

wangjin52748232 发表于 2018-5-28 14:47
你有软件成型的吗?求

我源码上传好了
页: [1] 2
查看完整版本: [Android]利用Andorid广播实现短信验证码自动填写