Создание PDU для Android, работающего с SmsMessage.createFromPdu() (GSM 3gpp)
Цель: (ПРИМЕЧАНИЕ: выбранный ответ генерирует PDU GSM (3gpp)) для CDMA (3gpp2), пожалуйста, обратитесь сюда
Чтобы создать PDU, в который можно передавать SmsMessage.createFromPdu(byte[] pdu)
. Я "Транслирую намерение" одному из моихBroadcastReciever
, который прослушивает SMS-сообщения.
Один BroadcastReciever
Использование android.provider.Telephony.SMS_RECEIVED
для "реальных" SMS
Использование пользовательского intent-filter
действия для этих новых "SMS-сообщений приложения".
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
Object[] pdusObj = (Object[]) bundle.get("pdus");
SmsMessage[] messages = new SmsMessage[pdusObj.length];
// getting SMS information from Pdu.
for (int i = 0; i < pdusObj.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdusObj[i]);
}
for (SmsMessage currentMessage : messages) {
//the currentMessage.getDisplayOriginatingAddress()
//or .getDisplayMessageBody() is null if I Broadcast a fake sms
Log.i("BB", "address:"+currentMessage.getDisplayOriginatingAddress()+" message:"+currentMessage.getDisplayMessageBody());
...
Итак, я хочу, чтобы мой BroadcastReciever
мог обрабатывать оба типа сообщений без добавления дополнительного кода
(да, я знаю, что у меня может быть другое BroadcastReciever
для другого intent-filter
действия, но я хотел бы на самом деле осуществить это, поскольку я знаю, что это можно сделать, я упрямый)
Исследования:
Я занимался исследованиями весь день и ночь. Я пытался написать свой собственный, хотя я очень плохо разбираюсь в математике и преобразованиях и создаю подходящий алгоритм. Я просмотрел разделы Stack о PDU и Создание PDU Android, но ссылка в ответе не работает. Я даже посмотрел на com.google.android.mms.pdu
исходный код
пока мне удалось создать PDU только без "исходного адреса", используя некоторый код из http://www.wrankl.de/JavaPC/SMSTools.html
PDU:
назначение: 555 сообщение: helloworld
"1100038155f50000aa0ae8329bfdbebfe56c32"
Что, очевидно, недопустимо...
Дополнительные примечания:
Я не планирую ничего делать с PDU, кроме локального использования, я не хочу жестко закодированных PDU в моем коде, потому что я не использую PDU повторно.
Если есть что-то, что я могу добавить к коду, который я использую для добавления в "исходный адрес", это сработает. Или у кого-нибудь есть информация о библиотеке, о которой я не знаю?
Спасибо
Обновления:
пробовал
byte[] by =(byte[])(SmsMessage.getSubmitPdu("12345", "1234", "hello", false).encodedMessage);
который дает мне следующее (в шестнадцатеричном представлении)
"0000100200000000000000000000000004010203040000000e000320ec400107102e8cbb366f00"
не сработало
Переведено автоматически
Ответ 1
Возможно, в этом фрагменте не так много полей сведений, как вы хотите, но для моей простой цели он может вызывать уведомление, как другое sms.
private static void createFakeSms(Context context, String sender,
String body) {
byte[] pdu = null;
byte[] scBytes = PhoneNumberUtils
.networkPortionToCalledPartyBCD("0000000000");
byte[] senderBytes = PhoneNumberUtils
.networkPortionToCalledPartyBCD(sender);
int lsmcs = scBytes.length;
byte[] dateBytes = new byte[7];
Calendar calendar = new GregorianCalendar();
dateBytes[0] = reverseByte((byte)(calendar.get(Calendar.YEAR)));
dateBytes[1] = reverseByte((byte)(calendar.get(Calendar.MONTH) + 1));
dateBytes[2] = reverseByte((byte)(calendar.get(Calendar.DAY_OF_MONTH)));
dateBytes[3] = reverseByte((byte)(calendar.get(Calendar.HOUR_OF_DAY)));
dateBytes[4] = reverseByte((byte)(calendar.get(Calendar.MINUTE)));
dateBytes[5] = reverseByte((byte)(calendar.get(Calendar.SECOND)));
dateBytes[6] = reverseByte((byte)((calendar.get(Calendar.ZONE_OFFSET) + calendar
.get(Calendar.DST_OFFSET)) / (60 * 1000 * 15)));
try {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
bo.write(lsmcs);
bo.write(scBytes);
bo.write(0x04);
bo.write((byte) sender.length());
bo.write(senderBytes);
bo.write(0x00);
bo.write(0x00); // encoding: 0 for default 7bit
bo.write(dateBytes);
try {
String sReflectedClassName = "com.android.internal.telephony.GsmAlphabet";
Class cReflectedNFCExtras = Class.forName(sReflectedClassName);
Method stringToGsm7BitPacked = cReflectedNFCExtras.getMethod(
"stringToGsm7BitPacked", new Class[] {
String.class
});
stringToGsm7BitPacked.setAccessible(true);
byte[] bodybytes = (byte[]) stringToGsm7BitPacked.invoke(null,
body);
bo.write(bodybytes);
} catch (Exception e) {}
pdu = bo.toByteArray();
} catch (IOException e) {}
Intent intent = new Intent();
intent.setClassName("com.android.mms",
"com.android.mms.transaction.SmsReceiverService");
intent.setAction("android.provider.Telephony.SMS_RECEIVED");
intent.putExtra("pdus", new Object[] {
pdu
});
intent.putExtra("format", "3gpp");
context.startService(intent);
}
private static byte reverseByte(byte b) {
return (byte)((b & 0xF0) >> 4 | (b & 0x0F) << 4);
}
public static final 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;
}
Ответ 2
Прошло много времени с тех пор, как я выполнял какие-либо прямые операции с PDU, но когда я это сделал, я быстро сдался и использовал SMSLib: утилиты PDU, которые он отлично использовал для отправки через телефоны Nokia (по последовательной ссылке). Мое предположение (которое может быть неверным) заключается в том, что они будут работать и для Android, предполагая, что интерфейс действительно соответствует спецификации.
Ответ 3
Проверьте этот код в console.c. Здесь эмулятор Android создает pdu и RIL.java где сообщение CMT преобразуется в SmsMessage. Вы можете использовать SmsMessage.getPdu
для получения pdu. Но SmsMessage.newFromCmt
похоже, что это внутренний API. Так что это может быть ненадежно.
Далее, это только для Gsm, cdma имеет совершенно другой поток кодов, и поскольку RIL.java и модем полностью зависят от производителя, это может работать только на эмуляторе.
Обычно GSM-код более надежен на Android, поэтому может также работать на телефоне gsm. Попробуйте.