Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: monitor IMA ad events for the user #42

Merged
merged 21 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ DerivedData
# Bundler
.bundle

.swiftpm/**

# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts

Expand Down
32 changes: 20 additions & 12 deletions Example/DemoApp/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import GoogleInteractiveMediaAds
class ViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {

private let DEMO_PLAYER_NAME = "adplayer"
private let MUX_DATA_ENV_KEY = "YOUR KEY HERE"
private let MUX_DATA_ENV_KEY = "YOUR ENV KEY HERE"

private let AD_TAG_URL = "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostlongpod&cmsid=496&vid=short_tencue&correlator="
private let VOD_TEST_URL_STEVE = "http://qthttp.apple.com.edgesuite.net/1010qwoeiuryfg/sl.m3u8"
Expand Down Expand Up @@ -52,7 +52,7 @@ class ViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDeleg
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated);
super.viewDidAppear(animated)
requestAds()
player?.play()
}
Expand All @@ -67,8 +67,6 @@ class ViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDeleg
playerViewController = AVPlayerViewController()
playerViewController.player = player

setUpMux(player: player)

self.player = player

// Set up your content playhead and contentComplete callback.
Expand All @@ -77,12 +75,13 @@ class ViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDeleg
self,
selector: #selector(ViewController.contentDidFinishPlaying(_:)),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: player.currentItem);
object: player.currentItem)

showContentPlayer()
}

func setUpMux(player: AVPlayer) {
// MARK: mux: Monitor your AVPlayer and IMAAdsLoader
func setUpMux(player: AVPlayer, adsLoader: IMAAdsLoader) {
// Basic Data
let envKey = ProcessInfo.processInfo.environment["ENV_KEY"] ?? MUX_DATA_ENV_KEY
let customerPlayerData = MUXSDKCustomerPlayerData(environmentKey: envKey)
Expand All @@ -93,12 +92,21 @@ class ViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDeleg
self.playerBinding = playerBinding

// IMA Ads
imaListener = MuxImaListener(playerBinding: playerBinding)
imaListener = MuxImaListener(
playerBinding: playerBinding,
monitoringAdsLoader: adsLoader
)
}

func setUpAdsLoader() {

adsLoader = IMAAdsLoader(settings: nil)
adsLoader.delegate = self

// MARK: mux - Set up Mux after you set up your AVPlayer and IAMAdsLoader
if let player = player {
setUpMux(player: player, adsLoader: adsLoader)
}
}

func requestAds() {
Expand All @@ -116,6 +124,7 @@ class ViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDeleg
contentPlayhead: contentPlayhead,
userContext: nil)

// MARK: mux - Tell us when you first request CSAI ads
imaListener?.clientAdRequest(request)
adsLoader.requestAds(with: request)
}
Expand All @@ -139,6 +148,10 @@ class ViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDeleg
func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) {
adsManager = adsLoadedData.adsManager
adsManager.delegate = self

//MARK: mux: Call before initialize() but after setting your IMAAdsManagerDelegate
imaListener?.monitorAdsManager(adsManager)

adsManager.initialize(with: nil)
}

Expand All @@ -155,8 +168,6 @@ class ViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDeleg
// MARK: - IMAAdsManagerDelegate

func adsManager(_ adsManager: IMAAdsManager, didReceive event: IMAAdEvent) {
imaListener?.dispatchEvent(event)

// Play each ad once it has been loaded
if event.type == IMAAdEventType.LOADED {
adsManager.start()
Expand All @@ -166,22 +177,19 @@ class ViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDeleg
func adsManager(_ adsManager: IMAAdsManager, didReceive error: IMAAdError) {
// Fall back to playing content
print("AdsManager error: " + (error.message ?? "nil"))
imaListener?.dispatchError(error.message ?? "nil")
showContentPlayer()
playerViewController.player?.play()
}

func adsManagerDidRequestContentPause(_ adsManager: IMAAdsManager) {
// Pause the content for the SDK to play ads.
playerViewController.player?.pause()
imaListener?.onContentPauseOrResume(true)
hideContentPlayer()
}

func adsManagerDidRequestContentResume(_ adsManager: IMAAdsManager) {
// Resume the content since the SDK is done playing ads (at least for now).
showContentPlayer()
imaListener?.onContentPauseOrResume(false)
playerViewController.player?.play()
}

Expand Down
58 changes: 58 additions & 0 deletions Example/MUXSDKImaListener.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
351790CC293822A200ABBCC9 /* DemoAppUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 351790CB293822A200ABBCC9 /* DemoAppUITests.swift */; };
351790D92939012600ABBCC9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 351790D82939012600ABBCC9 /* Main.storyboard */; };
3F45BFB39833B0A140B2D654 /* Pods_DemoApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D425C49793FF6747BCDF2143 /* Pods_DemoApp.framework */; };
9879F2DC09AE853F7DDAF891 /* Pods_DemoAppUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AC6C06928453745F77F45981 /* Pods_DemoAppUITests.framework */; };
BE12B5A92AA014C21BD93DA6 /* Pods_MUXSDKIMATVOSExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A782E661634F3D498956804C /* Pods_MUXSDKIMATVOSExample.framework */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -93,12 +94,15 @@
606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = "<group>"; };
7A13E82601D5529389AC360D /* Pods-MUXSDKIMATVOSExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MUXSDKIMATVOSExample.release.xcconfig"; path = "Target Support Files/Pods-MUXSDKIMATVOSExample/Pods-MUXSDKIMATVOSExample.release.xcconfig"; sourceTree = "<group>"; };
98CC587B53F5022354CB7AEB /* Pods-DemoAppTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DemoAppTests.debug.xcconfig"; path = "Target Support Files/Pods-DemoAppTests/Pods-DemoAppTests.debug.xcconfig"; sourceTree = "<group>"; };
9BFD2676DCFF3512F5D69415 /* Pods-DemoAppUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DemoAppUITests.release.xcconfig"; path = "Target Support Files/Pods-DemoAppUITests/Pods-DemoAppUITests.release.xcconfig"; sourceTree = "<group>"; };
A782E661634F3D498956804C /* Pods_MUXSDKIMATVOSExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MUXSDKIMATVOSExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
AC6C06928453745F77F45981 /* Pods_DemoAppUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DemoAppUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
ADF4605B56F017F8453719DF /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
CA186C69153F734E132A4463 /* Pods-DemoApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DemoApp.debug.xcconfig"; path = "Target Support Files/Pods-DemoApp/Pods-DemoApp.debug.xcconfig"; sourceTree = "<group>"; };
D425C49793FF6747BCDF2143 /* Pods_DemoApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DemoApp.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DA374CB46C9E95D16EA14492 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
DA92FA8AF23EA9FC463F0A94 /* Pods-DemoAppTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DemoAppTests.release.xcconfig"; path = "Target Support Files/Pods-DemoAppTests/Pods-DemoAppTests.release.xcconfig"; sourceTree = "<group>"; };
E21C226A97A08CF45802D6D0 /* Pods-DemoAppUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DemoAppUITests.debug.xcconfig"; path = "Target Support Files/Pods-DemoAppUITests/Pods-DemoAppUITests.debug.xcconfig"; sourceTree = "<group>"; };
F788D6CC3F7561EFD76310E8 /* Pods-MUXSDKIMATVOSExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MUXSDKIMATVOSExample.debug.xcconfig"; path = "Target Support Files/Pods-MUXSDKIMATVOSExample/Pods-MUXSDKIMATVOSExample.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -137,6 +141,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9879F2DC09AE853F7DDAF891 /* Pods_DemoAppUITests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -256,6 +261,7 @@
D425C49793FF6747BCDF2143 /* Pods_DemoApp.framework */,
4DA624DBCF643ABD487E347F /* Pods_DemoAppTests.framework */,
A782E661634F3D498956804C /* Pods_MUXSDKIMATVOSExample.framework */,
AC6C06928453745F77F45981 /* Pods_DemoAppUITests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
Expand Down Expand Up @@ -290,6 +296,8 @@
DA92FA8AF23EA9FC463F0A94 /* Pods-DemoAppTests.release.xcconfig */,
F788D6CC3F7561EFD76310E8 /* Pods-MUXSDKIMATVOSExample.debug.xcconfig */,
7A13E82601D5529389AC360D /* Pods-MUXSDKIMATVOSExample.release.xcconfig */,
E21C226A97A08CF45802D6D0 /* Pods-DemoAppUITests.debug.xcconfig */,
9BFD2676DCFF3512F5D69415 /* Pods-DemoAppUITests.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
Expand Down Expand Up @@ -375,9 +383,11 @@
isa = PBXNativeTarget;
buildConfigurationList = 351790D7293822A200ABBCC9 /* Build configuration list for PBXNativeTarget "DemoAppUITests" */;
buildPhases = (
0AD3FB6282256E36F4A4D9B9 /* [CP] Check Pods Manifest.lock */,
351790C3293822A200ABBCC9 /* Sources */,
351790C4293822A200ABBCC9 /* Frameworks */,
351790C5293822A200ABBCC9 /* Resources */,
D71F78E24DB087A6F231899A /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
Expand Down Expand Up @@ -498,6 +508,28 @@
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
0AD3FB6282256E36F4A4D9B9 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-DemoAppUITests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
50EA43BD8874A3F8D9933A45 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
Expand Down Expand Up @@ -566,6 +598,30 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
D71F78E24DB087A6F231899A /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-DemoAppUITests/Pods-DemoAppUITests-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/Mux-Stats-Google-IMA-iOS/MuxStatsGoogleIMAPlugin.framework",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAds-IMA-iOS-SDK/GoogleInteractiveMediaAds.framework/GoogleInteractiveMediaAds",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/Mux-Stats-AVPlayer/MUXSDKStats.framework/MUXSDKStats",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/Mux-Stats-Core/MuxCore.framework/MuxCore",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MuxStatsGoogleIMAPlugin.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleInteractiveMediaAds.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MUXSDKStats.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MuxCore.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-DemoAppUITests/Pods-DemoAppUITests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
D8DDAB152CFE634C8615554D /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
Expand Down Expand Up @@ -1100,6 +1156,7 @@
};
351790D3293822A200ABBCC9 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = E21C226A97A08CF45802D6D0 /* Pods-DemoAppUITests.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CLANG_ANALYZER_NONNULL = YES;
Expand Down Expand Up @@ -1145,6 +1202,7 @@
};
351790D4293822A200ABBCC9 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9BFD2676DCFF3512F5D69415 /* Pods-DemoAppUITests.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CLANG_ANALYZER_NONNULL = YES;
Expand Down
2 changes: 1 addition & 1 deletion Example/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ target 'MUXSDKIMATVOSExample' do
pod 'Mux-Stats-Google-IMA', :path => '../'
end

target 'DemoAppTests' do
target 'DemoAppUITests' do
platform :ios, '12.0'
pod 'Mux-Stats-Google-IMA', :path => '../'
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,21 @@ class PlayerContainerViewController: UIViewController {
// MARK: Setup Content Player
playerViewController.player = contentPlayer

// MARK: Setup Mux Data
NotificationCenter.default.addObserver(
self,
selector: #selector(Self.handleContentDidFinishPlaying(_:)),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: contentPlayer.currentItem)

// MARK: Setup Google IMA Ads
contentPlayhead = IMAAVPlayerContentPlayhead(
avPlayer: contentPlayer
)

adsLoader = IMAAdsLoader(settings: IMASettings())
adsLoader.delegate = self

// MARK: Setup Mux Data
guard let environmentKey = ProcessInfo.processInfo.environmentKey else {
return
}
Expand All @@ -74,28 +87,15 @@ class PlayerContainerViewController: UIViewController {
}

// MARK: Setup Mux Data IMA Plugin

imaListener = MuxImaListener(
playerBinding: playerBinding
)

NotificationCenter.default.addObserver(
self,
selector: #selector(Self.handleContentDidFinishPlaying(_:)),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: contentPlayer.currentItem)

// MARK: Setup Google IMA Ads

contentPlayhead = IMAAVPlayerContentPlayhead(
avPlayer: contentPlayer
playerBinding: playerBinding,
monitoringAdsLoader: adsLoader
)

// TODO: viewWillAppear?
showContentPlayer()

adsLoader = IMAAdsLoader(settings: IMASettings())
adsLoader.delegate = self
}

override func viewWillAppear() {
daytime-em marked this conversation as resolved.
Show resolved Hide resolved
super. viewWillAppear(animated)
showContentPlayer()
}

// MARK: Show and hide content player
Expand Down Expand Up @@ -168,7 +168,11 @@ extension PlayerContainerViewController: IMAAdsLoaderDelegate {
}

loadedAdsManager.delegate = self


// MARK: Monitor the IMAAdsManager with Mux
// note - do this *after* setting your delegate but *before*
imaListener?.monitorAdsManager(loadedAdsManager)

let renderingSettings = IMAAdsRenderingSettings()
renderingSettings.enablePreloading = true;
loadedAdsManager.initialize(
Expand All @@ -195,9 +199,6 @@ extension PlayerContainerViewController: IMAAdsManagerDelegate {
_ adsManager: IMAAdsManager,
didReceive event: IMAAdEvent
) {

imaListener?.dispatchEvent(event)

// Play each ad once it has been loaded
if event.type == IMAAdEventType.LOADED {
adsManager.start()
Expand All @@ -212,8 +213,6 @@ extension PlayerContainerViewController: IMAAdsManagerDelegate {
showContentPlayer()
contentPlayer.play()

imaListener?.dispatchError(error.message ?? "nil")

if let message = error.message {
print("AdsManager error: \(message)")
}
Expand All @@ -227,7 +226,6 @@ extension PlayerContainerViewController: IMAAdsManagerDelegate {
playerViewController.player?.pause()

hideContentPlayer()
imaListener?.dispatchPauseOrResume(true)
}

func adsManagerDidRequestContentResume(_ adsManager: IMAAdsManager) {
Expand All @@ -237,7 +235,5 @@ extension PlayerContainerViewController: IMAAdsManagerDelegate {

showContentPlayer()
contentPlayer.play()

imaListener?.dispatchPauseOrResume(false)
}
}
Loading
Loading