Skip to main content

Installation

iOS build versions

VykVKWebView SDK is built with using the following Gradle configuration values.

NameValue
Minimum DeplymentsiOS 14.4

Swift Package Manager

The SDK is provided as a Swift Package Manager package.

NameValue
Repository Addresshttps://github.com/ChrisKlimpke/VykWKWebView

Releases

  • 1.1.2 First documented release

The Minimum vyking-apparel version required is v1.2.9.

VyKWebView Class

The VykWebView class is a subclass of the iOS native WKWebView class and knowledge of this class and how to use it is assumed. An instance of this class must be used to host the vyking-apparel VTO webpage if the vyking-apparel element wants to get its camera feed from the hosting app.

Notes

  • A valid VykingData.lzma configuration file, provided by Vyking, is required.
  • Camera permission must be granted.

Properties

webSocketPort

webSocketPort: UInt16?

A read only property specifying the webSocketPort being used (zero, if not active connection).

Methods

init

public protocol VykWKWebViewSetupDelegate: AnyObject {
func listenerSetupComplete(_ vykWKWebView: VykWebView)
func listenerSetupError(_ vykWKWebView: VykWebView, error: NWError?, port: UInt16 )
func vykReady(_ good : Bool)
}

public init( frame: CGRect,
configuration: WKWebViewConfiguration,
TrackerConfig: [String : Any],
setupDelegate: VykWKWebViewSetupDelegate,
uiDelegate: WKUIDelegate,
navigationDelegate: WKNavigationDelegate )

Use this constructor to provide the appropriate delegates and the filepath to the ".lzma" configuration file supplied by Vyking.

let urlRq = URLRequest(url: url,
cachePolicy: .reloadRevalidatingCacheData,
timeoutInterval: 60.0 )
let webView = VykWebView(frame: CGRect(x: 10, y: 10,
width: EnclosingUIView.frame.size.width - 20, height: EnclosingUIView.frame.size.height - 20),
configuration: webConfiguration,
TrackerConfig: [ "baseDir": Bundle.main.bundlePath + "/Data/Raw/Vyking", "vykingFile": "VykingData99.lzma" ],
setupDelegate: self,
uiDelegate: self,
navigationDelegate: self )
webView.load( urlRq )

shutdown

public func shutdown() -> Void

Usage

VykWebView uses a webSocket to communicate with the hosting application. The vyking-apparel element needs to be told the port number the hosting application is listening on, but only once the page has finished loading. This is achieved through the use of the delegates: The WebView's WKNavigationDelegate delegate for page load completion and the VykWebView's VykWKWebViewSetupDelegate for socket setup completion.

WebView.WKNavigationDelegate

Setting the WebView's WKNavigationDelegate delegate allows the "didFinish navigation" delegate method to be used to detect the completion of the webpage load and call an appropriate VykWebView setup method.

Also, VykWebView uses a secure webSocket to communicate with the hosting application, so requires a certificate. The certificate used is a self-signed certificate, so certain conditions need to be detected and handled appropriately. Setting the WebView's webViewClient delegate allows the setting of the didReceive delegate function which can be used to detect these certificate warnings and handle them appropriately. Note that development web servers also tend to use self-signed certificates, so the delegate function can also be coded to allow these certificates to be granted permission as well.

Example WKNavigationDelegate delegate

extension ViewController: WKNavigationDelegate {
public func webView(_: WKWebView,
didReceive: URLAuthenticationChallenge,
completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {

// Special handling is required for the self-signed certificate used by VykWebView.
// Typically, development web servers also use self-signed certificates so we need to handle these in a special way too.
guard didReceive.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust &&
(didReceive.protectionSpace.host == "localhost" || didReceive.protectionSpace.host == "127.0.0.1" || // For Internal WebSocket
didReceive.protectionSpace.host == "192.168.0.20" || // For dev server
didReceive.protectionSpace.host == "192.168.1.130" || // For dev server
didReceive.protectionSpace.host == "192.168.77.88") // For dev server
else { return completionHandler(.performDefaultHandling, nil) }

NSLog("webView \(didReceive.protectionSpace.host)")

if let trust = didReceive.protectionSpace.serverTrust {
completionHandler(.useCredential, URLCredential(trust: trust ))
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}

public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
NSLog("webView didFinish navigation view.frame \(webView.frame)")
(webView as! VykWebView).setup()
}
}

VykWebView.VykWKWebViewSetupDelegate

The VykWebView setup delegate allows VykWebView to report the success/failure of its various setup requirements. The listenerSetupComplete delegate function reports the listener's port number when VykWebView has successfully started listening for socket connections and can now be used to setup the vyking-apparel HTML element by calling an appropriate VykWebView setup method.

Example VykWKWebViewSetupDelegate

extension ViewController: VykWKWebViewSetupDelegate {
func vykReady(_ good: Bool) {
NSLog("ViewController.vykReady good \(good)")
if !good {
NSLog("ViewController.vykReady ############################## FAILED ####################")
}
}

public func listenerSetupComplete(_ vykWKWebView: VykWebView) {
NSLog("ViewController.listenerSetupComplete")
DispatchQueue.main.async {
vykWKWebView.setup()
}
}

public func listenerSetupError(_ vykWKWebView: VykWebView, error: NWError?, port: UInt16) {
NSLog("ViewController.listenerSetupError port \(port), error \(String(describing: error))")
}
}

Custom VykWebView Extension

The code examples above refer to example VykWebView methods, such as play and pause, that need to be tailored to the specific implementation of the VTO page being hosted by the VykWebView instance. These methods can be provided through the use of VykWebView Extension. The example extension below shows how a simple vyking-apparel HTML page can be setup, paused, played and have the virtual apparel changed.

extension VykWebView {
/**
There are two stages of initialization that need to complete before we can successfully setup the vto experience. This
setup method can be called on the completion of each stage and only the last one will succeed. The stages are:
1. Finish loading the page
2. Finish setting up the webSocket listener.
*/
public func setup() {
NSLog("VykWKWebView.setup \(String(describing: webSocketPort))")

// Only attempt the setup when we have a valid port number.
guard let port = webSocketPort else {
NSLog("VykWKWebView.setup FAILED on port guard")
return
}

let vykingSrc = "https://sneaker-window.vyking.io/vyking-assets/customer/vyking-io/yeezy_boost_700_carbon_blue"
let name = "Yeezy Boost"

evaluateJavaScript("""
if (document.querySelector('vyking-apparel') != null) {
document.querySelector('vyking-apparel').setAttribute('alt', '\(name)');
document.querySelector('vyking-apparel').setAttribute('poster', '\(vykingSrc)/shoeIcon.png');
document.querySelector('vyking-apparel').setAttribute('apparel', '\(vykingSrc)/offsets.json');
document.querySelector('vyking-apparel').autocameraInAppSrc = 'wss://localhost:\(port)';
}
""") { (result, error) in
NSLog("VykWKWebView.setup.vyking-apparel")
}
}

public func replaceApparel(url: String, name: String, poster: String) {
evaluateJavaScript("""
document.querySelector('vyking-apparel')?.setAttribute('alt', '\(name)');
document.querySelector('vyking-apparel')?.setAttribute('poster', '\(poster)');
document.querySelector('vyking-apparel')?.setAttribute('apparel', '\(url)');
""") { (result, error) in
NSLog("VykWKWebView.replaceApparel")
}
}

public func play() {
evaluateJavaScript("""
document.querySelector('vyking-apparel')?.play()
""") { (result, error) in
NSLog("VykWKWebView.play")
}
}

public func pause() {
evaluateJavaScript("""
document.querySelector('vyking-apparel')?.pause()
""") { (result, error) in
NSLog("VykWKWebView.pause")
}
}
}