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

Jetpack Compose Kotlin实现OTP短信发送与自动填充指导请求

Jetpack Compose 实现OTP短信发送与自动填充功能指导

问题描述

需实现以下功能:

  • 向上一屏输入的手机号发送4位OTP短信
  • 自动读取短信并填充OTP输入框
  • 允许用户手动输入OTP

现有代码

@Composable
fun VerificationPhoneCodeScreen(
    navHostController: NavHostController,
    state:VerificationPhoneCodeScreenState,
    onChangeOtpValue:(String)->Unit
) {
    Scaffold(
        topBar = {
            BackPopUp(navController = navHostController, route = null)
        },
        backgroundColor = Color.Transparent
    ) {
        Column(
            modifier = Modifier.fillMaxSize(),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Top
        ) {
            Text(
                textAlign = TextAlign.Center,
                modifier = Modifier.padding(10.dp),
                text = stringResource(id = R.string.telefonuna_gelen_kodu_asagidaki_alana_giriniz),
                style = MaterialTheme.typography.subtitle1
            )

            OtpTextField(
                otpText = state.otpValue,
                onOtpTextChange = { value, otpInputFilled ->
                    onChangeOtpValue(value)
                }
            )
        }
    }
}

解决方案

一、发送OTP短信

前端无法直接发送短信,需依赖后端接口对接短信服务商(如阿里云、腾讯云),流程如下:

  1. 在进入VerificationPhoneCodeScreen时,从上个页面获取手机号
  2. 调用后端接口,传入手机号,由后端生成4位随机OTP并发送,同时存储OTP与手机号的关联(用于后续验证)

ViewModel示例代码:

class VerificationViewModel(
    private val apiService: ApiService,
    private val phoneNumber: String
) : ViewModel() {
    fun sendOtp() {
        viewModelScope.launch {
            try {
                val otp = (1000..9999).random().toString()
                apiService.sendOtp(phoneNumber, otp)
                // 可标记OTP已发送状态,用于UI提示
            } catch (e: Exception) {
                // 处理发送失败逻辑
            }
        }
    }
}

二、自动读取短信填充OTP

使用Android官方的SMS Retriever API(无需READ_SMS权限,适配Android 10+),步骤如下:

  1. 添加依赖
    在build.gradle(app)中引入:
implementation "com.google.android.gms:play-services-auth-api-phone:18.0.1"
  1. 配置短信格式
    短信内容必须包含APP专属哈希值,格式示例:
    您的验证码是:1234。[APP_HASH]
    APP_HASH可通过代码生成:
private fun getAppHash(context: Context): String {
    val packageName = context.packageName
    val packageInfo = context.packageManager.getPackageInfo(
        packageName,
        PackageManager.GET_SIGNATURES
    )
    val signature = packageInfo.signatures[0]
    val message = "$packageName ${signature.toCharsString()}"
    val md = MessageDigest.getInstance("SHA-256")
    md.update(message.toByteArray())
    val hashBytes = md.digest()
    return Base64.encodeToString(hashBytes, Base64.NO_WRAP).substring(0, 11)
}
  1. 实现短信监听
    创建广播接收器捕获短信:
class SmsBroadcastReceiver(private val onOtpReceived: (String) -> Unit) : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (SmsRetriever.SMS_RETRIEVED_ACTION == intent?.action) {
            val extras = intent.extras ?: return
            val status = extras.get(SmsRetriever.EXTRA_STATUS) as Status

            when (status.statusCode) {
                CommonStatusCodes.SUCCESS -> {
                    val message = extras.get(SmsRetriever.EXTRA_SMS_MESSAGE) as String
                    // 提取4位OTP
                    "\\d{4}".toRegex().find(message)?.value?.let(onOtpReceived)
                }
                CommonStatusCodes.TIMEOUT -> {
                    // 超时,引导用户手动输入
                }
            }
        }
    }
}
  1. 在Compose页面中启动监听
@Composable
fun VerificationPhoneCodeScreen(
    navHostController: NavHostController,
    state:VerificationPhoneCodeScreenState,
    onChangeOtpValue:(String)->Unit,
    viewModel: VerificationViewModel
) {
    val context = LocalContext.current

    // 注册广播接收器,页面销毁时注销
    DisposableEffect(Unit) {
        val receiver = SmsBroadcastReceiver { otp ->
            onChangeOtpValue(otp)
        }
        val filter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION)
        context.registerReceiver(receiver, filter)
        viewModel.startSmsRetrieval()

        onDispose {
            context.unregisterReceiver(receiver)
        }
    }

    // 原有Scaffold代码...
}

ViewModel中启动SMS Retriever:

fun startSmsRetrieval(context: Context) {
    val smsRetrieverClient = SmsRetriever.getClient(context)
    val task = smsRetrieverClient.startSmsRetriever()
    task.addOnSuccessListener {
        // 监听已启动,等待短信
    }
    task.addOnFailureListener {
        // 监听启动失败
    }
}

三、兼容手动输入

现有代码已支持手动输入,只需补充输入完成后的验证逻辑:

OtpTextField(
    otpText = state.otpValue,
    onOtpTextChange = { value, otpInputFilled ->
        onChangeOtpValue(value)
        // 输入满4位时自动触发验证
        if (otpInputFilled) {
            viewModel.verifyOtp(value)
        }
    }
)

ViewModel验证逻辑:

fun verifyOtp(otp: String, navHostController: NavHostController) {
    viewModelScope.launch {
        try {
            val response = apiService.verifyOtp(phoneNumber, otp)
            if (response.isSuccess) {
                navHostController.navigate("home_screen")
            } else {
                // 验证失败,提示用户
            }
        } catch (e: Exception) {
            // 处理网络错误
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 22:44:55