From 57c82330cb56c324772ddc4a7a90bd6d81c1cbb7 Mon Sep 17 00:00:00 2001 From: Kelly Dun Date: Mon, 19 Jun 2017 11:37:33 -0700 Subject: [PATCH 1/3] 4.15.0 --- .../Facebook/FacebookBannerCustomEvent.m | 11 ++- .../FacebookInterstitialCustomEvent.m | 5 + CHANGELOG.md | 5 + MoPubSDK.xcodeproj/project.pbxproj | 28 +++++- MoPubSDK/Internal/Common/MPAdConfiguration.h | 2 + MoPubSDK/Internal/Common/MPAdConfiguration.m | 25 +++++ .../Common/MPAdDestinationDisplayAgent.h | 7 ++ .../Common/MPAdDestinationDisplayAgent.m | 94 ++++++++++++++---- MoPubSDK/Internal/Common/MPURLResolver.m | 42 ++++++++ .../Utility/MOPUBExperimentProvider.h | 16 ++++ .../Utility/MOPUBExperimentProvider.m | 39 ++++++++ MoPubSDK/MPConstants.h | 2 +- MoPubSDK/MoPub.h | 12 +++ MoPubSDK/MoPub.m | 6 ++ .../MOPUBExperimentProvider+Testing.h | 14 +++ MoPubSDKTests/MOPUBExperimentProviderTests.m | 70 ++++++++++++++ MoPubSDKTests/MPAdConfiguration+Testing.h | 14 +++ MoPubSDKTests/MPAdConfiguration+Testing.m | 14 +++ MoPubSDKTests/MPAdConfigurationTests.m | 2 + MoPubSDKTests/MPURLResolverTests.m | 95 +++++++++++++++++++ MoPubSampleApp.xcodeproj/project.pbxproj | 12 +++ MoPubSampleApp/AppDelegate.m | 8 ++ README.md | 13 +-- SampleApps/SwiftSampleApp/Podfile.lock | 42 ++++---- 24 files changed, 521 insertions(+), 57 deletions(-) create mode 100644 MoPubSDK/Internal/Utility/MOPUBExperimentProvider.h create mode 100644 MoPubSDK/Internal/Utility/MOPUBExperimentProvider.m create mode 100644 MoPubSDKTests/MOPUBExperimentProvider+Testing.h create mode 100644 MoPubSDKTests/MOPUBExperimentProviderTests.m create mode 100644 MoPubSDKTests/MPAdConfiguration+Testing.h create mode 100644 MoPubSDKTests/MPAdConfiguration+Testing.m create mode 100644 MoPubSDKTests/MPURLResolverTests.m diff --git a/AdNetworkSupport/Facebook/FacebookBannerCustomEvent.m b/AdNetworkSupport/Facebook/FacebookBannerCustomEvent.m index 06830d861..3f4ce340b 100644 --- a/AdNetworkSupport/Facebook/FacebookBannerCustomEvent.m +++ b/AdNetworkSupport/Facebook/FacebookBannerCustomEvent.m @@ -107,19 +107,24 @@ - (void)dealloc #pragma mark FBAdViewDelegate methods -- (void)adView:(FBAdView *)adView didFailWithError:(NSError *)error; +- (void)adView:(FBAdView *)adView didFailWithError:(NSError *)error { MPLogInfo(@"Facebook banner failed to load with error: %@", error.description); [self.delegate bannerCustomEvent:self didFailToLoadAdWithError:error]; } -- (void)adViewDidLoad:(FBAdView *)adView; +- (void)adViewDidLoad:(FBAdView *)adView { MPLogInfo(@"Facebook banner ad did load"); - [self.delegate trackImpression]; [self.delegate bannerCustomEvent:self didLoadAd:adView]; } +- (void)adViewWillLogImpression:(FBAdView *)adView +{ + MPLogInfo(@"Facebook banner ad did log impression"); + [self.delegate trackImpression]; +} + - (void)adViewDidClick:(FBAdView *)adView { MPLogInfo(@"Facebook banner ad was clicked"); diff --git a/AdNetworkSupport/Facebook/FacebookInterstitialCustomEvent.m b/AdNetworkSupport/Facebook/FacebookInterstitialCustomEvent.m index 2a624ff52..ba763cedc 100644 --- a/AdNetworkSupport/Facebook/FacebookInterstitialCustomEvent.m +++ b/AdNetworkSupport/Facebook/FacebookInterstitialCustomEvent.m @@ -81,6 +81,11 @@ - (void)interstitialAdDidLoad:(FBInterstitialAd *)interstitialAd [self.delegate interstitialCustomEvent:self didLoadAd:interstitialAd]; } +- (void)interstitialAdWillLogImpression:(FBInterstitialAd *)interstitialAd +{ + MPLogInfo(@"Facebook intersitital ad is logging impressions for interstitials"); +} + - (void)interstitialAd:(FBInterstitialAd *)interstitialAd didFailWithError:(NSError *)error { MPLogInfo(@"Facebook intersitital ad failed to load with error: %@", error.description); diff --git a/CHANGELOG.md b/CHANGELOG.md index 8707cd778..77b21a440 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## Version 4.15.0 (June 19th, 2017) +- **Bug Fixes** +- Updated Facebook Audience Network banner and interstitial impression tracking +- Allow taps to pass through the gradient overlays for rewarded videos + ## Version 4.14.0 (May 10th, 2017) - **Features** - For Rewarded ads, the client-side callback will now be invoked when using server-side rewarding. diff --git a/MoPubSDK.xcodeproj/project.pbxproj b/MoPubSDK.xcodeproj/project.pbxproj index 915521a52..635329163 100644 --- a/MoPubSDK.xcodeproj/project.pbxproj +++ b/MoPubSDK.xcodeproj/project.pbxproj @@ -985,6 +985,11 @@ B294E06A1BACDB1E00909531 /* MOPUBNativeVideoAdRendererSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = B294E0661BACDB1E00909531 /* MOPUBNativeVideoAdRendererSettings.m */; }; B294E06B1BACDB1E00909531 /* MOPUBNativeVideoAdRendererSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = B294E0661BACDB1E00909531 /* MOPUBNativeVideoAdRendererSettings.m */; }; B2C14D8A1C98C3B600F3D554 /* CedarApplicationDelegate+MPSpecs.m in Sources */ = {isa = PBXBuildFile; fileRef = B2C14D891C98C3B600F3D554 /* CedarApplicationDelegate+MPSpecs.m */; }; + B2D54B561ED20521004E3C7B /* MOPUBExperimentProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D54B551ED20521004E3C7B /* MOPUBExperimentProvider.m */; }; + B2D54B621ED2058E004E3C7B /* SafariServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2D54B611ED2058E004E3C7B /* SafariServices.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + B2D54B651ED20B80004E3C7B /* MPAdConfiguration+Testing.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D54B641ED20B80004E3C7B /* MPAdConfiguration+Testing.m */; }; + B2D54B671ED20C95004E3C7B /* MOPUBExperimentProviderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D54B661ED20C95004E3C7B /* MOPUBExperimentProviderTests.m */; }; + B2D54B691ED20FA1004E3C7B /* MPURLResolverTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D54B681ED20FA1004E3C7B /* MPURLResolverTests.m */; }; B2E3F54E1BAB8529000BB32D /* MOPUBNativeVideoAdRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E3F53C1BAB8529000BB32D /* MOPUBNativeVideoAdRenderer.m */; }; B2E3F54F1BAB8529000BB32D /* MOPUBNativeVideoAdRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E3F53C1BAB8529000BB32D /* MOPUBNativeVideoAdRenderer.m */; }; B2E3F5501BAB8529000BB32D /* MOPUBNativeVideoAdRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E3F53C1BAB8529000BB32D /* MOPUBNativeVideoAdRenderer.m */; }; @@ -2029,6 +2034,7 @@ B257A3061BA3911300F5D320 /* MPUnmutedBtn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = MPUnmutedBtn.png; sourceTree = ""; }; B257A3071BA3911300F5D320 /* MPUnmutedBtn@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MPUnmutedBtn@2x.png"; sourceTree = ""; }; B257A3081BA3911300F5D320 /* MPUnmutedBtn@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MPUnmutedBtn@3x.png"; sourceTree = ""; }; + B2745AA41EEB195300A86A5B /* MOPUBExperimentProvider+Testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MOPUBExperimentProvider+Testing.h"; sourceTree = ""; }; B27783881CE3BA5C00BAB0B1 /* MPRewardedVideoConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRewardedVideoConnection.h; sourceTree = ""; }; B27783891CE3BA5C00BAB0B1 /* MPRewardedVideoConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRewardedVideoConnection.m; sourceTree = ""; }; B27783A01CE3D47400BAB0B1 /* MPRewardedVideoConnectionSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MPRewardedVideoConnectionSpec.mm; sourceTree = ""; }; @@ -2040,6 +2046,13 @@ B294E0661BACDB1E00909531 /* MOPUBNativeVideoAdRendererSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MOPUBNativeVideoAdRendererSettings.m; sourceTree = ""; }; B2C14D881C98C3B600F3D554 /* CedarApplicationDelegate+MPSpecs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CedarApplicationDelegate+MPSpecs.h"; sourceTree = ""; }; B2C14D891C98C3B600F3D554 /* CedarApplicationDelegate+MPSpecs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CedarApplicationDelegate+MPSpecs.m"; sourceTree = ""; }; + B2D54B541ED20521004E3C7B /* MOPUBExperimentProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MOPUBExperimentProvider.h; path = Internal/Utility/MOPUBExperimentProvider.h; sourceTree = ""; }; + B2D54B551ED20521004E3C7B /* MOPUBExperimentProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MOPUBExperimentProvider.m; path = Internal/Utility/MOPUBExperimentProvider.m; sourceTree = ""; }; + B2D54B611ED2058E004E3C7B /* SafariServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SafariServices.framework; path = System/Library/Frameworks/SafariServices.framework; sourceTree = SDKROOT; }; + B2D54B631ED20B80004E3C7B /* MPAdConfiguration+Testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MPAdConfiguration+Testing.h"; sourceTree = ""; }; + B2D54B641ED20B80004E3C7B /* MPAdConfiguration+Testing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MPAdConfiguration+Testing.m"; sourceTree = ""; }; + B2D54B661ED20C95004E3C7B /* MOPUBExperimentProviderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MOPUBExperimentProviderTests.m; sourceTree = ""; }; + B2D54B681ED20FA1004E3C7B /* MPURLResolverTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPURLResolverTests.m; sourceTree = ""; }; B2E3F53B1BAB8529000BB32D /* MOPUBNativeVideoAdRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MOPUBNativeVideoAdRenderer.h; sourceTree = ""; }; B2E3F53C1BAB8529000BB32D /* MOPUBNativeVideoAdRenderer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MOPUBNativeVideoAdRenderer.m; sourceTree = ""; }; B2E47F641C7E362A00DE5EA6 /* MPMoPubRewardedVideoCustomEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPMoPubRewardedVideoCustomEvent.h; sourceTree = ""; }; @@ -2132,6 +2145,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + B2D54B621ED2058E004E3C7B /* SafariServices.framework in Frameworks */, BC8621371DCBE0EC0012275D /* MediaPlayer.framework in Frameworks */, BC8621361DCBE0DA0012275D /* SystemConfiguration.framework in Frameworks */, BC8621351DCBE0C70012275D /* MessageUI.framework in Frameworks */, @@ -2258,6 +2272,8 @@ 2AF177321E9846A000A600BD /* MPRewardedVideoAdapterTests.m */, 2A922D391E9C4CF900F83923 /* MPInterstitialCustomEventAdapterTests.m */, 2AFF1BA61EC289E600495994 /* MPRealTimeTimerTests.m */, + B2D54B661ED20C95004E3C7B /* MOPUBExperimentProviderTests.m */, + B2D54B681ED20FA1004E3C7B /* MPURLResolverTests.m */, ); path = MoPubSDKTests; sourceTree = ""; @@ -3060,6 +3076,7 @@ AEF1F32A16EF9AD700273462 /* Frameworks */ = { isa = PBXGroup; children = ( + B2D54B611ED2058E004E3C7B /* SafariServices.framework */, BC86212F1DCBE0590012275D /* CoreMotion.framework */, BC86212A1DCBE00D0012275D /* AVKit.framework */, AEE38886171F4EEE0019601C /* AddressBook.framework */, @@ -3099,6 +3116,8 @@ AEF9D4C6171CA895005AAA5A /* MoPubSDK */ = { isa = PBXGroup; children = ( + B2D54B541ED20521004E3C7B /* MOPUBExperimentProvider.h */, + B2D54B551ED20521004E3C7B /* MOPUBExperimentProvider.m */, B27114991B8549ED0066CE82 /* NativeVideo */, 57ACE3ED1AA7E8D900A05633 /* RewardedVideo */, A77FBED818C533B400531E8A /* Native Ads */, @@ -3865,8 +3884,8 @@ BCAED25F1DF628D400D45480 /* MPMoPubRewardedPlayableCustomEvent+Testing.h */, BCAED2601DF628D400D45480 /* MPMoPubRewardedPlayableCustomEvent+Testing.m */, BC246A771E5675CB00CEFA33 /* MPRewardedVideoAdManager+Testing.h */, - BC246A781E5675CB00CEFA33 /* MPRewardedVideoAdManager+Testing.m */, BCAC6F6C1E5D0730002B2656 /* MPRewardedVideo+Testing.h */, + BC246A781E5675CB00CEFA33 /* MPRewardedVideoAdManager+Testing.m */, BCAC6F6D1E5D0730002B2656 /* MPRewardedVideo+Testing.m */, BCB43DCC1E5F932000A95E22 /* NSURLComponents+Testing.h */, BCB43DCD1E5F932000A95E22 /* NSURLComponents+Testing.m */, @@ -3878,6 +3897,9 @@ 2AB6301B1E9C2D0C00B0DDC7 /* MPConstants+Testing.m */, 2AE45D3C1E9D8FFA00ED5DD2 /* MPInterstitialCustomEventAdapter+Testing.h */, 2AE45D3D1E9D8FFA00ED5DD2 /* MPInterstitialCustomEventAdapter+Testing.m */, + B2D54B631ED20B80004E3C7B /* MPAdConfiguration+Testing.h */, + B2D54B641ED20B80004E3C7B /* MPAdConfiguration+Testing.m */, + B2745AA41EEB195300A86A5B /* MOPUBExperimentProvider+Testing.h */, ); name = Categories; sourceTree = ""; @@ -4385,13 +4407,16 @@ BC08C7831E36AD7C00444F16 /* MPVASTLinearAdTests.m in Sources */, 2AE45D3E1E9D8FFA00ED5DD2 /* MPInterstitialCustomEventAdapter+Testing.m in Sources */, 2AF177441E984DED00A600BD /* MPRewardedVideoAdapterDelegateHandler.m in Sources */, + B2D54B671ED20C95004E3C7B /* MOPUBExperimentProviderTests.m in Sources */, B23C3B641E3588190003D79E /* MPAdConfigurationFactory.m in Sources */, BCAED2541DF6194E00D45480 /* MPMoPubRewardedPlayableCustomEventTests.m in Sources */, + B2D54B691ED20FA1004E3C7B /* MPURLResolverTests.m in Sources */, BC246A7C1E56795000CEFA33 /* MPRewardedVideoDelegateHandler.m in Sources */, 2AE45D3B1E9D882B00ED5DD2 /* MPInterstitialAdapterDelegateHandler.m in Sources */, BCAED2611DF628D400D45480 /* MPMoPubRewardedPlayableCustomEvent+Testing.m in Sources */, BC246A6C1E5672AA00CEFA33 /* MPRewardedVideoAdManagerTests.m in Sources */, BCAC6F5E1E5CF6F5002B2656 /* MPRewardedVideoTests.m in Sources */, + B2D54B651ED20B80004E3C7B /* MPAdConfiguration+Testing.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4582,6 +4607,7 @@ AE515F47171F1B110086B464 /* MPBaseBannerAdapter.m in Sources */, B294E0681BACDB1E00909531 /* MOPUBNativeVideoAdRendererSettings.m in Sources */, A7759F061A1EB19500087E00 /* MPGeolocationProvider.m in Sources */, + B2D54B561ED20521004E3C7B /* MOPUBExperimentProvider.m in Sources */, 57E6B8801BA25B4B001FE403 /* MPNativeAd+Internal.m in Sources */, 573A82F71B8E488400ED4067 /* MPNativeView.m in Sources */, A776A5561B5DDFD800095706 /* MPVASTCompanionAd.m in Sources */, diff --git a/MoPubSDK/Internal/Common/MPAdConfiguration.h b/MoPubSDK/Internal/Common/MPAdConfiguration.h index f9432ae82..5fa8b1e11 100644 --- a/MoPubSDK/Internal/Common/MPAdConfiguration.h +++ b/MoPubSDK/Internal/Common/MPAdConfiguration.h @@ -55,6 +55,8 @@ extern NSString * const kAdTypeClear; extern NSString * const kAdTypeNative; extern NSString * const kAdTypeNativeVideo; +extern NSString * const kClickthroughExperimentBrowserAgent; + @interface MPAdConfiguration : NSObject @property (nonatomic, assign) MPAdType adType; diff --git a/MoPubSDK/Internal/Common/MPAdConfiguration.m b/MoPubSDK/Internal/Common/MPAdConfiguration.m index 9a2a72d8d..cc295622e 100644 --- a/MoPubSDK/Internal/Common/MPAdConfiguration.m +++ b/MoPubSDK/Internal/Common/MPAdConfiguration.m @@ -12,6 +12,7 @@ #import "math.h" #import "NSJSONSerialization+MPAdditions.h" #import "MPRewardedVideoReward.h" +#import "MOPUBExperimentProvider.h" #if MP_HAS_NATIVE_PACKAGE #import "MPVASTTrackingEvent.h" @@ -73,11 +74,16 @@ NSString * const kNativeVideoTrackerEventDictionaryKey = @"event"; NSString * const kNativeVideoTrackerTextDictionaryKey = @"text"; +// clickthrough experiment +NSString * const kClickthroughExperimentBrowserAgent = @"X-Browser-Agent"; +static const NSInteger kMaximumVariantForClickthroughExperiment = 2; + @interface MPAdConfiguration () @property (nonatomic, copy) NSString *adResponseHTMLString; @property (nonatomic, strong, readwrite) NSArray *availableRewards; +@property (nonatomic) MOPUBDisplayAgentType clickthroughExperimentBrowserAgent; - (MPAdType)adTypeFromHeaders:(NSDictionary *)headers; - (NSString *)networkTypeFromHeaders:(NSDictionary *)headers; @@ -199,6 +205,10 @@ - (id)initWithHeaders:(NSDictionary *)headers data:(NSData *)data // rewarded playables self.rewardedPlayableDuration = [self timeIntervalFromHeaders:headers forKey:kRewardedPlayableDurationHeaderKey]; self.rewardedPlayableShouldRewardOnClick = [[headers objectForKey:kRewardedPlayableRewardOnClickHeaderKey] boolValue]; + + // clickthrough experiment + self.clickthroughExperimentBrowserAgent = [self clickthroughExperimentVariantFromHeaders:headers forKey:kClickthroughExperimentBrowserAgent]; + [MOPUBExperimentProvider setDisplayAgentFromAdServer:self.clickthroughExperimentBrowserAgent]; } return self; } @@ -466,4 +476,19 @@ - (NSArray *)parseAvailableRewardsFromHeaders:(NSDictionary *)headers { return availableRewards; } +- (MOPUBDisplayAgentType)clickthroughExperimentVariantFromHeaders:(NSDictionary *)headers forKey:(NSString *)key +{ + NSString *variantString = [headers objectForKey:key]; + NSInteger variant = 0; + if (variantString) { + int parsedInt = -1; + BOOL isNumber = [[NSScanner scannerWithString:variantString] scanInt:&parsedInt]; + if (isNumber && parsedInt >= 0 && parsedInt <= kMaximumVariantForClickthroughExperiment) { + variant = parsedInt; + } + } + + return variant; +} + @end diff --git a/MoPubSDK/Internal/Common/MPAdDestinationDisplayAgent.h b/MoPubSDK/Internal/Common/MPAdDestinationDisplayAgent.h index ff7b3fb54..04c263256 100644 --- a/MoPubSDK/Internal/Common/MPAdDestinationDisplayAgent.h +++ b/MoPubSDK/Internal/Common/MPAdDestinationDisplayAgent.h @@ -12,6 +12,12 @@ #import "MPAdBrowserController.h" #import "MPStoreKitProvider.h" +typedef NS_ENUM(NSInteger, MOPUBDisplayAgentType) { + MOPUBDisplayAgentTypeInApp = 0, + MOPUBDisplayAgentTypeNativeSafari, + MOPUBDisplayAgentTypeSafariViewController +}; + @protocol MPAdDestinationDisplayAgentDelegate; @interface MPAdDestinationDisplayAgent : NSObject delegate; + (MPAdDestinationDisplayAgent *)agentWithDelegate:(id)delegate; ++ (BOOL)shouldUseSafariViewController; - (void)displayDestinationForURL:(NSURL *)URL; - (void)cancel; diff --git a/MoPubSDK/Internal/Common/MPAdDestinationDisplayAgent.m b/MoPubSDK/Internal/Common/MPAdDestinationDisplayAgent.m index f906aea8d..3857be50a 100644 --- a/MoPubSDK/Internal/Common/MPAdDestinationDisplayAgent.m +++ b/MoPubSDK/Internal/Common/MPAdDestinationDisplayAgent.m @@ -12,23 +12,28 @@ #import "NSURL+MPAdditions.h" #import "MPCoreInstanceProvider.h" #import "MPAnalyticsTracker.h" +#import "MOPUBExperimentProvider.h" +#import static NSString * const kDisplayAgentErrorDomain = @"com.mopub.displayagent"; //////////////////////////////////////////////////////////////////////////////////////////////////// -@interface MPAdDestinationDisplayAgent () +@interface MPAdDestinationDisplayAgent () @property (nonatomic, strong) MPURLResolver *resolver; @property (nonatomic, strong) MPURLResolver *enhancedDeeplinkFallbackResolver; @property (nonatomic, strong) MPProgressOverlayView *overlayView; @property (nonatomic, assign) BOOL isLoadingDestination; +@property (nonatomic) MOPUBDisplayAgentType displayAgentType; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= MP_IOS_6_0 @property (nonatomic, strong) SKStoreProductViewController *storeKitController; #endif @property (nonatomic, strong) MPAdBrowserController *browserController; +@property (nonatomic, strong) SFSafariViewController *safariController; + @property (nonatomic, strong) MPTelephoneConfirmationController *telephoneConfirmationController; @property (nonatomic, strong) MPActivityViewControllerHelper *activityViewControllerHelper; @@ -53,6 +58,7 @@ + (MPAdDestinationDisplayAgent *)agentWithDelegate:(id + +- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller { + self.isLoadingDestination = NO; + [self.delegate displayAgentDidDismissModal]; +} + #pragma mark - - (void)overlayCancelButtonPressed @@ -345,6 +369,16 @@ - (void)hideModalAndNotifyDelegate }]; } ++ (BOOL)shouldUseSafariViewController +{ + MOPUBDisplayAgentType displayAgentType = [MOPUBExperimentProvider displayAgentType]; + if ([SFSafariViewController class] && displayAgentType == MOPUBDisplayAgentTypeSafariViewController) { + return YES; + } + + return NO; +} + - (void)hideOverlay { [self.overlayView hide]; @@ -369,4 +403,22 @@ - (void)activityViewControllerDidDismiss [self.delegate displayAgentDidDismissModal]; } +#pragma mark - Experiment with 3 display agent types: 0 -> keep existing, 1 -> use native safari, 2 -> use SafariViewController + +- (void)showStoreKitWithAction:(MPURLActionInfo *)actionInfo +{ + switch (self.displayAgentType) { + case MOPUBDisplayAgentTypeInApp: + case MOPUBDisplayAgentTypeSafariViewController: // It doesn't make sense to open store kit in SafariViewController so storeKitController is used here. + [self showStoreKitProductWithParameter:actionInfo.iTunesItemIdentifier + fallbackURL:actionInfo.iTunesStoreFallbackURL]; + break; + case MOPUBDisplayAgentTypeNativeSafari: + [self openURLInApplication:actionInfo.iTunesStoreFallbackURL]; + break; + default: + break; + } +} + @end diff --git a/MoPubSDK/Internal/Common/MPURLResolver.m b/MoPubSDK/Internal/Common/MPURLResolver.m index 8eb655219..beec27e2f 100644 --- a/MoPubSDK/Internal/Common/MPURLResolver.m +++ b/MoPubSDK/Internal/Common/MPURLResolver.m @@ -12,10 +12,15 @@ #import "MPInstanceProvider.h" #import "MPLogging.h" #import "MPCoreInstanceProvider.h" +#import "MOPUBExperimentProvider.h" +#import "NSURL+MPAdditions.h" static NSString * const kMoPubSafariScheme = @"mopubnativebrowser"; static NSString * const kMoPubSafariNavigateHost = @"navigate"; static NSString * const kResolverErrorDomain = @"com.mopub.resolver"; +static NSString * const kWebviewClickthroughHost = @"ads.mopub.com"; +static NSString * const kWebviewClickthroughPath = @"/m/aclk"; +static NSString * const kRedirectURLQueryStringKey = @"r"; @interface MPURLResolver () @@ -68,6 +73,9 @@ - (void)start if (info) { [self safeInvokeAndNilCompletionBlock:info error:nil]; + } else if ([self shouldEnableClickthroughExperiment]) { + MPURLActionInfo *info = [MPURLActionInfo infoWithURL:self.originalURL webViewBaseURL:self.currentURL]; + [self safeInvokeAndNilCompletionBlock:info error:nil]; } else if (error) { [self safeInvokeAndNilCompletionBlock:nil error:error]; } else { @@ -283,4 +291,38 @@ - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)err [self safeInvokeAndNilCompletionBlock:nil error:error]; } +#pragma mark - Check if it's necessary to include a URL in the clickthrough experiment. +// There are two types of clickthrough URL sources: from webviews and from non-web views. +// The ones from webviews start with (https|http)://ads.mopub.com/m/aclk +// For webviews, in order for a URL to be included in the clickthrough experiment, redirect URL scheme needs to be http/https. + +- (BOOL)shouldEnableClickthroughExperiment +{ + if (!self.currentURL) { + return NO; + } + + // If redirect URL isn't http/https, do not include it in the clickthrough experiment. + if (![self URLIsHTTPOrHTTPS:self.currentURL]) { + return NO; + } + + // Clickthroughs from webviews + if ([self.currentURL.host isEqualToString:kWebviewClickthroughHost] && + [self.currentURL.path isEqualToString:kWebviewClickthroughPath]) { + + NSString *redirectURLStr = [self.currentURL mp_queryParameterForKey:kRedirectURLQueryStringKey]; + if (!redirectURLStr || ![self URLIsHTTPOrHTTPS:[NSURL URLWithString:redirectURLStr]]) { + return NO; + } + } + + // Check experiment variant is in test group. + if ([MPAdDestinationDisplayAgent shouldUseSafariViewController] || + [MOPUBExperimentProvider displayAgentType] == MOPUBDisplayAgentTypeNativeSafari) { + return YES; + } + return NO; +} + @end diff --git a/MoPubSDK/Internal/Utility/MOPUBExperimentProvider.h b/MoPubSDK/Internal/Utility/MOPUBExperimentProvider.h new file mode 100644 index 000000000..6f2dbb82f --- /dev/null +++ b/MoPubSDK/Internal/Utility/MOPUBExperimentProvider.h @@ -0,0 +1,16 @@ +// +// MOPUBExperimentProvider.h +// MoPub +// +// Copyright © 2017 MoPub. All rights reserved. +// + +#import "MPAdDestinationDisplayAgent.h" + +@interface MOPUBExperimentProvider : NSObject + ++ (void)setDisplayAgentType:(MOPUBDisplayAgentType)displayAgentType; ++ (void)setDisplayAgentFromAdServer:(MOPUBDisplayAgentType)displayAgentType; ++ (MOPUBDisplayAgentType)displayAgentType; + +@end diff --git a/MoPubSDK/Internal/Utility/MOPUBExperimentProvider.m b/MoPubSDK/Internal/Utility/MOPUBExperimentProvider.m new file mode 100644 index 000000000..4d05b4013 --- /dev/null +++ b/MoPubSDK/Internal/Utility/MOPUBExperimentProvider.m @@ -0,0 +1,39 @@ +// +// MOPUBExperimentProvider.m +// MoPubSampleApp +// +// Copyright © 2017 MoPub. All rights reserved. +// + +#import "MOPUBExperimentProvider.h" + +@implementation MOPUBExperimentProvider + +static BOOL gIsDisplayAgentOverriddenByClient = NO; +static MOPUBDisplayAgentType gDisplayAgentType = MOPUBDisplayAgentTypeInApp; + ++ (void)setDisplayAgentType:(MOPUBDisplayAgentType)displayAgentType +{ + gIsDisplayAgentOverriddenByClient = YES; + gDisplayAgentType = displayAgentType; +} + ++ (void)setDisplayAgentFromAdServer:(MOPUBDisplayAgentType)displayAgentType +{ + if (!gIsDisplayAgentOverriddenByClient) { + gDisplayAgentType = displayAgentType; + } +} + ++ (MOPUBDisplayAgentType)displayAgentType +{ + return gDisplayAgentType; +} + +// used in test only ++ (void)setDisplayAgentOverriddenByClientFlag:(BOOL)flag +{ + gIsDisplayAgentOverriddenByClient = flag; +} + +@end diff --git a/MoPubSDK/MPConstants.h b/MoPubSDK/MPConstants.h index c80d82148..0cbe3e5c7 100644 --- a/MoPubSDK/MPConstants.h +++ b/MoPubSDK/MPConstants.h @@ -14,7 +14,7 @@ #define DEFAULT_PUB_ID @"agltb3B1Yi1pbmNyDAsSBFNpdGUYkaoMDA" #define MP_SERVER_VERSION @"8" #define MP_BUNDLE_IDENTIFIER @"com.mopub.mopub" -#define MP_SDK_VERSION @"4.14.0" +#define MP_SDK_VERSION @"4.15.0" // Sizing constants. extern CGSize const MOPUB_BANNER_SIZE; diff --git a/MoPubSDK/MoPub.h b/MoPubSDK/MoPub.h index b815d8956..f1b6b8a65 100644 --- a/MoPubSDK/MoPub.h +++ b/MoPubSDK/MoPub.h @@ -19,6 +19,7 @@ #import "MPRewardedVideoReward.h" #import "MPRewardedVideoCustomEvent.h" #import "MPRewardedVideoError.h" +#import "MPAdDestinationDisplayAgent.h" #if MP_HAS_NATIVE_PACKAGE #import "MPNativeAd.h" @@ -119,4 +120,15 @@ - (NSString *)version; - (NSString *)bundleIdentifier; +/** + * Default is MOPUBDisplayAgentTypeInApp = 0. + * + * If displayType is set to MOPUBDisplayAgentTypeNativeSafari = 1, http/https clickthrough URLs are opened in native + * safari browser. + * If displayType is set to MOPUBDisplayAgentTypeSafariViewController = 2, http/https clickthrough URLs are opened in + * SafariViewController. + * + */ +- (void)setClickthroughDisplayAgentType:(MOPUBDisplayAgentType)displayAgentType; + @end diff --git a/MoPubSDK/MoPub.m b/MoPubSDK/MoPub.m index 9662cf797..92d35b7a4 100644 --- a/MoPubSDK/MoPub.m +++ b/MoPubSDK/MoPub.m @@ -11,6 +11,7 @@ #import "MPGeolocationProvider.h" #import "MPRewardedVideo.h" #import "MPIdentityProvider.h" +#import "MOPUBExperimentProvider.h" @interface MoPub () @@ -45,6 +46,11 @@ - (void)setFrequencyCappingIdUsageEnabled:(BOOL)frequencyCappingIdUsageEnabled [MPIdentityProvider setFrequencyCappingIdUsageEnabled:frequencyCappingIdUsageEnabled]; } +- (void)setClickthroughDisplayAgentType:(MOPUBDisplayAgentType)displayAgentType +{ + [MOPUBExperimentProvider setDisplayAgentType:displayAgentType]; +} + - (BOOL)frequencyCappingIdUsageEnabled { return [MPIdentityProvider frequencyCappingIdUsageEnabled]; diff --git a/MoPubSDKTests/MOPUBExperimentProvider+Testing.h b/MoPubSDKTests/MOPUBExperimentProvider+Testing.h new file mode 100644 index 000000000..f55e2c5a2 --- /dev/null +++ b/MoPubSDKTests/MOPUBExperimentProvider+Testing.h @@ -0,0 +1,14 @@ +// +// MOPUBExperimentProvider+Testing.h +// MoPubSDK +// +// Copyright © 2017 MoPub. All rights reserved. +// + +#import "MOPUBExperimentProvider.h" + +@interface MOPUBExperimentProvider (Testing) + ++ (void)setDisplayAgentOverriddenByClientFlag:(BOOL)flag; + +@end diff --git a/MoPubSDKTests/MOPUBExperimentProviderTests.m b/MoPubSDKTests/MOPUBExperimentProviderTests.m new file mode 100644 index 000000000..b1563b4b5 --- /dev/null +++ b/MoPubSDKTests/MOPUBExperimentProviderTests.m @@ -0,0 +1,70 @@ +// +// MOPUBExperimentProviderTests.m +// MoPubSDK +// +// Copyright © 2017 MoPub. All rights reserved. +// + +#import +#import "MPAdConfiguration+Testing.h" +#import "MOPUBExperimentProvider.h" +#import "MoPub.h" +#import "MPAdConfiguration.h" +#import "MOPUBExperimentProvider+Testing.h" + +@interface MOPUBExperimentProviderTests : XCTestCase + +@end + +@implementation MOPUBExperimentProviderTests + +- (void)testClickthroughExperimentDefault { + [MOPUBExperimentProvider setDisplayAgentOverriddenByClientFlag:NO]; + MPAdConfiguration * config = [[MPAdConfiguration alloc] initWithHeaders:nil data:nil]; + XCTAssertEqual(config.clickthroughExperimentBrowserAgent, MOPUBDisplayAgentTypeInApp); + XCTAssertEqual([MOPUBExperimentProvider displayAgentType], MOPUBDisplayAgentTypeInApp); +} + +- (void)testClickthroughExperimentInApp { + [MOPUBExperimentProvider setDisplayAgentOverriddenByClientFlag:NO]; + NSDictionary * headers = @{ kClickthroughExperimentBrowserAgent: @"0"}; + MPAdConfiguration * config = [[MPAdConfiguration alloc] initWithHeaders:headers data:nil]; + XCTAssertEqual(config.clickthroughExperimentBrowserAgent, MOPUBDisplayAgentTypeInApp); + XCTAssertEqual([MOPUBExperimentProvider displayAgentType], MOPUBDisplayAgentTypeInApp); +} + +- (void)testClickthroughExperimentNativeBrowser { + [MOPUBExperimentProvider setDisplayAgentOverriddenByClientFlag:NO]; + NSDictionary * headers = @{ kClickthroughExperimentBrowserAgent: @"1"}; + MPAdConfiguration * config = [[MPAdConfiguration alloc] initWithHeaders:headers data:nil]; + XCTAssertEqual(config.clickthroughExperimentBrowserAgent, MOPUBDisplayAgentTypeNativeSafari); + XCTAssertEqual([MOPUBExperimentProvider displayAgentType], MOPUBDisplayAgentTypeNativeSafari); +} + +- (void)testClickthroughExperimentSafariViewController { + [MOPUBExperimentProvider setDisplayAgentOverriddenByClientFlag:NO]; + NSDictionary * headers = @{ kClickthroughExperimentBrowserAgent: @"2"}; + MPAdConfiguration * config = [[MPAdConfiguration alloc] initWithHeaders:headers data:nil]; + XCTAssertEqual(config.clickthroughExperimentBrowserAgent, MOPUBDisplayAgentTypeSafariViewController); + XCTAssertEqual([MOPUBExperimentProvider displayAgentType], MOPUBDisplayAgentTypeSafariViewController); +} + +- (void)testClickthroughClientOverride { + [[MoPub sharedInstance] setClickthroughDisplayAgentType:MOPUBDisplayAgentTypeInApp]; + + NSDictionary * headers = @{ kClickthroughExperimentBrowserAgent: @"2"}; + MPAdConfiguration * config = [[MPAdConfiguration alloc] initWithHeaders:headers data:nil]; + XCTAssertEqual(config.clickthroughExperimentBrowserAgent, MOPUBDisplayAgentTypeSafariViewController); + + XCTAssertEqual([MOPUBExperimentProvider displayAgentType], MOPUBDisplayAgentTypeInApp); + + // Display agent type is overridden to MOPUBDisplayAgentTypeSafariViewController + [[MoPub sharedInstance] setClickthroughDisplayAgentType:MOPUBDisplayAgentTypeSafariViewController]; + XCTAssertEqual([MOPUBExperimentProvider displayAgentType], MOPUBDisplayAgentTypeSafariViewController); + + // Display agent type is overridden to MOPUBDisplayAgentTypeNativeSafari + [[MoPub sharedInstance] setClickthroughDisplayAgentType:MOPUBDisplayAgentTypeNativeSafari]; + XCTAssertEqual([MOPUBExperimentProvider displayAgentType], MOPUBDisplayAgentTypeNativeSafari); +} + +@end diff --git a/MoPubSDKTests/MPAdConfiguration+Testing.h b/MoPubSDKTests/MPAdConfiguration+Testing.h new file mode 100644 index 000000000..0bc40d4cf --- /dev/null +++ b/MoPubSDKTests/MPAdConfiguration+Testing.h @@ -0,0 +1,14 @@ +// +// MPAdConfiguration+Testing.h +// MoPubSDK +// +// Copyright © 2017 MoPub. All rights reserved. +// + +#import "MPAdConfiguration.h" + +@interface MPAdConfiguration (Testing) + +@property (nonatomic) NSInteger clickthroughExperimentBrowserAgent; + +@end diff --git a/MoPubSDKTests/MPAdConfiguration+Testing.m b/MoPubSDKTests/MPAdConfiguration+Testing.m new file mode 100644 index 000000000..5dacf65a0 --- /dev/null +++ b/MoPubSDKTests/MPAdConfiguration+Testing.m @@ -0,0 +1,14 @@ +// +// MPAdConfiguration+Testing.m +// MoPubSDK +// +// Copyright © 2017 MoPub. All rights reserved. +// + +#import "MPAdConfiguration+Testing.h" + +@implementation MPAdConfiguration (Testing) + +@dynamic clickthroughExperimentBrowserAgent; + +@end diff --git a/MoPubSDKTests/MPAdConfigurationTests.m b/MoPubSDKTests/MPAdConfigurationTests.m index f51dcad0f..8c4a7171b 100644 --- a/MoPubSDKTests/MPAdConfigurationTests.m +++ b/MoPubSDKTests/MPAdConfigurationTests.m @@ -10,6 +10,8 @@ #import "MPAdConfigurationFactory.h" #import "MPVASTTrackingEvent.h" #import "MPRewardedVideoReward.h" +#import "MOPUBExperimentProvider.h" +#import "MPAdConfiguration+Testing.h" @interface MPAdConfigurationTests : XCTestCase diff --git a/MoPubSDKTests/MPURLResolverTests.m b/MoPubSDKTests/MPURLResolverTests.m new file mode 100644 index 000000000..ad5e331d6 --- /dev/null +++ b/MoPubSDKTests/MPURLResolverTests.m @@ -0,0 +1,95 @@ +// +// MPURLResolverTests.m +// MoPubSDK +// +// Copyright © 2017 MoPub. All rights reserved. +// + +#import +#import "MPURLResolver.h" +#import "MoPub.h" + +static NSString * const kWebviewClickthroughURLBase = @"https://ads.mopub.com/m/aclk?appid=&cid=dfc18f7f101e40489e2a091c845a1cab&city=Burlingame&ckv=2&country_code=US&cppck=4C7BD&dev=x86_64&exclude_adgroups=0769f1d048214c4f9ff4c05d9871a95b&id=abc6bfe824634bc1b70dfc2cc78c6940&is_mraid=0&os=iOS&osv=10.3.0&req=083033d5e9b9412f9b37ae08468191c7&reqt=1495340380.0&rev=0&udid=ifa%3A237E6BB9-EF1B-4287-B21E-42A39A69D3BB&video_type="; + +@interface MPURLResolver (Testing) + +- (BOOL)shouldEnableClickthroughExperiment; + +@end + +@interface MPURLResolverTests : XCTestCase + +@end + +@implementation MPURLResolverTests + +- (void)testResolverNonHttpNorHttps { + NSURL *url = [NSURL URLWithString:@"mopubnativebrowser://navigate?url=https://twitter.com"]; + MPURLResolver *resolver = [MPURLResolver resolverWithURL:url completion:nil]; + [resolver start]; + + + XCTAssertFalse([resolver shouldEnableClickthroughExperiment]); +} + +- (void)testHttpRedirectWithNativeSafari { + [[MoPub sharedInstance] setClickthroughDisplayAgentType:MOPUBDisplayAgentTypeNativeSafari]; + NSString *urlStr = [NSString stringWithFormat:@"%@%@", kWebviewClickthroughURLBase, @"&r=https%3A%2F%2Fwww.mopub.com%2F"]; + NSURL *url = [NSURL URLWithString:urlStr]; + MPURLResolver *resolver = [MPURLResolver resolverWithURL:url completion:nil]; + [resolver start]; + + XCTAssertTrue([resolver shouldEnableClickthroughExperiment]); +} + +- (void)testHttpRedirectWithInAppBrowser { + [[MoPub sharedInstance] setClickthroughDisplayAgentType:MOPUBDisplayAgentTypeInApp]; + NSString *urlStr = [NSString stringWithFormat:@"%@%@", kWebviewClickthroughURLBase, @"&r=https%3A%2F%2Fwww.mopub.com%2F"]; + NSURL *url = [NSURL URLWithString:urlStr]; + MPURLResolver *resolver = [MPURLResolver resolverWithURL:url completion:nil]; + [resolver start]; + + XCTAssertFalse([resolver shouldEnableClickthroughExperiment]); +} + +- (void)testMopubnativebrowserRedirectWithNativeSafari { + [[MoPub sharedInstance] setClickthroughDisplayAgentType:MOPUBDisplayAgentTypeNativeSafari]; + + NSString *urlStr = [NSString stringWithFormat:@"%@%@", kWebviewClickthroughURLBase, @"&r=mopubnativebrowser://navigate?url=https://twitter.com"]; + NSURL *url = [NSURL URLWithString:urlStr]; + MPURLResolver *resolver = [MPURLResolver resolverWithURL:url completion:nil]; + [resolver start]; + + XCTAssertFalse([resolver shouldEnableClickthroughExperiment]); +} + +- (void)testHttpNonRedirectWithNativeSafari { + [[MoPub sharedInstance] setClickthroughDisplayAgentType:MOPUBDisplayAgentTypeNativeSafari]; + NSURL *url = [NSURL URLWithString:kWebviewClickthroughURLBase]; + MPURLResolver *resolver = [MPURLResolver resolverWithURL:url completion:nil]; + [resolver start]; + + XCTAssertFalse([resolver shouldEnableClickthroughExperiment]); +} + +- (void)testNonWebviewWithNativeSafari { + [[MoPub sharedInstance] setClickthroughDisplayAgentType:MOPUBDisplayAgentTypeNativeSafari]; + + NSURL *url = [NSURL URLWithString:@"https://ads.mopub.com"]; + MPURLResolver *resolver = [MPURLResolver resolverWithURL:url completion:nil]; + [resolver start]; + + XCTAssertTrue([resolver shouldEnableClickthroughExperiment]); +} + +- (void)testNonWebviewWithInappBrowser { + [[MoPub sharedInstance] setClickthroughDisplayAgentType:MOPUBDisplayAgentTypeInApp]; + + NSURL *url = [NSURL URLWithString:@"https://ads.mopub.com"]; + MPURLResolver *resolver = [MPURLResolver resolverWithURL:url completion:nil]; + [resolver start]; + + XCTAssertFalse([resolver shouldEnableClickthroughExperiment]); +} + +@end diff --git a/MoPubSampleApp.xcodeproj/project.pbxproj b/MoPubSampleApp.xcodeproj/project.pbxproj index 8b9ce6f90..3210f8e76 100644 --- a/MoPubSampleApp.xcodeproj/project.pbxproj +++ b/MoPubSampleApp.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 2A6FF7171D8CA566000B353D /* MPWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A6FF7161D8CA566000B353D /* MPWebView.m */; }; 2A86E7F21D710CE60087594C /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57EF00CD1BD96EB5002634DE /* WebKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 2AC79F441DF7814700195AC5 /* SafariServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AC79F431DF7814700195AC5 /* SafariServices.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 2AFF1B621EC26FC300495994 /* MPRealTimeTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AFF1B611EC26FC300495994 /* MPRealTimeTimer.m */; }; 2AFF1B631EC26FC300495994 /* MPRealTimeTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AFF1B611EC26FC300495994 /* MPRealTimeTimer.m */; }; 442B54EC1E57DAF900A74D44 /* MPInstanceProvider+Unity.m in Sources */ = {isa = PBXBuildFile; fileRef = 442B54E21E57DAF900A74D44 /* MPInstanceProvider+Unity.m */; }; @@ -518,6 +519,8 @@ B230612E1B8E8E52000D4045 /* MPPlayBtn@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B230612C1B8E8E52000D4045 /* MPPlayBtn@2x.png */; }; B23061301B8E8E61000D4045 /* MPPlayBtn.png in Resources */ = {isa = PBXBuildFile; fileRef = B230612F1B8E8E61000D4045 /* MPPlayBtn.png */; }; B23061311B8E8E61000D4045 /* MPPlayBtn.png in Resources */ = {isa = PBXBuildFile; fileRef = B230612F1B8E8E61000D4045 /* MPPlayBtn.png */; }; + B25486BC1EC91F8C0005A596 /* MOPUBExperimentProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = B25486BB1EC91F8C0005A596 /* MOPUBExperimentProvider.m */; }; + B25486BD1EC91F8C0005A596 /* MOPUBExperimentProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = B25486BB1EC91F8C0005A596 /* MOPUBExperimentProvider.m */; }; B257A2E71BA38F1200F5D320 /* MPMutedBtn.png in Resources */ = {isa = PBXBuildFile; fileRef = B257A2E11BA38F1200F5D320 /* MPMutedBtn.png */; }; B257A2E81BA38F1200F5D320 /* MPMutedBtn.png in Resources */ = {isa = PBXBuildFile; fileRef = B257A2E11BA38F1200F5D320 /* MPMutedBtn.png */; }; B257A2E91BA38F1200F5D320 /* MPMutedBtn@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B257A2E21BA38F1200F5D320 /* MPMutedBtn@2x.png */; }; @@ -664,6 +667,7 @@ /* Begin PBXFileReference section */ 2A6FF7151D8CA566000B353D /* MPWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPWebView.h; sourceTree = ""; }; 2A6FF7161D8CA566000B353D /* MPWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPWebView.m; sourceTree = ""; }; + 2AC79F431DF7814700195AC5 /* SafariServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SafariServices.framework; path = System/Library/Frameworks/SafariServices.framework; sourceTree = SDKROOT; }; 2AFF1B601EC26FC300495994 /* MPRealTimeTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRealTimeTimer.h; sourceTree = ""; }; 2AFF1B611EC26FC300495994 /* MPRealTimeTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRealTimeTimer.m; sourceTree = ""; }; 3D3BC88B1CBEE8E100BDA2FA /* MPNativeAdRendererConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPNativeAdRendererConstants.h; sourceTree = ""; }; @@ -1220,6 +1224,8 @@ B23061291B8E8E3F000D4045 /* MPPlayBtn@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MPPlayBtn@3x.png"; sourceTree = ""; }; B230612C1B8E8E52000D4045 /* MPPlayBtn@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MPPlayBtn@2x.png"; sourceTree = ""; }; B230612F1B8E8E61000D4045 /* MPPlayBtn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = MPPlayBtn.png; sourceTree = ""; }; + B25486BA1EC91F8C0005A596 /* MOPUBExperimentProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MOPUBExperimentProvider.h; sourceTree = ""; }; + B25486BB1EC91F8C0005A596 /* MOPUBExperimentProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MOPUBExperimentProvider.m; sourceTree = ""; }; B257A2E11BA38F1200F5D320 /* MPMutedBtn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = MPMutedBtn.png; sourceTree = ""; }; B257A2E21BA38F1200F5D320 /* MPMutedBtn@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MPMutedBtn@2x.png"; sourceTree = ""; }; B257A2E31BA38F1200F5D320 /* MPMutedBtn@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MPMutedBtn@3x.png"; sourceTree = ""; }; @@ -1353,6 +1359,7 @@ BC3B98671E70C7E400C77554 /* QuartzCore.framework in Frameworks */, 447AE7071E6B2A0700823DF1 /* CoreData.framework in Frameworks */, AEF1E33317270AA400FC49F8 /* CoreTelephony.framework in Frameworks */, + 2AC79F441DF7814700195AC5 /* SafariServices.framework in Frameworks */, 2A86E7F21D710CE60087594C /* WebKit.framework in Frameworks */, B26284151B83CACE00960F74 /* CoreMedia.framework in Frameworks */, BC3B986A1E70C85400C77554 /* CoreGraphics.framework in Frameworks */, @@ -1666,6 +1673,8 @@ 572409441A688C05009271B8 /* MPTimer.m */, 572409451A688C05009271B8 /* MPUserInteractionGestureRecognizer.h */, 572409461A688C05009271B8 /* MPUserInteractionGestureRecognizer.m */, + B25486BA1EC91F8C0005A596 /* MOPUBExperimentProvider.h */, + B25486BB1EC91F8C0005A596 /* MOPUBExperimentProvider.m */, ); path = Utility; sourceTree = ""; @@ -2266,6 +2275,7 @@ 447AE7061E6B2A0700823DF1 /* CoreData.framework */, 44F0E2DF1E6AB43400A059DA /* EventKit.framework */, 44F0E2E01E6AB43400A059DA /* EventKitUI.framework */, + 2AC79F431DF7814700195AC5 /* SafariServices.framework */, AE902A31171F559400991DF9 /* AddressBook.framework */, AE902A32171F559400991DF9 /* AddressBookUI.framework */, AED9E47216F78DAD00EA71A7 /* AdSupport.framework */, @@ -2972,6 +2982,7 @@ 572409A71A688C05009271B8 /* MPBaseBannerAdapter.m in Sources */, 575F4A6D1B977714001352D7 /* MPStaticNativeAdRendererSettings.m in Sources */, 46B333CB19F075680078078A /* MPTableViewAdPlacerView.m in Sources */, + B25486BD1EC91F8C0005A596 /* MOPUBExperimentProvider.m in Sources */, 57AC6A1F1BB221370053C556 /* UIView+MPAdditions.m in Sources */, 469A15F11AC1F0BA00D6F0EF /* MPSampleAppLogReader.m in Sources */, A778C8C41ABB550E003F427D /* MPAPIEndpoints.m in Sources */, @@ -3095,6 +3106,7 @@ 57240A6F1A688C05009271B8 /* MPConstants.m in Sources */, 57AC6A041BB221130053C556 /* MOPUBActivityIndicatorView.m in Sources */, A714FE751B699B1B000EAEC4 /* MPVASTStringUtilities.m in Sources */, + B25486BC1EC91F8C0005A596 /* MOPUBExperimentProvider.m in Sources */, 5755D62C1AA8F62900DC32EA /* MPRewardedVideo.m in Sources */, 5755D6261AA8F62900DC32EA /* MPRewardedVideoAdapter.m in Sources */, 57240AB11A688C05009271B8 /* MPNativeAdRequest.m in Sources */, diff --git a/MoPubSampleApp/AppDelegate.m b/MoPubSampleApp/AppDelegate.m index 7679f6bad..c3c3053d4 100644 --- a/MoPubSampleApp/AppDelegate.m +++ b/MoPubSampleApp/AppDelegate.m @@ -15,6 +15,10 @@ #import "MPLogging.h" #import +#if CUSTOM_EVENTS_ENABLED +#import +#endif + @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions @@ -33,6 +37,10 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( navController.navigationBar.barStyle = UIBarStyleBlackOpaque; navController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName: [UIColor colorWithRed:0.86 green:0.86 blue:0.86 alpha:1]}; +#if CUSTOM_EVENTS_ENABLED + [FBAdSettings addTestDevice:[FBAdSettings testDeviceHash]]; +#endif + return YES; } diff --git a/README.md b/README.md index f4af70a27..bfa687b7f 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ The MoPub SDK is distributed as source code that you can include in your applica Includes everything you need to serve HTML and MRAID advertisements. Third party ad networks and Native MoPub advertisements are not included. -The current version of the SDK is 4.14.0 +The current version of the SDK is 4.15.0 ## Integrate @@ -36,16 +36,9 @@ More detailed class documentation is available in the repo under the `ClassDocum Please view the [changelog](https://github.com/mopub/mopub-ios-sdk/blob/master/CHANGELOG.md) for details. -- **Features** - - For Rewarded ads, the client-side callback will now be invoked when using server-side rewarding. - - Non-mediated interstitial, rewarded, and native ad placer ads will expire within 4 hours. - - **Bug Fixes** - - Fix old custom events that use the wrong native renderer. - - Replace usage of typeof with __typeof__ for C99 and C11 compliance. - - Fix CFBridgingRetain casting bug. - - Native ad impression tracker will now fire while scrolling. - - Fix HTML click tracker to fire when using window.location and window.open. + - Updated Facebook Audience Network banner and interstitial impression tracking + - Allow taps to pass through the gradient overlays for rewarded videos See the [Getting Started Guide](https://github.com/mopub/mopub-ios-sdk/wiki/Getting-Started#app-transport-security-settings) for instructions on setting up ATS in your app. diff --git a/SampleApps/SwiftSampleApp/Podfile.lock b/SampleApps/SwiftSampleApp/Podfile.lock index 6c35df25b..f651b9d5f 100644 --- a/SampleApps/SwiftSampleApp/Podfile.lock +++ b/SampleApps/SwiftSampleApp/Podfile.lock @@ -1,38 +1,38 @@ PODS: - AdColony (3.1.1) - - ChartboostSDK (6.6.2) - - FBAudienceNetwork (4.15.1) - - Flurry-iOS-SDK/FlurryAds (7.6.6): + - ChartboostSDK (6.6.3) + - FBAudienceNetwork (4.23.0) + - Flurry-iOS-SDK/FlurryAds (8.1.0): - Flurry-iOS-SDK/FlurrySDK - - Flurry-iOS-SDK/FlurrySDK (7.6.6) - - Google-Mobile-Ads-SDK (7.18.0) + - Flurry-iOS-SDK/FlurrySDK (8.1.0) + - Google-Mobile-Ads-SDK (7.19.1) - mopub-ios-sdk (4.11.1): - mopub-ios-sdk/MoPubSDK (= 4.11.1) - mopub-ios-sdk/AdColonyCustomEvents (4.11.1): - AdColony (~> 3.0) - mopub-ios-sdk/MoPubSDK - mopub-ios-sdk/AdMobCustomEvents (4.11.1): - - Google-Mobile-Ads-SDK (~> 7.18.0) + - Google-Mobile-Ads-SDK (~> 7.19.0) - mopub-ios-sdk/MoPubSDK - mopub-ios-sdk/ChartboostCustomEvents (4.11.1): - - ChartboostSDK (~> 6.5) + - ChartboostSDK (~> 6.0) - mopub-ios-sdk/MoPubSDK - mopub-ios-sdk/FacebookCustomEvents (4.11.1): - - FBAudienceNetwork (~> 4.15.1) + - FBAudienceNetwork (~> 4.0) - mopub-ios-sdk/MoPubSDK - mopub-ios-sdk/FlurryCustomEvents (4.11.1): - - Flurry-iOS-SDK/FlurryAds (~> 7.6.4) - - Flurry-iOS-SDK/FlurrySDK (~> 7.6.4) + - Flurry-iOS-SDK/FlurryAds (~> 8.0) + - Flurry-iOS-SDK/FlurrySDK (~> 8.0) - mopub-ios-sdk/MoPubSDK - mopub-ios-sdk/MoPubSDK (4.11.1) - mopub-ios-sdk/TapjoyCustomEvents (4.11.1): - mopub-ios-sdk/MoPubSDK - - TapjoySDK (= 11.5.1) + - TapjoySDK (~> 11.0) - mopub-ios-sdk/VungleCustomEvents (4.11.1): - mopub-ios-sdk/MoPubSDK - - VungleSDK-iOS (~> 4.0.6) - - TapjoySDK (11.5.1) - - VungleSDK-iOS (4.0.9) + - VungleSDK-iOS (~> 4.0) + - TapjoySDK (11.10.2) + - VungleSDK-iOS (4.1.0) DEPENDENCIES: - mopub-ios-sdk (from `../../`) @@ -50,13 +50,13 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: AdColony: 27bcddd3d79b24f61765dd799fcc666975f90daa - ChartboostSDK: 9248a129d363432b43eee0a18454dcf6f46f8d9d - FBAudienceNetwork: 4e3859a04314972e6b3ab401784379fa8dfd56a6 - Flurry-iOS-SDK: 97bbeec09cca666c2f1772f6e161c4f8ccff611e - Google-Mobile-Ads-SDK: 658065b4cb5a299bea254c4d24bf7786b6d3e75d - mopub-ios-sdk: 9a45395400b42b2ea2e22b24d6f703945e88646b - TapjoySDK: af2985b5de89af5b9ba61c762a7ecad76fc60c78 - VungleSDK-iOS: '053446955ef1fa777fd699b6bea6635cac604524' + ChartboostSDK: c0aefb3c25efcd1fa9a43fb45547ea98b323c95c + FBAudienceNetwork: 20a0e3d20e377dbb6708365e4c6d0711bf08ca97 + Flurry-iOS-SDK: 51065be4436f3e21fc8d3d7bb0b7d6869df6333d + Google-Mobile-Ads-SDK: 43ac87810e4961f5093024d3525bfe022f956da3 + mopub-ios-sdk: ec1bfa23bf2e72790a0dd6133ae1c3db4726bb5b + TapjoySDK: e12ca74dc0ff0ef18c252c9035975857ee1e032d + VungleSDK-iOS: 0dac102fa56e0a6f24444b4f500d1ccf2e43ea79 PODFILE CHECKSUM: a249b82bc975fd6b0adb4dbd94bde82e888c121b From 9507e2e5448cfba8b59271f445d2c6ba450ec56e Mon Sep 17 00:00:00 2001 From: kdun Date: Wed, 5 Jul 2017 10:31:23 -0700 Subject: [PATCH 2/3] Minor documentation fixes (#205) * Fix change log formatting * remove billy link and add back in certified version comment --- .../ChartboostInterstitialCustomEvent.h | 3 +- .../ChartboostRewardedVideoCustomEvent.h | 3 +- .../Flurry/FlurryBannerCustomEvent.h | 3 +- .../Flurry/FlurryInterstitialCustomEvent.h | 3 +- .../Flurry/FlurryNativeCustomEvent.h | 3 +- .../Flurry/FlurryNativeVideoAdRenderer.h | 3 +- CHANGELOG.md | 40 +++++++++---------- 7 files changed, 26 insertions(+), 32 deletions(-) diff --git a/AdNetworkSupport/Chartboost/ChartboostInterstitialCustomEvent.h b/AdNetworkSupport/Chartboost/ChartboostInterstitialCustomEvent.h index b7a3391de..63bca73a6 100644 --- a/AdNetworkSupport/Chartboost/ChartboostInterstitialCustomEvent.h +++ b/AdNetworkSupport/Chartboost/ChartboostInterstitialCustomEvent.h @@ -12,8 +12,7 @@ #endif /* - * Please reference the Supported Mediation Partner page at http://bit.ly/2mqsuFH for the - * latest version and ad format certifications. + * Certified with Chartboost 6.6.3 */ @interface ChartboostInterstitialCustomEvent : MPInterstitialCustomEvent diff --git a/AdNetworkSupport/Chartboost/ChartboostRewardedVideoCustomEvent.h b/AdNetworkSupport/Chartboost/ChartboostRewardedVideoCustomEvent.h index 23409da1f..121114fc6 100644 --- a/AdNetworkSupport/Chartboost/ChartboostRewardedVideoCustomEvent.h +++ b/AdNetworkSupport/Chartboost/ChartboostRewardedVideoCustomEvent.h @@ -12,8 +12,7 @@ #endif /* - * Please reference the Supported Mediation Partner page at http://bit.ly/2mqsuFH for the - * latest version and ad format certifications. + * Certified with Chartboost 6.6.3 */ @interface ChartboostRewardedVideoCustomEvent : MPRewardedVideoCustomEvent diff --git a/AdNetworkSupport/Flurry/FlurryBannerCustomEvent.h b/AdNetworkSupport/Flurry/FlurryBannerCustomEvent.h index dd9bc4672..eea9c4cdc 100644 --- a/AdNetworkSupport/Flurry/FlurryBannerCustomEvent.h +++ b/AdNetworkSupport/Flurry/FlurryBannerCustomEvent.h @@ -14,8 +14,7 @@ #endif /* - * Please reference the Supported Mediation Partner page at http://bit.ly/2mqsuFH for the - * latest version and ad format certifications. + * Certified with Flurry 8.0.0 */ @interface FlurryBannerCustomEvent : MPBannerCustomEvent diff --git a/AdNetworkSupport/Flurry/FlurryInterstitialCustomEvent.h b/AdNetworkSupport/Flurry/FlurryInterstitialCustomEvent.h index 5ebb23bf4..884aab1af 100644 --- a/AdNetworkSupport/Flurry/FlurryInterstitialCustomEvent.h +++ b/AdNetworkSupport/Flurry/FlurryInterstitialCustomEvent.h @@ -14,8 +14,7 @@ #endif /* - * Please reference the Supported Mediation Partner page at http://bit.ly/2mqsuFH for the - * latest version and ad format certifications. + * Certified with Flurry 8.0.0 */ @interface FlurryInterstitialCustomEvent : MPInterstitialCustomEvent diff --git a/AdNetworkSupport/Flurry/FlurryNativeCustomEvent.h b/AdNetworkSupport/Flurry/FlurryNativeCustomEvent.h index 6a30e74a0..1452dbb88 100644 --- a/AdNetworkSupport/Flurry/FlurryNativeCustomEvent.h +++ b/AdNetworkSupport/Flurry/FlurryNativeCustomEvent.h @@ -13,8 +13,7 @@ #endif /* - * Please reference the Supported Mediation Partner page at http://bit.ly/2mqsuFH for the - * latest version and ad format certifications. + * Certified with Flurry 8.0.0 */ @interface FlurryNativeCustomEvent : MPNativeCustomEvent diff --git a/AdNetworkSupport/Flurry/FlurryNativeVideoAdRenderer.h b/AdNetworkSupport/Flurry/FlurryNativeVideoAdRenderer.h index ac20644f1..c36e2fadc 100644 --- a/AdNetworkSupport/Flurry/FlurryNativeVideoAdRenderer.h +++ b/AdNetworkSupport/Flurry/FlurryNativeVideoAdRenderer.h @@ -13,8 +13,7 @@ @class MPStaticNativeAdRendererSettings; /* - * Please reference the Supported Mediation Partner page at http://bit.ly/2mqsuFH for the - * latest version and ad format certifications. + * Certified with Flurry 8.0.0 */ @interface FlurryNativeVideoAdRenderer : NSObject diff --git a/CHANGELOG.md b/CHANGELOG.md index 77b21a440..39338933f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,43 +1,43 @@ ## Version 4.15.0 (June 19th, 2017) - **Bug Fixes** -- Updated Facebook Audience Network banner and interstitial impression tracking -- Allow taps to pass through the gradient overlays for rewarded videos + - Updated Facebook Audience Network banner and interstitial impression tracking + - Allow taps to pass through the gradient overlays for rewarded videos ## Version 4.14.0 (May 10th, 2017) - **Features** -- For Rewarded ads, the client-side callback will now be invoked when using server-side rewarding. -- Non-mediated interstitial, rewarded, and native ad placer ads will expire within 4 hours. + - For Rewarded ads, the client-side callback will now be invoked when using server-side rewarding. + - Non-mediated interstitial, rewarded, and native ad placer ads will expire within 4 hours. - **Bug Fixes** -- Fix old custom events that use the wrong native renderer. -- Replace usage of typeof with __typeof__ for C99 and C11 compliance. -- Fix CFBridgingRetain casting bug. -- Native ad impression tracker will now fire while scrolling. -- Fix HTML click tracker to fire when using window.location and window.open. + - Fix old custom events that use the wrong native renderer. + - Replace usage of typeof with __typeof__ for C99 and C11 compliance. + - Fix CFBridgingRetain casting bug. + - Native ad impression tracker will now fire while scrolling. + - Fix HTML click tracker to fire when using window.location and window.open. ## Version 4.13.1 (April 6th, 2017) - **Bug Fixes** -- Fixed compile error in the MoPub Base SDK Excluding Native bundle. + - Fixed compile error in the MoPub Base SDK Excluding Native bundle. ## Version 4.13.0 (March 23rd, 2017) - **Features** -- Added support for mediation of Google AdMob rewarded video demand (Google Mobile Ads SDK v7.19.0). -- Google AdMob native ads mediation is now generally available (Google Mobile Ads SDK v7.19.0). -- Updated the Tapjoy network mediation adapter to support Tapjoy SDK v11.10.0 + - Added support for mediation of Google AdMob rewarded video demand (Google Mobile Ads SDK v7.19.0). + - Google AdMob native ads mediation is now generally available (Google Mobile Ads SDK v7.19.0). + - Updated the Tapjoy network mediation adapter to support Tapjoy SDK v11.10.0 - **Bug Fixes** -- Introduced additional preventative measures to improve creative quality. + - Introduced additional preventative measures to improve creative quality. ## Version 4.12.0 (February 9th, 2017) - **Features** -- Rewarded ad units now support rich media. -- Allow MoPub static native renderer to render Flurry native ads. -- Removed size limit for native ad main images. + - Rewarded ad units now support rich media. + - Allow MoPub static native renderer to render Flurry native ads. + - Removed size limit for native ad main images. - **Bug Fixes** -- Native video selection logic now filters by supported MIME types. -- Ad placer now supports section count. -- Fix CFStringRef variable initialization. + - Native video selection logic now filters by supported MIME types. + - Ad placer now supports section count. + - Fix CFStringRef variable initialization. ## Version 4.11.1 (November 28th, 2016) - **App Transport Security Updates** From 542a62f197e51520c5be8174514cf82644e138e0 Mon Sep 17 00:00:00 2001 From: kdun Date: Tue, 25 Jul 2017 13:26:43 -0700 Subject: [PATCH 3/3] Update AdMob and Unity custom events (#210) * Updated AdMob custom events, certified for version 7.21.0 * Updated Unity custom events, certified for version 2.1.0 --- .../MPGoogleAdMobInterstitialCustomEvent.m | 3 +- AdNetworkSupport/Unity/MPUnityRouter.h | 6 +- AdNetworkSupport/Unity/MPUnityRouter.m | 59 +++++++++++++++---- .../Unity/UnityAdsInterstitialCustomEvent.m | 10 +++- 4 files changed, 60 insertions(+), 18 deletions(-) diff --git a/AdNetworkSupport/GoogleAdMob/MPGoogleAdMobInterstitialCustomEvent.m b/AdNetworkSupport/GoogleAdMob/MPGoogleAdMobInterstitialCustomEvent.m index 0eb72664d..beba826dd 100644 --- a/AdNetworkSupport/GoogleAdMob/MPGoogleAdMobInterstitialCustomEvent.m +++ b/AdNetworkSupport/GoogleAdMob/MPGoogleAdMobInterstitialCustomEvent.m @@ -84,7 +84,7 @@ - (void)dealloc self.interstitial.delegate = nil; } -#pragma mark - IMAdInterstitialDelegate +#pragma mark - GADInterstitialDelegate - (void)interstitialDidReceiveAd:(GADInterstitial *)interstitial { @@ -121,6 +121,7 @@ - (void)interstitialWillLeaveApplication:(GADInterstitial *)ad { MPLogInfo(@"Google AdMob Interstitial will leave application"); [self.delegate interstitialCustomEventDidReceiveTapEvent:self]; + [self.delegate interstitialCustomEventWillLeaveApplication:self]; } @end diff --git a/AdNetworkSupport/Unity/MPUnityRouter.h b/AdNetworkSupport/Unity/MPUnityRouter.h index afab6ac84..025e20d81 100644 --- a/AdNetworkSupport/Unity/MPUnityRouter.h +++ b/AdNetworkSupport/Unity/MPUnityRouter.h @@ -15,6 +15,8 @@ @interface MPUnityRouter : NSObject @property (nonatomic, weak) id delegate; +@property NSMutableDictionary* delegateMap; +@property NSString* currentPlacementId; + (MPUnityRouter *)sharedRouter; @@ -32,7 +34,9 @@ - (void)unityAdsDidStart:(NSString *)placementId; - (void)unityAdsDidFinish:(NSString *)placementId withFinishState:(UnityAdsFinishState)state; - (void)unityAdsDidClick:(NSString *)placementId; - - (void)unityAdsDidFailWithError:(NSError *)error; +@optional +- (void)unityAdsPlacementStateChanged:(NSString*)placementId oldState:(UnityAdsPlacementState)oldState newState:(UnityAdsPlacementState)newState; + @end diff --git a/AdNetworkSupport/Unity/MPUnityRouter.m b/AdNetworkSupport/Unity/MPUnityRouter.m index b2b07f042..ba3eece3c 100644 --- a/AdNetworkSupport/Unity/MPUnityRouter.m +++ b/AdNetworkSupport/Unity/MPUnityRouter.m @@ -20,6 +20,13 @@ @interface MPUnityRouter () @implementation MPUnityRouter +- (id) init { + self = [super init]; + self.delegateMap = [[NSMutableDictionary alloc] init]; + + return self; +} + + (MPUnityRouter *)sharedRouter { return [[MPInstanceProvider sharedProvider] sharedMPUnityRouter]; @@ -28,8 +35,8 @@ + (MPUnityRouter *)sharedRouter - (void)requestVideoAdWithGameId:(NSString *)gameId placementId:(NSString *)placementId delegate:(id)delegate; { if (!self.isAdPlaying) { - self.delegate = delegate; - + [self.delegateMap setObject:delegate forKey:placementId]; + static dispatch_once_t unityInitToken; dispatch_once(&unityInitToken, ^{ UADSMediationMetaData *mediationMetaData = [[UADSMediationMetaData alloc] init]; @@ -41,7 +48,7 @@ - (void)requestVideoAdWithGameId:(NSString *)gameId placementId:(NSString *)plac // Need to check immediately as an ad may be cached. if ([self isAdAvailableForPlacementId:placementId]) { - [self.delegate unityAdsReady:placementId]; + [self unityAdsReady:placementId]; } // MoPub timeout will handle the case for an ad failing to load. } else { @@ -59,9 +66,7 @@ - (void)presentVideoAdFromViewController:(UIViewController *)viewController cust { if (!self.isAdPlaying && [self isAdAvailableForPlacementId:placementId]) { self.isAdPlaying = YES; - - self.delegate = delegate; - + self.currentPlacementId = placementId; [UnityAds show:viewController placementId:placementId]; } else { NSError *error = [NSError errorWithDomain:MoPubRewardedVideoAdsSDKDomain code:MPRewardedVideoAdErrorUnknown userInfo:nil]; @@ -69,6 +74,10 @@ - (void)presentVideoAdFromViewController:(UIViewController *)viewController cust } } +- (id)getDelegate:(NSString*) placementId { + return [self.delegateMap valueForKey:placementId]; +} + - (void)clearDelegate:(id)delegate { if (self.delegate == delegate) @@ -81,25 +90,49 @@ - (void)clearDelegate:(id)delegate - (void)unityAdsReady:(NSString *)placementId { - [self.delegate unityAdsReady:placementId]; + if (!self.isAdPlaying) { + id delegate = [self getDelegate:placementId]; + if (delegate != nil) { + [delegate unityAdsReady:placementId]; + } + } } - (void)unityAdsDidError:(UnityAdsError)error withMessage:(NSString *)message { - [self.delegate unityAdsDidError:error withMessage:message]; + id delegate = [self getDelegate:self.currentPlacementId]; + if (delegate != nil) { + [delegate unityAdsDidError:error withMessage:message]; + } } - (void)unityAdsDidStart:(NSString *)placementId { - [self.delegate unityAdsDidStart:placementId]; + id delegate = [self getDelegate:placementId]; + if (delegate != nil) { + [delegate unityAdsDidStart:placementId]; + } } - (void)unityAdsDidFinish:(NSString *)placementId withFinishState:(UnityAdsFinishState)state { - [self.delegate unityAdsDidFinish:placementId withFinishState:state]; + id delegate = [self getDelegate:placementId]; + if (delegate != nil) { + [delegate unityAdsDidFinish:placementId withFinishState:state]; + } + [self.delegateMap removeObjectForKey:placementId]; self.isAdPlaying = NO; } -- (void)unityAdsDidClick:(NSString *)placementId -{ - [self.delegate unityAdsDidClick:placementId]; +- (void)unityAdsDidClick:(NSString *)placementId { + id delegate = [self getDelegate:placementId]; + if (delegate != nil) { + [delegate unityAdsDidClick:placementId]; + } +} + +- (void)unityAdsPlacementStateChanged:(NSString *)placementId oldState:(UnityAdsPlacementState)oldState newState:(UnityAdsPlacementState)newState { + id delegate = [self getDelegate:placementId]; + if (delegate != nil && [delegate respondsToSelector:@selector(unityAdsPlacementStateChanged:oldState:newState:)]) { + [delegate unityAdsPlacementStateChanged:placementId oldState:oldState newState:newState]; + } } @end diff --git a/AdNetworkSupport/Unity/UnityAdsInterstitialCustomEvent.m b/AdNetworkSupport/Unity/UnityAdsInterstitialCustomEvent.m index 2bc6e9438..6dd98d640 100644 --- a/AdNetworkSupport/Unity/UnityAdsInterstitialCustomEvent.m +++ b/AdNetworkSupport/Unity/UnityAdsInterstitialCustomEvent.m @@ -16,6 +16,7 @@ @interface UnityAdsInterstitialCustomEvent () +@property BOOL loadRequested; @property (nonatomic, copy) NSString *placementId; @end @@ -27,8 +28,8 @@ - (void)dealloc [[MPUnityRouter sharedRouter] clearDelegate:self]; } -- (void)requestInterstitialWithCustomEventInfo:(NSDictionary *)info -{ +- (void)requestInterstitialWithCustomEventInfo:(NSDictionary *)info { + self.loadRequested = YES; NSString *gameId = [info objectForKey:kMPUnityRewardedVideoGameId]; self.placementId = [info objectForKey:kUnityAdsOptionPlacementIdKey]; if (self.placementId == nil) { @@ -74,7 +75,10 @@ - (void)handleAdPlayedForCustomEventNetwork - (void)unityAdsReady:(NSString *)placementId { - [self.delegate interstitialCustomEvent:self didLoadAd:placementId]; + if (self.loadRequested) { + [self.delegate interstitialCustomEvent:self didLoadAd:placementId]; + self.loadRequested = NO; + } } - (void)unityAdsDidError:(UnityAdsError)error withMessage:(NSString *)message