iOS – Handle OTP (one-time code) in Swift
Asked Answered
P

2

6

Is there any way to handle onetime-code tap by restricting other keyboard entries?

I have requirement for an OTP text field to prefill the sms OTP code. User should not enter the OTP manually using keyboard numeric buttons.

IOS 12 we have the onetime-code option, it will be auto-filled in QuickType bar & User can tap on it to fill the text field. I Couldn't find an option to restrict other keyboard entries.

Is there any way we can allow only Onetime code tap and restricting any entry from the numeric keyboard .

What I have tried is created 6 textfields. First textfield content type set as One Time code. UserInteractionEnabled only for the first text field so that user can't enter data onto other fields. Once I get the OTP & taps QuickType bar - onetime code, I am prefilling all the text fields.

viewdidload>

otp1TB.addTarget(self, action:#selector(textFieldDidChange(_:)), for: .editingChanged)


@objc func textFieldDidChange(_ textField: UITextField) {
    if let otpCode = textField.text ,  otpCode.count > 5 {
        otp1TB.text = String(otpCode[otpCode.startIndex])
        otp2TB.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 1)])
        otp3TB.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 2)])
        otp4TB.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 3)])
        otp5TB.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 4)])
        otp6TB.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 5)])
        otp1TB.isUserInteractionEnabled = false 
        self.view.endEditing(true)
    }
}

The issue here is since the first text field is active when the keyboard opens user has the ability to enter numeric data from the keyboard.

I need to allow only onetime code tap when the keyboard opens.

Pasargadae answered 21/6, 2019 at 5:21 Comment(1)
Can you share some code of what you've tried so far?Asymmetry
A
4

I think you can skip this entire complexity and just use the standard iOS 12 OTP input type:

otpTextField.textContentType = .oneTimeCode

See: Automatic OTP verification in iOS?

And the WWDC 2018 video that covers it: https://developer.apple.com/videos/play/wwdc2018/204

Asymmetry answered 21/6, 2019 at 6:2 Comment(5)
First text field content type set as One Time Code in storyboard. I am looking for a solution to restrict other keyboard numeric entry.Pasargadae
Sorry, that wasn't very clear in your question - it was hard to follow. Sounds like you want this: https://mcmap.net/q/551668/-how-to-auto-fetch-otp-if-we-use-multiple-text-fieldsAsymmetry
I have tried that. No luck with statement "if textField.textContentType == UITextContentType.oneTimeCode"Pasargadae
OK, then I would suggest rewording your question to make it clear what the problem is you're having, and explain how it relates to the code you've shown.Asymmetry
Sorry, if it was not clear. I have updated the textPasargadae
Y
1

You can try My 3rd party library:- https://github.com/Datt1994/DPOTPView

For Solution:-

In viewDidLoad add tag & delegate to all textfield

override func viewDidLoad() {
    super.viewDidLoad()
    otp1TB.delegate = self
    otp1TB.tag = 1000
    otp2TB.delegate = self
    otp2TB.tag = 2000
    otp3TB.delegate = self
    otp3TB.tag = 3000
    otp4TB.delegate = self
    otp4TB.tag = 4000
    otp5TB.delegate = self
    otp5TB.tag = 5000
    otp6TB.delegate = self
    otp6TB.tag = 6000
}

In UITextFieldDelegate extension implement shouldChangeCharactersIn function like below, It will also work with textField.textContentType = .oneTimeCode

extension ViewController : UITextFieldDelegate  {

public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    if string.trimmingCharacters(in: CharacterSet.whitespaces).count != 0 {
        textField.text = string
        if textField.tag < count*1000 {
            let next = textField.superview?.viewWithTag((textField.tag/1000 + 1)*1000)
            next?.becomeFirstResponder()
        } else if textField.tag == count*1000 {
            textField.resignFirstResponder()
        }
    } else if string.count == 0 { // is backspace
        textField.text = ""
    }

    return false
}

}
Yordan answered 31/5, 2020 at 23:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.