检测由于内容长度而发送的多条短信
Detect Multiple SMS sent due to length of content
我已经为 registerContentObserver
设置了后台服务,以便在发送 SMS 时得到通知。收到此事件后,我会增加一个变量以了解发送的消息数。这按预期工作。
当有人发送超过 140 个字符的短信时,移动运营商会将其视为多条短信,但我似乎只收到一条已发送短信的回调。这导致我的应用无法计算某些消息。
有什么正确的方法可以知道实际发送了多少条消息?
当应用程序负责将自己的消息写入 Provider 时,它很可能会一次性写入整个消息,而不管消息是否必须作为多部分发送。这就是为什么您的 Observer 通常只为每条完整的消息触发一次,无论消息有多大。
自 KitKat 起,系统将自动保存任何非默认应用程序的传出消息,对于多部分消息,每个部分将单独保存,每次都会触发你的观察者。当然,这对 KitKat 之前的任何事情都没有帮助,或者如果默认应用程序在更高版本中保存自己的消息。
一种可能是在您的 ContentObserver
中获取消息正文,并确定它会被拆分成多少个消息部分。 SmsMessage.calculateLength()
方法可以为我们做到这一点。它 returns 一个 int
数组,其第一个元素将包含给定文本的消息计数。
例如,使用旧的onChange(boolean)
方法,支持API < 16:
private class SmsObserver extends ContentObserver {
private static final Uri SMS_SENT_URI = Uri.parse("content://sms/sent");
private static final String COLUMN_ID = "_id";
private static final String COLUMN_BODY = "body";
private static final String[] PROJECTION = {COLUMN_ID, COLUMN_BODY};
// You might want to persist this value to storage, rather than
// keeping a field, in case the Observer is killed and recreated.
private int lastId;
public SmsObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
Cursor c = null;
try {
// Get the most recent sent message.
c = getContentResolver().query(SMS_SENT_URI, PROJECTION, null,
null, "date DESC LIMIT 1");
if (c != null && c.moveToFirst()) {
// Check that we've not already counted this one.
final int id = c.getInt(c.getColumnIndex(COLUMN_ID));
if (id == lastId) {
return;
}
lastId = id;
// Get the message body, and have the SmsMessage
// class calculate how many parts it would need.
final String body = c.getString(c.getColumnIndex(COLUMN_BODY));
final int numParts = SmsMessage.calculateLength(body, false)[0];
// Add the number of parts to the count,
// however you might be doing that.
addToCount(numParts);
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (c != null) {
c.close();
}
}
}
}
如果您支持 API 16 及更高版本,我们可以使用 onChange(boolean, Uri)
重载,事情变得简单一些,因为我们不一定需要跟踪最后一条消息身份证.
@Override
public void onChange(boolean selfChange, Uri uri) {
Cursor c = null;
try {
// type=2 restricts the query to the sent box, so this just
// won't return any records if the Uri isn't for a sent message.
c = getContentResolver().query(uri, PROJECTION, "type=2", null, null);
if (c != null && c.moveToFirst()) {
final String body = c.getString(c.getColumnIndex(COLUMN_BODY));
final int numParts = SmsMessage.calculateLength(body, false)[0];
addToCount(numParts);
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (c != null) {
c.close();
}
}
}
我已经为 registerContentObserver
设置了后台服务,以便在发送 SMS 时得到通知。收到此事件后,我会增加一个变量以了解发送的消息数。这按预期工作。
当有人发送超过 140 个字符的短信时,移动运营商会将其视为多条短信,但我似乎只收到一条已发送短信的回调。这导致我的应用无法计算某些消息。
有什么正确的方法可以知道实际发送了多少条消息?
当应用程序负责将自己的消息写入 Provider 时,它很可能会一次性写入整个消息,而不管消息是否必须作为多部分发送。这就是为什么您的 Observer 通常只为每条完整的消息触发一次,无论消息有多大。
自 KitKat 起,系统将自动保存任何非默认应用程序的传出消息,对于多部分消息,每个部分将单独保存,每次都会触发你的观察者。当然,这对 KitKat 之前的任何事情都没有帮助,或者如果默认应用程序在更高版本中保存自己的消息。
一种可能是在您的 ContentObserver
中获取消息正文,并确定它会被拆分成多少个消息部分。 SmsMessage.calculateLength()
方法可以为我们做到这一点。它 returns 一个 int
数组,其第一个元素将包含给定文本的消息计数。
例如,使用旧的onChange(boolean)
方法,支持API < 16:
private class SmsObserver extends ContentObserver {
private static final Uri SMS_SENT_URI = Uri.parse("content://sms/sent");
private static final String COLUMN_ID = "_id";
private static final String COLUMN_BODY = "body";
private static final String[] PROJECTION = {COLUMN_ID, COLUMN_BODY};
// You might want to persist this value to storage, rather than
// keeping a field, in case the Observer is killed and recreated.
private int lastId;
public SmsObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
Cursor c = null;
try {
// Get the most recent sent message.
c = getContentResolver().query(SMS_SENT_URI, PROJECTION, null,
null, "date DESC LIMIT 1");
if (c != null && c.moveToFirst()) {
// Check that we've not already counted this one.
final int id = c.getInt(c.getColumnIndex(COLUMN_ID));
if (id == lastId) {
return;
}
lastId = id;
// Get the message body, and have the SmsMessage
// class calculate how many parts it would need.
final String body = c.getString(c.getColumnIndex(COLUMN_BODY));
final int numParts = SmsMessage.calculateLength(body, false)[0];
// Add the number of parts to the count,
// however you might be doing that.
addToCount(numParts);
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (c != null) {
c.close();
}
}
}
}
如果您支持 API 16 及更高版本,我们可以使用 onChange(boolean, Uri)
重载,事情变得简单一些,因为我们不一定需要跟踪最后一条消息身份证.
@Override
public void onChange(boolean selfChange, Uri uri) {
Cursor c = null;
try {
// type=2 restricts the query to the sent box, so this just
// won't return any records if the Uri isn't for a sent message.
c = getContentResolver().query(uri, PROJECTION, "type=2", null, null);
if (c != null && c.moveToFirst()) {
final String body = c.getString(c.getColumnIndex(COLUMN_BODY));
final int numParts = SmsMessage.calculateLength(body, false)[0];
addToCount(numParts);
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (c != null) {
c.close();
}
}
}