How to detect when user used Password AutoFill on a UITextField












4














I've implemented all the app and server changes necessary to support Password Autofill on iOS 11, and it works well. I'd like it to work a little better.



My username and password fields are UITextFields. I would like to identify when a user has "autofilled" one of the two UITextFields, so I can progress to the next step. Currently the user autofills an item, then needs to press the "Next" button on the on-screen keyboard in order to advance. I'd like to trigger this on behalf of the user.



The WWDC2017 Password Autofill session says to use UITextFieldTextDidChange. This works, but of course this is also triggered when a user is manually typing in those fields.



My thought has been to compare the prior version of the text with the new version of the text, and assume that if the length has increased from zero to greater than some minimal length (2 or more), the user used autofill. That should work most of the time, but has a risk of a false trigger (fast typing on slow device perhaps). So to me, this may be a risky assumption.



I'm curious is anyone has found a more surefire way to determine if Password Autofill has been used on a UITextField, or just thinks my worry about a false trigger is unfounded.










share|improve this question






















  • I'd also like to know if users actually use Password AutoFill, by adding usage to the app's analytics. We do the same with 1Password.
    – Mitch Cohen
    Sep 25 '17 at 17:59










  • is this still not solvable?
    – Emrah Akgül
    Aug 9 '18 at 10:45
















4














I've implemented all the app and server changes necessary to support Password Autofill on iOS 11, and it works well. I'd like it to work a little better.



My username and password fields are UITextFields. I would like to identify when a user has "autofilled" one of the two UITextFields, so I can progress to the next step. Currently the user autofills an item, then needs to press the "Next" button on the on-screen keyboard in order to advance. I'd like to trigger this on behalf of the user.



The WWDC2017 Password Autofill session says to use UITextFieldTextDidChange. This works, but of course this is also triggered when a user is manually typing in those fields.



My thought has been to compare the prior version of the text with the new version of the text, and assume that if the length has increased from zero to greater than some minimal length (2 or more), the user used autofill. That should work most of the time, but has a risk of a false trigger (fast typing on slow device perhaps). So to me, this may be a risky assumption.



I'm curious is anyone has found a more surefire way to determine if Password Autofill has been used on a UITextField, or just thinks my worry about a false trigger is unfounded.










share|improve this question






















  • I'd also like to know if users actually use Password AutoFill, by adding usage to the app's analytics. We do the same with 1Password.
    – Mitch Cohen
    Sep 25 '17 at 17:59










  • is this still not solvable?
    – Emrah Akgül
    Aug 9 '18 at 10:45














4












4








4







I've implemented all the app and server changes necessary to support Password Autofill on iOS 11, and it works well. I'd like it to work a little better.



My username and password fields are UITextFields. I would like to identify when a user has "autofilled" one of the two UITextFields, so I can progress to the next step. Currently the user autofills an item, then needs to press the "Next" button on the on-screen keyboard in order to advance. I'd like to trigger this on behalf of the user.



The WWDC2017 Password Autofill session says to use UITextFieldTextDidChange. This works, but of course this is also triggered when a user is manually typing in those fields.



My thought has been to compare the prior version of the text with the new version of the text, and assume that if the length has increased from zero to greater than some minimal length (2 or more), the user used autofill. That should work most of the time, but has a risk of a false trigger (fast typing on slow device perhaps). So to me, this may be a risky assumption.



I'm curious is anyone has found a more surefire way to determine if Password Autofill has been used on a UITextField, or just thinks my worry about a false trigger is unfounded.










share|improve this question













I've implemented all the app and server changes necessary to support Password Autofill on iOS 11, and it works well. I'd like it to work a little better.



My username and password fields are UITextFields. I would like to identify when a user has "autofilled" one of the two UITextFields, so I can progress to the next step. Currently the user autofills an item, then needs to press the "Next" button on the on-screen keyboard in order to advance. I'd like to trigger this on behalf of the user.



The WWDC2017 Password Autofill session says to use UITextFieldTextDidChange. This works, but of course this is also triggered when a user is manually typing in those fields.



My thought has been to compare the prior version of the text with the new version of the text, and assume that if the length has increased from zero to greater than some minimal length (2 or more), the user used autofill. That should work most of the time, but has a risk of a false trigger (fast typing on slow device perhaps). So to me, this may be a risky assumption.



I'm curious is anyone has found a more surefire way to determine if Password Autofill has been used on a UITextField, or just thinks my worry about a false trigger is unfounded.







ios uitextfield autofill uitextfielddelegate






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Sep 24 '17 at 15:38









Mitch CohenMitch Cohen

4831517




4831517












  • I'd also like to know if users actually use Password AutoFill, by adding usage to the app's analytics. We do the same with 1Password.
    – Mitch Cohen
    Sep 25 '17 at 17:59










  • is this still not solvable?
    – Emrah Akgül
    Aug 9 '18 at 10:45


















  • I'd also like to know if users actually use Password AutoFill, by adding usage to the app's analytics. We do the same with 1Password.
    – Mitch Cohen
    Sep 25 '17 at 17:59










  • is this still not solvable?
    – Emrah Akgül
    Aug 9 '18 at 10:45
















I'd also like to know if users actually use Password AutoFill, by adding usage to the app's analytics. We do the same with 1Password.
– Mitch Cohen
Sep 25 '17 at 17:59




I'd also like to know if users actually use Password AutoFill, by adding usage to the app's analytics. We do the same with 1Password.
– Mitch Cohen
Sep 25 '17 at 17:59












is this still not solvable?
– Emrah Akgül
Aug 9 '18 at 10:45




is this still not solvable?
– Emrah Akgül
Aug 9 '18 at 10:45












3 Answers
3






active

oldest

votes


















1














Found a solution.



When the password manager is used to autofill username + password, it will trigger didBeginEditing twice, faster than a human ever could.



So, I calculate the time between the events. If the time is extremely fast, then I assume that autofill (e.g. FaceID or TouchID) was used to enter credentials and auto-trigger whatever UI is next -- in my case, the User tapping "Sign-in".



Obviously, you have to set up the correct delegation of the UITextFields you want to monitor, but once you do that:



var biometricAutofillTime: Date!

func textFieldDidBeginEditing(_ textField: UITextField) {
if biometricAutofillTime != nil {
if Date().timeIntervalSince(biometricAutofillTime) < 0.1 {
// NOTE: Need to hesitate for a very short amount of time,
// because, otherwise, the second UITextField (password)
// won't yet be populated
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { self.didTapSignin() }
}
biometricAutofillTime = nil
}
biometricAutofillTime = Date()
}





share|improve this answer































    0














    I don't think there is a better solution.



    One thing I noticed is that autofill is only enabled when the text field is empty.



    So if the text field went from empty to a length greater than the minimum password/username, then it is most likely autofill/paste.



    I am using shouldChangeCharactersIn to detect the change in the UITextField. I'm not for sure if there is a case where text from the keyboard could be batched together before the delegate method is called.






    share|improve this answer





















    • This is not true anymore. Autocomplete does need a blank field, it replaces any existing text.
      – InkGolem
      Aug 15 '18 at 17:45



















    0














    Not sure if the previous answer stopped working at some point, but I can't get it to work—I only get a single didBeginEditing call when AutoFill is used.



    However, I did find a way to detect AutoFill. And keep in mind that it is possible for AutoFill to be used after some characters have already been entered, for example if the user has already typed some numbers in the phone number, then they AutoFill the full number.



    For Swift 4:



    var rangeReplacedWithSpaceAt: Date?

    var rangeReplacedWithSpace: NSRange?

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    // To detect AutoFill, look for two quick replacements. The first replaces a range with a single space.
    // The next replaces the same range with the autofilled content.
    if string == " " {
    self.rangeReplacedWithSpace = range
    self.rangeReplacedWithSpaceAt = Date()
    } else {
    if rangeReplacedWithSpace == range,
    let rangeReplacedWithSpaceAt = self.rangeReplacedWithSpaceAt,
    Date().timeIntervalSince(rangeReplacedWithSpaceAt) < 0.1 {

    DispatchQueue.main.async {
    // Whatever you use to move forward.
    self.moveForward()
    }
    }
    self.rangeReplacedWithSpace = nil
    self.rangeReplacedWithSpaceAt = nil
    }
    }





    share|improve this answer





















      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f46391814%2fhow-to-detect-when-user-used-password-autofill-on-a-uitextfield%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      1














      Found a solution.



      When the password manager is used to autofill username + password, it will trigger didBeginEditing twice, faster than a human ever could.



      So, I calculate the time between the events. If the time is extremely fast, then I assume that autofill (e.g. FaceID or TouchID) was used to enter credentials and auto-trigger whatever UI is next -- in my case, the User tapping "Sign-in".



      Obviously, you have to set up the correct delegation of the UITextFields you want to monitor, but once you do that:



      var biometricAutofillTime: Date!

      func textFieldDidBeginEditing(_ textField: UITextField) {
      if biometricAutofillTime != nil {
      if Date().timeIntervalSince(biometricAutofillTime) < 0.1 {
      // NOTE: Need to hesitate for a very short amount of time,
      // because, otherwise, the second UITextField (password)
      // won't yet be populated
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { self.didTapSignin() }
      }
      biometricAutofillTime = nil
      }
      biometricAutofillTime = Date()
      }





      share|improve this answer




























        1














        Found a solution.



        When the password manager is used to autofill username + password, it will trigger didBeginEditing twice, faster than a human ever could.



        So, I calculate the time between the events. If the time is extremely fast, then I assume that autofill (e.g. FaceID or TouchID) was used to enter credentials and auto-trigger whatever UI is next -- in my case, the User tapping "Sign-in".



        Obviously, you have to set up the correct delegation of the UITextFields you want to monitor, but once you do that:



        var biometricAutofillTime: Date!

        func textFieldDidBeginEditing(_ textField: UITextField) {
        if biometricAutofillTime != nil {
        if Date().timeIntervalSince(biometricAutofillTime) < 0.1 {
        // NOTE: Need to hesitate for a very short amount of time,
        // because, otherwise, the second UITextField (password)
        // won't yet be populated
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { self.didTapSignin() }
        }
        biometricAutofillTime = nil
        }
        biometricAutofillTime = Date()
        }





        share|improve this answer


























          1












          1








          1






          Found a solution.



          When the password manager is used to autofill username + password, it will trigger didBeginEditing twice, faster than a human ever could.



          So, I calculate the time between the events. If the time is extremely fast, then I assume that autofill (e.g. FaceID or TouchID) was used to enter credentials and auto-trigger whatever UI is next -- in my case, the User tapping "Sign-in".



          Obviously, you have to set up the correct delegation of the UITextFields you want to monitor, but once you do that:



          var biometricAutofillTime: Date!

          func textFieldDidBeginEditing(_ textField: UITextField) {
          if biometricAutofillTime != nil {
          if Date().timeIntervalSince(biometricAutofillTime) < 0.1 {
          // NOTE: Need to hesitate for a very short amount of time,
          // because, otherwise, the second UITextField (password)
          // won't yet be populated
          DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { self.didTapSignin() }
          }
          biometricAutofillTime = nil
          }
          biometricAutofillTime = Date()
          }





          share|improve this answer














          Found a solution.



          When the password manager is used to autofill username + password, it will trigger didBeginEditing twice, faster than a human ever could.



          So, I calculate the time between the events. If the time is extremely fast, then I assume that autofill (e.g. FaceID or TouchID) was used to enter credentials and auto-trigger whatever UI is next -- in my case, the User tapping "Sign-in".



          Obviously, you have to set up the correct delegation of the UITextFields you want to monitor, but once you do that:



          var biometricAutofillTime: Date!

          func textFieldDidBeginEditing(_ textField: UITextField) {
          if biometricAutofillTime != nil {
          if Date().timeIntervalSince(biometricAutofillTime) < 0.1 {
          // NOTE: Need to hesitate for a very short amount of time,
          // because, otherwise, the second UITextField (password)
          // won't yet be populated
          DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { self.didTapSignin() }
          }
          biometricAutofillTime = nil
          }
          biometricAutofillTime = Date()
          }






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 19 '18 at 2:03

























          answered Nov 18 '18 at 23:21









          DanDan

          2,05531730




          2,05531730

























              0














              I don't think there is a better solution.



              One thing I noticed is that autofill is only enabled when the text field is empty.



              So if the text field went from empty to a length greater than the minimum password/username, then it is most likely autofill/paste.



              I am using shouldChangeCharactersIn to detect the change in the UITextField. I'm not for sure if there is a case where text from the keyboard could be batched together before the delegate method is called.






              share|improve this answer





















              • This is not true anymore. Autocomplete does need a blank field, it replaces any existing text.
                – InkGolem
                Aug 15 '18 at 17:45
















              0














              I don't think there is a better solution.



              One thing I noticed is that autofill is only enabled when the text field is empty.



              So if the text field went from empty to a length greater than the minimum password/username, then it is most likely autofill/paste.



              I am using shouldChangeCharactersIn to detect the change in the UITextField. I'm not for sure if there is a case where text from the keyboard could be batched together before the delegate method is called.






              share|improve this answer





















              • This is not true anymore. Autocomplete does need a blank field, it replaces any existing text.
                – InkGolem
                Aug 15 '18 at 17:45














              0












              0








              0






              I don't think there is a better solution.



              One thing I noticed is that autofill is only enabled when the text field is empty.



              So if the text field went from empty to a length greater than the minimum password/username, then it is most likely autofill/paste.



              I am using shouldChangeCharactersIn to detect the change in the UITextField. I'm not for sure if there is a case where text from the keyboard could be batched together before the delegate method is called.






              share|improve this answer












              I don't think there is a better solution.



              One thing I noticed is that autofill is only enabled when the text field is empty.



              So if the text field went from empty to a length greater than the minimum password/username, then it is most likely autofill/paste.



              I am using shouldChangeCharactersIn to detect the change in the UITextField. I'm not for sure if there is a case where text from the keyboard could be batched together before the delegate method is called.







              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Oct 5 '17 at 13:38









              duncanc4duncanc4

              728617




              728617












              • This is not true anymore. Autocomplete does need a blank field, it replaces any existing text.
                – InkGolem
                Aug 15 '18 at 17:45


















              • This is not true anymore. Autocomplete does need a blank field, it replaces any existing text.
                – InkGolem
                Aug 15 '18 at 17:45
















              This is not true anymore. Autocomplete does need a blank field, it replaces any existing text.
              – InkGolem
              Aug 15 '18 at 17:45




              This is not true anymore. Autocomplete does need a blank field, it replaces any existing text.
              – InkGolem
              Aug 15 '18 at 17:45











              0














              Not sure if the previous answer stopped working at some point, but I can't get it to work—I only get a single didBeginEditing call when AutoFill is used.



              However, I did find a way to detect AutoFill. And keep in mind that it is possible for AutoFill to be used after some characters have already been entered, for example if the user has already typed some numbers in the phone number, then they AutoFill the full number.



              For Swift 4:



              var rangeReplacedWithSpaceAt: Date?

              var rangeReplacedWithSpace: NSRange?

              func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
              // To detect AutoFill, look for two quick replacements. The first replaces a range with a single space.
              // The next replaces the same range with the autofilled content.
              if string == " " {
              self.rangeReplacedWithSpace = range
              self.rangeReplacedWithSpaceAt = Date()
              } else {
              if rangeReplacedWithSpace == range,
              let rangeReplacedWithSpaceAt = self.rangeReplacedWithSpaceAt,
              Date().timeIntervalSince(rangeReplacedWithSpaceAt) < 0.1 {

              DispatchQueue.main.async {
              // Whatever you use to move forward.
              self.moveForward()
              }
              }
              self.rangeReplacedWithSpace = nil
              self.rangeReplacedWithSpaceAt = nil
              }
              }





              share|improve this answer


























                0














                Not sure if the previous answer stopped working at some point, but I can't get it to work—I only get a single didBeginEditing call when AutoFill is used.



                However, I did find a way to detect AutoFill. And keep in mind that it is possible for AutoFill to be used after some characters have already been entered, for example if the user has already typed some numbers in the phone number, then they AutoFill the full number.



                For Swift 4:



                var rangeReplacedWithSpaceAt: Date?

                var rangeReplacedWithSpace: NSRange?

                func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
                // To detect AutoFill, look for two quick replacements. The first replaces a range with a single space.
                // The next replaces the same range with the autofilled content.
                if string == " " {
                self.rangeReplacedWithSpace = range
                self.rangeReplacedWithSpaceAt = Date()
                } else {
                if rangeReplacedWithSpace == range,
                let rangeReplacedWithSpaceAt = self.rangeReplacedWithSpaceAt,
                Date().timeIntervalSince(rangeReplacedWithSpaceAt) < 0.1 {

                DispatchQueue.main.async {
                // Whatever you use to move forward.
                self.moveForward()
                }
                }
                self.rangeReplacedWithSpace = nil
                self.rangeReplacedWithSpaceAt = nil
                }
                }





                share|improve this answer
























                  0












                  0








                  0






                  Not sure if the previous answer stopped working at some point, but I can't get it to work—I only get a single didBeginEditing call when AutoFill is used.



                  However, I did find a way to detect AutoFill. And keep in mind that it is possible for AutoFill to be used after some characters have already been entered, for example if the user has already typed some numbers in the phone number, then they AutoFill the full number.



                  For Swift 4:



                  var rangeReplacedWithSpaceAt: Date?

                  var rangeReplacedWithSpace: NSRange?

                  func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
                  // To detect AutoFill, look for two quick replacements. The first replaces a range with a single space.
                  // The next replaces the same range with the autofilled content.
                  if string == " " {
                  self.rangeReplacedWithSpace = range
                  self.rangeReplacedWithSpaceAt = Date()
                  } else {
                  if rangeReplacedWithSpace == range,
                  let rangeReplacedWithSpaceAt = self.rangeReplacedWithSpaceAt,
                  Date().timeIntervalSince(rangeReplacedWithSpaceAt) < 0.1 {

                  DispatchQueue.main.async {
                  // Whatever you use to move forward.
                  self.moveForward()
                  }
                  }
                  self.rangeReplacedWithSpace = nil
                  self.rangeReplacedWithSpaceAt = nil
                  }
                  }





                  share|improve this answer












                  Not sure if the previous answer stopped working at some point, but I can't get it to work—I only get a single didBeginEditing call when AutoFill is used.



                  However, I did find a way to detect AutoFill. And keep in mind that it is possible for AutoFill to be used after some characters have already been entered, for example if the user has already typed some numbers in the phone number, then they AutoFill the full number.



                  For Swift 4:



                  var rangeReplacedWithSpaceAt: Date?

                  var rangeReplacedWithSpace: NSRange?

                  func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
                  // To detect AutoFill, look for two quick replacements. The first replaces a range with a single space.
                  // The next replaces the same range with the autofilled content.
                  if string == " " {
                  self.rangeReplacedWithSpace = range
                  self.rangeReplacedWithSpaceAt = Date()
                  } else {
                  if rangeReplacedWithSpace == range,
                  let rangeReplacedWithSpaceAt = self.rangeReplacedWithSpaceAt,
                  Date().timeIntervalSince(rangeReplacedWithSpaceAt) < 0.1 {

                  DispatchQueue.main.async {
                  // Whatever you use to move forward.
                  self.moveForward()
                  }
                  }
                  self.rangeReplacedWithSpace = nil
                  self.rangeReplacedWithSpaceAt = nil
                  }
                  }






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 25 '18 at 6:45









                  Robin DaughertyRobin Daugherty

                  3,8282740




                  3,8282740






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f46391814%2fhow-to-detect-when-user-used-password-autofill-on-a-uitextfield%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      How to send String Array data to Server using php in android

                      Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents

                      Is anime1.com a legal site for watching anime?