Home > Software design >  WkWebView Message handler doesn't return the value of textbox first time, but it does the secon
WkWebView Message handler doesn't return the value of textbox first time, but it does the secon

Time:08-24

So, I have an HTML form with textboxes. I load the form inside WKWebView and I use a message handler inside my Swift app to be able to dump the content of the textboxes and use it later on inside Swift Variables.

The problem is, when I press the Register button which triggers the javascript function that grabs the value of the textboses, first result is blank. Not null, just a space.

If I press the button again, I get the actual content of the textboxes. I've tried using the evaluateJavascript function to get the element by ID, same thing, first time I get nothing, second time I get the expected values.

My ViewController's code:

private var webkitview: WKWebView!
    var lsusername = "";
    var lspassword = "";
    
    @IBOutlet weak var baseview: UIView!
    @IBOutlet weak var registerAccountButton: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        self.webkitview = WKWebView(frame: self.baseview.bounds, configuration: self.getWKWebViewConfiguration())
        baseview.addSubview(self.appvalleyRegistration)
        baseview.translatesAutoresizingMaskIntoConstraints = false;
        
        let url = URL(string: "https://redacted.com/registrationform.php")!
        webkitview.load(URLRequest(url: url))

    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        setNeedsStatusBarAppearanceUpdate()
    }
    override var preferredStatusBarStyle: UIStatusBarStyle {
        .darkContent
    }
    
    
    private func getWKWebViewConfiguration() -> WKWebViewConfiguration {
            let userController = WKUserContentController()
            userController.add(self, name: "observer")
            let configuration = WKWebViewConfiguration()
            configuration.userContentController = userController
            return configuration
    }
        
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if let data = message.body as? [String : String], let passw = data["passw"], let email = data["email"] {
            lsusername = email;
            lspassword = passw;
        } else {
            print("No data.");
        }
    }
    
    @IBAction func registerUser(_ sender: Any) {
        webkitview.evaluateJavaScript("submitForm()");
        showUser(email: lsusername, name: lspassword);
    }
    
    private func showUser(email: String, name: String) {
            let userDescription = "\(email) \(name)"
            let alertController = UIAlertController(title: "User", message: userDescription, preferredStyle: .alert)
            alertController.addAction(UIAlertAction(title: "OK", style: .default))
            present(alertController, animated: true)
    }

The alert I trigger using showUser() is blank the first time, and if I press the button again it shows the proper username and password grabbed from the page inside Webkit.

My form:

<body>
<script type="text/javascript">
          function submitForm() {
              var message = {
                passw: document.getElementById("passw").value,
                email: document.getElementById("email").value
              };
              window.webkit.messageHandlers.observer.postMessage(message);
          }
</script>
  <div >
    <h1>Welcome to my site</h1>
    <p>Let's set up your account</p>
    <hr>

    <label for="email"><b>Email</b></label>
    <input type="text" placeholder="Enter Email" name="email" id="email" required>

    <label for="psw"><b>Password</b></label>
    <input type="password" placeholder="Enter Password" name="passw" id="passw" required>

    <label for="psw-repeat"><b>Repeat Password</b></label>
    <input type="password" placeholder="Repeat Password" name="psw-repeat" id="psw-repeat" required>
  </div>
</body>

I don't understand why it works the second time but not the first.

I tried adding sleep() to maybe wait JS to fully complete evaluating but still nothing.

CodePudding user response:

evaluateJavascript is an asynchronous function. Try adding a completion block and calling showUser within it (but make sure you trigger UI updates on the main thread). I think that should fix your immediate problem:

webkitview.evaluateJavaScript("submitForm()") { [weak self] (_, _) in
    DispatchQueue.main.async { [weak self] in
        guard let self = self else { return }
        self.showUser(email: self.lsusername, name: self.lspassword)
    }
}

On a higher level note, would it make more sense to call showUser from within the didReceive function for the WKUserContentController? I haven't used this much, so I could be wrong here.

  • Related