Skip to content

Commit 6ee526f

Browse files
Merge pull request #189 from teads/webview_automatic_js_injection
update TeadsWebviewHelper implementation
2 parents 4b5d77a + 3943282 commit 6ee526f

File tree

4 files changed

+45
-48
lines changed

4 files changed

+45
-48
lines changed

TeadsSampleApp/Controllers/InRead/Admob/WebView/InReadAdmobWebViewController.swift

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,21 @@ class InReadAdmobWebViewController: TeadsViewController {
2323
override func viewDidLoad() {
2424
super.viewDidLoad()
2525

26+
/// init helper before loading html content
27+
webViewHelper = TeadsWebViewHelper(webView: webView, selector: "#teads-placement-slot", delegate: self)
28+
2629
guard let content = Bundle.main.path(forResource: "sample", ofType: "html"),
2730
let contentString = try? String(contentsOfFile: content) else {
2831
return
2932
}
3033
let contentStringWithIntegrationType = contentString.replacingOccurrences(of: "{INTEGRATION_TYPE}", with: "InRead Admob WebView Integration")
31-
webView.navigationDelegate = self
34+
3235
webView.loadHTMLString(contentStringWithIntegrationType, baseURL: Bundle.main.bundleURL)
3336

3437
bannerView = GAMBannerView(adSize: GADAdSizeMediumRectangle)
3538
bannerView.adUnitID = pid // Replace with your adunit
3639
bannerView.rootViewController = self
3740
bannerView.delegate = self
38-
39-
/// init helper
40-
webViewHelper = TeadsWebViewHelper(webView: webView, selector: "#teads-placement-slot", delegate: self)
4141
}
4242
}
4343

@@ -75,12 +75,6 @@ extension InReadAdmobWebViewController: GADBannerViewDelegate {
7575
}
7676
}
7777

78-
extension InReadAdmobWebViewController: WKNavigationDelegate {
79-
func webView(_: WKWebView, didFinish _: WKNavigation!) {
80-
webViewHelper?.injectJS()
81-
}
82-
}
83-
8478
extension InReadAdmobWebViewController: TeadsWebViewHelperDelegate {
8579
func webViewHelperSlotStartToShow() {
8680
print("webViewHelperSlotStartToShow")

TeadsSampleApp/Controllers/InRead/Direct/WebView/InReadDirectWebViewController.swift

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,34 +19,27 @@ class InReadDirectWebViewController: TeadsViewController, WKNavigationDelegate {
1919
override func viewDidLoad() {
2020
super.viewDidLoad()
2121

22+
// The html identifier where you want your slot to open`
23+
let domCSSSlotSelector = "#teads-placement-slot"
24+
25+
/// init helper before loading html content
26+
webViewHelper = TeadsWebViewHelper(webView: webView, selector: domCSSSlotSelector, delegate: self)
27+
2228
guard let content = Bundle.main.path(forResource: "sample", ofType: "html"),
2329
let contentString = try? String(contentsOfFile: content) else {
2430
return
2531
}
2632
let contentStringWithIntegrationType = contentString.replacingOccurrences(of: "{INTEGRATION_TYPE}", with: "InRead Direct WebView Integration")
2733

28-
// The html identifier where you want your slot to open`
29-
let domCSSSlotSelector = "#teads-placement-slot"
30-
webView.navigationDelegate = self
3134
webView.loadHTMLString(contentStringWithIntegrationType, baseURL: Bundle.main.bundleURL)
3235

33-
/// init helper
34-
webViewHelper = TeadsWebViewHelper(webView: webView, selector: domCSSSlotSelector, delegate: self)
35-
3636
let pSettings = TeadsAdPlacementSettings { _ in
3737
// settings.enableDebug()
3838
}
3939

4040
// keep a strong reference to placement instance
4141
placement = Teads.createInReadPlacement(pid: Int(pid) ?? 0, settings: pSettings, delegate: self)
4242
}
43-
44-
// MARK: WKNavigationDelegate
45-
46-
func webView(_: WKWebView, didFinish _: WKNavigation!) {
47-
print("injectJS")
48-
webViewHelper?.injectJS()
49-
}
5043
}
5144

5245
extension InReadDirectWebViewController: TeadsInReadAdPlacementDelegate {

TeadsSampleApp/WebViewHelper/Resources/bootstrap.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
(function() {
1313

1414
var verticalSpacer = 10;
15-
var showHideTimerDuration = 100;
15+
var showHideTimerDuration = 100;
1616
var intervalCheckPosition = 250;
1717
var opened = false;
1818
var bridge, teadsContainer, finalSize, intervalPosition, offset, heightSup, ratio, maxHeight;

TeadsSampleApp/WebViewHelper/TeadsWebViewHelper.swift

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,15 @@ import WebKit
8080

8181
/// Init the Teads webView helper
8282
///
83-
/// - Note: handles slot position injection from TeadsSDK
83+
/// Handles slot position injection from TeadsSDK
8484
///
8585
/// - Parameters:
8686
/// - webView: webView where you want to add your ad. The receiver holds a weak reference only.
8787
/// - 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
8888
/// - delegate: optional delegate to follow slot javascript lyfecycle
8989
///
90-
/// - Important: should be called from **main Thread**
90+
/// - Important: Should be called from **main Thread**: before loading html content.
91+
/// - Note: Make sure bootstrap.js file is present in the same bundle of this file
9192
@objc public init(webView: WKWebView, selector: String, delegate: TeadsWebViewHelperDelegate? = nil) {
9293
self.webView = webView
9394
self.selector = selector
@@ -101,6 +102,14 @@ import WebKit
101102
JSBootstrapOutput.allCases.map(\.rawValue).forEach {
102103
webView.configuration.userContentController.add(WKWeakScriptHandler(delegate: self), name: $0)
103104
}
105+
106+
guard let bootstrap = bootstrap else {
107+
delegate?.webViewHelperOnError?(error: "Unable to load bootstrap.js file, make sure to append to bundle")
108+
return
109+
}
110+
111+
let bootstrapUserScript = WKUserScript(source: bootstrap, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
112+
webView.configuration.userContentController.addUserScript(bootstrapUserScript)
104113
}
105114

106115
deinit {
@@ -126,36 +135,31 @@ import WebKit
126135
}
127136

128137
/// Inject Teads' bootstrap in the webview
129-
/// make sure bootstrap.js file is present in same the bundle of this file
130-
@objc public func injectJS() {
131-
guard let webView = webView,
132-
let bootStrapURL = Bundle(for: Self.self).url(forResource: "bootstrap", withExtension: "js"),
138+
@available(*, deprecated, message: "no longer needed, using WKUserScript logic to inject bootstrap automatically instead")
139+
@objc public func injectJS() {}
140+
141+
private var bootstrap: String? {
142+
guard let bootStrapURL = Bundle(for: Self.self).url(forResource: "bootstrap", withExtension: "js"),
133143
let data = try? Data(contentsOf: bootStrapURL) else {
134-
delegate?.webViewHelperOnError?(error: "Unable to load bootstrap.js file, make sure to append to bundle")
135-
return
144+
return nil
136145
}
137-
138146
let bootStrap64 = data.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
139147

140-
let javascript = """
148+
return """
141149
javascript:(function() { var scriptElement = document.getElementById('teadsbootstrap'); if(scriptElement) scriptElement.remove();
142150
var script = document.createElement('script');
143151
script.innerHTML = window.atob('\(bootStrap64)');
144152
script.setAttribute('id', 'teadsbootstrap');
145153
script.setAttribute('type', 'text/javascript');
146154
document.body.appendChild(script);})()
147155
"""
148-
webView.evaluateJavaScript(javascript) { [weak delegate, weak self] _, error in
149-
if error != nil {
150-
delegate?.webViewHelperOnError?(error: "injection of JS failed")
151-
}
152-
self?.isJsReady = true
153-
}
154156
}
155157

156-
/// the bootstrap calls this when it is ready
157-
/// insert the slot in the webview with the selector
158+
/// The bootstrap calls this when it is ready
159+
///
160+
/// Insert the slot in the webview with the `selector` specified at ``TeadsWebViewHelper/init(webView:selector:delegate:)``
158161
private func insertSlot() {
162+
isJsReady = true
159163
// add a timeout in case we are not able to find the slot
160164
let timer = Timer(timeInterval: 4, repeats: false) { [weak self] _ in
161165
self?.slotOpener = nil
@@ -188,6 +192,15 @@ import WebKit
188192
openSlot(adView: TeadsInReadAdView(bind: ad), adRatio: adRatio, topOffset: topOffset, bottomOffset: bottomOffset)
189193
}
190194

195+
/// Call the bootstrap to open the slot
196+
///
197+
/// - Parameters:
198+
/// - adView: any UIView
199+
/// - adRatio: ratio of the Teads ad
200+
/// - topOffset: topOffset of the View is 0 in most cases, useful if your website display a top bar and don't want the ad to overlap it
201+
/// - bottomOffset: bottomOffset of the View is 0 in most cases, useful if your website display a bottom bar and don't want the ad to overlap it
202+
///
203+
/// - Note: should be called from ```TeadsInReadAdPlacementDelegate.didReceiveAd(ad: TeadsInReadAd, adRatio: TeadsAdRatio)```
191204
@objc public func openSlot(adView: UIView, adRatio: TeadsAdRatio = .default, topOffset: CGFloat = 0.0, bottomOffset: CGFloat = 0.0) {
192205
slotOpener = { [self] in
193206
guard let slotPosition = self.slotPosition else {
@@ -235,12 +248,11 @@ import WebKit
235248
}
236249

237250
/// Update the slot height with the given ad ratio
251+
///
238252
/// - Parameters:
239253
/// - adRatio: ratio of the ad
240254
///
241-
/// - Note:
242-
/// sould be called from
243-
/// ```TeadsInReadAdPlacementDelegate.didUpdateRatio(ratio: TeadsAdRatio)```
255+
/// - Note: sould be called from ```TeadsInReadAdPlacementDelegate.didUpdateRatio(ratio: TeadsAdRatio)```
244256
@objc public func updateSlot(adRatio: TeadsAdRatio) {
245257
guard isJsReady else {
246258
return
@@ -269,9 +281,7 @@ import WebKit
269281

270282
/// Call the bootstrap to close the slot
271283
///
272-
/// - Note:
273-
/// sould be called from
274-
/// ```TeadsAdDelegate.onError(ad: TeadsAd, error: Error)```
284+
/// - Note: sould be called from ```TeadsAdDelegate.onError(ad: TeadsAd, error: Error)```
275285
@objc public func closeSlot() {
276286
Self.mainThread { [weak adView] in
277287
adView?.removeFromSuperview()

0 commit comments

Comments
 (0)