如何在Jetpack Compose Android中实现OTP自动获取(自动填充)
在Jetpack Compose中实现OTP自动填充与手动输入功能
1. 配置基础权限
如果依赖系统自动填充框架,无需额外权限;若要主动读取短信获取OTP,需在AndroidManifest.xml中添加:
<uses-permission android:name="android.permission.READ_SMS" /> <uses-permission android:name="android.permission.RECEIVE_SMS" />
2. 实现支持自动填充的OTP输入框
利用Android系统Autofill框架,让输入框自动识别OTP,同时保留手动输入能力:
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.autofill.AutofillNode import androidx.compose.ui.autofill.AutofillType import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.platform.LocalAutofillTree import androidx.compose.ui.text.input.KeyboardOptions import androidx.compose.ui.text.input.KeyboardType @Composable fun OTPTextField() { val otpValue = rememberSaveable { mutableStateOf("") } val focusRequester = remember { FocusRequester() } val autofillNode = remember { AutofillNode( autofillTypes = listOf(AutofillType.OneTimeCode), onFill = { otpValue.value = it } ) } LocalAutofillTree.current += autofillNode OutlinedTextField( value = otpValue.value, onValueChange = { if (it.length <= 6) otpValue.value = it // 限制6位OTP长度 }, label = { Text("验证码") }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword), modifier = Modifier .focusRequester(focusRequester) .autofill(autofillNode), singleLine = true, maxLines = 1 ) LaunchedEffect(Unit) { focusRequester.requestFocus() // 自动获取焦点,方便输入或触发自动填充 } }
3. 手动输入逻辑优化
上述代码已天然支持手动输入,可额外添加以下优化:
- 监听输入长度,当达到固定位数(如6位)时自动触发验证逻辑
- 添加清除按钮,允许用户快速重置输入内容
- 输入过程中实时反馈格式正确性
4. 可选:用SMS Retriever API主动获取OTP
无需用户授权即可自动捕获OTP,需集成Google SMS Retriever API:
步骤1:添加依赖
在Module级build.gradle中加入:
implementation "com.google.android.gms:play-services-auth:20.7.0" implementation "com.google.android.gms:play-services-auth-api-phone:18.0.1"
步骤2:实现短信接收器
import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import com.google.android.gms.auth.api.phone.SmsRetriever import com.google.android.gms.common.api.CommonStatusCodes import com.google.android.gms.common.api.Status class SMSReceiver : BroadcastReceiver() { private var otpCallback: ((String) -> Unit)? = null fun setOtpCallback(callback: (String) -> Unit) { otpCallback = callback } override fun onReceive(context: Context?, intent: Intent?) { if (SmsRetriever.SMS_RETRIEVED_ACTION == intent?.action) { val status = intent.extras?.get(SmsRetriever.EXTRA_STATUS) as Status when (status.statusCode) { CommonStatusCodes.SUCCESS -> { val sms = intent.extras?.get(SmsRetriever.EXTRA_SMS_MESSAGE) as String // 提取6位数字OTP "\\d{6}".toRegex().find(sms)?.value?.let { otpCallback?.invoke(it) } } CommonStatusCodes.TIMEOUT -> { // 超时未收到短信,提示手动输入 } } } } }
步骤3:在Compose中集成
import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.platform.LocalContext import com.google.android.gms.auth.api.phone.SmsRetriever @Composable fun OTPWithSMSRetriever() { val otpValue = rememberSaveable { mutableStateOf("") } val context = LocalContext.current val smsReceiver = remember { SMSReceiver() } LaunchedEffect(Unit) { val filter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION) context.registerReceiver(smsReceiver, filter) smsReceiver.setOtpCallback { otp -> otpValue.value = otp } // 启动短信监听 SmsRetriever.getClient(context).startSmsRetriever().apply { addOnSuccessListener { /* 监听启动成功 */ } addOnFailureListener { /* 启动失败,降级手动输入 */ } } onDispose { context.unregisterReceiver(smsReceiver) } } OTPTextField() // 复用之前的输入框组件 }
注意:使用SMS Retriever API时,短信内容必须包含应用签名生成的哈希值(格式如@your-app-domain #123456),否则无法被捕获。
内容的提问来源于stack exchange,提问作者MaheshGubbi
相关产品推荐
相关产品推荐

