Sending SMS via Android SDK & Mms.apk
Sending SMS using the Android SDK is simple enough, right? Get a hold of an SmsManager
instance and call sendTextMessage
. That does indeed send a message but:
- only works when the phone has reception
- is not multipart-aware (for longer messages)
- does not add the message to
content://sms/inbox
orcontent://sms/sent
- gives no UI feedback whatsoever
- includes no retry or recover scenarios
It is obviously possible to implement all of the above using the standard Android SDK but that requires a truckload of cumbersome PendingIntent
s, BroadcastReceiver
s and getResultCode()
s that make it unpleasant and error prone.
This might shock you but the standard Android Messaging application happens to implement all of it and more! When you look through the source code and find things like a TransactionService
or a RetryScheduler
among others, you realize that sending SMS might be a little tricker to get right afterall.
public class Sender {
private Context context;
private Method getOrCreateThreadIdMethod;
private Method sendMessageMethod;
private Constructor<?> smsMessageSenderConstructor;
public Sender(Context ctx) throws Exception {
this.context = ctx;
getOrCreateThreadIdMethod =
Class.forName("android.provider.Telephony$Threads")
.getMethod("getOrCreateThreadId", Context.class, String.class);
ClassLoader classLoader = new PathClassLoader(
"/system/app/Mms.apk", ctx.getClassLoader());
Class<?> smsMessageSenderClass = classLoader
.loadClass("com.android.mms.transaction.SmsMessageSender");
smsMessageSenderConstructor = smsMessageSenderClass
.getConstructor(Context.class, String[].class, String.class, long.class);
sendMessageMethod = smsMessageSenderClass.getMethod("sendMessage", long.class);
}
public void send(String dest, String msgText) throws Exception {
long threadId = (Long) getOrCreateThreadIdMethod.invoke(null, context, dest);
Object smsMessageSender = smsMessageSenderConstructor.newInstance(
context, new String[] { dest }, msgText, threadId);
sendMessageMethod.invoke(smsMessageSender, threadId);
}
}