如何在Android中通过编程安装eSIM?求示例代码与指引
Android eSIM 安装实现指引与示例代码
前置准备
确保项目满足以下条件:
- 目标API级别 ≥ 29(Android 10),eSIM核心API从该版本开始正式开放
- 设备硬件支持eSIM功能
- 在
AndroidManifest.xml中声明必要权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" /> <uses-permission android:name="android.permission.MANAGE_EMBEDDED_SUBSCRIPTIONS" />
注意:MANAGE_EMBEDDED_SUBSCRIPTIONS属于系统级权限,普通应用需向设备厂商申请签名授权,调试时可使用root设备或系统签名包测试。
核心实现步骤与代码示例
1. 动态申请危险权限
使用eSIM API前需先获取必要的危险权限:
private val REQUEST_ESIM_PERMISSIONS = 1001 private fun requestEsimPermissions() { val permissions = arrayOf( Manifest.permission.READ_PHONE_STATE, Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS ) ActivityCompat.requestPermissions(this, permissions, REQUEST_ESIM_PERMISSIONS) } override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == REQUEST_ESIM_PERMISSIONS) { if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) { initializeEsimManager() } else { Toast.makeText(this, "缺少权限无法操作eSIM", Toast.LENGTH_SHORT).show() } } }
2. 初始化EsimManager并发起安装请求
EsimManager是操作eSIM的核心类,以下是通过运营商提供的SM-DP+地址和激活码下载安装eSIM的示例:
private lateinit var esimManager: EsimManager private fun initializeEsimManager() { esimManager = getSystemService(EsimManager::class.java) } // 传入运营商提供的SM-DP+地址和激活码(Matching ID) fun installEsim(smDpAddress: String, activationCode: String) { val downloadRequest = EsimDownloadRequest.Builder() .setSmdpAddress(smDpAddress) .setMatchingId(activationCode) .build() esimManager.downloadSubscription( downloadRequest, Executors.newSingleThreadExecutor(), object : EsimManager.DownloadCallback { override fun onDownloadStarted() { runOnUiThread { Toast.makeText(this@MainActivity, "eSIM下载启动", Toast.LENGTH_SHORT).show() } } override fun onDownloadProgress(progress: Int) { runOnUiThread { // 可在此更新下载进度UI } } override fun onDownloadCompleted(downloadResult: EsimDownloadResult) { runOnUiThread { if (downloadResult.result == EsimDownloadResult.RESULT_SUCCESS) { activateEsim(downloadResult.iccid) } else { Toast.makeText(this@MainActivity, "下载失败:${downloadResult.result}", Toast.LENGTH_SHORT).show() } } } override fun onDownloadFailed(errorCode: Int) { runOnUiThread { Toast.makeText(this@MainActivity, "下载失败,错误码:$errorCode", Toast.LENGTH_SHORT).show() } } } ) } // 激活已下载完成的eSIM private fun activateEsim(iccid: String) { esimManager.setSubscriptionEnabled(iccid, true, object : EsimManager.SetEnabledCallback { override fun onSetEnabled(result: Int) { runOnUiThread { if (result == EsimManager.RESULT_SUCCESS) { Toast.makeText(this@MainActivity, "eSIM激活成功", Toast.LENGTH_SHORT).show() } else { Toast.makeText(this@MainActivity, "激活失败,错误码:$result", Toast.LENGTH_SHORT).show() } } } }) }
3. 监听eSIM状态变化(可选)
通过广播接收器监听eSIM的状态更新:
private val esimStateReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { intent ?: return when (intent.action) { EsimManager.ACTION_EMBEDDED_SUBSCRIPTION_INFO_UPDATED -> { loadEsimSubscriptions() } EsimManager.ACTION_EMBEDDED_SUBSCRIPTION_DELETED -> { // 处理eSIM被删除的逻辑 } } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val filter = IntentFilter().apply { addAction(EsimManager.ACTION_EMBEDDED_SUBSCRIPTION_INFO_UPDATED) addAction(EsimManager.ACTION_EMBEDDED_SUBSCRIPTION_DELETED) } registerReceiver(esimStateReceiver, filter) } override fun onDestroy() { super.onDestroy() unregisterReceiver(esimStateReceiver) } // 获取当前设备的eSIM列表 private fun loadEsimSubscriptions() { val subscriptions = esimManager.embeddedSubscriptionInfos subscriptions.forEach { info -> Log.d("EsimInfo", "ICCID: ${info.iccid}, 状态: ${info.state}") } }
关键注意事项
- 权限限制:
MANAGE_EMBEDDED_SUBSCRIPTIONS权限默认仅开放给系统应用,普通应用需联系厂商获取签名授权,否则部分操作会返回权限错误 - 激活码有效性:SM-DP+地址和激活码必须由运营商提供,无效参数会导致下载失败
- 设备兼容性:部分支持eSIM的Android设备可能对API实现有差异,需在目标设备上做充分测试
- 错误码处理:API返回的错误码可参考
EsimManager类中的常量定义(如ERROR_SMDP_CONNECTION_FAILED),用于定位问题
内容的提问来源于stack exchange,提问作者Ahmed Rehman
相关产品推荐
相关产品推荐

