隐藏

Android短信发送,监听,及其工具类封装

发布:2019/4/1 14:49:17作者:管理员 来源:本站 浏览次数:1283

Android短信发送,监听,及其工具类封装


这几天在读ViewPager及相关控件的源码和相关开源的代码,还没构思好比较系统容易理解记忆的文章内容概述,就分享个封装的工具类供同仁们参考一下吧

一,封装 :发送短信

发送短信比较简单,主要有两种实现方式,一种是使用Intent通过系统短信应用,一种是直接调用短信接口发送短信;根据使用场景不同我一共封装了三个方法:

  • 调用系统发短信界面 不需要用户自己输入接收方的电话号码
  • 
    			
    1. /**
    2. * 调用系统发短信界面 不需要用户自己输入接收方的电话号码
    3. *
    4. * @param context Activity
    5. * @param phoneNumber 手机号码
    6. * @param smsContent 短信内容
    7. */
    8. public static void sendMessageByIntent(Context context, String phoneNumber, String smsContent) {
    9. if (phoneNumber == null || phoneNumber.length() < 4) {
    10. return;
    11. }
    12. Uri uri = Uri.parse("smsto:" + phoneNumber);
    13. Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
    14. intent.putExtra("sms_body", smsContent);
    15. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    16. if (intent.resolveActivity(context.getPackageManager()) != null) {
    17. context.startActivity(intent);
    18. }
    19. }

    • 调用系统发短信界面,需要用户自己输入接收方的电话号码
    
    			
    1. /** 调用系统发短信界面,需要用户自己输入接收方的电话号码
    2. *
    3. * 示例:SMSUtil.sendMessageByIntent(MainActivity.this,"你好");
    4. *
    5. * @param context
    6. * @param message
    7. */
    8. public static void sendMessageByIntent(Context context, String message) {
    9. Intent intent = new Intent(Intent.ACTION_VIEW);
    10. intent.putExtra("sms_body", message);
    11. intent.setType("vnd.android-dir/mms-sms");
    12. if (intent.resolveActivity(context.getPackageManager()) != null) {
    13. context.startActivity(intent);
    14. }
    15. }
    • 直接调用短信接口发短信
    
    			
    1. /**
    2. * 直接调用短信接口发短信
    3. * @param ActivityOrSetvice Activity
    4. * @param phoneNumber
    5. * @param smsContent
    6. */
    7. public static void sendMessageBySysterm(Context ActivityOrSetvice, String phoneNumber, String smsContent) {
    8. if (phoneNumber == null || phoneNumber.length() < 4) {
    9. return;
    10. }
    11. //获取短信管理器
    12. android.telephony.SmsManager smsManager = android.telephony.SmsManager.getDefault();
    13. //拆分短信内容(手机短信长度限制)
    14. List<String> divideContents = smsManager.divideMessage(smsContent);
    15. for (String text : divideContents) {
    16. smsManager.sendTextMessage(phoneNumber, null, text, null, null);
    17. }
    18. }

    别忘记了添加权限:
  • <uses-permission android:name="android.permission.SEND_SMS" />

    二,通过BroadcastReceiver监听短信的代码

    此段代码实现的是通过监听sms广播,把或得到指定号码的短信内容传给声明的TextView,为什么是TextView呢,因为几乎所有有setText()或android:setText=”“属性的View都是TextView的子类(或间接子类)。

    
    			
    1. /**
    2. * 原理:
    3. * Android收到短信后系统会发送一个android.provider.Telephony.SMS_RECEIVED广播。
    4. * 把它放在Bundle(intent.Extras)中,Bundle可以理解为一个Map,短信采用"pdus"作为键,
    5. * pdus应该是protocol description units的简写,也就是一组短信。
    6. * Android不是一接收到短信就立刻发出广播,会有一定的延迟,
    7. * 所以就有可能有多条短信,所以才会用数组来存放。
    8. */
    9. import android.content.BroadcastReceiver;
    10. import android.content.Context;
    11. import android.content.Intent;
    12. import android.os.Bundle;
    13. import android.telephony.SmsMessage;
    14. import android.widget.TextView;
    15. /**
    16. * 作者:liuyaowei ;日期:2016-07-16.
    17. * QQ:1054185214
    18. * 类作用:监听短信广播, 获取短信
    19. */
    20. public class SmsBroadcastReceiver extends BroadcastReceiver {
    21. private String address=null; //需要监听的号码
    22. private TextView text ;
    23. public SmsBroadcastReceiver(String address, TextView text) {
    24. this.address=address;
    25. this.text=text;
    26. }
    27. @Override
    28. public void onReceive(Context context, Intent intent) {
    29. Bundle bundle = intent.getExtras();
    30. SmsMessage[] smsMessages = null;
    31. Object[] pdus = null;
    32. if (bundle != null) {
    33. pdus = (Object[]) bundle.get("pdus");
    34. }
    35. if (pdus !=null){
    36. smsMessages = new SmsMessage[pdus.length];
    37. String sender = null;
    38. String content = null;
    39. for (int i=0; i<pdus.length; i++){
    40. smsMessages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
    41. sender = smsMessages[i].getOriginatingAddress(); // 获取短信的发送者
    42. content = smsMessages[i].getMessageBody(); // 获取短信的内容
    43. if (sender.equals(address)){ //如果收到信息的号码和指定的号码相同
    44. text.setText(content); //返回信息内容
    45. break;
    46. }
    47. }
    48. }
    49. }
    50. }

    三,通过ContentObserver监听短信的代码

    ContentObserver,是Android实现的内容观察者其中一个实现(与另一类DataSetObservable都是抽象类ContentObserver的实现),目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理。这个是我在曾经看到并收集的认为较好代码实现,和上一个功能类似,更进一步处理短信内容得到验证码中的数字,稍加修改,把得到的验证码同样传入TextView中。

    
    			
    1. /**
    2. * 为了减少用户的操作步骤,在获得短信验证码的时候,我们可以监听特殊手机号码的短信,
    3. * 截取信息当中的短信验证码(其实有很多应用都监听短信例如360短信,一些信用卡或者是记账类的应用)。
    4. *
    5. * 原理:可以使用一个自定义的BroadcastReceiver来监听短信,在监听结果当中过滤手机号,
    6. * 在需要回填的activity当中实现实例化广播并且实现其回调接口,在接口当中进行回填验证码,
    7. * 在销毁activity时销毁链接。但是这样操作会出现一些问题,
    8. * 由于一些其他的应用也会使用广播监听手机例如QQ通讯录或者是360通讯录等有的时候会被其拦截,
    9. * 即使修改优先级也会出现不能进行回填的问题。所有这里可以采用另外一种的解决方法:
    10. * 使用ContentProvider来监听短信数据库的变化,
    11. * 在自定义的ContentObserver当中实现onChange的方法进行监听特定手机号的短信,
    12. * 然后进行信息截取在填充到需要填充的位置。
    13. *
    14. * “ContentObserver,内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,
    15. * 它类似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它。
    16. * 触发器分为表触发器、行触发器,相应地ContentObserver也分为“表“ContentObserver、“行”ContentObserver,
    17. * 当然这是与它所监听的Uri MIME Type有关的。”
    18. *
    19. * 摘自:自动填充短信验证码(使用ContentObserver):http://www.tuicool.com/articles/bMVRru
    20. */
    21. import android.app.Activity;
    22. import android.content.ContentValues;
    23. import android.database.ContentObserver;
    24. import android.database.Cursor;
    25. import android.net.Uri;
    26. import android.os.Build;
    27. import android.os.Handler;
    28. import android.widget.EditText;
    29. import android.widget.TextView;
    30. import java.util.regex.Matcher;
    31. import java.util.regex.Pattern;
    32. /**
    33. * 作者:liuyaowei ;日期:2016-07-16.
    34. * QQ:1054185214
    35. * 类作用:监听短信数据库, 获取短信 验证码
    36. */
    37. public class SmsContentObserver extends ContentObserver {
    38. private Activity activity;
    39. private String address;
    40. private TextView text;
    41. public SmsContentObserver(Handler handler, Activity activity, String number, TextView text) {
    42. super(handler);
    43. this.activity=activity;
    44. this.address=number;
    45. this.text=text;
    46. }
    47. @Override
    48. public void onChange(boolean selfChange) {
    49. super.onChange(selfChange);
    50. // 读取收件箱中指定号码的短信
    51. // content://sms/inbox 收件箱
    52. // content://sms/sent 已发送
    53. // content://sms/draft 草稿
    54. // content://sms/outbox 发件箱
    55. // content://sms/failed 发送失败
    56. // content://sms/queued 待发送列表
    57. Cursor cursor= activity.managedQuery(Uri.parse("content://sms/inbox"),
    58. new String[]{"_id","address","body","read"},
    59. " address=? and read=?",
    60. new String[] { address, "0" }, "_id desc");
    61. // 按id排序,如果按date排序的话,修改手机时间后,读取的短信就不准了
    62. if (cursor!=null&&cursor.getCount()>0){
    63. ContentValues values=new ContentValues();
    64. if (Build.VERSION.SDK_INT < 21){
    65. values.put("type",1);//修改短信为已读短信 5.0后以不能修改
    66. }
    67. cursor.moveToNext();
    68. int smsbodyColumn=cursor.getColumnIndex("body");
    69. String smsbody=cursor.getString(smsbodyColumn);
    70. text.setText(getDynamicPassword(smsbody)); //调用下面的截取短信中六位数字验证码的方法
    71. }
    72. // 在用managedQuery的时候,不能主动调用close()方法, 否则在Android 4.0+的系统上, 会发生崩溃
    73. if (Build.VERSION.SDK_INT < 14) {
    74. cursor.close();
    75. }
    76. }
    77. /**
    78. * 从字符串中截取连续6位数字组合 ([0-9]{" + 6 + "})截取六位数字 进行前后断言不能出现数字 用于从短信中获取动态密码
    79. *
    80. * @param st 短信内容
    81. * @return 截取得到的6位动态密码
    82. */
    83. public String getDynamicPassword(String st){
    84. // 6是验证码的位数一般为六位 如果验证码的位数变化只要将6修改为想要的位数,
    85. // 过验证如果不止为数字,直接修改正则为想要的内容即可
    86. //Pattern是java.util.regex(一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包)中的一个类。
    87. // 一个Pattern是一个正则表达式经编译后的表现模式
    88. Pattern pattern=Pattern.compile("(?<![0-9])([0-9]{" + 6 + "})(?![0-9])") ;
    89. Matcher matcher=pattern.matcher(st);
    90. String dynamicPassword=null;
    91. while (matcher.find()){
    92. System.out.println(matcher.group());
    93. dynamicPassword=matcher.group();
    94. }
    95. return dynamicPassword;
    96. }
    97. }

    四,对上面BroadcastReceiver,ContentObserver注册取消监听的封装

    对BroadcastReceiver注册和取消监听的封装:

    
    			
    1. static BroadcastReceiver receiver;
    2. /**
    3. * 供其它组件调用 注册短信变化监听
    4. * @param context
    5. */
    6. public static void registerSmsBroadcastReceiver(Activity context,String number,TextView text){
    7. if (receiver!=null){
    8. return;
    9. }
    10. receiver= new SmsBroadcastReceiver(number,text);
    11. //注册短信变化监听
    12. context.registerReceiver(receiver, new IntentFilter("android.provider.Telephony.SMS_RECEIVED"));
    13. }
    14. /**
    15. * 供其它组件调用 关闭数据库监听
    16. * @param context
    17. */
    18. public static void unregisterSmsBroadcastReceiver(Activity context){
    19. if (receiver!=null) {
    20. //关闭数据库监听
    21. context.unregisterReceiver(receiver);
    22. }
    23. }
    对ContentObserver注册和取消监听的封装:
  • 
    			
    1. static SmsContentObserver content;
    2. /**
    3. * <uses-permission android:name="android.permission.RECEIVE_SMS" />
    4. * 供其它组件调用 注册短信变化监听
    5. * @param context
    6. */
    7. public static void registerSmsContentObserver(Activity context,String number,TextView text){
    8. if (content!=null){
    9. return;
    10. }
    11. content= new SmsContentObserver(new Handler(),context,number,text);
    12. //注册短信变化监听
    13. context.getContentResolver().registerContentObserver(Uri.parse("content://sms"), true, content);
    14. }
    15. /**
    16. * 供其它组件调用 关闭数据库监听
    17. * @param context
    18. */
    19. public static void unregisterSmsContentObserver(Activity context){
    20. if (content!=null) {
    21. //关闭数据库监听
    22. context.getContentResolver().unregisterContentObserver(content);
    23. }
    24. }

    五,不要忘记添加权限

    我把这些封装的代码都放到SmsPhoneUtil.java工具类中,在使用中直接通过SmsPhoneUtil调用相关方法就可以了,很方便吧,不过在发送短信和监听短信的时候千万不要忘记添加相应权限。 
    还有一个通过反射修改短信数据库的示例,还没比较满意的封装,就暂不贴出来了,留待以后仔细研究之后再说。

    
    			
    1. /**
    2. * 作者:liuyaowei ;日期:2016-07-14.
    3. * QQ:1054185214
    4. * 类作用:Sms and Phone工具类
    5. */
    6. public class SmsPhoneUtil {
    7. private BitmapUtil() {
    8. throw new Error("Do not instantiate it!/不要实例化");
    9. }
    10. }
    11. <!-- 发送短信 -->
    12. <uses-permission android:name="android.permission.SEND_SMS"/>
    13. <!-- 读取短信 -->
    14. <uses-permission android:name="android.permission.READ_SMS"/>
    15. <!-- 接收短信 -->
    16. <uses-permission android:name="android.permission.RECEIVE_SMS"/>