Page cover image

Purpose of this document

This document will serve as a guide to integrate a Satisfi Labs webview chat page into your IOS application. Along with this document, Satisfi Labs also provides a fully working sample IOS application and code available for download.

The test application can be download from the Apple App Store: https://apps.apple.com/us/app/satisfi-labs-webview-tester/id1556211591

The associated codebase can be downloaded here:

https://github.com/satisfi-github/SatisfiInAppWebviewIOS

For an instance of a web chat URL, you can use the URL provided to you by your Satisfi Labs Customer success representative or you can use the following sample Url:

https://chat.satis.fi/?pageID=4398

Requirements

IDE version: Xcode 11 or above

Min Deployment Target: iOS 13.0

Technology Required: Swift (5.0 or above)

OS Required: MacOS 10.14. 4 (Mojave) or above

Third party Libraries: None

Sample Application Documentation

Satisfi Labs has created this sample webview application to both serve as a best practice guide for a successful install as well as to provide a testing platform to ensure that Satisfi Chat pages work properly in the most commonly used WebView schemas. While the application can accept any URL, it is designed specifically for Satisfi Labs InApp Chat urls.

The iOS Mobile Application lets the user to browse any website using two different types of webview schemes available:

  1. WKWebView

  2. Safari browser

Important Note

Since Apple recommends to use WKWebView for improved security and reliability, the apps that use UIWebView are longer accepted in the App Store. So UIWebView functionality is not added in the app but UIWebView support has been added in the Code base ( link mentioned above ) for reference.

WKWebView is improved and recommended, as the most common issues faced in UIWebView are fixed in WKWebView.

The webviews can be seen in two ways:

  1. Pushed in Navigation Controller

2. Present Modally

There are options to hide the top header bar or bottom footer bar.

Shows header bar on the webview

Shows footer bar on the webview

System Components

Webview parameters
Type
Description

urlString

String

The URL is passed as a parameter to the desired Webview.

headerBarTitle

String

The title of the top header bar is shown on webview if showHeaderBar is true.

showHeaderBar

Bool

ON: Displays header bar with Back button to return back to home/initial screen.

OFF: No header bar displayed. Users can return to the home/initial screen using the Left-Right swipe gesture.

showFooterBar

Bool

ON: Displays bottom footer bar with back, forward and refresh buttons to navigate between the web pages only.

OFF: Bottom footer bar is not displayed thus back, forward and refresh buttons are not accessible.

Integration Instructions

  1. Download or clone the code base from the repo link shared above.

  2. Go to WebView_SatisfiLabs > Classes > ViewControllers > WebViews

    Or Access the files directly from the browser

Step 2: Create new Xcode project

  1. Install the latest version Xcode IDE (skip if already installed)

  2. Open Xcode and Create a new Xcode project.

  3. Choose a template for a new project as an App and click Next.

  4. Assign <Any Desired Name> to the Product Name and set following values.

5. Click Next and select the folder where the new project will be kept.

6. Click on Create and a new Xcode project is created.

Step 3: Add the .swift file to your project

Simply add the desired webview controller file to your project by drag & drop that was downloaded in Step-1 (either one or both [recommended - WKWebViewController.swift] )

WKWebViewController.swift

UIWebViewController.swift

File adding can be achieved as shown below.

Note

To open the URL in Safari browser, no file needs to be added. Just add the following code.

if let url = URL(string: urlString) { UIApplication.shared.open(url) }

Step 4: There can be two cases mentioned below

Case-1 WKWebViewController.swift is added

  1. Initialize the webview controller and set the system components values based on the preferred requirement. The following code can be added to the viewDidLoad() method of the default ViewController.swift file of the new project.

let wkWebView = WKWebViewController(with: urlString)
// optional wkWebView.headerBarTitle = "<Any Suitable Name"
wkWebView.showHeaderBar = true
wkWebView.showFooterBar = false

2. Webview can be presented Modally (presentModally = true)

Webview can be pushed to the navigation controller (presentModally = false)

let presentModally = true     // set false for pushing to navigation stack

if presentModally {

    let navC = UINavigationController(rootViewController: wkWebView)
    self.present(navC, animated: true, completion: nil)

} else {
   
    self.navigationController?.pushViewController(wkWebView, animated: true)

}

Note Make sure that the current ViewController is embedded inside the Navigation controller in the storyboard. Learn More

Case-2 UIWebViewController.swift is added

  1. Uncomment all the code in UIWebViewController.swift and Initialize the webview controller and set the system components values based on the preferred requirement. The following code can be added to the default ViewController.swift file of the new project.

let uiWebView = UIWebViewController(with: urlString)

// optional uiWebView.headerBarTitle = "<Any Suitable Name>"

uiWebView.showHeaderBar = true

uiWebView.showFooterBar = false

2. Webview can be presented Modally (presentModally = true)

Webview can be pushed to the navigation controller (presentModally = false)

let presentModally = true   // set false for pushing to navigation stack

if presentModally {

    let navC = UINavigationController(rootViewController: uiWebView)
    self.present(navC, animated: true, completion: nil)

} else {
   
    self.navigationController?.pushViewController(uiWebView, animated: true)

}

Note Make sure that the current ViewController is embedded inside the Navigation controller in the storyboard. Learn More

Step 5: Add the following code to the Info.plist

Add NSAppTransportSecurity key to the Info.plist file (required if http links are used)

Setting this value as true exempts your app’s web views from App Transport Security restrictions without affecting your URLSession connections.

<key>NSAppTransportSecurity</key>
	<dict>
		<key>NSAllowsArbitraryLoadsInWebContent</key>
		<true/>
	</dict>

Add NSLocationWhenInUseUsageDescription key to the Info.plist file (required if Location access is needed)

A message that tells the user why the app is requesting access to the user's location at all times.

<key>NSLocationWhenInUseUsageDescription</key>
    <string> The app uses your location to help you navigate on Webview </string>

Troubleshooting Tips

Solution:

Cancel the navigation and load the request with webview.load(request). It basically opens the new window in the current frame.

Step 1: Conform to WKUIDelegate protocol and following code to delegate method

extension WKWebViewController : WKUIDelegate {
    
    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        
        if (navigationAction.targetFrame?.isMainFrame == nil) {
            webView.load(navigationAction.request)
        }
        return nil;
    }
}

Step 2: Set delegate for wkWebView in viewDidLoad() method

override func viewDidLoad() {
	super.viewDidLoad()
	self.wkWebView.uiDelegate = self
}

Problem: WKWebView does not open the pop up windows.

Solution:

Everytime the webview wants to create a new window, we create a popup webview for that window and add it to the current view hierarchy.

Step 1: Conform to WKUIDelegate protocol and declare popupWebView variable as WKWebView type.

class WKWebViewController: UIViewController, WKUIDelegate { 
  var popupWebView : WKWebView?
}

Step 2: Add the following code to the delegate methods mentioned below.

func webView(_ webView: WKWebView, createWebViewWith configuration:    WKWebViewConfiguration, for navigationAction: WKNavigationAction,   windowFeatures: WKWindowFeatures) -> WKWebView? {

     popupWebView = WKWebView(frame: view.bounds, configuration: configuration)
     popupWebView!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
     popupWebView!.navigationDelegate = self
     popupWebView!.uiDelegate = self

     view.addSubview(popupWebView!)
     return popupWebView!
}

Step 3: When the user closes the popup, we just have to remove the popup webview.

func webViewDidClose(_ webView: WKWebView) {
     webView.removeFromSuperview()
     popupWebview = nil
}

Problem: Keyboard covers the HTML input text field when the device is rotated.

Solution:

Dismiss the keyboard whenever the device is rotated in viewWillTransition() method of UIViewController because the scrollview of Webview comes back to the default setting of the page i.e. the contentOffset of scrollView becomes zero on rotation. And adjusting the contentOffset may hinder the behaviour of Webview in some cases. So dismissing the keyboard is a best practice on rotation of the device.

override func viewWillTransition(to size: CGSize, with coordinator:   UIViewControllerTransitionCoordinator) {
        
    self.view.endEditing(true)
}

And then the user can simply tap on the input container to make the keyboard appear again

Problem: Zooming In of the screen when the keyboard is tapped or the view is looking bigger than it should be.

Solution:

  • This issue is mostly seen in UIWebView, so the first solution is to upgrade to WKWebView.

  • Follow the webview initial settings (as mentioned on the next page) , specially the contentMode of the webview should be scaleAspectFit .

Problem: Black and white space may appear under the webview while scrolling.

Solution:

Turn the scrollview bounce off to avoid the inappropriate black or white space while scrolling.

wkWebView.scrollView.bounces = false

Webview Initial Settings

private lazy var wkWebView: WKWebView = {
	let webConfiguration = WKWebViewConfiguration()
	let webView = WKWebView(frame: .zero, configuration: webConfiguration)


     webView.scrollView.isOpaque = true
      webView.translatesAutoresizingMaskIntoConstraints = false
      webView.contentMode = .scaleAspectFit

	return webView
}()

NSLayoutConstraint.activate([
     wkWebView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
     wkWebView.leftAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leftAnchor),
     wkWebView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),
     wkWebView.rightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.rightAnchor)
])

Embed ViewController inside Navigation Controller ()

Points to remember

  1. To use the feature of pushing the Webview in the Navigation stack i.e when the toggle button of Modal is turned OFF, this step is mandatory.

  2. Embedding the View Controller inside the Navigation Controller would not do any harm even when the toggle button of Modal is turned ON, simply this would be of no use.

Conclusion

Modal ON: Embedding not required

Modal OFF: Embedding is mandatory

So it is better to Embed the ViewController inside the Navigation Controller to make the Modal functionality work in both cases.

Step 1: Open Storyboard

Open Main.storyboard file of the project.

Step 2: Embed root view controller inside a navigation controller

In your storyboard, select the initial view controller in your hierarchy. With this view controller selected, choose the menu item as follows:

Editor -> Embed In -> Navigation Controller

Step 3: Match attribute inspector

Open Attribute inspector of the Navigation Controller and match for the selections as shown in the figure. Make sure to turn off both bar visibility options while selecting it as the Initial View Controller.

Last updated

Was this helpful?