灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:2318回复:0

android学习笔记25--------------短信的各种操作操作

楼主#
更多 发布于:2012-09-06 13:43


1.注册广播接收器

[java]
<receiver Android:name="SMSReceiver">
            <intent-filter>
                <action Android:name="Android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver>
<receiver Android:name="SMSReceiver">
            <intent-filter>
                <action Android:name="Android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver>
[java]
import Android.content.BroadcastReceiver;
import Android.content.Context;
import Android.content.Intent;
import Android.os.Bundle;
import Android.telephony.SmsMessage;
import Android.widget.Toast;

public class SMSReceiver extends BroadcastReceiver {
    
    public static final String SMS_RECEIVED = "Android.provider.Telephony.SMS_RECEIVED";
    
    @Override
    public void onReceive(Context context, Intent intent) {
        if (SMS_RECEIVED.equals(intent.getAction())) {
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
                Object[] pdus = (Object[]) bundle.get("pdus");
                final SmsMessage[] messages = new SmsMessage[pdus.length];
                String msg = "";
                for (int i = 0; i < pdus.length; i++) {
                    messages = SmsMessage.createFromPdu((byte[]) pdus);
                    msg += messages.getMessageBody();
                }
                Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
            }
        }
    }

}
import Android.content.BroadcastReceiver;
import Android.content.Context;
import Android.content.Intent;
import Android.os.Bundle;
import Android.telephony.SmsMessage;
import Android.widget.Toast;
public class SMSReceiver extends BroadcastReceiver {
  
    public static final String SMS_RECEIVED = "Android.provider.Telephony.SMS_RECEIVED";
  
    @Override
    public void onReceive(Context context, Intent intent) {
        if (SMS_RECEIVED.equals(intent.getAction())) {
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
                Object[] pdus = (Object[]) bundle.get("pdus");
                final SmsMessage[] messages = new SmsMessage[pdus.length];
                String msg = "";
                for (int i = 0; i < pdus.length; i++) {
                    messages = SmsMessage.createFromPdu((byte[]) pdus);
                    msg += messages.getMessageBody();
                }
                Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
            }
        }
    }
}

2.添加权限
[java]
<uses-permission Android:name="Android.permission.RECEIVE_SMS"></uses-permission>
<uses-permission Android:name="Android.permission.RECEIVE_SMS"></uses-permission>
二、读取收件箱中的短信
1.从数据库中读取,URI为"content://sms/inbox"
[java]
import Android.app.Activity;
import Android.content.ContentResolver;
import Android.database.Cursor;
import Android.net.Uri;
import Android.os.Bundle;
import Android.widget.TextView;

public class MySMSManager extends Activity {
    
    private TextView textview;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        textview = (TextView) findViewById(R.id.textview);
        readShortMessage();
    }
    
    public void readShortMessage() {
        ContentResolver cr = getContentResolver();
        Cursor cursor = cr.query(Uri.parse("content://sms/inbox"), null, null, null, null);
        String msg = "";
        while(cursor.moveToNext()) {
            int phoneColumn = cursor.getColumnIndex("address");  
            int smsColumn = cursor.getColumnIndex("body");  
            msg += cursor.getString(phoneColumn) + ":" + cursor.getString(smsColumn) + "n";
        }
        textview.setText(msg);
    }
}
import Android.app.Activity;
import Android.content.ContentResolver;
import Android.database.Cursor;
import Android.net.Uri;
import Android.os.Bundle;
import Android.widget.TextView;
public class MySMSManager extends Activity {
  
    private TextView textview;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        textview = (TextView) findViewById(R.id.textview);
        readShortMessage();
    }
  
    public void readShortMessage() {
        ContentResolver cr = getContentResolver();
        Cursor cursor = cr.query(Uri.parse("content://sms/inbox"), null, null, null, null);
        String msg = "";
        while(cursor.moveToNext()) {
            int phoneColumn = cursor.getColumnIndex("address");
            int smsColumn = cursor.getColumnIndex("body");
            msg += cursor.getString(phoneColumn) + ":" + cursor.getString(smsColumn) + "n";
        }
        textview.setText(msg);
    }
}
2.添加权限
[java]
<uses-permission Android:name="Android.permission.READ_SMS"></uses-permission>
<uses-permission Android:name="Android.permission.READ_SMS"></uses-permission>
附:其它短信的URI和数据库表字段
[java]
String SMS_URI_ALL =  "content://sms/";  
String SMS_URI_INBOX = "content://sms/inbox";
String SMS_URI_SENT = "content://sms/sent";    
String SMS_URI_DRAFT = "content://sms/draft";      
String SMS_URI_OUTBOX = "content://sms/outbox";    
String SMS_URI_FAILED = "content://sms/failed";      
String SMS_URI_QUEUED = "content://sms/queued";
String SMS_URI_ALL =  "content://sms/";
String SMS_URI_INBOX = "content://sms/inbox";
String SMS_URI_SENT = "content://sms/sent";  
String SMS_URI_DRAFT = "content://sms/draft";    
String SMS_URI_OUTBOX = "content://sms/outbox";  
String SMS_URI_FAILED = "content://sms/failed";    
String SMS_URI_QUEUED = "content://sms/queued";

content://sms/inbox 收件箱
content://sms/sent 已发送
content://sms/draft 草稿
content://sms/outbox 发件箱
content://sms/failed 发送失败
content://sms/queued 待发送列表

检索数据方法很简单:
Uri uri = Uri.parse("content://sms/inbox");
Cursor cur = this.managedQuery(uri, null, null, null, null);
if (cur.moveToFirst())
{
do
{
  for(int j = 0; j < cur.getColumnCount(); j++)
  {
  info = "name:" + cur.getColumnName(j) + "=" + cur.getString(j);
  Log.i("====>", info);
  }
}while(cur.moveToNext());
}

--------------------------------------------------------------------------------



[java]
/*
_id => 短消息序号 如100  
thread_id => 对话的序号 如100  
address => 发件人地址,手机号.如+8613811810000  
person => 发件人,返回一个数字就是联系人列表里的序号,陌生人为null  
date => 日期  long型。如1256539465022  
protocol => 协议 0 SMS_RPOTO, 1 MMS_PROTO  
read => 是否阅读 0未读, 1已读  
status => 状态 -1接收,0 complete, 64 pending, 128 failed  
type => 类型 1是接收到的,2是已发出  
body => 短消息内容  
service_center => 短信服务中心号码编号。如+8613800755500  
*/
/*
_id => 短消息序号 如100
thread_id => 对话的序号 如100
address => 发件人地址,手机号.如+8613811810000
person => 发件人,返回一个数字就是联系人列表里的序号,陌生人为null
date => 日期  long型。如1256539465022
protocol => 协议 0 SMS_RPOTO, 1 MMS_PROTO  
read => 是否阅读 0未读, 1已读  
status => 状态 -1接收,0 complete, 64 pending, 128 failed  
type => 类型 1是接收到的,2是已发出  
body => 短消息内容  
service_center => 短信服务中心号码编号。如+8613800755500
*/

其中,delete方法中支持的协议为:
SMS_ALL 根据参数中的条件删除sms表数据
SMS_ALL_ID 根据_id删除sms表数据
SMS_CONVERSATIONS_ID 根据thread_id删除sms表数据,可以带其它条件
SMS_RAW_MESSAGE 根据参数中的条件删除 raw表
SMS_STATUS_PENDING 根据参数中的条件删除 sr_pending表
SMS_SIM 从Sim卡上删除数据
试一下SMS_CONVERSATIONS_ID:"content://sms/conversations/3 ",删除thread_id="3", _id="5"的数据
在eclipse中的Emulator Control中,以13800给模拟器发送三条数据,然后以13900发送一条
this.getContentResolver().delete(Uri.parse("content://sms/conversations/3"), "_id=?", new String{"5"});
成功删除一条数据。
数据库中每个发送者的thread_id虽然一样,但不是固定的,如果把一个发送者的全部数据删除掉,
然后换一个新号码发送短信时,thread_id是以数据库中最大的id+1赋值的。



三、打开发送短信界面
[java]
Uri uri = Uri.parse("smsto:13800138000");
        Intent it = new Intent(Intent.ACTION_SENDTO, uri);
        it.putExtra("sms_body", "The SMS text");
        startActivity(it);
Uri uri = Uri.parse("smsto:13800138000");
        Intent it = new Intent(Intent.ACTION_SENDTO, uri);
        it.putExtra("sms_body", "The SMS text");
        startActivity(it);
四、发送短信
1.通过SmsManager的sendTextMessage(destinationAddress, scaddress, text, sentIntent, deliveryIntent)方法发送
[java]
String msg ="hello";  
        String number = "1234565678";  
        SmsManager sms = SmsManager.getDefault();  
        PendingIntent pi = PendingIntent.getBroadcast(this,0,new Intent(),0);  
        sms.sendTextMessage(number,null,msg,pi,null);
String msg ="hello";
        String number = "1234565678";
        SmsManager sms = SmsManager.getDefault();
        PendingIntent pi = PendingIntent.getBroadcast(this,0,new Intent(),0);
        sms.sendTextMessage(number,null,msg,pi,null);
2.添加权限
[java]
<uses-permission Android:name="Android.permission.SEND_SMS"></uses-permission>
<uses-permission Android:name="Android.permission.SEND_SMS"></uses-permission>

五、直接向数据库写短信

[java]
ContentResolver cr = getContentResolver();
        ContentValues cv = new ContentValues();
        cv.put("address", "13800138000");
        cv.put("body", "hello!");
        cr.insert(Uri.parse("content://sms/inbox"), cv);
ContentResolver cr = getContentResolver();
        ContentValues cv = new ContentValues();
        cv.put("address", "13800138000");
        cv.put("body", "hello!");
        cr.insert(Uri.parse("content://sms/inbox"), cv);

权限:
[java]
<uses-permission Android:name="Android.permission.WRITE_SMS"></uses-permission>
<uses-permission Android:name="Android.permission.WRITE_SMS"></uses-permission>
六、监听短信数据库变化
使用ContentObserver ,观察"content://sms"的变化,调用重写的onChange方法,可以监听到短信记录的
变化,这样可以监听发短信,同样也是可以监听收短信的。

[java]
import Android.database.ContentObserver;
import Android.os.Handler;
import Android.util.Log;

public class SMSObserver extends ContentObserver {

    public SMSObserver(Handler handler) {
        super(handler);
    }
    
    @Override
    public void onChange(boolean selfChange) {
        Log.i("sms", "sms");
    }

}
import Android.database.ContentObserver;
import Android.os.Handler;
import Android.util.Log;
public class SMSObserver extends ContentObserver {
    public SMSObserver(Handler handler) {
        super(handler);
    }
  
    @Override
    public void onChange(boolean selfChange) {
        Log.i("sms", "sms");
    }
}

然后在Acitivty或Service里注册这个观察者
[java]
getContentResolver().registerContentObserver(Uri.parse("content://sms"),
                                true, new SMSObserver(new Handler()));
getContentResolver().registerContentObserver(Uri.parse("content://sms"),
                                true, new SMSObserver(new Handler()));

Smsmessage.getTimestampMillis() 获得短信发送时间
System.currentTimeMillis()获得系统当前时间
一般短信软件都是获取当前时间
System.currentTimeMillis()改为Smsmessage.getTimestampMillis()
就能读到短信发送时间。

在做读取短信的时候,读取到date字段,需要转换成例如7/21 或者 8:21这种格式,不用手动转换 通过调用相应的类来实现
SimpleDateFormat sfd = new SimpleDateFormat("yyyy-MM-dd hh:mms");// 这里我们可以指定可是 例如 MM-DD就是只显示月和日  。。。。
Date date = new Date(Long.parseLong(cursor.getString(cursor.getColumnIndex("date"))));//从短信中获得时间

String time = sfd.format(date); //转换完成的字符串 很简单
dataTextView.setText(time); //显示出来就行了
使用前:



使用后:





/**
* 通过电话号码获取姓名
*/

    public String getContactNameFromPhoneNum(Context context, String phoneNum)
    {
        String contactName = "";
        ContentResolver cr = context.getContentResolver();
        Cursor pCur = cr.query(
                ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
                ContactsContract.CommonDataKinds.Phone.NUMBER + " = ?",
                new String[]
                { phoneNum }, null);
        if (pCur.moveToFirst())
        {
            contactName = pCur
                    .getString(pCur
                            .getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
            pCur.close();
        }
        return contactName;
    }
/**
* 通过电话号码获取姓名
*/
public String getContactNameFromPhoneNum(Context context, String phoneNum)
{
  String contactName = "";
  ContentResolver cr = context.getContentResolver();
  Cursor pCur = cr.query(
    ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
    ContactsContract.CommonDataKinds.Phone.NUMBER + " = ?",
    new String[]
    { phoneNum }, null);
  if (pCur.moveToFirst())
  {
   contactName = pCur
     .getString(pCur
       .getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
   pCur.close();
  }
  return contactName;
}
Android系统源码数据库(mmssms.db)中几个表之前的关系.
首先明了未接信息的数据库的位置在系统
/data/data/com.Android.providers.telephony/databases/mmssms.db 包下。
希望大家能够结合源码中的
1.       Telephony.java (主要讲这些表里有哪些字段)
2.       MmsSmsProvider.java (ContentProvider被重写)
3.       MmsProvider.java (ContentProvider被重写)
4.       SmsProvider.java (ContentProvider被重写)

5.       Conversation.java  描述 mmssms数据库的Threads表

当我们查询mmssms.db数据库时,这其中涉及到以下几张表:
1.       threads表
2.       存放短信的表(sms表)
3.       存放彩信的表(pdu表,part表)
4.       存放phone number的表( Canonical_address表)
threads表字段说明:
_id: 用于区分不同的电话号码,系统会为不同的电话号码分配不同的_id.
date: 收到信息的时间(如果收到来自同一个phone number多条信息,并且有对于一条信息未读,那么date表示收到的最后一条信息时的时间)
message_count: 收到的信息的数目(sms+mms)
snippet: 如果来自某个phone number,仅仅有一条信息,那么会是如下情况
      如果是未接短信,代表未接短信的内容
      如果是未接彩信,代表未接彩信的subject.
      如果来自某个phone number,仅仅有多条信息,那么则是如下情况
      如果是最后一条是未接短信,代表最后一条未接短信的内容
      如果是最后一条是未接彩信,代表最后一条未接彩信的subject.
      然而这个字段存储的仅仅是一条短信内容或者彩信subject的部分内容,其余内容用省略号表示。
read: 0. 代表未读。 1.代表 已读
has_attchment: 代表来自该phone number的信息是否包含有附件。

依据上面的表结构,也许会有人问,phone number 呢?有这样的疑问是非常正常的,别着急,学过数据库的人都知道,表结构之间并不是孤立的,而是相互关联的。
phone number 会在另外几张表中出现。



Sms表
查询该表时的uri :   URI_SMS_INBOX = Uri.parse("content://sms/inbox")
_id
thread_id
address
date
read
subject
body
locked
Sms表字段说明
_id: 区分不同的短信。
threads_id: (外键)threads表的_id.
date: 该条短信接收的时间
read: 0表未读,1表已读
body: 表示具体的短信内容,(注意,虽然在thread表的snippet字段已经存储了一部分body,但是那里的并不全,仅仅是一部分body)
locked: 该字段我也不是很清楚,用到的不多,不过如果我标识某条信息为locked时,当我再删除这条信息时,系统会提示我“是否删除locked信息”。
很明显以上:_id为4.或5的短信,来自同一个phone number,也就是说他们的thread_id是相同的.


Pdu表:
URI_MMS_INBOX = Uri.parse("content://mms/inbox");
_id
Thread_id
date
Msg_box
read
M_id
sub
Ct_l
m_type

Pdu表字段说明:
_id: 区分不同的彩信
thread_id : 外键 (thread表的_id)
msg_box: 区分彩信的收件箱,发件箱,草稿箱等.
         很明显1.代表收件箱
read:是否已读,0 未读,1.已读
sub: 彩信的subject
ct_l: 如果彩信太大,或者由于网络原因,也又是由于手机设备原因,dowload失败,彩信看不了,这个字段就会有彩信的网址(我曾经见到过一次,http://格式的,就是一个网址)


喜欢0 评分0
游客

返回顶部