Skip to content

Commit 6e3b73b

Browse files
committed
improve WebViewHelper lifecycle
1 parent a2d0dee commit 6e3b73b

File tree

1 file changed

+43
-33
lines changed

1 file changed

+43
-33
lines changed

TeadsSampleApp/WebViewHelper/TeadsWebViewHelper.swift

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ import TeadsSDK
1313
import UIKit
1414
import WebKit
1515

16-
/// follow slot javascript lyfecycle
17-
/// - Note:
18-
/// method will be triggered on mainThread or thead from original call
16+
/// Follow slot javascript lyfecycle
17+
///
18+
/// Methods will be triggered on mainThread or thead from original call
19+
///
1920
@objc public protocol TeadsWebViewHelperDelegate {
2021
/// This is called when the teads slot is shown.
2122
@objc optional func webViewHelperSlotStartToShow()
@@ -25,12 +26,12 @@ import WebKit
2526

2627
/// This is called when the html element slot has been found.
2728
/// - Note
28-
/// This indicates slot specified with `selector` on `TeadsWebViewHelper` init has been found in webview html DOM.
29+
/// This indicates slot specified with `selector` on ``TeadsWebViewHelper/init(webView:selector:delegate:)`` has been found in webview html DOM.
2930
@objc optional func webViewHelperSlotFoundSuccessfully()
3031

3132
/// This is called when no slot is found.
3233
/// - Note
33-
/// This indicates slot specified with `selector` on `TeadsWebViewHelper` init has not been found in webview html DOM.
34+
/// This indicates slot specified with `selector` on ``TeadsWebViewHelper/init(webView:selector:delegate:)`` has **NOT** been found in webview html DOM.
3435
@objc optional func webViewHelperSlotNotFound()
3536

3637
/// This is called when an error occured with the reason.
@@ -56,15 +57,19 @@ import WebKit
5657

5758
// latest slot position updated
5859
private var slotPosition: SlotPosition?
59-
private var isSlotFound: Bool {
60-
return slotPosition != nil
60+
private var isSlotNotFound: Bool {
61+
return slotPosition == nil
6162
}
6263

6364
// width of element in Web content, needed to compute ratio
64-
public var adViewHTMLElementWidth: CGFloat = 0
65+
public var adViewHTMLElementWidth: CGFloat {
66+
if let slotPosition = slotPosition {
67+
return slotPosition.right - slotPosition.left
68+
}
69+
return .zero
70+
}
6571

6672
private var webViewObservation: NSKeyValueObservation?
67-
private var orientationStateObserver: NSObjectProtocol?
6873

6974
private var isJsReady = false
7075

@@ -79,7 +84,7 @@ import WebKit
7984
///
8085
/// - Parameters:
8186
/// - webView: webView where you want to add your ad. The receiver holds a weak reference only.
82-
/// - selector: name of the html identifier where you want your slot to open `#mySelector`
87+
/// - selector: name of the html identifier where you want your slot to open `#mySelector` will pick the first [CSS Selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors) found in the DOM
8388
/// - delegate: optional delegate to follow slot javascript lyfecycle
8489
///
8590
/// - Important: should be called from **main Thread**
@@ -109,6 +114,8 @@ import WebKit
109114
NotificationCenter.default.removeObserver(self)
110115
}
111116

117+
/// Track url requests change in order to reset adView and position tracking
118+
/// When position is located a new time, alert through ``TeadsWebViewHelperDelegate/webViewHelperSlotFoundSuccessfully()``
112119
override public func observeValue(forKeyPath keyPath: String?, of _: Any?, change: [NSKeyValueChangeKey: Any]?, context _: UnsafeMutableRawPointer?) {
113120
if keyPath == Self.urlKeyPath,
114121
let _ = change?[NSKeyValueChangeKey.newKey] {
@@ -183,6 +190,10 @@ import WebKit
183190

184191
@objc public func openSlot(adView: UIView, adRatio: TeadsAdRatio = .default, topOffset: CGFloat = 0.0, bottomOffset: CGFloat = 0.0) {
185192
slotOpener = { [self] in
193+
guard let slotPosition = self.slotPosition else {
194+
return
195+
}
196+
186197
// update slot with the right ratio
187198
self.updateSlot(adRatio: adRatio)
188199

@@ -195,16 +206,15 @@ import WebKit
195206
self.containerView = createContainerView(topOffset: topOffset, bottomOffset: bottomOffset)
196207
self.containerView?.addSubview(adView)
197208
self.adView = adView
209+
self.updateAdViewPosition(position: slotPosition)
198210
self.evaluateBootstrapInput(JSBootstrapInput.showPlaceholder(0)) { [weak delegate] _, error in
199211
if error != nil {
200212
delegate?.webViewHelperOnError?(error: "openSlot failed")
201213
}
202214
}
203215
self.slotOpener = nil
204216
}
205-
if isSlotFound {
206-
slotOpener?()
207-
}
217+
slotOpener?()
208218
}
209219

210220
private func createContainerView(topOffset: CGFloat, bottomOffset: CGFloat) -> UIView {
@@ -276,17 +286,29 @@ import WebKit
276286

277287
// MARK: JS Interface
278288

279-
/// the bootstrap calls this when the slot is updated
289+
/// the bootstrap calls this when the slot is updated: slot found or moved to another position due to runtime evolution of the HTML content
280290
///
281291
/// - Parameter position: json describing the position with top/bottom/right/left
282292
private func onSlotUpdated(position: String?) {
283-
if let data = position?.data(using: .utf8),
284-
let slotPosition = try? JSONDecoder().decode(SlotPosition.self, from: data) {
285-
noSlotTimer?.invalidate()
286-
updateAdViewPosition(position: slotPosition)
287-
} else {
293+
guard let data = position?.data(using: .utf8),
294+
let slotPosition = try? JSONDecoder().decode(SlotPosition.self, from: data) else {
288295
delegate?.webViewHelperOnError?(error: "The json is malformed")
296+
return
297+
}
298+
noSlotTimer?.invalidate()
299+
300+
if isSlotNotFound {
301+
// triggered once: only when slot is found
302+
delegate?.webViewHelperSlotFoundSuccessfully?()
289303
}
304+
305+
self.slotPosition = slotPosition
306+
guard let webView = webView else {
307+
return
308+
}
309+
slotOpportunity?(webView, slotPosition)
310+
slotOpener?()
311+
updateAdViewPosition(position: slotPosition)
290312
}
291313

292314
// MARK: WKScriptMessageHandler
@@ -318,24 +340,12 @@ import WebKit
318340
}
319341
}
320342

321-
/// Change the constraint of the ad so it follows what the bootstrap ask
343+
/// Change the constraint of the ad so it follows DOM position
322344
///
323345
/// - Parameters:
324346
/// - position: top/bottom/right/left position of the slot
325347
private func updateAdViewPosition(position: SlotPosition) {
326-
if !isSlotFound {
327-
delegate?.webViewHelperSlotFoundSuccessfully?()
328-
}
329-
330-
adViewHTMLElementWidth = position.right - position.left
331-
slotPosition = position
332-
slotOpener?()
333-
guard let webView = webView else {
334-
return
335-
}
336-
slotOpportunity?(webView, position)
337-
338-
guard let adView = adView else {
348+
guard let webView = webView, let adView = adView else {
339349
return
340350
}
341351

0 commit comments

Comments
 (0)