Ich möchte MMS-Daten lesen. Ich habe mmssms.db
die Teiletabelle gesehen, in der die MMS- Einträge gespeichert sind. Ich benutze einen Cursor und möchte das entsprechende wissen URI
; Ich verwende "Inhalt: // mms-sms / Konversationen" und die Spaltennamen "Adresse" (gesendet an), "Text" oder "Betreff" und "Daten" Spaltenname des Bildes.
Ich habe das Schema mmssms.db
und die Spalte der Teiletabelle gesehen.
mmssms.db
Datenbank ist Teil der Firmware und für Android-Anwendungen nicht zugänglich. Dercontent://mms-sms/conversations
Inhaltsanbieter ist nicht Teil des SDK und sollte nicht von Android-Anwendungen aufgerufen werden.Antworten:
Es ist schwierig, eine Dokumentation darüber zu finden, deshalb werde ich hier alle Informationen sammeln, die ich gefunden habe. Wenn Sie in Eile sind oder einfach nicht lesen möchten, springen Sie zum Abschnitt So erhalten Sie Daten aus einer SMS .
Inhalt: // mms-sms / gespräche
Dies ist die URI des MMS- und SMS-Anbieters ... mit der wir die MMS- und SMS-Datenbanken gleichzeitig abfragen und in einem einzigen Thread (sogenannte Konversationen ) mischen können .
Warum ist die URI wichtig? Nun, das ist die Standardmethode, um MMS- und SMS-Nachrichten zu erhalten. Wenn Sie beispielsweise eine SMS empfangen und auf die Benachrichtigungsleiste klicken, wird eine Broadcast-Absicht wie folgt gesendet:
content://mms-sms/conversations/XXX
WoXXX
ist die ID der Konversation?Holen Sie sich eine Liste aller Gespräche
Das einzige, was Sie tun müssen, ist die
content://mms-sms/conversations
Uri abzufragen :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);
Hinweis: Wenn Sie
query
alle Spalten aufrufen und zurückgeben möchten, können Sie sie normalerweisenull
alsprojection
Parameter übergeben. Bei diesem Anbieter ist dies jedoch nicht möglich. Deshalb verwende ich*
.Jetzt können Sie das
Cursor
wie gewohnt durchlaufen . Dies sind die wichtigeren Spalten, die Sie verwenden möchten:_id
ist die ID der Nachricht. Kapitän offensichtlich zur Rettung? Nicht wirklich. Diese ID kann verwendet werden, um detaillierte Informationen mit entwedercontent://sms
oder abzurufencontent://mms
.date
Keine Erklärung erforderlich.thread_id
ist die ID des Gesprächsbody
Der Inhalt der letzten SMS zu diesem Gespräch. Wenn es sich um eine MMS handelt, auch wenn sie einen Textteil enthält, ist dies der Fallnull
.Hinweis: Wenn Sie eine Abfrage durchführen
content://mms-sms/conversations
, wird eine Liste verschiedener Konversationen zurückgegeben, bei denen_id
es sich um die letzte SMS oder MMS in jeder Konversation handelt. Wenn Sie abfragencontent://mms-sms/conversations/xxx
, wird jede SMS und / oder MMS in der Konversation zurückgegeben, deren ID lautetxxx
.So unterscheiden Sie zwischen SMS und MMS
Normalerweise möchten Sie wissen, welche Art von Nachricht Sie bearbeiten. Die Dokumentation sagt:
Ich denke, es bezieht sich auf diese Variable ... aber ich konnte es nicht zum Laufen bringen. Wenn Sie haben, sagen Sie mir bitte, wie oder bearbeiten Sie diesen Beitrag.
Bisher habe ich das getan und es scheint zu funktionieren, aber es muss bessere Wege geben:
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()); }
So erhalten Sie Daten aus einer SMS
Sie haben also die ID der SMS und müssen dann nur noch Folgendes tun:
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"));
Wie erhalte ich Daten aus MMS-Daten?
MMS sind etwas anders. Sie können aus verschiedenen Teilen (Text, Audio, Bilder usw.) bestehen. Hier erfahren Sie, wie Sie jede Art von Daten separat abrufen.
Nehmen wir also an, wir haben die MMS-ID in der
mmsId
Variablen. Detaillierte Informationen zu dieser MMS erhalten Sie über dencontent://mms/
Anbieter:Uri uri = Uri.parse("content://mms/"); String selection = "_id = " + mmsId; Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
Die einzige interessante Spalte ist
read
jedoch,1
ob die Nachricht bereits gelesen wurde.So erhalten Sie Textinhalte von MMS
Hier müssen wir verwenden
content://mms/part
... zum Beispiel: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()); }
Es könnte verschiedene Textteile enthalten ... aber normalerweise ist es nur einer. Wenn Sie also die Schleife entfernen möchten, funktioniert dies meistens. So sieht die
getMmsText
Methode aus: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(); }
So erhalten Sie ein Bild von MMS
Es ist dasselbe wie das Erhalten des Textteils ... der einzige Unterschied besteht darin, dass Sie nach einem anderen MIME-Typ suchen:
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()); }
So sieht die
getMmsImage
Methode aus: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; }
So erhalten Sie die Absenderadresse
Sie müssen den
content://mms/xxx/addr
Anbieter verwenden, wobeixxx
die ID der MMS lautet: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; }
Abschließende Gedanken
quelle
content://mms-sms/conversations
funktioniert nicht auf allen Handys (ich habe ein Galaxy S6 und es funktioniert nicht). Ich musstecontent://mms/
für alles verwenden.MessageFormat.format("content://mms/{0}/addr", id);
funktioniert dies nur für IDs mit weniger als 1.000. Sollte es nicht seinMessageFormat.format("content://mms/{0,number,#}/addr", id);
?Die Antwort von Christian ist ausgezeichnet. Die Methode zum Abrufen der Absenderadresse hat bei mir jedoch nicht funktioniert. Die Long.parseLong-Anweisung führt nur eine Ausnahme und einen neuen String (...) aus.
Auf meinem Gerät beträgt die Cursorzahl 2 oder mehr. Der erste hat typischerweise einen "Typ" von 137 und die anderen einen "Typ" von 151. Ich kann nicht finden, wo dies dokumentiert ist, aber man kann ableiten, dass 137 "von" und 151 "bis" ist. Wenn ich die Methode so ausführe, wie sie ist, erhalte ich keine Ausnahme und es wird die letzte Zeile zurückgegeben, die in vielen Fällen ein Empfänger und nur eine von mehreren ist.
Auch AFAICT die Auswahl ist nicht notwendig, da alle Zeilen die gleiche msg_id haben. Es tut jedoch nicht weh.
Dies funktioniert für mich, um die Absenderadresse zu erhalten:
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; }
Es war mir egal, ob alles numerisch ist, aber ich habe eine Möglichkeit eingefügt, alles außer Zahlen als Kommentar zu entfernen, wenn dies gewünscht wird. Es kann leicht geändert werden, um auch alle Empfänger zurückzugeben.
Ich nehme an, es hat bei ihm funktioniert. Es sieht so aus, als würde es die richtige Antwort geben, wenn die Ausnahme in der ersten Zeile auftritt.
quelle
type
Konstanten zu verdeutlichen , stammen sie aus derPduHeaders
Klasse:0x97
/ 151 istPduHeaders.TO
und0x89
/ 137 istPduHeaders.FROM
. Andere gültige Referenzwerte sind:0x81
/ 129 istPduHeaders.BCC
und0x82
/ 130 istPduHeaders.CC
. Siehe auch Telephony.Mms.Addr .Ich habe gerade damit gekämpft; Ich habe es jedoch endlich zum Laufen gebracht und dachte, dieser Thread könnte von meiner Erfahrung profitieren.
Ich konnte
content://mms-sms/conversations/ (Telephony.Threads.CONTENT_URI)
Adressen und Teile abfragen und abrufen, wie im Thread hilfreich beschrieben, aber ich stellte fest, dass dieser URI keine Threads abruft, die nur MMS-Nachrichten enthalten - beispielsweise Threads mit mehr als zwei Korrespondenten.Nachdem ich einige Male in der AOSP MMS-App-Quelle gesucht hatte, stellte ich fest, dass sie eine Variante
Telephony.Threads.CONTENT_URI
zum Generieren ihrer Konversationsliste verwendete - sie fügte den Parameter "simple" mit dem Wert "true" hinzu. Als ich diesen Parameter hinzufügte, stellte ich fest, dass der Anbieter eine völlig andere Tabelle abfragen würde, die tatsächlich alle SMS- und MMS-Threads enthielt.Diese Tabelle hat ein völlig anderes Schema als die reguläre Telephony.Threads.CONTENT_URI one (???); Dies ist die Projektion, die die AOSP-App verwendet -
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 };
Die _ID hier ist die ID des Threads - also eine ID in Telephony.Sms.CONTENT_URI oder Telephony.Mms.CONTENT_URI.
Nachdem ich dieses bizarre Detail entdeckt hatte, begannen die Dinge viel besser zu funktionieren! Beachten Sie jedoch, dass die DATE-Spalte in der Variante "simple = true" nicht zuverlässig ist. Stattdessen musste ich das Datum aus der letzten SMS- oder Mms-Nachricht verwenden.
Eine andere Sache, die ich wahrscheinlich erwähnen sollte, ist, dass ich, um eine korrekte Liste von Nachrichten für einen bestimmten Thread zu erhalten, sowohl die Mms- als auch die SMS-Anbieter abfragen, die Ergebnisse in einer Liste zusammenfassen und sie dann nach Datum sortieren musste.
Ich habe das Verhalten unter Android 5.x und 7.x überprüft.
Ich hoffe das hilft ein bisschen mehr.
quelle
Ich musste einige Änderungen vornehmen, damit dies für mich funktioniert.
Wenn ich den cursor.getString (cursor.getColumnIndex ("Typ")) aus dem Inhalt von mms-sms / gespräche ("content: // mms-sms / gespräche /") abrufe, teste ich den Wert des Feldes "Typ" für null. Wenn die Variable null ist - dh
String otype = c.getString(c.getColumnIndex("type")); if(otype != null) { //this is an sms - handle it...
Die Nachricht ist eine SMS, sonst ist es eine MMS. Für MMS müssen Sie beide MIME-Typen wie folgt testen: -
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...
Die einzige Möglichkeit, die ich finden konnte, um zwischen eingehenden und ausgehenden MMS zu unterscheiden, besteht darin, den Nullstatus des Felds "m_id" des Inhalts von mms-sms / gespräche zu testen.
String m_id = c.getString(c.getColumnIndex("m_id")); String mDirection = m_id == null? "OUT": "IN";
Ein letzter Gedanke, wie man das Adressfeld erhält. Aus irgendeinem Grund möchte der Adressinhalt nicht mit einem {"*"} Parameter abgefragt werden, aber dies funktioniert: -
final String[] projection = new String[] {"address", "contact_id", "charset", "type"};
Wenn es sich um eine ausgehende Nachricht handelt, ist der zu suchende "Typ" 151. Bei einer eingehenden Nachricht ist der "Typ" 137. Ein voll funktionsfähiger Code sieht ungefähr so aus: -
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; }
An alle tapferen Krieger, die in diesem Beitrag vor mir gegangen sind - ich danke dir von ganzem Herzen!
quelle
Die oben angegebene Antwort zum Abrufen von getMMSAddress () sollte die Schleife while (cursor.moveToNext ()) nicht enthalten. Es sollte nur die Adresse aus dem ersten Element im Cursor extrahieren. Aus einem mir unbekannten Grund hat dieser Cursor mehr als einen Datensatz. Die erste enthält die Adresse des Absenders. Die anderen Elemente des Cursors nach dem ersten enthalten die Adresse des Empfängers. Somit gibt der Code wie er ist die Empfängeradresse und nicht die Absenderadresse zurück.
Dies war sehr hilfreich, um den Inhalt einer MMS aufzubrechen.
quelle