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

Flutter集成Android原生eSIM安装:系统确认弹窗点击无响应求助

Flutter调用Android原生eSIM安装无响应问题修复

核心问题分析

点击系统安装确认弹窗后无响应,主要是广播接收器未正确处理弹窗回调结果、变量引用错误、权限与PendingIntent配置不规范导致。以下是具体修复方案:


1. 修复BroadcastReceiver的resultCode获取逻辑

原代码直接使用resultCode变量,但BroadcastReceiver中需通过getResultCode()方法获取系统回调的结果码,这是导致弹窗点击后无反应的核心原因。

2. 修复变量引用错误

原代码中定义了TEST_SIM_PROFILE但调用时用了未定义的PROFILE,直接替换为正确变量名。

3. 规范PendingIntent与广播注册配置

Android 12+要求PendingIntent必须指定FLAG_MUTABLE/FLAG_IMMUTABLE,同时广播注册需明确指定导出状态。

4. 清理冗余代码

移除重复定义的mgr、ACTION_DOWNLOAD_SUBSCRIPTION等冗余变量,避免逻辑混淆。


修复后的完整Kotlin代码

class MainActivity : FlutterFragmentActivity() {
    private val CHANNEL1 = "com.demo.methodchannel"
    private const val DOWNLOAD_ACTION = "download_subscription"
    private const val BROADCAST_PERMISSION = "com.your.company.lpa.permission.BROADCAST"
    private val TEST_SIM_PROFILE = "LPA:1\$MTAwMDAwMDAwMzQ2MzM5Y2E2NDgwNQ==$7UMyhYJKZLBfHZt2ve9vQH0oKvE=$"

    @RequiresApi(Build.VERSION_CODES.P)
    private lateinit var manager: EuiccManager
    private var resultIntent: Intent? = null

    @RequiresApi(VERSION_CODES.P)
    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL1).setMethodCallHandler { call, result ->
            if (call.method == "messageFunction") {
                manager = getSystemService(EUICC_SERVICE) as EuiccManager
                downloadTestProfile()
            } else {
                result.notImplemented()
            }
        }
    }

    private val eSimBroadcastReceiver = object : BroadcastReceiver() {
        @SuppressLint("UnsafeIntentLaunch")
        @RequiresApi(Build.VERSION_CODES.P)
        override fun onReceive(context: Context, intent: Intent) {
            // 避免重复处理同一回调
            if (resultIntent?.action == intent.action) {
                return
            }

            // 正确获取系统返回的结果码
            val resultCode = getResultCode()
            val detailedCode = intent.getIntExtra(EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0)
            val embeddedOperationCode = intent.getIntExtra(EXTRA_EMBEDDED_SUBSCRIPTION_OPERATION_CODE, 0)

            println("detailedCode: $detailedCode")
            println("embeddedOperationCode: $embeddedOperationCode")

            when (resultCode) {
                EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK -> {
                    Toast.makeText(context, "eSIM安装成功", Toast.LENGTH_LONG).show()
                }
                EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR -> {
                    // 处理系统弹窗后的回调
                    val callbackIntent = PendingIntent.getBroadcast(
                        baseContext,
                        1,
                        intent,
                        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
                    )
                    try {
                        manager.startResolutionActivity(
                            this@MainActivity,
                            0,
                            intent,
                            callbackIntent
                        )
                    } catch (e: IntentSender.SendIntentException) {
                        e.printStackTrace()
                    }
                }
                else -> {
                    Toast.makeText(context, "eSIM安装失败,错误码:$resultCode", Toast.LENGTH_LONG).show()
                }
            }
            resultIntent = intent
        }
    }

    @SuppressLint("UnspecifiedRegisterReceiverFlag")
    override fun onStart() {
        super.onStart()
        registerReceiver(
            eSimBroadcastReceiver,
            IntentFilter(DOWNLOAD_ACTION),
            BROADCAST_PERMISSION,
            null,
            Context.RECEIVER_EXPORTED // Android 12+必须指定导出/非导出状态
        )
    }

    override fun onStop() {
        super.onStop()
        unregisterReceiver(eSimBroadcastReceiver)
    }

    @RequiresApi(Build.VERSION_CODES.P)
    private fun downloadTestProfile() {
        if (!manager.isEnabled) {
            Toast.makeText(this, "当前设备不支持eSIM", Toast.LENGTH_LONG).show()
            return
        }
        val osVer = manager.euiccInfo?.osVersion
        println("euicc osVer: $osVer")

        val subscription = DownloadableSubscription.forActivationCode(TEST_SIM_PROFILE)
        val callbackIntent = PendingIntent.getBroadcast(
            baseContext,
            0,
            Intent(DOWNLOAD_ACTION),
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
        )
        manager.downloadSubscription(subscription, true, callbackIntent)
    }
}

权限配置调整建议

<uses-permission android:name="android.permission.INTERNET"/>
<!-- 读写存储权限对eSIM安装非必需,可移除 -->
<!-- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> -->
<!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> -->

<permission 
    android:name="com.your.company.lpa.permission.BROADCAST" 
    android:protectionLevel="signature" />
<uses-permission android:name="com.your.company.lpa.permission.BROADCAST"/>

<!-- 注意:WRITE_EMBEDDED_SUBSCRIPTIONS是系统签名权限,普通应用无法获取,需运营商合作签名 -->
<uses-permission 
    android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" 
    tools:ignore="ProtectedPermissions" />

额外注意事项

  • 设备兼容性:eSIM功能仅支持Android 9+(API 28)设备,且需硬件支持eSIM,模拟器无法测试。
  • 系统权限:WRITE_EMBEDDED_SUBSCRIPTIONS为系统保护权限,普通应用需获得运营商签名授权才能正常使用,否则会静默失败。
  • 测试环境:需使用真实运营商提供的有效LPA码进行测试,测试用LPA码可能存在有效期限制。

内容的提问来源于stack exchange,提问作者danish

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 18:42:05