最近因为项目的需要,需要处理android手机中的短信,在PC端读取手机上的短信信息。那么首先需要得到手机上的会话信息进行概要显示。
网上关于如何获取会话信息的文章不少,我也是以它们为参考。但是在测试中发现一些问题,以及处理的方法,记录如下:
一、刚开始根据网上的文章,使用sql注释的方式直接操作threads表。
参考文章地址:
http://blog.csdn.net/vennl/article/details/7079135
http://www.cnblogs.com/GnagWang/archive/2011/01/06/1929075.html
使用的代码片段:
String SMS_URI_ALL = "content://sms/";
cursor = cr.query(Uri.parse(SMS_URI_ALL),
new String[]{"* from threads order by date desc--"}, null, null, null);
使用这段代码,开始视乎一切正常。在很多机器上测试也OK。但是在小米note3上会抛出异常:
E/AndroidRuntime(26724): android.database.sqlite.SQLiteException: near “FROM”: syntax error (code 1): , while compiling:
SELECT FROM sms
WHERE ((thread_id IN (select _id from threads where private_addr_ids is NULL AND sp_type=0)) AND (deleted=0)) ORDER BY date DESC
看异常提示发现 FROM后面的*号不见了。暂时还不知什么原因,或者是红米做了什么限制。
二、这时开始换第二种方法.
参考文章:
http://www.tuicool.com/articles/fyeEVb
private static final String[] PROJECTION = new String[]{
//cursor 查询 需要_id
"sms.thread_id AS _id",
"sms.body AS snippet",
"groups.msg_count AS msg_count",
"sms.address AS address",
"sms.date AS date"
};
//查询短信数据
private void startQuery() {
/**
* 查询会话数据
* token Sql id 查询结果的唯一标识 _ID
* cookie 用来传递数据 通常VIEW
* uri 指定查询数据的地址
* projection 相当于SQL查询中 select 中的字段
* selection 相当于SQL查询中 where id = ?
* selectionArgs ?
* orderBy 排序
*/
Uri uri = Uri.parse("content://sms/conversations/");
queryHandler.startQuery(0, null, uri, PROJECTION, null, null, " date DESC");
}
但是使用这段代码会有错误提示:
no such column: sms.thread_id (code 1): , while compiling:
SELECT sms.thread_id AS _id, sms.body AS snippet, groups.msg_count AS msg_count, sms.address AS address, sms.date AS date
FROM
(SELECT thread_id AS tid, date * 1000 AS normalized_date, NULL AS error_code, ct_t, recipient_cc_ids, msg_box, NULL AS reply_path_present, v, sub, rr, NULL AS status, retr_txt_cs, ct_l, ct_cls, NULL AS dest_port, phone_id, NULL AS subject, NULL AS format_data, _id, m_size, NULL AS type, exp, sub_cs, NULL AS address, st, NULL AS person, tr_id, read, resp_st, date, NULL AS body, m_id, date_sent, recipient_bcc_ids, NULL AS sms_pdu, pri, NULL AS expiry, m_type, thread_id, read_status, d_rpt, locked, NULL AS service_date, NULL AS priority, resp_txt, rpt_a, retr_st, m_cls, NULL AS service_center
FROM pdu_restricted
WHERE ((msg_box != 3 AND (m_type = 128 OR m_type = 132 OR m_type = 160 OR m_type = 161 OR m_type = 130)))
GROUP BY thread_id
HAVING date = MAX(date)
UNION
SELECT thread_id AS tid, date * 1 AS normalized_date, error_code, NULL AS ct_t, recipient_cc_ids, NULL AS msg_box, reply_path_present, NULL AS v, NULL AS sub, NULL AS rr, status, NULL AS retr_txt_cs, NULL AS ct_l, NULL AS ct_cls, dest_port, phone_id, subject, format_data, _id, NULL AS m_size, type, NULL AS exp, NULL AS sub_cs, address, NULL AS st, person, NULL AS tr_id, read, NULL AS resp_st, date, body, NULL AS m_id, date_sent, recipient_bcc_ids, sms_pdu, NULL AS pri, expiry, NULL AS m_type, thread_id, NULL AS read_status, NULL AS d_rpt, locked, service_date, priority, NULL AS resp_txt, NULL AS rpt_a, NULL AS retr_st, NULL AS m_cls, service_center
FROM sms_restricted
WHERE ((type != 3))
GROUP BY thread_id
HAVING date = MAX(date))
GROUP BY tid
HAVING normalized_date = MAX(normalized_date)
ORDER BY date DESC
我们从提示中也能看出android是如何读取短信数据库的。
根据错误提示,修改代码如下:
String[] PROJECTION = new String[]{
"thread_id"
};
Uri uri = Uri.parse( "content://mms-sms/conversations" );
cursor = cr.query( uri, PROJECTION , null ,null, "date DESC" );
然后一切似乎都OK, 不过后来发现在mate 9 和部分moto机器上读不出会话信息。
三、终极解决方案,直接找源码
直接参考android中关于这部分的源码实现。
https://github.com/android/platform_packages_apps_mms
使用的代码片段如下:
Uri sAllThreadsUri =
Threads.CONTENT_URI.buildUpon().appendQueryParameter("simple", "true").build();
String[] ALL_THREADS_PROJECTION = {
Threads._ID, Threads.DATE, Threads.MESSAGE_COUNT, Threads.RECIPIENT_IDS,
Threads.SNIPPET, Threads.SNIPPET_CHARSET, Threads.READ, Threads.ERROR,
Threads.HAS_ATTACHMENT
};
cursor = cr.query( sAllThreadsUri, ALL_THREADS_PROJECTION , null ,null, "date DESC" );
和第二种方法的区别是多了参数simple=true
这种方式在现在手头有的机型中测试正常。