You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中SmsManager.sendMultimediaMessage使用及contentUri创建问题

解决Android SmsManager.sendMultimediaMessage()发送MMS失败的问题

你的代码存在几个关键问题导致MMS发送失败,以下是修复方案:

1. 补充MMS核心必填字段

Telephony.Mms表需要一些必填字段才能让系统识别为可发送的MMS,你的代码只设置了SUBJECT,缺失了日期、消息类型、状态等关键字段:

ContentValues mmsValues = new ContentValues();
mmsValues.put(Telephony.Mms.SUBJECT, "Subject");
// 补充必填字段
mmsValues.put(Telephony.Mms.DATE, System.currentTimeMillis() / 1000); // Unix时间戳(秒)
mmsValues.put(Telephony.Mms.MESSAGE_TYPE, Telephony.Mms.MESSAGE_TYPE_SEND); // 标记为待发送的消息
mmsValues.put(Telephony.Mms.READ, 1); // 标记为已读(避免系统重复处理)
mmsValues.put(Telephony.Mms.STATUS, Telephony.Mms.STATUS_PENDING); // 标记为待发送状态
mmsValues.put(Telephony.Mms.REPORT_REQUESTED, 0); // 关闭送达报告(可选)

2. 修正收件人地址类型

你使用的TYPE=137不是标准的收件人类型,应该使用官方定义的TYPE_TO:

ContentValues addrValues = new ContentValues();
addrValues.put(Telephony.Mms.Addr.MSG_ID, messageId);
addrValues.put(Telephony.Mms.Addr.ADDRESS, phoneNumber);
addrValues.put(Telephony.Mms.Addr.TYPE, Telephony.Mms.Addr.TYPE_TO); // 标准收件人类型(值为1)
addrValues.put(Telephony.Mms.Addr.CHARSET, "UTF-8"); // 补充字符集

3. 正确存储文本内容

Telephony.Mms.Part的TEXT字段并非所有系统都支持,正确的做法是将文本写入到ContentResolver的输出流中:

Uri partUri = Uri.withAppendedPath(mmsUri, "part");
ContentValues partValues = new ContentValues();
partValues.put(Telephony.Mms.Part.MSG_ID, messageId);
partValues.put(Telephony.Mms.Part.CONTENT_TYPE, "text/plain");
partValues.put(Telephony.Mms.Part.NAME, "body.txt");
partValues.put(Telephony.Mms.Part.FILENAME, "body.txt");
partValues.put(Telephony.Mms.Part.CONTENT_LOCATION, "body.txt");
partValues.put(Telephony.Mms.Part.CHARSET, "UTF-8");

Uri insertedPartUri = context.getContentResolver().insert(partUri, partValues);
if (insertedPartUri == null) {
    Log.e("SendDirectSms", "Failed to create text part");
    context.getContentResolver().delete(mmsUri, null, null); // 清理无效MMS
    return;
}

// 将文本写入到part的输出流
try (OutputStream os = context.getContentResolver().openOutputStream(insertedPartUri)) {
    os.write(msg.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
    Log.e("SendDirectSms", "Failed to write text content", e);
    context.getContentResolver().delete(mmsUri, null, null);
    return;
}

4. 添加发送状态监听(可选但关键)

通过PendingIntent监听发送结果,既能确认是否发送成功,也能在失败时清理无效记录:

// 创建发送状态广播的PendingIntent
String SENT_ACTION = "com.your.app.package.MMS_SENT";
Intent sentIntent = new Intent(SENT_ACTION);
PendingIntent sentPendingIntent = PendingIntent.getBroadcast(
    context,
    0,
    sentIntent,
    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);

// 发送MMS
smsManager.sendMultimediaMessage(context, mmsUri, null, null, sentPendingIntent);

然后注册广播接收器处理结果(在React Native模块中初始化时注册):

private BroadcastReceiver mmsSentReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        int resultCode = getResultCode();
        switch (resultCode) {
            case Activity.RESULT_OK:
                Log.i("SendDirectSms", "MMS发送成功");
                // 更新MMS状态为已完成
                ContentValues updateValues = new ContentValues();
                updateValues.put(Telephony.Mms.STATUS, Telephony.Mms.STATUS_COMPLETE);
                context.getContentResolver().update(mmsUri, updateValues, null, null);
                break;
            case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
            case SmsManager.RESULT_ERROR_NO_SERVICE:
            case SmsManager.RESULT_ERROR_NULL_PDU:
            case SmsManager.RESULT_ERROR_RADIO_OFF:
                Log.e("SendDirectSms", "MMS发送失败,错误码:" + resultCode);
                // 更新MMS状态为失败
                ContentValues failValues = new ContentValues();
                failValues.put(Telephony.Mms.STATUS, Telephony.Mms.STATUS_FAILED);
                context.getContentResolver().update(mmsUri, failValues, null, null);
                break;
        }
    }
};

// 在模块初始化时注册接收器
@Override
public void initialize(ReactApplicationContext reactContext) {
    super.initialize(reactContext);
    this.context = reactContext;
    IntentFilter filter = new IntentFilter(SENT_ACTION);
    reactContext.registerReceiver(mmsSentReceiver, filter);
}

// 在模块销毁时注销
@Override
public void onCatalystInstanceDestroy() {
    super.onCatalystInstanceDestroy();
    if (mmsSentReceiver != null) {
        context.unregisterReceiver(mmsSentReceiver);
    }
}

5. 确保权限齐全

在AndroidManifest.xml中添加必要权限,并在运行时动态申请:

<uses-permission android:name="android.permission.SEND_MMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<!-- Android 12+ 需要通知权限才能触发广播 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

最终修正后的完整代码

@ReactMethod
public void sendDirectSms(String phoneNumber, String msg) {
    // 检查权限(需要提前动态申请)
    if (ContextCompat.checkSelfPermission(context, Manifest.permission.SEND_MMS) != PackageManager.PERMISSION_GRANTED ||
        ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_SMS) != PackageManager.PERMISSION_GRANTED) {
        Log.e("SendDirectSms", "Missing required permissions");
        return;
    }

    try {
        SmsManager smsManager = SmsManager.getDefault();
        // 1. 创建MMS主记录
        ContentValues mmsValues = new ContentValues();
        mmsValues.put(Telephony.Mms.SUBJECT, "Subject");
        mmsValues.put(Telephony.Mms.DATE, System.currentTimeMillis() / 1000);
        mmsValues.put(Telephony.Mms.MESSAGE_TYPE, Telephony.Mms.MESSAGE_TYPE_SEND);
        mmsValues.put(Telephony.Mms.READ, 1);
        mmsValues.put(Telephony.Mms.STATUS, Telephony.Mms.STATUS_PENDING);
        mmsValues.put(Telephony.Mms.REPORT_REQUESTED, 0);

        Uri mmsUri = context.getContentResolver().insert(Telephony.Mms.CONTENT_URI, mmsValues);
        if (mmsUri == null) {
            Log.e("SendDirectSms", "Failed to create MMS message.");
            return;
        }
        String messageId = mmsUri.getLastPathSegment();

        // 2. 添加收件人地址
        Uri addrUri = Uri.withAppendedPath(mmsUri, "addr");
        ContentValues addrValues = new ContentValues();
        addrValues.put(Telephony.Mms.Addr.MSG_ID, messageId);
        addrValues.put(Telephony.Mms.Addr.ADDRESS, phoneNumber);
        addrValues.put(Telephony.Mms.Addr.TYPE, Telephony.Mms.Addr.TYPE_TO);
        addrValues.put(Telephony.Mms.Addr.CHARSET, "UTF-8");
        Uri insertedAddrUri = context.getContentResolver().insert(addrUri, addrValues);
        if (insertedAddrUri == null) {
            Log.e("SendDirectSms", "Failed to add recipient");
            context.getContentResolver().delete(mmsUri, null, null);
            return;
        }

        // 3. 添加文本内容部分
        Uri partUri = Uri.withAppendedPath(mmsUri, "part");
        ContentValues partValues = new ContentValues();
        partValues.put(Telephony.Mms.Part.MSG_ID, messageId);
        partValues.put(Telephony.Mms.Part.CONTENT_TYPE, "text/plain");
        partValues.put(Telephony.Mms.Part.NAME, "body.txt");
        partValues.put(Telephony.Mms.Part.FILENAME, "body.txt");
        partValues.put(Telephony.Mms.Part.CONTENT_LOCATION, "body.txt");
        partValues.put(Telephony.Mms.Part.CHARSET, "UTF-8");

        Uri insertedPartUri = context.getContentResolver().insert(partUri, partValues);
        if (insertedPartUri == null) {
            Log.e("SendDirectSms", "Failed to create text part");
            context.getContentResolver().delete(mmsUri, null, null);
            return;
        }

        try (OutputStream os = context.getContentResolver().openOutputStream(insertedPartUri)) {
            os.write(msg.getBytes(StandardCharsets.UTF_8));
        } catch (IOException e) {
            Log.e("SendDirectSms", "Failed to write text content", e);
            context.getContentResolver().delete(mmsUri, null, null);
            return;
        }

        // 4. 发送MMS并监听状态
        String SENT_ACTION = "com.your.app.package.MMS_SENT";
        Intent sentIntent = new Intent(SENT_ACTION);
        PendingIntent sentPendingIntent = PendingIntent.getBroadcast(
            context,
            0,
            sentIntent,
            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
        );

        smsManager.sendMultimediaMessage(context, mmsUri, null, null, sentPendingIntent);

    } catch (Exception ex) {
        Log.e("SendDirectSms", "Exception occurred", ex);
    }
}

注意事项

  • 部分运营商要求MMS必须包含主题(SUBJECT),即使是空字符串也可以,但不能缺失
  • Android 10及以上对短信/MMS的读写权限限制更严格,确保动态申请权限时用户授权
  • 若仍发送失败,可检查设备的MMSC配置是否正确(可通过Telephony.Carriers获取默认配置,或在sendMultimediaMessage的第三个参数configOverrides中指定)

内容的提问来源于stack exchange,提问作者이제준

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 19:35:52