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短信
前端无法直接发送短信,需依赖后端接口对接短信服务商(如阿里云、腾讯云),流程如下:
- 在进入
VerificationPhoneCodeScreen时,从上个页面获取手机号 - 调用后端接口,传入手机号,由后端生成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+),步骤如下:
- 添加依赖
在build.gradle(app)中引入:
implementation "com.google.android.gms:play-services-auth-api-phone:18.0.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) }
- 实现短信监听
创建广播接收器捕获短信:
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 -> { // 超时,引导用户手动输入 } } } } }
- 在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
相关产品推荐
相关产品推荐

