ionic-framework: bug: ios, autofill not working properly in wkwebview

Bug Report

I believe it is the same issue as #22682 and #22757, with reproduction instruction.

Ionic version:

[ ] 4.x [x] 5.x

Current behavior: On a login form using ion-input, the iOS Keychain does fill username and password. But the secondary ion-input item does not see changes. By “secondary” I mean the one that was not touched.

For example:

  1. Touch “email” input
  2. Autofill with iOS Keychain
  3. email and password are filled but only the ion-input email field is updated. The value of ion-input password is empty.

Or:

  1. Touch the “password” input
  2. Autofill with iOS Keychain
  3. email and password are filled but only the ion-input password field is updated. The value of ion-input email is empty.

Expected behavior: Ion-Input should see the change of the underlying input item.

Steps to reproduce:

Sample project based on ionic starter blank: https://github.com/florian72810/ion-input-password-ios-keychain

The issue happens on real device or simulator, I checked on “Simulator iPod touch 7th Generation - iOS 14.5”, “Simulator iPod touch 7th Generation - iOS 13.0”, and also on real device “iPhone XS Max - iOS 14.5”.

The iOS Keychain need to have some content. You have to enable it first and put some data. (see screenshot at bottom)

If you are using a simulator, you have to disconnect the hardware keyboard in order to see the visual keyboard: I/O > Keyboard > Connect Hardware Keyboard (unchecked).

On the following video, you can see the bug.

  • touch “password” input
  • select “Passwords” in visual keyboard
  • select something from the keychain
  • now both fields show data, but you can see that only ion-input email value is still empty.

  • write the letter “a” in the end of email input
  • now the ion-input email value has data: the data from the keychain (here ‘demo’) and the letter added (here ‘a’)

https://user-images.githubusercontent.com/20518933/118987623-1e016c80-b989-11eb-890e-7611df8c0882.mp4

Other information:

  • The bug also happens with Ionic/Vue.
  • I have not tested with Capacitor.
  • I am 99% sure that it was working as expected before, around September 2020.

The AppStore validation team seem to be using the keychain to test app because they refused my app yesterday due to this bug.

It is still possible to access the native input field to bypass this bug.

Ionic info:


Ionic:

   Ionic CLI                     : 6.12.3 (/usr/local/lib/node_modules/@ionic/cli)
   Ionic Framework               : @ionic/angular 5.6.7
   @angular-devkit/build-angular : 0.1102.13
   @angular-devkit/schematics    : 11.2.13
   @angular/cli                  : 11.2.13
   @ionic/angular-toolkit        : 3.1.1

Cordova:

   Cordova CLI       : 10.0.0
   Cordova Platforms : ios 6.2.0
   Cordova Plugins   : cordova-plugin-ionic-keyboard 2.2.0, cordova-plugin-ionic-webview 4.2.1, (and 4 other plugins)

Utility:

   cordova-res : not installed
   native-run  : 1.3.0

System:

   Android SDK Tools : 26.1.1 (/Users/foxer/Library/Android/sdk)
   ios-deploy        : 1.11.4
   ios-sim           : 8.0.2
   NodeJS            : v14.15.4 (/Users/foxer/.nvm/versions/node/v14.15.4/bin/node)
   npm               : 6.14.10
   OS                : macOS Big Sur
   Xcode             : Xcode 12.5 Build version 12E262

Simulator Screen Shot - iPod touch (7th generation) - 2021-05-20 at 16 26 55

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 1
  • Comments: 17 (8 by maintainers)

Most upvoted comments

The workaround works 👍

Hi everyone,

I am posting here again as I am merging a related thread.

This thread is tracking a bug in WKWebView where the autofill feature in iOS is not updating the value property in ion-input. This bug impacts Cordova/Capacitor apps but does not impact apps running in mobile Safari.

I will post here when a fix has been shipped in iOS. In the meantime, if anyone has links to production apps that are impacted by this bug, please feel free to post them. This can sometimes help get WebKit bugs fixed faster.

We are waiting for Apple to implement a fix in iOS. I will update this thread when I have more to share.

Thanks for the issue. I took a closer look at your GitHub repo and this appears to be a bug in WKWebView, which is the WebKit-based webview on iOS that Capacitor and Cordova applications use.

<ion-input> relies on the input event to be fired from the inner <input> element in order for the value property to be changed correctly since the autofill functionality sets the value on the inner <input>, not the <ion-input> Web Component. When autofilling on the password text field in WKWebView, this input event is not fired for the email text field, even though its value changes. When running your app in Safari, the input event is fired as expected.

I have reported this issue to the WebKit team for them to fix, and I have also noted that this is impacting your app’s ability to get onto the iOS App Store: https://bugs.webkit.org/show_bug.cgi?id=226023.


I have put together this workaround you can use that should resolve the issue for now. Can you try it and let me know how it works in your application? I tested in your demo repo and it was working fine for me.

home.page.html

Email:
<ion-input #emailInput [(ngModel)]="email" type="email" name="email"></ion-input>

Password:
<ion-input #passwordInput [(ngModel)]="password" type="password" name="password"></ion-input>

home.page.ts

import { Component, ViewChild } from '@angular/core';
import { IonInput } from '@ionic/angular';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {
  @ViewChild('emailInput', { static: true }) emailInput: IonInput;
  @ViewChild('passwordInput', { static: true }) passwordInput: IonInput;

  public email = '';
  public password = '';

  constructor() {}

  async ngOnInit() {
    const nativeEmailInput = await this.emailInput.getInputElement();
    const nativePasswordInput = await this.passwordInput.getInputElement();

    nativeEmailInput.addEventListener('change', (ev: Event) => {
      requestAnimationFrame(() => {
        this.email = (ev.target as HTMLInputElement).value;
      });
    });

    nativePasswordInput.addEventListener('change', (ev: Event) => {
      requestAnimationFrame(() => {
        this.password = (ev.target as HTMLInputElement).value;
      });
    });
  }
}