@@ -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