# iOS Advanced Install Guide

## 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.&#x20;

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:&#x20;

<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:&#x20;

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

## Requirements&#x20;

IDE version: Xcode 11 or above&#x20;

Min Deployment Target: iOS 13.0&#x20;

Technology Required: Swift (5.0 or above)&#x20;

OS Required: MacOS 10.14. 4 (Mojave) or above&#x20;

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

<img src="https://lh3.googleusercontent.com/0HAxzqYaAWsiOA95hd3NPrCJWnoSaOK62tNcTRCYouQO7gvaPBRuB7ioD3R98jQeEZ6bYqyfya9KtwTio98MX8V_OS0NazOagyMxul9iSe9yr9YS1tmT18Gwt2AFkx8Fwp-SqceBdhKKshgHEA" alt="" data-size="original">

**Important Note**

{% hint style="info" %}
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.
{% endhint %}

The webviews can be seen in two ways:

1. **Pushed in Navigation Controller**           &#x20;

![](https://lh3.googleusercontent.com/xQhcP-BVkgBK9PctWkU94C-BjFTiczaihj0TxUIjp25pAjK3UzWpks8IP1Lnviw3beJy4dkiCH_fKw4N_6bUjCFSL47kOCB7q8qu4PNNsIJ2reVTKaH2lxspGVkBvePK_9lYWQO9QLv_1qJOfA)

**2. Present Modally**

![](https://lh6.googleusercontent.com/lPxZG_T1XDLP4R20M1ZqD5Z95-GohSj6ux1VQ3rCGj3IdQWhVa_XvmiCAnkBgPK1HA-OH9qU9tR15xuN_iyv3iPb1uGRkz-GilOxq6QAXHrIOOgs18o5SCcumb4b-0GewVfiUKMELbURWayTEg)

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

**Shows header bar on the webview**

![](https://lh4.googleusercontent.com/kM9Fau3tv7eg2W0KdasjwF1bUhcm6sPoSOpGOFfiaE9-S6TV0QiDys37pLb5PdOgqvMsOSFEVdtTkjF1jv6d6_SNsu14lgn2ok13-3Rnxg7qUSlZlavnogugUrKQwGxXxdXEWg54A82_tku32Q)

![](https://lh6.googleusercontent.com/tPyThc8iAHbbsQH75hSIU7tNfdTPVlmI5FiipZoh5QHtngp0SqVbVUbine78vlmFgA-ScRs54PNymFseX3XgHpkrGRViCkEuUoe3M0Dg193Ns-_q3CyAqPFBc2K67X3K8POUc8Nnx0E7oknuIQ)

**Shows footer bar on the webview**

![](https://lh3.googleusercontent.com/MXYgAVjCv7Kven84ioFUm6opKN2U9z97et17SiI1pbU45F0AnB-IpdwpT6D7hFPm_BIDFcToCsOCiUga-YWk8MrhQ7GWumV0WcgIsPEHUNz3CAV6wD9gjEfSbO-BHS4sZIag4Bz9Ke2CQXJPrg)

![](https://lh4.googleusercontent.com/PScnb8pmA1uIUmIj3xMg47S6LRHPrpercAr4bmiABd5-kVsp07FxYcucoCFMdWWCVA9dYApbQIxiB-hcidQZxTauaL7lXrBR-mS82uueHm0PtroJ89fb5VkDtehT_8Am2NjF13rNTPy98AhKLA)

## 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   | <p>ON: Displays header bar with Back button to return back to home/initial screen.</p><p>OFF: No header bar displayed. Users can return to the home/initial screen using the Left-Right swipe gesture.</p>                    |
| `showFooterBar`    | Bool   | <p>ON: Displays bottom footer bar with back, forward and refresh buttons to navigate between the web pages only.</p><p>OFF: Bottom footer bar is not displayed thus back, forward and refresh buttons are not accessible.</p> |

## Integration Instructions

### Step 1: Go to the code base and download repo (recommended)&#x20;

1. Download or clone the code base from the repo link shared above.&#x20;
2. Go to **WebView\_SatisfiLabs > Classes > ViewControllers > WebViews**&#x20;

   Or Access the files directly from the browser

### Step 2: Create new Xcode project&#x20;

1. Install the latest version **Xcode IDE** (skip if already installed)&#x20;
2. Open Xcode and **Create a new Xcode project.**&#x20;
3. Choose a template for a new project as an **App** and click **Next**.&#x20;
4. Assign \<Any Desired Name> to the **Product Name** and set following values.

![](https://lh5.googleusercontent.com/8MpraNqC4uhcY-qF-f0Xssy9c3Hl6_LPO8uA2MJmV_4t4oKNKb-H1cRdYVZ2rw4ZfAeZ_yBGpSDdtyCtlG3oZ6rs9s5ohet1nVpjl6XML38x265lEyo7gzn2Xdkup7CPH41DPvw6mW_V_lmPKg)

5\. Click Next and select the folder where the new project will be kept.&#x20;

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

### Step 3: Add the .swift file to your project&#x20;

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] )&#x20;

[WKWebViewController.swift](https://bitbucket.org/satisfi/satisfiinappwebviewios/src/master/WebView_SatisfiLabs/Classes/ViewControllers/WebViews/WKWebViewController.swift)

[UIWebViewController.swift](https://bitbucket.org/satisfi/satisfiinappwebviewios/src/master/WebView_SatisfiLabs/Classes/ViewControllers/WebViews/UIWebViewController.swift)

File adding can be achieved as shown below.

{% hint style="info" %}
**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)`**\
\&#xNAN;**`}`**
{% endhint %}

### Step 4: There can be two cases mentioned below&#x20;

#### Case-1 `WKWebViewController.swift` is added&#x20;

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)&#x20;

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)

}
```

{% hint style="info" %}
**Note**\
Make sure that the current ViewController is embedded inside the Navigation controller in the storyboard. [Learn More](https://docs.google.com/document/d/1RRMv0kfudoKyzdcjwq3Q2JOcCDkhlW8asqEjc_9d8CM/edit#heading=h.a40juktppdh6)
{% endhint %}

#### 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)&#x20;

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)

}

```

{% hint style="info" %}
**Note**\
Make sure that the current ViewController is embedded inside the Navigation controller in the storyboard. [Learn More](https://docs.google.com/document/d/1RRMv0kfudoKyzdcjwq3Q2JOcCDkhlW8asqEjc_9d8CM/edit#heading=h.a40juktppdh6)
{% endhint %}

### 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

#### Problem: WKWebview does not open links which it requires to “Open in new window”.

#### Solution:&#x20;

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.&#x20;

#### Solution:&#x20;

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:&#x20;

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:&#x20;

* This issue is mostly seen in UIWebView, so the first solution is to upgrade to WKWebView.&#x20;
* 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:&#x20;

Turn the scrollview bounce off to avoid the inappropriate black or white space while scrolling.&#x20;

```
wkWebView.scrollView.bounces = false
```

### Webview Initial Settings&#x20;

```
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 ()&#x20;

#### Points to remember&#x20;

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.&#x20;

#### Conclusion&#x20;

Modal ON: Embedding not required&#x20;

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&#x20;

Open `Main.storyboard` file of the project.

#### Step 2: Embed root view controller inside a navigation controller&#x20;

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

`Editor -> Embed In -> Navigation Controller`&#x20;

Step 3: Match attribute inspector&#x20;

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.

![](https://lh5.googleusercontent.com/fW1RROjUQkFKjW_RZQBFYlq_SqwxRz5JVf6w8HD_VmWjn2FXTgByWuPyKMG0E5zrSw-Isu0JJ7mX1iM7QvcozDQBCQteYMvvCE6YWGtu8L_s7IyAMh8dsWe5A1elS3WCOAuuYuWaOU0QpQbHhA)
