Android Kotlin中使用BroadcastReceiver获取MMS并传递数据的问题
问题解答
一、关于清单注册的问题
你的MmsReceiverK是ComponentActivity子类,必须在清单文件中注册,否则系统无法启动该Activity,动态注册的广播接收器也不会生效。但用Activity监听MMS广播存在局限:只有Activity处于存活状态时,接收器才能接收广播;一旦Activity被销毁,接收器会自动注销,无法实现后台持续监听。若需要后台监听,更推荐用Service结合动态注册,以下先按你的Activity方案实现。
二、修正后的完整实现代码
你的代码存在广播逻辑位置错误、列名硬编码、MMS ID获取错误、IntentFilter配置顺序错误等问题,以下是修正后的Kotlin代码:
package radwil.sms.routing import android.annotation.SuppressLint import android.content.* import android.database.Cursor import android.net.Uri import android.os.Bundle import android.provider.Telephony import android.provider.Telephony.Sms.Intents.WAP_PUSH_RECEIVED_ACTION import android.text.TextUtils import androidx.activity.ComponentActivity import androidx.core.app.ActivityCompat import radwil.sms.utils.log import java.io.IOException class MmsReceiverK : ComponentActivity() { private lateinit var mmsReceiver: BroadcastReceiver // 所需危险权限 private val REQUIRED_PERMISSIONS = arrayOf( android.Manifest.permission.RECEIVE_MMS, android.Manifest.permission.READ_SMS, android.Manifest.permission.RECEIVE_SMS ) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Android 6.0+必须动态申请危险权限 requestPermissions() // 初始化广播接收器,将MMS处理逻辑放在onReceive内 mmsReceiver = object : BroadcastReceiver() { @SuppressLint("Range") override fun onReceive(context: Context, intent: Intent) { log("+++++inside receiver") if (TextUtils.equals(intent.action, WAP_PUSH_RECEIVED_ACTION)) { handleMmsReceived(context) } } } // 先配置IntentFilter参数,再注册接收器 val filterMMS = IntentFilter.create( "android.provider.Telephony.WAP_PUSH_RECEIVED", "application/vnd.wap.mms-message" ) filterMMS.priority = IntentFilter.SYSTEM_HIGH_PRIORITY filterMMS.addAction(WAP_PUSH_RECEIVED_ACTION) registerReceiver(mmsReceiver, filterMMS) } private fun requestPermissions() { ActivityCompat.requestPermissions( this, REQUIRED_PERMISSIONS, 1001 ) } @SuppressLint("Range") private fun handleMmsReceived(context: Context) { val contentResolver = context.contentResolver // 使用系统常量作为列名,避免硬编码导致的索引找不到问题 val projection = arrayOf( Telephony.Mms._ID, Telephony.Mms.CONTENT_TYPE, Telephony.Mms.Addr.ADDRESS ) // 直接查询MMS表,按时间倒序取最新一条 val uri = Telephony.Mms.CONTENT_URI contentResolver.query(uri, projection, null, null, "${Telephony.Mms.DATE} DESC")?.use { cursor -> if (cursor.moveToFirst()) { val contentType = cursor.getString(cursor.getColumnIndex(Telephony.Mms.CONTENT_TYPE)) if ("application/vnd.wap.multipart.related" == contentType) { // 获取MMS的实际ID(不是列索引) val mmsId = cursor.getLong(cursor.getColumnIndex(Telephony.Mms._ID)) val mmsAddress = cursor.getString(cursor.getColumnIndex(Telephony.Mms.Addr.ADDRESS)) val mmsText = getMmsText(context, mmsId) log("received MMS from: $mmsAddress with message: $mmsText") // 将MMS数据传递给其他函数 passMmsDataToOtherFunction(mmsAddress, mmsText) } } } } // 修正后的MMS文本提取逻辑 private fun getMmsText(context: Context, mmsId: Long): String { val sb = StringBuilder() val partUri = Uri.parse("content://mms/part") val projection = arrayOf(Telephony.Mms.Part.TEXT) val selection = "${Telephony.Mms.Part.MSG_ID} = ? AND ${Telephony.Mms.Part.CONTENT_TYPE} = 'text/plain'" val selectionArgs = arrayOf(mmsId.toString()) context.contentResolver.query(partUri, projection, selection, selectionArgs, null)?.use { cursor -> while (cursor.moveToNext()) { val text = cursor.getString(cursor.getColumnIndex(Telephony.Mms.Part.TEXT)) text?.let { sb.append(it) } } } return sb.toString() } // 示例:将MMS数据传递给其他业务函数 private fun passMmsDataToOtherFunction(address: String?, content: String) { // 这里实现你的业务逻辑,比如存储、上传等 log("Passing MMS data: address=$address, content=$content") } override fun onDestroy() { super.onDestroy() // 注销接收器,避免内存泄漏 unregisterReceiver(mmsReceiver) } }
三、关键问题修复说明
- 广播逻辑位置错误:原代码将MMS处理逻辑放在
onCreate中,只会在Activity启动时执行一次;修正后将逻辑移到BroadcastReceiver的onReceive方法,确保收到广播时触发处理。 - 列索引为空问题:原代码使用硬编码列名(如
"ct_t"),改用Telephony.Mms系统常量,避免因系统版本/厂商定制导致列名不匹配。 - MMS ID获取错误:原代码误将列索引值当作MMS ID,修正后用
getLong()获取列的实际数值。 - IntentFilter配置顺序:先完成filter的所有参数配置(action、priority),再调用
registerReceiver,确保配置生效。 - 权限处理:Android 6.0+需动态申请
RECEIVE_MMS、READ_SMS等危险权限,否则无法读取MMS数据。
四、清单文件配置
必须在AndroidManifest.xml中注册Activity并声明权限:
<uses-permission android:name="android.permission.RECEIVE_MMS" /> <uses-permission android:name="android.permission.READ_SMS" /> <uses-permission android:name="android.permission.RECEIVE_SMS" /> <!-- Android 13+ 部分机型需添加通知权限 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <application ...> <activity android:name=".routing.MmsReceiverK" android:exported="true"> <!-- 可选:如需从桌面启动,添加以下intent-filter --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>
内容的提问来源于stack exchange,提问作者Will R.
相关产品推荐
相关产品推荐

