AB#280444 - Add GamifyWidget SDK module#140
Conversation
0ac9128 to
fa68645
Compare
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…wrapper Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fa68645 to
da1effe
Compare
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Match the ensureMain + assertOnMainThread pattern from InAppPresenter.swift so public entry points dispatch to main themselves instead of relying on a debug-only assert that strips in release builds. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a new “Gamify Widget” feature area to the OptimoveSDK, providing a public SDK entry point to configure a widget URL and present a modal sheet hosting a WKWebView with a simple JS bridge handshake.
Changes:
- Introduces
GamifyWidgetSDKas the public API for configuring and opening the widget. - Adds
GamifyWidgetViewControllerto host theWKWebView, show loading/error UI, and handle READY/INIT/CLOSE messages. - Adds
GamifyWidgetSDKTestscovering URL initialization behavior (including a background-thread call case).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| OptimoveSDK/Sources/Classes/GamifyWidget/GamifyWidgetSDK.swift | Public entry point to initialize widget URL and present the widget as a modal sheet. |
| OptimoveSDK/Sources/Classes/GamifyWidget/GamifyWidgetViewController.swift | Internal UIKit controller with WKWebView + JS bridge, loading spinner, and error state. |
| OptimoveSDK/Tests/Sources/GamifyWidget/GamifyWidgetSDKTests.swift | Unit tests validating widget URL initialization behavior. |
Comments suppressed due to low confidence (1)
OptimoveSDK/Tests/Sources/GamifyWidget/GamifyWidgetSDKTests.swift:21
- Same issue as above: this test asserts immediately after calling
initialize, butinitializemay be async if invoked off the main thread. Make the test deterministic by running the call on the main thread or waiting until the main-queue work has executed.
func testInitializeOverwritesPreviousUrl() {
GamifyWidgetSDK.initialize(widgetUrl: "https://first.example.com")
GamifyWidgetSDK.initialize(widgetUrl: "https://second.example.com")
XCTAssertEqual(GamifyWidgetSDK.widgetUrl, "https://second.example.com")
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Copyright © 2026 Optimove. All rights reserved. | ||
|
|
||
| import UIKit | ||
| import WebKit |
There was a problem hiding this comment.
Logger is already usable without an explicit import OptimoveCore
https://github.com/optimove-tech/Optimove-SDK-iOS/blob/feature/280444-gamify-widget-ios/OptimoveSDK/Sources/Classes/OptimoveConfig.swift
There was a problem hiding this comment.
Hmm, interesting how it was linked then
| private enum BridgeMessage { | ||
| static let receiveMessage = "receiveMessage" | ||
| static let closeWidget = "closeWidget" | ||
| } |
| assertOnMainThread() | ||
| let vc = GamifyWidgetViewController( | ||
| widgetUrl: widgetUrl, | ||
| userId: userId, | ||
| token: token | ||
| ) |
There was a problem hiding this comment.
Empty/invalid widgetUrl doesn't produce a blank sheet — GamifyWidgetViewController.loadWidget() guards via URL(string:) and falls through to showError(), which reveals the error label set up in setupErrorLabel() (L80-L102):
"Unable to load widget.\nCheck your connection and try again."
There was a problem hiding this comment.
How does this error message help a user?
Copilot says not to open the error screen if we know that the user will see it immediately.
Summary
GamifyWidgetSDK— public entry point withinitialize(widgetUrl:)andopen(from:userId:token:)that presents a modal sheetGamifyWidgetViewController— internal UIKit view controller hosting aWKWebViewwith JS bridge (READY → INIT → CLOSE handshake), loading spinner, and error stateGamifyWidgetSDKTests— unit tests for URL initialisationiOS equivalent of Android SDK PR #91 (AB#280444). No changes to
Package.swift— new files sit inside the existingOptimoveSDKtarget source path.JS Bridge
Widget fires
READY→ native responds withINIT(userId/token) viawindow.postMessage. Widget callswindow.webkit.messageHandlers.nativeBridge.postMessageto close. Token is redacted in logs.Test plan
cmd+UonOptimoveSDKscheme —GamifyWidgetSDKTestspasscmd+BoniOSscheme — clean build, no errors or warnings