Nauczyłem się wysyłać i odbierać wiadomości SMS. Aby wysyłać wiadomości SMS, musiałem zadzwonić do metod sendTextMessage()
i klasy. Aby odbierać wiadomości SMS, musiałem zarejestrować odbiorcę w pliku. Następnie musiałem zastąpić metodę . Poniżej zamieściłem przykłady.sendMultipartTextMessage()
SmsManager
AndroidMainfest.xml
onReceive()
BroadcastReceiver
MainActivity.java
public class MainActivity extends Activity {
private static String SENT = "SMS_SENT";
private static String DELIVERED = "SMS_DELIVERED";
private static int MAX_SMS_MESSAGE_LENGTH = 160;
// ---sends an SMS message to another device---
public static void sendSMS(String phoneNumber, String message) {
PendingIntent piSent = PendingIntent.getBroadcast(mContext, 0, new Intent(SENT), 0);
PendingIntent piDelivered = PendingIntent.getBroadcast(mContext, 0,new Intent(DELIVERED), 0);
SmsManager smsManager = SmsManager.getDefault();
int length = message.length();
if(length > MAX_SMS_MESSAGE_LENGTH) {
ArrayList<String> messagelist = smsManager.divideMessage(message);
smsManager.sendMultipartTextMessage(phoneNumber, null, messagelist, null, null);
}
else
smsManager.sendTextMessage(phoneNumber, null, message, piSent, piDelivered);
}
}
//More methods of MainActivity ...
}
SMSReceiver.java
public class SMSReceiver extends BroadcastReceiver {
private final String DEBUG_TAG = getClass().getSimpleName().toString();
private static final String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
private Context mContext;
private Intent mIntent;
// Retrieve SMS
public void onReceive(Context context, Intent intent) {
mContext = context;
mIntent = intent;
String action = intent.getAction();
if(action.equals(ACTION_SMS_RECEIVED)){
String address, str = "";
int contactId = -1;
SmsMessage[] msgs = getMessagesFromIntent(mIntent);
if (msgs != null) {
for (int i = 0; i < msgs.length; i++) {
address = msgs[i].getOriginatingAddress();
contactId = ContactsUtils.getContactId(mContext, address, "address");
str += msgs[i].getMessageBody().toString();
str += "\n";
}
}
if(contactId != -1){
showNotification(contactId, str);
}
// ---send a broadcast intent to update the SMS received in the
// activity---
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("SMS_RECEIVED_ACTION");
broadcastIntent.putExtra("sms", str);
context.sendBroadcast(broadcastIntent);
}
}
public static SmsMessage[] getMessagesFromIntent(Intent intent) {
Object[] messages = (Object[]) intent.getSerializableExtra("pdus");
byte[][] pduObjs = new byte[messages.length][];
for (int i = 0; i < messages.length; i++) {
pduObjs[i] = (byte[]) messages[i];
}
byte[][] pdus = new byte[pduObjs.length][];
int pduCount = pdus.length;
SmsMessage[] msgs = new SmsMessage[pduCount];
for (int i = 0; i < pduCount; i++) {
pdus[i] = pduObjs[i];
msgs[i] = SmsMessage.createFromPdu(pdus[i]);
}
return msgs;
}
/**
* The notification is the icon and associated expanded entry in the status
* bar.
*/
protected void showNotification(int contactId, String message) {
//Display notification...
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.myexample"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.WRITE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:debuggable="true"
android:icon="@drawable/ic_launcher_icon"
android:label="@string/app_name" >
<activity
//Main activity...
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
//Activity 2 ...
</activity>
//More acitivies ...
// SMS Receiver
<receiver android:name="com.myexample.receivers.SMSReceiver" >
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
</manifest>
Zastanawiałem się jednak, czy możesz wysyłać i odbierać wiadomości MMS w podobny sposób. Po przeprowadzeniu pewnych badań wiele przykładów zamieszczonych na blogach po prostu przechodzi Intent
do natywnej aplikacji Messaging. Próbuję wysłać MMS bez opuszczania aplikacji. Wydaje się, że nie ma standardowego sposobu wysyłania i odbierania MMS-ów. Czy ktoś sprawił, że to zadziałało?
Mam również świadomość, że dostawca treści SMS / MMS nie jest częścią oficjalnego zestawu Android SDK, ale myślałem, że ktoś mógł to zaimplementować. Każda pomoc jest mile widziana.
Aktualizacja
Dodałem BroadcastReceiver
do AndroidManifest.xml
pliku, aby otrzymywać wiadomości MMS
<receiver android:name="com.sendit.receivers.MMSReceiver" >
<intent-filter>
<action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
<data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
</receiver>
W klasie MMSReceiver onReceive()
metoda jest w stanie pobrać tylko numer phoneNumber, z którego wysłano wiadomość. W jaki sposób można pobrać inne ważne informacje z wiadomości MMS, takie jak ścieżka pliku do załącznika multimedialnego (obraz / dźwięk / wideo) lub tekst w wiadomości MMS?
MMSReceiver.java
public class MMSReceiver extends BroadcastReceiver {
private final String DEBUG_TAG = getClass().getSimpleName().toString();
private static final String ACTION_MMS_RECEIVED = "android.provider.Telephony.WAP_PUSH_RECEIVED";
private static final String MMS_DATA_TYPE = "application/vnd.wap.mms-message";
// Retrieve MMS
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
String type = intent.getType();
if(action.equals(ACTION_MMS_RECEIVED) && type.equals(MMS_DATA_TYPE)){
Bundle bundle = intent.getExtras();
Log.d(DEBUG_TAG, "bundle " + bundle);
SmsMessage[] msgs = null;
String str = "";
int contactId = -1;
String address;
if (bundle != null) {
byte[] buffer = bundle.getByteArray("data");
Log.d(DEBUG_TAG, "buffer " + buffer);
String incomingNumber = new String(buffer);
int indx = incomingNumber.indexOf("/TYPE");
if(indx>0 && (indx-15)>0){
int newIndx = indx - 15;
incomingNumber = incomingNumber.substring(newIndx, indx);
indx = incomingNumber.indexOf("+");
if(indx>0){
incomingNumber = incomingNumber.substring(indx);
Log.d(DEBUG_TAG, "Mobile Number: " + incomingNumber);
}
}
int transactionId = bundle.getInt("transactionId");
Log.d(DEBUG_TAG, "transactionId " + transactionId);
int pduType = bundle.getInt("pduType");
Log.d(DEBUG_TAG, "pduType " + pduType);
byte[] buffer2 = bundle.getByteArray("header");
String header = new String(buffer2);
Log.d(DEBUG_TAG, "header " + header);
if(contactId != -1){
showNotification(contactId, str);
}
// ---send a broadcast intent to update the MMS received in the
// activity---
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("MMS_RECEIVED_ACTION");
broadcastIntent.putExtra("mms", str);
context.sendBroadcast(broadcastIntent);
}
}
}
/**
* The notification is the icon and associated expanded entry in the status
* bar.
*/
protected void showNotification(int contactId, String message) {
//Display notification...
}
}
Zgodnie z dokumentacją android.provider.Telephony :
Akcja transmisji: nowa wiadomość tekstowa SMS została odebrana przez urządzenie. Zamiar będzie miał następujące dodatkowe wartości:
pdus
- WObject[]
odbyte[]
s zawierających PDU, które składają się na wiadomość.Dodatkowe wartości można wyodrębnić za pomocą
getMessagesFromIntent(android.content.Intent)
Jeśli BroadcastReceiver napotka błąd podczas przetwarzania tego celu, powinien odpowiednio ustawić kod wynikowy.
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
Akcja transmisji: nowa wiadomość SMS oparta na danych została odebrana przez urządzenie. Zamiar będzie miał następujące dodatkowe wartości:
pdus
- WObject[]
odbyte[]
s zawierających PDU, które składają się na wiadomość.Dodatkowe wartości można wyodrębnić za pomocą funkcji getMessagesFromIntent (android.content.Intent). Jeśli BroadcastReceiver napotka błąd podczas przetwarzania tego celu, powinien odpowiednio ustawić kod wynikowy.
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED";
Akcja transmisji: nowa wiadomość WAP PUSH została odebrana przez urządzenie. Zamiar będzie miał następujące dodatkowe wartości:
transactionId (Integer)
- identyfikator transakcji WAP
pduType (Integer)
- Typ WAP PDU`
header (byte[])
- nagłówek wiadomości
data (byte[])
- ładunek danych wiadomości
contentTypeParameters (HashMap<String,String>)
- Wszelkie parametry związane z typem treści (zdekodowane z nagłówka WSP Content-Type)Jeśli BroadcastReceiver napotka błąd podczas przetwarzania tego celu, powinien odpowiednio ustawić kod wynikowy. Dodatkową wartością contentTypeParameters jest mapa parametrów zawartości z kluczami według ich nazw. Jeśli napotkane zostaną jakiekolwiek nieprzypisane, dobrze znane parametry, klucz mapy będzie miał wartość „nieprzypisane / 0x ...”, gdzie „...” jest wartością szesnastkową nieprzypisanego parametru. Jeśli parametr nie ma wartości, wartość w mapie będzie miała wartość null.
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
Aktualizacja nr 2
Dowiedziałem się, jak przekazać dodatki w PendingIntent
celu odebrania przez BroadcastReceiver
:
Dodatki PendingIntent na Androida, które nie zostały odebrane przez BroadcastReceiver
Jednak te dodatkowe są przekazywane do SendBroadcastReceiver, a nie do SMSReceiver . Jak mogę przekazać dodatkowe do SMSReceiver ?
Aktualizacja nr 3
Odbieranie wiadomości MMS
Więc po przeprowadzeniu dalszych badań zobaczyłem kilka sugestii dotyczących zarejestrowania domeny ContentObserver
. W ten sposób można wykryć zmiany content://mms-sms/conversations
dostawcy treści, co w konsekwencji umożliwia wykrywanie przychodzących wiadomości MMS. Oto najbliższy przykład, jaki znalazłem, jak to działa: Odbieranie wiadomości MMS
Istnieje jednak zmienna mainActivity
typu ServiceController
. Gdzie jest ServiceController
zaimplementowana klasa? Czy są jakieś inne implementacje zarejestrowanego ContentObserver
?
Wysyłanie MMS-ów
Jeśli chodzi o wysyłanie MMS-ów, natknąłem się na taki przykład: Wyślij MMS
Problem polega na tym, że próbowałem uruchomić ten kod na moim Nexusie 4, który jest na Androidzie w wersji 4.2.2, i otrzymuję ten błąd:
java.lang.SecurityException: No permission to write APN settings: Neither user 10099 nor current process has android.permission.WRITE_APN_SETTINGS.
Błąd jest generowany po wysłaniu zapytania do Carriers
ContentProvider w getMMSApns()
metodzie APNHelper
klasy.
final Cursor apnCursor = this.context.getContentResolver().query(Uri.withAppendedPath(Carriers.CONTENT_URI, "current"), null, null, null, null);
Najwyraźniej nie możesz czytać APN w Androidzie 4.2
Jaka jest alternatywa dla wszystkich aplikacji, które używają danych mobilnych do wykonywania operacji (takich jak wysyłanie MMS-ów) i nie znają domyślnego ustawienia APN obecnego w urządzeniu?
Aktualizacja # 4
Wysyłanie MMS-ów
Próbowałem postępować zgodnie z tym przykładem: Wyślij MMS
Jak zasugerował @Sam w swojej odpowiedzi:
You have to add jsoup to the build path, the jar to the build path and import com.droidprism.*; To do that in android, add the jars to the libs directory first, then configure the project build path to use the jars already in the libs directory, then on the build path config click order and export and check the boxes of the jars and move jsoup and droidprism jar to the top of the build order.
Więc teraz nie otrzymuję już błędów SecurityException. Testuję teraz na Nexusie 5 na Androidzie KitKat. Po uruchomieniu przykładowego kodu daje mi kod odpowiedzi 200 po wywołaniu
MMResponse mmResponse = sender.send(out, isProxySet, MMSProxy, MMSPort);
Jednak sprawdziłem z osobą, do której próbowałem wysłać MMS. Powiedzieli, że nigdy nie otrzymali MMS-a.