Oreo (8.0) - 以编程方式删除短信
Oreo (8.0) - Remove sms programmatically
我无法删除 Android 8.0
上的特定消息
private void foo() {
Uri dummySms = insertDummySms(context, threadId);
removeDummySms(context, dummySms);
}
private Uri insertDummySms(Context context, long threadId) {
ContentValues values = new ContentValues();
values.put("thread_id", threadId);
values.put("body", "Dummy SMS body.");
Uri insert = context.getContentResolver().insert(Uri.parse("content://sms/sent"), values);
Log.i(TAG, "insertDummySms: " + insert);
return insert;
}
private void removeDummySms(Context context, Uri uri) {
Log.i(TAG, "removeDummySms: START: " + uri.toString() + " :: " + context.getContentResolver().getType(uri));
context.getContentResolver().delete(uri, null, null);
Log.i(TAG, "removeDummySms: END!!!");
}
当我使用 运行 foo()
方法时,日志显示:
I/Test: insertDummySms: content://sms/sent//8
I/Test: removeDummySms: START: content://sms/sent//8 :: vnd.android.cursor.item/sms,
然后它崩溃了:
java.lang.IllegalArgumentException: Unknown URL
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:165)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
相同的代码适用于 android 6.x 和 7.x
有趣的是:如果我像这样删除每条短信:
context.getContentResolver().delete(uri, null, null); // where uri is equal: content://sms
它就像一个魅力。
知道失败的原因吗?
目前我只有一个 phone 带有 Android O,所以我不知道它是否在每个 Android O 设备上崩溃。我有 Nokia TA-1004
最近对 SmsProvider
class 的更改有点破坏了那里的预期功能。来自提供商 insert()
调用的 Uri
returned 以前非常简单地计算为:
Uri uri = Uri.parse("content://" + table + "/" + rowID);
其中 rowID
是来自对 SQLiteDatabase
的 insert()
调用的 return。
对于插入常规的完整 SMS 消息,如您的情况,table
为 "sms"
。但是,还有其他几个表,主要由系统和默认消息传递应用程序使用,它们使用相同的 insert()
方法;例如,"raw"
、"attachments"
等。对这些表的插入导致对 returned Uri
的无效权限;例如content://raw/123
.
较新的版本现在对无效权限抛出异常,而不是静默失败,因此 Uri
结构更改为:
Uri uri;
if (table == TABLE_SMS) {
uri = Uri.withAppendedPath(url, "/" + rowID);
} else {
uri = Uri.withAppendedPath(url, "/" + table + "/" + rowID );
}
以后到:
Uri uri = Uri.withAppendedPath(url, String.valueOf(rowID));
首先解决问题。
在这两个版本中,url
是您在 ContentResolver#insert()
调用中传递的版本。对于您的代码段中的 insert()
调用,这最终会 returning 一个类似于 content://sms/sent/123
的 URI,这就是问题所在。当它在 delete()
调用中传递时,它不匹配 Provider 的相应方法认为有效的任何 URI,因此它抛出 IllegalArgumentException
of Unknown URL
.
要解决此问题,您可以从 return 构建您自己的有效 URI,因为您只需要知道 ID。例如:
Uri del = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, dummySms.getLastPathSegment());
但是,可以说在 "content://sms/sent"
(Sms.Sent.CONTENT_URI
) 上开始插入是不正确的。该 URI 和其他类似的 "box" URI - 即 Sms.Inbox.CONTENT_URI
、Sms.Drafts.CONTENT_URI
等 - 旨在用于查询,而不是写入操作。
您应该改为在基数 Sms.CONTENT_URI
("content://sms"
) 上插入,并在 ContentValues
中将 TYPE
设置为 MESSAGE_TYPE_SENT
。例如,推荐修复:
ContentValues cv = new ContentValues();
cv.put(Telephony.Sms.ADDRESS, ...);
cv.put(Telephony.Sms.BODY, ...);
cv.put(Telephony.Sms.TYPE, Telephony.Sms.MESSAGE_TYPE_SENT);
Uri uri = getContentResolver().insert(Telephony.Sms.CONTENT_URI, cv);
这将导致 Uri
被 SmsProvider
的 delete()
方法识别,并且您的删除应该像以前一样成功。
我无法删除 Android 8.0
上的特定消息 private void foo() {
Uri dummySms = insertDummySms(context, threadId);
removeDummySms(context, dummySms);
}
private Uri insertDummySms(Context context, long threadId) {
ContentValues values = new ContentValues();
values.put("thread_id", threadId);
values.put("body", "Dummy SMS body.");
Uri insert = context.getContentResolver().insert(Uri.parse("content://sms/sent"), values);
Log.i(TAG, "insertDummySms: " + insert);
return insert;
}
private void removeDummySms(Context context, Uri uri) {
Log.i(TAG, "removeDummySms: START: " + uri.toString() + " :: " + context.getContentResolver().getType(uri));
context.getContentResolver().delete(uri, null, null);
Log.i(TAG, "removeDummySms: END!!!");
}
当我使用 运行 foo()
方法时,日志显示:
I/Test: insertDummySms: content://sms/sent//8
I/Test: removeDummySms: START: content://sms/sent//8 :: vnd.android.cursor.item/sms,
然后它崩溃了:
java.lang.IllegalArgumentException: Unknown URL
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:165)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
相同的代码适用于 android 6.x 和 7.x
有趣的是:如果我像这样删除每条短信:
context.getContentResolver().delete(uri, null, null); // where uri is equal: content://sms
它就像一个魅力。
知道失败的原因吗?
目前我只有一个 phone 带有 Android O,所以我不知道它是否在每个 Android O 设备上崩溃。我有 Nokia TA-1004
最近对 SmsProvider
class 的更改有点破坏了那里的预期功能。来自提供商 insert()
调用的 Uri
returned 以前非常简单地计算为:
Uri uri = Uri.parse("content://" + table + "/" + rowID);
其中 rowID
是来自对 SQLiteDatabase
的 insert()
调用的 return。
对于插入常规的完整 SMS 消息,如您的情况,table
为 "sms"
。但是,还有其他几个表,主要由系统和默认消息传递应用程序使用,它们使用相同的 insert()
方法;例如,"raw"
、"attachments"
等。对这些表的插入导致对 returned Uri
的无效权限;例如content://raw/123
.
较新的版本现在对无效权限抛出异常,而不是静默失败,因此 Uri
结构更改为:
Uri uri;
if (table == TABLE_SMS) {
uri = Uri.withAppendedPath(url, "/" + rowID);
} else {
uri = Uri.withAppendedPath(url, "/" + table + "/" + rowID );
}
以后到:
Uri uri = Uri.withAppendedPath(url, String.valueOf(rowID));
首先解决问题。
在这两个版本中,url
是您在 ContentResolver#insert()
调用中传递的版本。对于您的代码段中的 insert()
调用,这最终会 returning 一个类似于 content://sms/sent/123
的 URI,这就是问题所在。当它在 delete()
调用中传递时,它不匹配 Provider 的相应方法认为有效的任何 URI,因此它抛出 IllegalArgumentException
of Unknown URL
.
要解决此问题,您可以从 return 构建您自己的有效 URI,因为您只需要知道 ID。例如:
Uri del = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, dummySms.getLastPathSegment());
但是,可以说在 "content://sms/sent"
(Sms.Sent.CONTENT_URI
) 上开始插入是不正确的。该 URI 和其他类似的 "box" URI - 即 Sms.Inbox.CONTENT_URI
、Sms.Drafts.CONTENT_URI
等 - 旨在用于查询,而不是写入操作。
您应该改为在基数 Sms.CONTENT_URI
("content://sms"
) 上插入,并在 ContentValues
中将 TYPE
设置为 MESSAGE_TYPE_SENT
。例如,推荐修复:
ContentValues cv = new ContentValues();
cv.put(Telephony.Sms.ADDRESS, ...);
cv.put(Telephony.Sms.BODY, ...);
cv.put(Telephony.Sms.TYPE, Telephony.Sms.MESSAGE_TYPE_SENT);
Uri uri = getContentResolver().insert(Telephony.Sms.CONTENT_URI, cv);
这将导致 Uri
被 SmsProvider
的 delete()
方法识别,并且您的删除应该像以前一样成功。