我的小米根本不发送短信,但默认短信客户端的消息历史记录中显示该短信为未发送。
三星将真正发送短信,但不会调用 BroadcastReceiver.onReceive() 并且我的应用程序不知道它是否已发送。 sms.sent() 的结果是我的超时错误消息。
(我不是 Java 开发人员 - 我只是将我找到的所有解决方案放在一起。如果您发现任何错误,请随时向我指出。)
LogCat展示:
SMS.java:
public class SMS {
public Context context = null;
SMS(Context context) { this.context = context; }
static class Result {
public String status = null;
public String body = null;
public String error = null;
Result(String body) { this.body = body; }
Result(String body, String error) { this.error = error; }
Result(String body, String error, String status) {
if (body != null && !body.equals(""))
this.body = body;
else this.error = error;
this.status = status;
}
}
public static String SENT = "SMS_SENT";
public static String DELIVERED = "SMS_DELIVERED";
public Result sendSMS(JSONObject input) {
final Result[] res = {null};
try {
ArrayList<PendingIntent> sentPendingIntents = new ArrayList<PendingIntent>();
ArrayList<PendingIntent> deliveredPendingIntents = new ArrayList<PendingIntent>();
SmsManager smsManager = SmsManager.getDefault();
ArrayList<String> mSMSMessage = smsManager.divideMessage(input.getString("message"));
for (int i = 0; i < mSMSMessage.size(); i++) {
Intent iSent = new Intent(SENT)
.setPackage(context.getPackageName())
.setClass(context, SMSBroadcastReceiver.class)
.putExtra("result", res);
Intent iDelivered = new Intent(DELIVERED)
.setPackage(context.getPackageName())
.setClass(context, SMSBroadcastReceiver.class)
.putExtra("result", res);
PendingIntent sentPI = PendingIntent.getBroadcast(context, i, iSent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
PendingIntent deliveredPI = PendingIntent.getBroadcast(context, i, iDelivered, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
sentPendingIntents.add(i, sentPI);
deliveredPendingIntents.add(i, deliveredPI);
}
BroadcastReceiver sentReceiver = new SMSBroadcastReceiver();
context.registerReceiver(sentReceiver, new IntentFilter(SENT), context.RECEIVER_NOT_EXPORTED);
BroadcastReceiver deliveredReceiver = new SMSBroadcastReceiver();
context.registerReceiver(deliveredReceiver, new IntentFilter(DELIVERED), context.RECEIVER_NOT_EXPORTED);
smsManager.sendMultipartTextMessage(input.getString("number"), null, mSMSMessage, sentPendingIntents, deliveredPendingIntents);
int miliSecSleep = 300;
int miliSecMax = 1000 * 18;
int miliSecDeliveredMin = 1000 * 5;
while (miliSecMax > 0) {
Thread.sleep(miliSecSleep);
miliSecMax = miliSecMax - miliSecSleep;
miliSecDeliveredMin = miliSecDeliveredMin - miliSecSleep;
if (res[0] != null && (res[0].status.equals(DELIVERED) || miliSecDeliveredMin < 0)) {
if (res[0].error != null)
Log.e("~=", res[0].error);
else Log.d("~=", res[0].body);
break;
}
}
if (res[0] == null) {
res[0] = new Result("", "SMS status: 25s TimeOut for SMS sending has expired");
}
context.unregisterReceiver(sentReceiver);
context.unregisterReceiver(deliveredReceiver);
} catch (Exception e) {
Log.e("~=", "SMS error: " + e.toString());
res[0] = new Result("", "SMS error: " + e.toString());
}
return res[0];
}
}
service.java:
public class SMSService extends Service {
SMS sms = new SMS(this);
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
sms.sent('123456', 'test message');
SMSBroadcastReceiver.java:
public class SMSBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("~=", "this is never be called");
Functions.Result[] result = intent.getExtras().getParcelableArray("result", Functions.Result.class);
SmsMessage smsM = SmsMessage.createFromPdu(
intent.getByteArrayExtra("pdu"),
intent.getStringExtra("format")
);
if (getResultCode() == Activity.RESULT_OK || (smsM != null && smsM.getStatus() == Telephony.Sms.STATUS_COMPLETE))
result[0] = new Functions.Result(intent.getAction() + " status: DONE", null, intent.getAction());
else if (intent.getAction().equals(Functions.SENT))
result[0] = new Functions.Result(null, intent.getAction() + " status: " + getConstantName(getResultCode(), SmsManager.class), intent.getAction());
else if (smsM != null && smsM.getStatus() == Telephony.Sms.STATUS_FAILED)
result[0] = new Functions.Result(null, intent.getAction() + " status: STATUS_FAILED (SMS not delivered)", intent.getAction());
}
private String getConstantName(int value, Class<?> cls) {
for ( java.lang.reflect.Field f : cls.getDeclaredFields()) {
int mod = f.getModifiers();
if (Modifier.isStatic(mod) && Modifier.isPublic(mod) && Modifier.isFinal(mod)) {
try {
// Log.d(LOG_TAG, String.format("%s = %d%n", f.getName(), (int) f.get(null)));
if ((int) f.get(null) == value) return f.getName();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return null;
}
}
MainActivity.java -> 权限:READ_SMS、SEND_SMS、RECEIVE_SMS
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher_foreground"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.Material3.DayNight"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".SMSService"
android:enabled="true"
android:exported="true">
</service>
<receiver
android:name=".SMSBroadcastReceiver"
android:exported="false">
<intent-filter android:priority="2147483645">
<action android:name="SMS_SENT" />
<action android:name="SMS_DELIVERED" />
<action android:name="android.provider.telephony.SMS_RECEIVED"></action>
</intent-filter>
</receiver>
</application>
</manifest>
非常感谢@MikeM。我已经彻底郁闷了。我将你的代码(在我看来是非必要部分)与我的代码结合起来,莫名其妙地它开始在三星 \o/ 上为我工作。它要么在小米上不起作用,要么完全随机工作,并且根本无法识别传递的事件消息(SmsMessage.createFromPdu() 为空),但现在我可能没有勇气进行下一步编辑我的解决方案。经过这次短信体验后,我认为 Android 是一个非常糟糕的操作系统。我很高兴我没有正式开发移动应用程序:D .
只是为了好玩,我的代码的当前版本在这里https://github.com/ObscurusGrassator/jjplugin-sms/tree/main/android-apk-source/app/src/main/java/jjplugin/obsgrass/sms
Java @MikeM 解决方案:https://gist.github.com/gonodono/8802779b2119497b848b72803fbaeec1
Kotlin @MikeM 解决方案:https://github.com/gonodono/sms-sender