Skip to content

Instantly share code, notes, and snippets.

@AmitaiB
Last active July 6, 2022 15:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AmitaiB/2dee746618fc2916637a08e3eb7c21e6 to your computer and use it in GitHub Desktop.
Save AmitaiB/2dee746618fc2916637a08e3eb7c21e6 to your computer and use it in GitHub Desktop.
Quick and dirty JWAdCompanion implementation
// In a JWPlayerViewController, with player configured, etc.
// For example, our BPA: https://github.com/jwplayer/jwplayer-ios-bestPracticeApps
// Override the implementation of this JWAdDelegate method,
// which reports when any ad event is emitted by the player.
override func jwplayer(_ player: AnyObject, adEvent event: JWAdEvent) {
super.jwplayer(player, adEvent: event) // When overriding (only), must call the `super` method.
if let companions = event[.companions] as? [JWAdCompanion] {
handleCompanion(companions.first)
}
}
func handleCompanion(_ ad: JWAdCompanion?) {
switch ad!.type {
case .`static`:
handleStaticImage(ad)
case .html:
handleHTML(ad)
case .iframe:
handleiFrame(ad)
default:
break
}
}
func handleStaticImage(_ ad: JWAdCompanion?) {
guard
let ad = ad,
ad.type == .`static`,
// get the concrete object from the protocol
let playerView = playerView as? JWPlayerView
else { return }
// Layout the companion ad view under the player with JWAdCompanion.size
let adOrigin = CGPoint(x: playerView.left, y: playerView.bottom)
let adImageView = UIImageView(frame: CGRect(origin: adOrigin, size: ad.size))
// Get the image with JWAdCompanion.resource
let adImageData = try! Data(contentsOf: ad.resource)
adImageView.image = UIImage(data: adImageData)
// Assign the UI action with JWAdCompanion.clickUrl
// for simplicity, using 3rd party pod https://cocoapods.org/pods/Actions
let tapGesture = UITapGestureRecognizer { present(SFSafariViewController(url: ad.clickUrl), animated: true) }
adImageView.addGestureRecognizer(tapGesture)
// Handle event reporting — JWAdCompanion.creativeView is an `Array` of `String`s
// that contain the info, e.g. the IAB's VAST §3.14 example: http://server1.com/start.jpg and .../complete.jpg
// The developer, knowing what to expect, can handle this accordingly.
if let pixels = ad.creativeView {
pixels.forEach { handleCompanionEventPixel($0) }
}
}
// Your analytics server's requirements determines what goes here. The following is hypothetical:
func handleCompanionEventPixel(_ pixel: String) {
guard let pixelTarget = URL(string: pixel)
else { return }
var eventRequest = URLRequest(url: pixelTarget)
eventRequest.httpMethod = "PUT"
eventRequest.allHTTPHeaderFields = [
"Content-Type": "application/json",
"Accept": "application/json",
"SomeCustomHeaderMaybeAnID": UUID().uuidString
]
let task = URLSession.shared.dataTask(with: eventRequest)
task.resume()
}
func handleHTML(_ ad: JWAdCompanion?) {
// perhaps a WKWebView?
}
func handleiFrame(_ ad: JWAdCompanion?) {
// ditto?
}
// Helpful when using frames
extension UIView {
var width: CGFloat { frame.size.width }
var height: CGFloat { frame.size.height }
var left: CGFloat { frame.origin.x }
var right: CGFloat { left + width }
var top: CGFloat { frame.origin.y }
var bottom: CGFloat { top + height }
}
@AmitaiB
Copy link
Author

AmitaiB commented Jul 5, 2022

⚠️ Please keep in mind that this does not take any precautions for thread safety, or concurrency in general. ⚠️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment