Android14下Flutter应用eSIM下载功能返回结果异常问题排查
问题回顾
你的 Flutter 应用在 Android14 上调用 EuiccManager.ACTION_START_EUICC_ACTIVATION 启动 LPA 页面完成 eSIM 激活后,系统始终返回 RESULT_CANCELED,但 Android13 及以下版本正常返回 RESULT_OK。当前使用 startActivityForResult 处理结果,通过 Platform Channel 传递至 Dart 层。
核心原因
Android14 对 eSIM 激活流程的结果回调逻辑做了调整:即使 eSIM 激活成功,系统也可能不再通过 Activity 结果返回 RESULT_OK,而是需要主动查询 eSIM 配置文件状态;同时旧的 startActivityForResult API 在 Android14 上的兼容性有所下降。
解决方案
1. 替换为 Activity Result API(官方推荐)
放弃旧的 startActivityForResult,改用 Jetpack 的 Activity Result API,这是 Android 10+ 官方推荐的 Activity 结果处理方式,适配性更好:
// 在 Android 原生代码中初始化 Launcher private val activationLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> when (result.resultCode) { Activity.RESULT_OK -> { // 传递成功结果到 Flutter channel.invokeMethod("onActivationResult", mapOf("status" to "success")) } Activity.RESULT_CANCELED -> { // Android14 下需主动校验激活状态 verifyEsimActivationStatus() } } } // 启动 LPA 页面时调用 launcher activationLauncher.launch(lpaActivityIntent)
2. 主动校验 eSIM 激活状态
在收到 RESULT_CANCELED 时,通过 EuiccManager 查询当前已激活的 eSIM 配置文件,以此判定是否激活成功:
private fun verifyEsimActivationStatus() { val euiccManager = requireContext().getSystemService(EuiccManager::class.java) euiccManager.getEuiccProfileIds(EuiccManager.PROFILE_TYPE_ACTIVE) .addOnSuccessListener { activeProfileIds -> val status = if (activeProfileIds.isNotEmpty()) "success" else "canceled" channel.invokeMethod("onActivationResult", mapOf("status" to status)) } .addOnFailureListener { // 查询失败时默认返回取消状态 channel.invokeMethod("onActivationResult", mapOf("status" to "canceled")) } }
3. 权限适配
确保 AndroidManifest.xml 中添加必要权限,并在 Android13+ 中动态申请危险权限:
<!-- 声明权限 --> <uses-permission android:name="android.permission.READ_EMBEDDED_SUBSCRIPTIONS" /> <uses-permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" />
动态申请权限代码示例:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { requestPermissions( arrayOf(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS), PERMISSION_REQUEST_CODE ) }
4. 跨版本分支处理
针对不同 Android 版本做兼容,保留旧版本的原有逻辑:
val lpaIntent = Intent().apply { action = EuiccManager.ACTION_START_EUICC_ACTIVATION putExtra(EuiccManager.EXTRA_USE_QR_SCANNER, false) } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { // Android14+ 使用新 API + 主动校验 activationLauncher.launch(lpaIntent) } else { // Android13 及以下使用原有 startActivityForResult startActivityForResult(lpaIntent, ACTIVATE_ACTIVITY_CODE) }
Dart 层适配
在 Flutter 端接收结果时,不再依赖 RESULT_OK/RESULT_CANCELED,而是根据原生传递的 status 字段处理:
// Platform Channel 监听 platformChannel.setMethodCallHandler((call) async { if (call.method == 'onActivationResult') { final status = call.arguments['status'] as String; if (status == 'success') { // 处理激活成功逻辑 } else { // 处理取消/失败逻辑 } } });
内容的提问来源于stack exchange,提问作者Avinash avinu

