Webview App Integration

Use the Javascript-Widget within a web-view in your mobile app.

You can also integrate our Javascript-Widget solution inside a web-view in your mobile App(s).

The integration follows almost the same procedure as described in our description for Javascript-Widget.

Some special steps have to be taken when integrating the JS-Widget in a web-view, which will be described below in the examples.

Implementation Steps for the Hosted Page Implementing the JS-Widget

You will need a HTML page that implements the JS-Widget, just like described in Javascript-Widget. In addition, the following changes are recommended:

HTML

<!-- in the <head> -->
<!-- Scale settings so the page does not zoom/move-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no, maximum-scale=1.0, user-scalable=no">

CSS

#XS2A-Form input:not([type='checkbox']):not([type='radio']), #XS2A-Form select {
    /* Increase the font size for input elements, 16px minimum is recommended */
    font-size: 16px !important;
}

JS-to-Native Callbacks

The most important steps to be taken are about handling the callbacks the JS-Widget does in your mobile app. For example, when the user finishes the process, you probably want to close the web-view and show the user a specific screen. The same needs to be done when the user aborts.

This can be accomplished with registering callbacks, that notify the host app (your app) from within the Javascript on the hosted page. You might already have callbacks defined such as xs2a.finish() or xs2a.abort() , for which you will need to add some more functionality:

xs2a.finish(function () {
    if (window.App) {
        // Callback to native Android App
        App.finishTransaction();
    } else if (window.webkit) {
        // Callback to native iOS App
        webkit.messageHandlers.callback.postMessage("finished");
    }
});

xs2a.abort(function () {
    if (window.App) {
        // Callback to native Android App
        App.abortTransaction();
    } else if (window.webkit) {
        // Callback to native iOS App
        webkit.messageHandlers.callback.postMessage("aborted");
    }
});

xs2a.configure({
    // ESSENTIAL!
    // this needs to be set so that in-app webviews handle redirects properly
    'reuse-tab-on-redirect': true
});

Implementation Steps for the Native Apps

In the app, we need some functionality to show the web-view and to deal with the callbacks defined above.

iOS

The following is an example class showing an integration with WKWebView and how the JS-to-Native callbacks are defined and configured:

import UIKit
import WebKit

class WebViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, UIAdaptivePresentationControllerDelegate {
	var webView: WKWebView!
	var urlToLoad: URL!
	
	/* Capture Javascript Messages */
	func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
		guard let response = message.body as? String else { return }
		let storyboard = UIStoryboard(name: "Main", bundle: nil)
		var screenToPresent: UIViewController?
		
		if response == "finished" {
			/* The user finished the session */
			screenToPresent = storyboard.instantiateViewController(withIdentifier: "successView") as UIViewController
		} else if response == "aborted" {
			/* User pressed abort button */
			screenToPresent = storyboard.instantiateViewController(withIdentifier: "abortedView") as UIViewController
		}

		if let screenToPresent = screenToPresent {
			present(screenToPresent, animated: true, completion: nil)
		}
		
	}
	
	
	override func loadView() {
		let contentController = WKUserContentController()
		/* Register javascript-to-native callbacks */
		/* This lets us use "webkit.messageHandlers.callback.postMessage" in the JS */
		contentController.add(self, name: "callback")
		
		let config = WKWebViewConfiguration()
		config.userContentController = contentController
		
		let frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
		webView = WKWebView(frame: frame, configuration: config)
		webView.navigationDelegate = self
		view = webView
	}

	override func viewDidLoad() {
		super.viewDidLoad()
		self.presentationController?.delegate = self
		webView.load(URLRequest(url: urlToLoad!))
		webView.allowsBackForwardNavigationGestures = false
	}

	init(url: URL) {
		self.urlToLoad = url
		super.init(nibName: nil, bundle: nil)
	}
	
	required init?(coder: NSCoder) {
		super.init(coder: coder)
	}

	func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
		webView.removeFromSuperview()
		view = nil
	}
}

You can present this web-view like this:

let vc = WebViewController(url: <URL_TO_HOSTED_PAGE>)
self.present(vc, animated: true, completion: nil)

Android

Register the JS-to-Native callbacks:

import android.util.Log;
import android.webkit.JavascriptInterface;
import android.widget.Toast;

import androidx.navigation.fragment.NavHostFragment;

public class WebViewJSInterface {
    private static final String TAG = "WebViewJSInterface";

    SecondFragment fragment;

    public WebViewJSInterface(SecondFragment fragment) {
        this.fragment = fragment;
    }

    @JavascriptInterface
    public void finishTransaction() {
        Log.d(TAG, "finishTransaction: Finish Transaction on Android");
        
        // navigate to success screen
    }

    @JavascriptInterface
    public void abortTransaction() {
        Log.d(TAG, "finishTransaction: Abort Transaction on Android");

        // navigate to e.g. abort screen
    }
}

Configure and present the web-view:

private void loadXS2AIntoWebView(@NonNull View view, String wizardSessionKey) {
    WebView webView = view.findViewById(R.id.main_web_view);
    webView.getSettings().setJavaScriptEnabled(true);
    // This lets use use window.App in the JS
    webView.addJavascriptInterface(new WebViewJSInterface(this), "App");
    webView.setWebViewClient(new WebViewClient() {
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    });

    webView.loadUrl(<URL_TO_HOSTED_PAGE>);
}

Last updated