作者@恺风Wei

读短信需要READ_SMS的权限。

<uses-permission android:name="android.permission.READ_SMS" />

Content Provider的URI

通过content Provider可以读取短信。相关的URI如下:

  • 所有:   content://sms/all
  • 收件箱:content://sms/inbox
  • 已发送:content://sms/sent
  • 草稿箱:content://sms/draft
  • 发信箱:content://sms/outbox
  • 发送失败:content://sms/failed
  • 排队待发送:content://sms/queued
  • 未送达:content://sms/undelivered
  • 会话:   content://sms/conversations

彩信也可以通过content provider来获取,authority改为mms-sms即可,例如content://mms-sms/inbox。

通过content Provider可以获得cursor,每个元素即为一条短信,下面是常用的属性:

_id               一个自增字段,从1开始
thread_id    序号,同一发信人的id相同
address      发件人手机号码
person        联系人列表里的序号,陌生人为null
date            发件日期
protocol      协议,分为: 0 SMS_RPOTO, 1 MMS_PROTO
read           是否阅读 0未读, 1已读
status         状态 -1接收,0 complete, 64 pending, 128 failed
type            ALL = 0;INBOX  = 1; SENT = 2; DRAFT  = 3;OUTBOX = 4; FAILED = 5; QUEUED = 6;
body           短信内容
service_center     短信服务中心号码编号
subject       短信的主题

读取短信

小例子代码如下:

public class ReadSMSActivity extends ListActivity{ 
    @Override 
    protected void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);         
         Cursor c = getContentResolver().query(Uri.parse("content://sms/inbox"), null, null, null, null);
         String[] columns = new String[] { "address","body" }; 
         int[] names = new int[] {android.R.id.text1,android.R.id.text2}; 
          
         ListAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2,
                 c, columns, names, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
         
         setListAdapter(adapter);    
     } 
 }

读取新收短信

短信的顺序是按时间反序排列,第一条短信即使最后接收的短信,我们需要的是在短信发生变化时,通过回调函数读取最后收到的短信。Content的内容,通过ContentProvider来获取,而Content的内容变化,则通过ContentObserver来获取。

public class SMSContentObserver extends ContentObserver{ 
     private Activity activity = null;  

     public SMSContentObserver(Handler handler, Activity activity) { 
         super(handler); 
         this.activity = activity;   
     } 

     @Override //content发生变化的回调函数,可以直接通过该uri来获得该短信内容,或者读取全部的短信,获取其最新的一条。 
    public void onChange(boolean selfChange, Uri uri) {  
         super.onChange(selfChange, uri); 
         getFirstSMS(); 
     } 
     
     //通过content provider读取第一条短信  
     private void getFirstSMS(){ 
         Cursor c = activity.getContentResolver().query(Uri.parse("content://sms/inbox"), null, null, null, null);
         if(!c.moveToFirst()) 
             return; 
         String address = c.getString(c.getColumnIndex("address")); 
         String body = c.getString(c.getColumnIndex("body")); 
         c.close(); 
         Toast.makeText(activity, "From " + address + ":\n" + body, Toast.LENGTH_LONG).show();
     } 
 }

我们在Activity中注册要观察内容变更,如下:

public class ReadSMSActivity extends ListActivity{ 
     … …     
     private SMSContentObserver observer = null; 
     @Override 
    protected void onResume() {  
        super.onResume();         
         observer = new SMSContentObserver(new Handler(),ReadSMSActivity.this);       // 在测试中,如果填入content://sms/inbox,除一台4.1.2的设备起作用外,其他都不其作用        getContentResolver().registerContentObserver(Uri.parse("content://sms/"), true, observer); 
     } 

    @Override 
     protected void onPause() {  
         super.onPause(); 
         getContentResolver().unregisterContentObserver(observer);
     }  
     
 }

小例子代码在:Pro Android学习:telephony小例子