Swift (iOS) Installation
Integrate the Asurion Widget into your native iOS application using WKWebView. This approach loads the web widget inside a native WebView component, providing a seamless experience on iOS devices.
Prerequisites
- iOS 11.0 or higher
- Xcode 13.0 or higher
- Swift 5.0 or higher
Basic Usage
Create a view controller that renders the widget inside a WKWebView:
import UIKit
import WebKit
class AsurionWidgetViewController: UIViewController, WKUIDelegate {
private var webView: WKWebView!
private let widgetId = "<WIDGET_ID>"
private let context: [String: Any] = ["userId": "user-123", "platform": "ios"]
private let trackingParameters: [String: String] = ["utm_source": "mobile-app", "utm_medium": "webview"]
override func viewDidLoad() {
super.viewDidLoad()
setupWebView()
loadWidget()
}
private func setupWebView() {
let configuration = WKWebViewConfiguration()
configuration.allowsInlineMediaPlayback = true
configuration.mediaTypesRequiringUserActionForPlayback = []
webView = WKWebView(frame: view.bounds, configuration: configuration)
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
webView.scrollView.bounces = false
webView.isOpaque = false
webView.backgroundColor = .clear
webView.uiDelegate = self
view.addSubview(webView)
}
// Handle window.open() calls from JavaScript
func webView(_ webView: WKWebView,
createWebViewWith configuration: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures) -> WKWebView? {
if let url = navigationAction.request.url {
UIApplication.shared.open(url)
}
return nil
}
private func loadWidget() {
let html = generateWidgetHTML()
webView.loadHTMLString(html, baseURL: nil)
}
private func generateWidgetHTML() -> String {
return """
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style>
* { margin: 0; padding: 0; }
html, body { height: 100%; width: 100%; overflow: hidden; }
</style>
<script>
(function (w, d, s, o, f, a, js, fjs) {
w[o] = function () {
const [action, ...params] = arguments;
(w[o].q = w[o].q || []).push([action, ...params]);
};
(js = d.createElement(s)), (fjs = d.getElementsByTagName(s)[0]);
js.id = o;
js.src = f;
js.async = 1;
js.setAttribute('data-widget-id', a.id);
js.setAttribute('data-variant', a.variant);
w[o + '_context'] = a.context;
w[o + '_trackingParameters'] = a.trackingParameters;
fjs.parentNode.insertBefore(js, fjs);
// Forward widget events to native
w[o]('subscribe', 'state', function (state) {
window.webkit.messageHandlers.widgetEvents.postMessage({ type: 'state', payload: state });
});
w[o]('subscribe', 'options', function (options) {
window.webkit.messageHandlers.widgetEvents.postMessage({ type: 'options', payload: options });
});
})(
window,
document,
'script',
'_asurion_widget',
'https://app.widget-loader.service-initiation.asurion.com/widget-loader.js',
{
id: '\(widgetId)',
variant: 'embedded',
context: \(jsonString(from: context) ?? "{}"),
trackingParameters: \(jsonString(from: trackingParameters) ?? "{}"),
}
);
</script>
</head>
<body></body>
</html>
"""
}
private func jsonString(from dictionary: [String: Any]?) -> String? {
guard let dictionary = dictionary,
let data = try? JSONSerialization.data(withJSONObject: dictionary),
let string = String(data: data, encoding: .utf8) else {
return nil
}
return string
}
}
SwiftUI Integration
For SwiftUI applications, create a UIViewRepresentable wrapper:
import SwiftUI
import WebKit
struct AsurionWidgetView: UIViewRepresentable {
let widgetId: String
var context: [String: Any]?
var trackingParameters: [String: String]?
func makeCoordinator() -> Coordinator {
Coordinator()
}
func makeUIView(context: Context) -> WKWebView {
let configuration = WKWebViewConfiguration()
configuration.allowsInlineMediaPlayback = true
configuration.mediaTypesRequiringUserActionForPlayback = []
let webView = WKWebView(frame: .zero, configuration: configuration)
webView.scrollView.bounces = false
webView.isOpaque = false
webView.backgroundColor = .clear
webView.uiDelegate = context.coordinator
return webView
}
func updateUIView(_ webView: WKWebView, context: Context) {
let html = generateWidgetHTML()
webView.loadHTMLString(html, baseURL: nil)
}
class Coordinator: NSObject, WKUIDelegate {
func webView(_ webView: WKWebView,
createWebViewWith configuration: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures) -> WKWebView? {
if let url = navigationAction.request.url {
UIApplication.shared.open(url)
}
return nil
}
}
private func generateWidgetHTML() -> String {
let contextJSON = jsonString(from: self.context) ?? "{}"
let trackingJSON = jsonString(from: trackingParameters) ?? "{}"
return """
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style>
* { margin: 0; padding: 0; }
html, body { height: 100%; width: 100%; overflow: hidden; }
</style>
<script>
(function (w, d, s, o, f, a, js, fjs) {
w[o] = function () {
const [action, ...params] = arguments;
(w[o].q = w[o].q || []).push([action, ...params]);
};
(js = d.createElement(s)), (fjs = d.getElementsByTagName(s)[0]);
js.id = o;
js.src = f;
js.async = 1;
js.setAttribute('data-widget-id', a.id);
js.setAttribute('data-variant', a.variant);
w[o + '_context'] = a.context;
w[o + '_trackingParameters'] = a.trackingParameters;
fjs.parentNode.insertBefore(js, fjs);
// Forward widget events to native
w[o]('subscribe', 'state', function (state) {
window.webkit.messageHandlers.widgetEvents.postMessage({ type: 'state', payload: state });
});
w[o]('subscribe', 'options', function (options) {
window.webkit.messageHandlers.widgetEvents.postMessage({ type: 'options', payload: options });
});
})(
window,
document,
'script',
'_asurion_widget',
'https://app.widget-loader.service-initiation.asurion.com/widget-loader.js',
{
id: '\(widgetId)',
variant: 'embedded',
context: \(contextJSON),
trackingParameters: \(trackingJSON),
}
);
</script>
</head>
<body></body>
</html>
"""
}
private func jsonString(from dictionary: [String: Any]?) -> String? {
guard let dictionary = dictionary,
let data = try? JSONSerialization.data(withJSONObject: dictionary),
let string = String(data: data, encoding: .utf8) else {
return nil
}
return string
}
}
// Usage in SwiftUI
struct ContentView: View {
var body: some View {
AsurionWidgetView(
widgetId: "<WIDGET_ID>",
context: ["userId": "user-123", "platform": "ios"]
)
.edgesIgnoringSafeArea(.all)
}
}
Configuration Options
| Option | Type | Required | Description |
|---|---|---|---|
id | string | true | Your unique widget identifier provided by Asurion |
variant | string | true | Widget variant type. For iOS WebView, only 'embedded' is supported |
context | object | false | Additional context data to pass to the widget. Can contain any key-value pairs |
trackingParameters | object | false | Tracking parameters that will be appended to external links within the widget. Must be string key-value pairs |
Communicating with the Widget
You can send commands to the widget using the evaluateJavaScript method:
class AsurionWidgetViewController: UIViewController, WKUIDelegate {
private var webView: WKWebView!
// ... viewDidLoad, setupWebView, loadWidget, generateWidgetHTML ...
// ... webView(_:createWebViewWith:for:windowFeatures:) ...
func extendContext(_ data: [String: Any]) {
guard let jsonData = try? JSONSerialization.data(withJSONObject: data),
let jsonString = String(data: jsonData, encoding: .utf8) else {
return
}
let script = "window._asurion_widget('extendContext', \(jsonString));"
webView.evaluateJavaScript(script, completionHandler: nil)
}
func extendTrackingParameters(_ params: [String: String]) {
guard let jsonData = try? JSONSerialization.data(withJSONObject: params),
let jsonString = String(data: jsonData, encoding: .utf8) else {
return
}
let script = "window._asurion_widget('extendTrackingParameters', \(jsonString));"
webView.evaluateJavaScript(script, completionHandler: nil)
}
}
Subscribing to Widget Events
The widget forwards events to native code using window.webkit.messageHandlers (configured in Basic Usage above). Handle these events by adding a script message handler:
class AsurionWidgetViewController: UIViewController, WKUIDelegate, WKScriptMessageHandler {
private var webView: WKWebView!
// ...
private func setupWebView() {
let configuration = WKWebViewConfiguration()
configuration.allowsInlineMediaPlayback = true
configuration.mediaTypesRequiringUserActionForPlayback = []
configuration.userContentController.add(self, name: "widgetEvents")
webView = WKWebView(frame: view.bounds, configuration: configuration)
// ... other setup ...
}
func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
guard message.name == "widgetEvents",
let body = message.body as? [String: Any],
let type = body["type"] as? String else {
return
}
switch type {
case "state":
if let payload = body["payload"] as? String {
print("Widget state: \(payload)")
}
case "options":
if let payload = body["payload"] {
print("Widget options: \(payload)")
}
default:
break
}
}
}