Oreo(8.0) - 以编程方式删除短信

时间:2018-01-25 15:00:10

标签: android database sms android-contentresolver android-8.0-oreo

我无法删除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

它就像一个魅力。

任何想法失败的原因?

目前我只有一部手机安装了Android O,所以我不知道它是否会在每台Android O设备上崩溃。我有Nokia TA-1004

1 个答案:

答案 0 :(得分:1)

SmsProvider类的一个相对较新的更改打破了那里的预期功能。从提供商的Uri电话中返回的insert()之前非常简单地表示为:

Uri uri = Uri.parse("content://" + table + "/" + rowID);

其中rowID是来自insert()的{​​{1}}来电的回复。

为了插入常规的完整短信,与您的情况一样,SQLiteDatabasetable。但是,还有其他几个表,主要由系统和默认消息传递应用程序使用,使用相同的"sms"方法;例如,insert()"raw"等。这些表上的插入导致返回的"attachments"的权限无效;例如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()的URI,其中存在问题。当在content://sms/sent/123调用中传递它时,它与提供者的相应方法认为有效的任何URI都不匹配,因此它会抛出delete() IllegalArgumentException

要解决此问题,您可以从返回中构建自己的有效URI,因为ID实际上只需要知道。例如:

Unknown URL

但是,在Uri del = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, dummySms.getLastPathSegment()); "content://sms/sent")开始插入可能是不正确的。该URI和其他类似的“盒子”URI(即Sms.Sent.CONTENT_URISms.Inbox.CONTENT_URI等 - 用于查询,而不是写操作。

您应该在基座Sms.Drafts.CONTENT_URISms.CONTENT_URI)上插入,并在"content://sms"中将TYPE设置为MESSAGE_TYPE_SENT。例如,推荐的修复:

ContentValues

这将导致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(),您的删除操作应该像以前一样成功。