如何在Android中读取彩信数据?

发布于 2024-09-05 01:11:13 字数 232 浏览 6 评论 0原文

我想读取彩信数据 我在 mmssms.db 中看到了存储彩信条目的部分表;我正在使用游标,我想知道适当的 URI;我正在使用“content://mms-sms/conversations”以及图像的“地址”(发送至)、“文本”或“主题”和“数据”列名称的列名称

我已经看到了 mmssms.db 的架构及其零件表的列。

I want to read MMS data I have seen the part table in the mmssms.db where the mms entries are stored; I am using a cursor and I want to know the appropriate URI; I am using "content://mms-sms/conversations" and the Column names of "Address"(Sent to), "Text" or "Subject" and "Data" column name of image.

I have seen the schema of mmssms.db and Their Column of part Table.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

赤濁 2024-09-12 01:11:14

找到这方面的文档有点困难,所以我将在这里收集我找到的所有信息。如果您很匆忙或只是不喜欢阅读,请跳至如何从短信获取数据部分。

content://mms-sms/conversations

这是 彩信和短信提供商...它允许我们查询彩信和短信数据库同时,并将它们混合在一个线程中(称为对话)。

为什么 URI 很重要?嗯,这是获取彩信和短信的标准方式;例如,当您收到短信并点击通知栏时,它会发送如下广播意图:content://mms-sms/conversations/XXX,其中XXX 是对话的 ID。

获取所有对话的列表

您唯一要做的就是查询 content://mms-sms/conversations Uri:

ContentResolver contentResolver = getContentResolver();
final String[] projection = new String[]{"*"};
Uri uri = Uri.parse("content://mms-sms/conversations/");
Cursor query = contentResolver.query(uri, projection, null, null, null);

注意:通常,当您致电 < code>query 并且想要返回所有列,您可以将 null 作为 projection 参数传递。但是,您无法使用此提供程序执行此操作,因此这就是我使用 * 的原因。

现在您可以像往常一样循环遍历Cursor。这些是您需要使用的更重要的列:

  • _id 是消息的 ID。 队长显然会来救援吗? 事实并非如此。此 ID 可用于使用 content://smscontent://mms 检索详细信息。
  • 日期 无需解释。
  • thread_id 是对话的 ID
  • body 此对话的最后一条短信的内容。如果它是彩信,即使它有文本部分,这也将为 null

注意:如果您查询content://mms-sms/conversations,它将返回不同对话的列表,其_id是最后一条短信或每次对话中都有彩信。如果您查询 content://mms-sms/conversations/xxx,它将返回 ID 为 xxx 的对话中的每条短信和/或彩信。

如何区分短信和彩信

通常,您会想知道您正在处理哪种类型的消息。文档说:

虚拟专栏,
MmsSms.TYPE_DISCRIMINATOR_COLUMN,可能
在预测中要求
询问。它的值是“mms”或
“短信”,取决于是否
该行代表的消息是
彩信或短信,
分别。

我认为它指的是 此变量...但是我无法使其工作。如果您有,请告诉我如何或编辑这篇文章。

到目前为止,这就是我所做的,它似乎有效,但必须有更好的方法:

ContentResolver contentResolver = getContentResolver();
final String[] projection = new String[]{"_id", "ct_t"};
Uri uri = Uri.parse("content://mms-sms/conversations/");
Cursor query = contentResolver.query(uri, projection, null, null, null);
if (query.moveToFirst()) {
    do {
        String string = query.getString(query.getColumnIndex("ct_t"));
        if ("application/vnd.wap.multipart.related".equals(string)) {
            // it's MMS
        } else {
            // it's SMS
        }
    } while (query.moveToNext());
}

如何从短信获取数据

所以你有了短信的 ID,那么你唯一要做的就是:

String selection = "_id = "+id;
Uri uri = Uri.parse("content://sms");
Cursor cursor = contentResolver.query(uri, null, selection, null, null);
String phone = cursor.getString(cursor.getColumnIndex("address"));
int type = cursor.getInt(cursor.getColumnIndex("type"));// 2 = sent, etc.
String date = cursor.getString(cursor.getColumnIndex("date"));
String body = cursor.getString(cursor.getColumnIndex("body"));

如何获取数据来自彩信数据?

彩信有点不同。它们可以由不同的部分(文本、音频、图像等)构建;所以这里将看看如何分别检索每种数据。

因此,我们假设 mmsId 变量中有彩信 ID。我们可以使用 content://mms/ 提供程序获取有关此 MMS 的详细信息:

Uri uri = Uri.parse("content://mms/");
String selection = "_id = " + mmsId;
Cursor cursor = getContentResolver().query(uri, null, selection, null, null);

但是,唯一有趣的列是 read,即 1 > 如果该消息已被阅读。

如何从彩信获取文本内容

这里我们必须使用 content://mms/part...例如:

String selectionPart = "mid=" + mmsId;
Uri uri = Uri.parse("content://mms/part");
Cursor cursor = getContentResolver().query(uri, null,
    selectionPart, null, null);
if (cursor.moveToFirst()) {
    do {
        String partId = cursor.getString(cursor.getColumnIndex("_id"));
        String type = cursor.getString(cursor.getColumnIndex("ct"));
        if ("text/plain".equals(type)) {
            String data = cursor.getString(cursor.getColumnIndex("_data"));
            String body;
            if (data != null) {
                // implementation of this method below
                body = getMmsText(partId);
            } else {
                body = cursor.getString(cursor.getColumnIndex("text"));
            }
        }
    } while (cursor.moveToNext());
}

它可以包含文本的不同部分...但通常只有一个。因此,如果你想删除循环,它在大多数情况下都会起作用。 getMmsText 方法如下所示:

private String getMmsText(String id) {
    Uri partURI = Uri.parse("content://mms/part/" + id);
    InputStream is = null;
    StringBuilder sb = new StringBuilder();
    try {
        is = getContentResolver().openInputStream(partURI);
        if (is != null) {
            InputStreamReader isr = new InputStreamReader(is, "UTF-8");
            BufferedReader reader = new BufferedReader(isr);
            String temp = reader.readLine();
            while (temp != null) {
                sb.append(temp);
                temp = reader.readLine();
            }
        }
    } catch (IOException e) {}
    finally {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {}
        }
    }
    return sb.toString();
}

How to get image from MMS

这与获取文本部分相同...唯一的区别是您将寻找不同的 mime-type:

String selectionPart = "mid=" + mmsId;
Uri uri = Uri.parse("content://mms/part");
Cursor cPart = getContentResolver().query(uri, null,
    selectionPart, null, null);
if (cPart.moveToFirst()) {
    do {
        String partId = cPart.getString(cPart.getColumnIndex("_id"));
        String type = cPart.getString(cPart.getColumnIndex("ct"));
        if ("image/jpeg".equals(type) || "image/bmp".equals(type) ||
                "image/gif".equals(type) || "image/jpg".equals(type) ||
                "image/png".equals(type)) {
            Bitmap bitmap = getMmsImage(partId);
        }
    } while (cPart.moveToNext());
}

getMmsImage 方法如下所示:

private Bitmap getMmsImage(String _id) {
    Uri partURI = Uri.parse("content://mms/part/" + _id);
    InputStream is = null;
    Bitmap bitmap = null;
    try {
        is = getContentResolver().openInputStream(partURI);
        bitmap = BitmapFactory.decodeStream(is);
    } catch (IOException e) {}
    finally {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {}
        }
    }
    return bitmap;
}

如何获取发件人地址

您将需要使用 content://mms/xxx/addr 提供程序,其中 xxx 是 MMS 的 id:

private String getAddressNumber(int id) {
    String selectionAdd = new String("msg_id=" + id);
    String uriStr = MessageFormat.format("content://mms/{0}/addr", id);
    Uri uriAddress = Uri.parse(uriStr);
    Cursor cAdd = getContentResolver().query(uriAddress, null,
        selectionAdd, null, null);
    String name = null;
    if (cAdd.moveToFirst()) {
        do {
            String number = cAdd.getString(cAdd.getColumnIndex("address"));
            if (number != null) {
                try {
                    Long.parseLong(number.replace("-", ""));
                    name = number;
                } catch (NumberFormatException nfe) {
                    if (name == null) {
                        name = number;
                    }
                }
            }
        } while (cAdd.moveToNext());
    }
    if (cAdd != null) {
        cAdd.close();
    }
    return name;
}

最后的想法

  • 无法理解为什么 Google 花费了数亿美元,却不付费给学生或其他人来记录此 API。您必须检查源代码才能知道它是如何工作的,更糟糕​​的是,他们没有公开数据库列中使用的那些常量,因此我们必须手动编写它们。
  • 对于 MMS 中的其他类型的数据,您可以应用上面学到的相同想法......这只是了解 mime 类型的问题。

It's kind of difficult to find documentation about this, so I will collect here all information I have found. If you are in a rush or just don't like to read, jump to the How to get data from a SMS section.

content://mms-sms/conversations

This is the URI of the Mms and SMS provider... which allows us to query the MMS and SMS databases at the same time, and mix them in a single thread (which are called conversations).

Why is the URI important? Well, that's the standard way of getting MMS and SMS messages; for instance, when you receive a SMS and click on the notification bar, it will send a broadcast intent like this: content://mms-sms/conversations/XXX, where XXX is the id of the conversation.

Get a list of all conversations

The only thing you have to do is to query the content://mms-sms/conversations Uri:

ContentResolver contentResolver = getContentResolver();
final String[] projection = new String[]{"*"};
Uri uri = Uri.parse("content://mms-sms/conversations/");
Cursor query = contentResolver.query(uri, projection, null, null, null);

Note: usually, when you call query and want to return all columns you can pass null as the projection parameter. However, you cannot do that with this provider, so that's why I'm using *.

Now you can loop through the Cursor as usual. These are the more important columns you would want to use:

  • _id is the ID of the message. Captain obvious to the rescue? Not really. This ID can be used to retrieve detailed information using either content://sms or content://mms.
  • date no explanation needed.
  • thread_id is the ID of the conversation
  • body The content of the last SMS on this conversation. If it's an MMS, even if it has a text part, this will be null.

Note: if you query content://mms-sms/conversations it will return a list of different conversations whose _id is the last SMS or MMS in each conversation. If you query content://mms-sms/conversations/xxx it will return each SMS and/or MMS on the conversation whose ID is xxx.

How to differentiate between SMS and MMS

Usually, you will want to know which type of message you are handling. Documentation says:

A virtual column,
MmsSms.TYPE_DISCRIMINATOR_COLUMN, may
be requested in the projection for a
query. Its value is either "mms" or
"sms", depending on whether the
message represented by the row is an
MMS message or an SMS message,
respectively.

I think it's referring to this variable... however I have not been able to make it work. If you have please tell me how or edit this post.

So far this is what I have done and it seems to work but there must be better ways:

ContentResolver contentResolver = getContentResolver();
final String[] projection = new String[]{"_id", "ct_t"};
Uri uri = Uri.parse("content://mms-sms/conversations/");
Cursor query = contentResolver.query(uri, projection, null, null, null);
if (query.moveToFirst()) {
    do {
        String string = query.getString(query.getColumnIndex("ct_t"));
        if ("application/vnd.wap.multipart.related".equals(string)) {
            // it's MMS
        } else {
            // it's SMS
        }
    } while (query.moveToNext());
}

How to get data from a SMS

So you have the ID of the SMS, then the only thing you have to do is:

String selection = "_id = "+id;
Uri uri = Uri.parse("content://sms");
Cursor cursor = contentResolver.query(uri, null, selection, null, null);
String phone = cursor.getString(cursor.getColumnIndex("address"));
int type = cursor.getInt(cursor.getColumnIndex("type"));// 2 = sent, etc.
String date = cursor.getString(cursor.getColumnIndex("date"));
String body = cursor.getString(cursor.getColumnIndex("body"));

How to get data from a MMS data?

MMSs are a little bit different. They can be built with different parts (text, audio, images, etc.); so here will see how to retrieve each kind of data separately.

So let's guess we have the MMS id in the mmsId variable. We can get detailed information about this MMS by using the content://mms/ provider:

Uri uri = Uri.parse("content://mms/");
String selection = "_id = " + mmsId;
Cursor cursor = getContentResolver().query(uri, null, selection, null, null);

However, the only interesting column is read which is 1 if the message has already been read.

How to get text content from MMS

Here we have to use content://mms/part... for instance:

String selectionPart = "mid=" + mmsId;
Uri uri = Uri.parse("content://mms/part");
Cursor cursor = getContentResolver().query(uri, null,
    selectionPart, null, null);
if (cursor.moveToFirst()) {
    do {
        String partId = cursor.getString(cursor.getColumnIndex("_id"));
        String type = cursor.getString(cursor.getColumnIndex("ct"));
        if ("text/plain".equals(type)) {
            String data = cursor.getString(cursor.getColumnIndex("_data"));
            String body;
            if (data != null) {
                // implementation of this method below
                body = getMmsText(partId);
            } else {
                body = cursor.getString(cursor.getColumnIndex("text"));
            }
        }
    } while (cursor.moveToNext());
}

It could contain different parts of text... but usually it'd be only one. So if you want to remove the loop it will work most of the times. This is how the getMmsText method looks like:

private String getMmsText(String id) {
    Uri partURI = Uri.parse("content://mms/part/" + id);
    InputStream is = null;
    StringBuilder sb = new StringBuilder();
    try {
        is = getContentResolver().openInputStream(partURI);
        if (is != null) {
            InputStreamReader isr = new InputStreamReader(is, "UTF-8");
            BufferedReader reader = new BufferedReader(isr);
            String temp = reader.readLine();
            while (temp != null) {
                sb.append(temp);
                temp = reader.readLine();
            }
        }
    } catch (IOException e) {}
    finally {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {}
        }
    }
    return sb.toString();
}

How to get image from MMS

It's the same than getting the text part... the only difference is that you will be looking for a different mime-type:

String selectionPart = "mid=" + mmsId;
Uri uri = Uri.parse("content://mms/part");
Cursor cPart = getContentResolver().query(uri, null,
    selectionPart, null, null);
if (cPart.moveToFirst()) {
    do {
        String partId = cPart.getString(cPart.getColumnIndex("_id"));
        String type = cPart.getString(cPart.getColumnIndex("ct"));
        if ("image/jpeg".equals(type) || "image/bmp".equals(type) ||
                "image/gif".equals(type) || "image/jpg".equals(type) ||
                "image/png".equals(type)) {
            Bitmap bitmap = getMmsImage(partId);
        }
    } while (cPart.moveToNext());
}

This is how the getMmsImage method looks like:

private Bitmap getMmsImage(String _id) {
    Uri partURI = Uri.parse("content://mms/part/" + _id);
    InputStream is = null;
    Bitmap bitmap = null;
    try {
        is = getContentResolver().openInputStream(partURI);
        bitmap = BitmapFactory.decodeStream(is);
    } catch (IOException e) {}
    finally {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {}
        }
    }
    return bitmap;
}

How to get the sender address

You will need to use the content://mms/xxx/addr provider, where xxx is the id of the MMS:

private String getAddressNumber(int id) {
    String selectionAdd = new String("msg_id=" + id);
    String uriStr = MessageFormat.format("content://mms/{0}/addr", id);
    Uri uriAddress = Uri.parse(uriStr);
    Cursor cAdd = getContentResolver().query(uriAddress, null,
        selectionAdd, null, null);
    String name = null;
    if (cAdd.moveToFirst()) {
        do {
            String number = cAdd.getString(cAdd.getColumnIndex("address"));
            if (number != null) {
                try {
                    Long.parseLong(number.replace("-", ""));
                    name = number;
                } catch (NumberFormatException nfe) {
                    if (name == null) {
                        name = number;
                    }
                }
            }
        } while (cAdd.moveToNext());
    }
    if (cAdd != null) {
        cAdd.close();
    }
    return name;
}

Final thoughts

  • Can't understand why Google, with those thousands of millions of dollars, don't pay a student or someone else to document this API. You have to check the source code to know how it works and, which is worse, they don't make public those constants used in the columns of the database, so we have to write them manually.
  • For other kind of data inside an MMS you can apply the same idea learned above... it's just a matter of knowing the mime-type.
獨角戲 2024-09-12 01:11:14

克里斯蒂安的回答非常好。但是,获取发件人地址的方法对我不起作用。 Long.parseLong 语句除了可能抛出异常和 new String(...) 之外不执行任何操作?

在我的设备上,光标计数为 2 个或更多。第一个的“类型”通常为 137,其他的“类型”为 151。我找不到记录的地方,但可以推断出 137 是“来自”,151 是“到”。因此,如果我按原样运行该方法,则不会出现异常,并且它返回最后一行,该行是收件人,并且在许多情况下只是其中之一。

另外,AFAICT 不需要进行选择,因为所有行都具有相同的 msg_id。不过,这并没有什么坏处。

这就是我获取发件人地址的方法:

public static String getMMSAddress(Context context, String id) {
    String addrSelection = "type=137 AND msg_id=" + id;
    String uriStr = MessageFormat.format("content://mms/{0}/addr", id);
    Uri uriAddress = Uri.parse(uriStr);
    String[] columns = { "address" };
    Cursor cursor = context.getContentResolver().query(uriAddress, columns,
            addrSelection, null, null);
    String address = "";
    String val;
    if (cursor.moveToFirst()) {
        do {
            val = cursor.getString(cursor.getColumnIndex("address"));
            if (val != null) {
                address = val;
                // Use the first one found if more than one
                break;
            }
        } while (cursor.moveToNext());
    }
    if (cursor != null) {
        cursor.close();
    }
    // return address.replaceAll("[^0-9]", "");
    return address;
}

我不关心它是否都是数字,但如果需要的话,我提供了一种消除除数字之外的所有内容的方法作为注释。它也可以轻松修改以返回所有收件人。

我认为这对他有用。如果异常发生在第一行,看起来它会给出正确的答案。

The answer by Christian is excellent. However, the method for getting the sender's address did not work for me. The Long.parseLong statement doesn't do anything except possibly throw an exception and new String(...) ?.

On my device the cursor count is 2 or more. The first typically has a "type" of 137 and the others have a "type" of 151. I cannot find where this is documented, but one can deduce 137 is "from" and 151 is "to". Thus, if I run the method as is, I do not get an exception, and it returns the last row, which is a recipient and only one of several in many cases.

Also AFAICT the selection is not necessary as all the rows have the same msg_id. However, it doesn't hurt.

This is what works for me to get the sender's address:

public static String getMMSAddress(Context context, String id) {
    String addrSelection = "type=137 AND msg_id=" + id;
    String uriStr = MessageFormat.format("content://mms/{0}/addr", id);
    Uri uriAddress = Uri.parse(uriStr);
    String[] columns = { "address" };
    Cursor cursor = context.getContentResolver().query(uriAddress, columns,
            addrSelection, null, null);
    String address = "";
    String val;
    if (cursor.moveToFirst()) {
        do {
            val = cursor.getString(cursor.getColumnIndex("address"));
            if (val != null) {
                address = val;
                // Use the first one found if more than one
                break;
            }
        } while (cursor.moveToNext());
    }
    if (cursor != null) {
        cursor.close();
    }
    // return address.replaceAll("[^0-9]", "");
    return address;
}

I didn't care about whether it is all numeric, but I included a way to eliminate everything but numerals as a comment if that is desired. It can easily be modified to return all the recipients, as well.

I assume it worked for him. It looks like it would give the right answer if the exception occurred on the first row.

爱情眠于流年 2024-09-12 01:11:14

我一直在为此苦苦挣扎;然而,我终于让它工作了,我认为这个线程可能会从我的经验中受益。

我可以查询 content://mms-sms/conversations/ (Telephony.Threads.CONTENT_URI) 并获取线程中有用描述的地址和部分,但我发现此 URI 不会检索线程其中包含彩信 - 例如,具有两个以上通信者的线程。

在对 AOSP MMS 应用程序源代码进行一些挖掘后,我发现它使用 Telephony.Threads.CONTENT_URI 上的变体来生成其对话列表 - 它添加了参数“simple”,其值为“真的”。当我添加此参数时,我发现提供程序将查询一个完全不同的表,该表中确实包含所有 SMS 和 MMS 线程。

该表具有与常规 Telephony.Threads.CONTENT_URI 完全不同的架构 (???);这是 AOSP 应用程序正在使用的投影 -

public static final 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
};

这里的 _ID 是线程的 ID - 因此是 Telephony.Sms.CONTENT_URI 或 Telephony.Mms.CONTENT_URI 中的 ID。

当我发现这个奇怪的细节后,事情开始变得更好了!但请注意,“simple=true”变体中的日期列不可靠,我必须使用最近的短信或彩信中的日期。

我可能应该提到的另一件事是,为了获得特定线程的正确消息列表,我必须查询彩信和短信提供商,然后将结果合并到一个列表中,然后按日期对它们进行排序。

我验证了 Android 5.x 和 7.x 上的行为。

我希望这能有所帮助。

I've just been struggling with this; however, I finally got it to work and I thought this thread might benefit from my experience.

I could query on content://mms-sms/conversations/ (Telephony.Threads.CONTENT_URI) and get addresses and parts as helpfully described in the thread, but I found that this URI would not retrieve threads that only had MMS messages in them - for example, threads with more than two correspondents.

After doing some digging in the AOSP MMS app source, I found that it was using a variant on Telephony.Threads.CONTENT_URI to generate its conversation list - it was adding the parameter "simple" with the value "true". when I added this parameter, I found that the provider would query a completely different table, which did indeed have all the SMS and MMS threads in it.

This table has a completely different schema from the regular Telephony.Threads.CONTENT_URI one (???); this is the projection that the AOSP app is using --

public static final 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
};

The _ID here is the ID of the thread - so an ID into Telephony.Sms.CONTENT_URI or Telephony.Mms.CONTENT_URI.

After I discovered this bizarre detail, things started to work a lot better! Note however that the DATE column in the "simple=true" variant is not reliable, i had to use the date from the most recent Sms or Mms message instead.

Another thing I should probably mention is that in order to get a proper list of messages for a particular thread, I had to query on both the Mms and Sms providers, then combine the results into one list, then sort them by date.

I verified behaviour on Android 5.x and 7.x.

I hope this helps a bit more.

自此以后,行同陌路 2024-09-12 01:11:14

我必须进行一些修改才能让它为我工作。

  1. 当我从 mms-sms/conversations 内容中检索 cursor.getString(cursor.getColumnIndex("type")) 时,("content://mms-sms/conversations/")我测试“type”字段的值是否为空。如果变量为 null - 即

    String otype = c.getString(c.getColumnIndex("type"));
    if(otype!= null) {
        //这是一条短信 - 处理它...
    

    消息是短信,否则是彩信。对于彩信,您必须测试两种 mime 类型,如下所示:-

    if (("application/vnd.wap.multipart.lated".equalsIgnoreCase(msg_type)
        ||"application/vnd.wap.multipart.mixed".equalsIgnoreCase(msg_type))
        && !id.equalsIgnoreCase(lastMMSID)) {
             //这是一条彩信 - 处理它...
    
  2. 当您使用 ContentObserver 监视消息内容的更改时,它会针对同一消息触发多个通知。我使用静态变量(在我的例子中是lastMMSID)来跟踪消息。
  3. 此代码可以很好地检索入站和出站消息的内容。迭代“content://mms/part/”uri 返回的所有记录非常重要,以便获取 MMS 的内容(文本和/或附件)。
  4. 我发现区分入站和出站彩信的唯一方法是测试彩信/对话内容的“m_id”字段的空状态。

    String m_id = c.getString(c.getColumnIndex("m_id"));
    字符串 mDirection = m_id == null? “出”:“入”;
    

关于如何获取地址字段的最后一个想法。由于某种原因,地址内容不喜欢使用 {" * "} 参数进行查询,但这有效:-

final String[] projection = new String[] {"address", "contact_id", "charset", "type"};

如果它是出站消息,则要查找的“类型”将为 151。对于入站消息, “type”将是 137。一段功能齐全的代码将如下所示:-

private String getANumber(int id) {
    String add = "";
    final String[] projection = new String[] {"address","contact_id","charset","type"};
    final String selection = "type=137 or type=151"; // PduHeaders
    Uri.Builder builder = Uri.parse("content://mms").buildUpon();
    builder.appendPath(String.valueOf(id)).appendPath("addr");

    Cursor cursor = context.getContentResolver().query(
        builder.build(),
        projection,
        selection,
        null, null);

if (cursor.moveToFirst()) {
          do {
              String add = cursor.getString(cursor.getColumnIndex("address"));
              String type: cursor.getString(cursor.getColumnIndex("type"));
          } while(cursor.moveToNext());
      }
      // Outbound messages address type=137 and the value will be 'insert-address-token'
      // Outbound messages address type=151 and the value will be the address
      // Additional checking can be done here to return the correct address.
      return add;
}

致所有在我之前写这篇文章的勇敢的战士-我从心底里感谢你们!

I had to make some modifications in order to get this to work for me.

  1. When I retrieve the cursor.getString(cursor.getColumnIndex("type")) from the mms-sms/conversations content, ("content://mms-sms/conversations/") I test the value of the "type" field for null. If the variable is null - i.e.

    String otype = c.getString(c.getColumnIndex("type"));
    if(otype != null) {
        //this is an sms - handle it...
    

    the message is an SMS, else it is an MMS. For MMS's you have to test for both mime types as follows:-

    if (("application/vnd.wap.multipart.related".equalsIgnoreCase(msg_type)
        ||"application/vnd.wap.multipart.mixed".equalsIgnoreCase(msg_type))
        && !id.equalsIgnoreCase(lastMMSID)) {
             //this is a MMS - handle it...
    
  2. When you use a ContentObserver to monitor the message content for changes, it fires several notifications for the same message. I use a static variable - in my case lastMMSID - to keep track of the message.
  3. This code works well to retrieve the content of both Inbound and Outbound messages. It is important to iterate through all the records that are returned by the "content://mms/part/" uri in order to get to the content - text and/or attachments - of the MMS.
  4. The only way that I could find that works pretty well to differentiate between inbound and outbound MMS's, is to test the null status of the "m_id" field of the mms-sms/conversations content.

    String m_id = c.getString(c.getColumnIndex("m_id"));
    String mDirection = m_id == null? "OUT": "IN";
    

A final thought on how to get the Address Field. For some reason the Address Content does not like to be queried with a {" * "} parameter, but this works:-

final String[] projection = new String[] {"address", "contact_id", "charset", "type"};

If it is an outbound message, the "type" to look for will be 151. For an inbound message, the "type" will be 137. A fully functional piece of code will look something like this:-

private String getANumber(int id) {
    String add = "";
    final String[] projection = new String[] {"address","contact_id","charset","type"};
    final String selection = "type=137 or type=151"; // PduHeaders
    Uri.Builder builder = Uri.parse("content://mms").buildUpon();
    builder.appendPath(String.valueOf(id)).appendPath("addr");

    Cursor cursor = context.getContentResolver().query(
        builder.build(),
        projection,
        selection,
        null, null);

if (cursor.moveToFirst()) {
          do {
              String add = cursor.getString(cursor.getColumnIndex("address"));
              String type: cursor.getString(cursor.getColumnIndex("type"));
          } while(cursor.moveToNext());
      }
      // Outbound messages address type=137 and the value will be 'insert-address-token'
      // Outbound messages address type=151 and the value will be the address
      // Additional checking can be done here to return the correct address.
      return add;
}

To all the brave warriors who have gone before me in this post - I thank thee from the bottom of my heart!

稚气少女 2024-09-12 01:11:14

上面给出的获取 getMMSAddress() 的答案不应包含循环 while (cursor.moveToNext());。它应该只从游标中的第一个元素中提取地址。由于某种我不知道的原因,该游标有多个记录。第一个包含发件人的地址。除了第一个元素之外,光标的其他元素包含接收者的地址。因此,代码按原样返回接收者地址而不是发送者地址。

这对于破解彩信内容非常有帮助。

The answer given above for getting the getMMSAddress() should not contain the loop while (cursor.moveToNext());. It should only extract the address from the first element in the cursor. For some reason that is unknown to me, this cursor has more than one record. The first one contains the Sender's address. The other elements of the cursor beyond the first one, contain the receiver's address. Thus the code as is return the receivers address and not the sender address.

This has been very helpful for cracking open the contents of an MMS.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文