diff --git a/Objective-C/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/SimpleCustomNativeAdView.xib b/Objective-C/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/SimpleCustomNativeAdView.xib index d81b71b3..f4665f9c 100644 --- a/Objective-C/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/SimpleCustomNativeAdView.xib +++ b/Objective-C/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/SimpleCustomNativeAdView.xib @@ -1,11 +1,11 @@ - + - + @@ -50,9 +50,9 @@ - + - + diff --git a/Objective-C/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/MySimpleNativeAdView.h b/Objective-C/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/MySimpleNativeAdView.h index 61eadf6e..38c10a2e 100644 --- a/Objective-C/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/MySimpleNativeAdView.h +++ b/Objective-C/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/MySimpleNativeAdView.h @@ -8,7 +8,7 @@ // Weak references to this ad's asset views. @property(nonatomic, weak) IBOutlet UILabel *headlineView; -@property(nonatomic, weak) IBOutlet UIView *mediaPlaceholder; +@property(nonatomic, weak) IBOutlet UIView *mainPlaceholder; @property(nonatomic, weak) IBOutlet UILabel *captionView; /// Populates the ad view with the custom native ad object. diff --git a/Objective-C/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/MySimpleNativeAdView.m b/Objective-C/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/MySimpleNativeAdView.m index 06bbd7be..83697d95 100644 --- a/Objective-C/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/MySimpleNativeAdView.m +++ b/Objective-C/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/MySimpleNativeAdView.m @@ -31,29 +31,29 @@ - (void)awakeFromNib { } - (void)performClickOnHeadline { + [self.customNativeAd performClickOnAssetWithKey:MySimpleNativeAdViewHeadlineKey]; +} + +- (void)populateWithCustomNativeAd:(GADNativeCustomTemplateAd *)customNativeAd { + self.customNativeAd = customNativeAd; // The custom click handler is an optional block which will override the normal click action // defined by the ad. Pass nil for the click handler to let the SDK process the default click // action. - dispatch_block_t customClickHandler = ^{ + __weak typeof(self) weakSelf = self; + [self.customNativeAd setCustomClickHandler:^(NSString *assetID){ [[[UIAlertView alloc] initWithTitle:@"Custom Click" message:@"You just clicked on the headline!" - delegate:self + delegate:weakSelf cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; - }; - [self.customNativeAd performClickOnAssetWithKey:MySimpleNativeAdViewHeadlineKey - customClickHandler:customClickHandler]; -} - -- (void)populateWithCustomNativeAd:(GADNativeCustomTemplateAd *)customNativeAd { - self.customNativeAd = customNativeAd; + }]; // Populate the custom native ad assets. self.headlineView.text = [customNativeAd stringForKey:MySimpleNativeAdViewHeadlineKey]; self.captionView.text = [customNativeAd stringForKey:MySimpleNativeAdViewCaptionKey]; // Remove all the media placeholder's subviews. - for (UIView *subview in self.mediaPlaceholder.subviews) { + for (UIView *subview in self.mainPlaceholder.subviews) { [subview removeFromSuperview]; } @@ -66,17 +66,17 @@ - (void)populateWithCustomNativeAd:(GADNativeCustomTemplateAd *)customNativeAd { UIImage *image = [customNativeAd imageForKey:MySimpleNativeAdViewMainImageKey].image; mainView = [[UIImageView alloc] initWithImage:image]; } - [self.mediaPlaceholder addSubview:mainView]; + [self.mainPlaceholder addSubview:mainView]; // Size the media view to fill our container size. [mainView setTranslatesAutoresizingMaskIntoConstraints:NO]; NSDictionary *viewDictionary = NSDictionaryOfVariableBindings(mainView); - [self.mediaPlaceholder + [self.mainPlaceholder addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[mainView]|" options:0 metrics:nil views:viewDictionary]]; - [self.mediaPlaceholder + [self.mainPlaceholder addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[mainView]|" options:0 metrics:nil diff --git a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample.xcodeproj/project.pbxproj b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample.xcodeproj/project.pbxproj index a505c35b..0a25b0a6 100644 --- a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample.xcodeproj/project.pbxproj +++ b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample.xcodeproj/project.pbxproj @@ -7,29 +7,29 @@ objects = { /* Begin PBXBuildFile section */ - 4AE4C01A1BFCCF8300655115 /* NativeAppInstallAdView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4AE4C0141BFCCF8300655115 /* NativeAppInstallAdView.xib */; }; - 4AE4C01B1BFCCF8300655115 /* NativeContentAdView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4AE4C0161BFCCF8300655115 /* NativeContentAdView.xib */; }; - 4AE4C01C1BFCCF8300655115 /* SimpleCustomNativeAdView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4AE4C0181BFCCF8300655115 /* SimpleCustomNativeAdView.xib */; }; 4AEBD8B41BF01CF200874961 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBD8B31BF01CF200874961 /* AppDelegate.swift */; }; 4AEBD8B61BF01CF200874961 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBD8B51BF01CF200874961 /* ViewController.swift */; }; - 4AEBD8B91BF01CF200874961 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4AEBD8B71BF01CF200874961 /* Main.storyboard */; }; 4AEBD8BB1BF01CF200874961 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4AEBD8BA1BF01CF200874961 /* Assets.xcassets */; }; 4AEBD8BE1BF01CF200874961 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4AEBD8BC1BF01CF200874961 /* LaunchScreen.storyboard */; }; 4AEBD8CC1BF01E7300874961 /* MySimpleNativeAdView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBD8CB1BF01E7300874961 /* MySimpleNativeAdView.swift */; }; + AEB485B61F31462D0030B852 /* SimpleCustomNativeAdView.xib in Resources */ = {isa = PBXBuildFile; fileRef = AEB485B51F31462D0030B852 /* SimpleCustomNativeAdView.xib */; }; + AEB485B81F314BA90030B852 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AEB485B71F314BA90030B852 /* Main.storyboard */; }; + AEB485BB1F314D6E0030B852 /* NativeAppInstallAdView.xib in Resources */ = {isa = PBXBuildFile; fileRef = AEB485B91F314D6E0030B852 /* NativeAppInstallAdView.xib */; }; + AEB485BC1F314D6E0030B852 /* NativeContentAdView.xib in Resources */ = {isa = PBXBuildFile; fileRef = AEB485BA1F314D6E0030B852 /* NativeContentAdView.xib */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 4AE4C0151BFCCF8300655115 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/NativeAppInstallAdView.xib; sourceTree = ""; }; - 4AE4C0171BFCCF8300655115 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/NativeContentAdView.xib; sourceTree = ""; }; - 4AE4C0191BFCCF8300655115 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SimpleCustomNativeAdView.xib; sourceTree = ""; }; 4AEBD8B01BF01CF200874961 /* DFPCustomRenderingExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DFPCustomRenderingExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4AEBD8B31BF01CF200874961 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 4AEBD8B51BF01CF200874961 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - 4AEBD8B81BF01CF200874961 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 4AEBD8BA1BF01CF200874961 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 4AEBD8BD1BF01CF200874961 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 4AEBD8BF1BF01CF200874961 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4AEBD8CB1BF01E7300874961 /* MySimpleNativeAdView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MySimpleNativeAdView.swift; sourceTree = ""; }; + AEB485B51F31462D0030B852 /* SimpleCustomNativeAdView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = SimpleCustomNativeAdView.xib; path = Base.lproj/SimpleCustomNativeAdView.xib; sourceTree = ""; }; + AEB485B71F314BA90030B852 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + AEB485B91F314D6E0030B852 /* NativeAppInstallAdView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = NativeAppInstallAdView.xib; path = Base.lproj/NativeAppInstallAdView.xib; sourceTree = ""; }; + AEB485BA1F314D6E0030B852 /* NativeContentAdView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = NativeContentAdView.xib; path = Base.lproj/NativeContentAdView.xib; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -65,11 +65,11 @@ 4AEBD8B31BF01CF200874961 /* AppDelegate.swift */, 4AEBD8B51BF01CF200874961 /* ViewController.swift */, 4AEBD8CB1BF01E7300874961 /* MySimpleNativeAdView.swift */, - 4AEBD8B71BF01CF200874961 /* Main.storyboard */, + AEB485B71F314BA90030B852 /* Main.storyboard */, 4AEBD8BC1BF01CF200874961 /* LaunchScreen.storyboard */, - 4AE4C0141BFCCF8300655115 /* NativeAppInstallAdView.xib */, - 4AE4C0161BFCCF8300655115 /* NativeContentAdView.xib */, - 4AE4C0181BFCCF8300655115 /* SimpleCustomNativeAdView.xib */, + AEB485B91F314D6E0030B852 /* NativeAppInstallAdView.xib */, + AEB485BA1F314D6E0030B852 /* NativeContentAdView.xib */, + AEB485B51F31462D0030B852 /* SimpleCustomNativeAdView.xib */, 4AEBD8BA1BF01CF200874961 /* Assets.xcassets */, 4AEBD8BF1BF01CF200874961 /* Info.plist */, ); @@ -136,11 +136,11 @@ buildActionMask = 2147483647; files = ( 4AEBD8BE1BF01CF200874961 /* LaunchScreen.storyboard in Resources */, - 4AE4C01C1BFCCF8300655115 /* SimpleCustomNativeAdView.xib in Resources */, + AEB485B61F31462D0030B852 /* SimpleCustomNativeAdView.xib in Resources */, 4AEBD8BB1BF01CF200874961 /* Assets.xcassets in Resources */, - 4AE4C01B1BFCCF8300655115 /* NativeContentAdView.xib in Resources */, - 4AE4C01A1BFCCF8300655115 /* NativeAppInstallAdView.xib in Resources */, - 4AEBD8B91BF01CF200874961 /* Main.storyboard in Resources */, + AEB485BB1F314D6E0030B852 /* NativeAppInstallAdView.xib in Resources */, + AEB485BC1F314D6E0030B852 /* NativeContentAdView.xib in Resources */, + AEB485B81F314BA90030B852 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -160,38 +160,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ - 4AE4C0141BFCCF8300655115 /* NativeAppInstallAdView.xib */ = { - isa = PBXVariantGroup; - children = ( - 4AE4C0151BFCCF8300655115 /* Base */, - ); - name = NativeAppInstallAdView.xib; - sourceTree = ""; - }; - 4AE4C0161BFCCF8300655115 /* NativeContentAdView.xib */ = { - isa = PBXVariantGroup; - children = ( - 4AE4C0171BFCCF8300655115 /* Base */, - ); - name = NativeContentAdView.xib; - sourceTree = ""; - }; - 4AE4C0181BFCCF8300655115 /* SimpleCustomNativeAdView.xib */ = { - isa = PBXVariantGroup; - children = ( - 4AE4C0191BFCCF8300655115 /* Base */, - ); - name = SimpleCustomNativeAdView.xib; - sourceTree = ""; - }; - 4AEBD8B71BF01CF200874961 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 4AEBD8B81BF01CF200874961 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; 4AEBD8BC1BF01CF200874961 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( diff --git a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Assets.xcassets/AppIcon.appiconset/Contents.json b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Assets.xcassets/AppIcon.appiconset/Contents.json index eeea76c2..1d060ed2 100644 --- a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,5 +1,15 @@ { "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "29x29", @@ -30,6 +40,16 @@ "size" : "60x60", "scale" : "3x" }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, { "idiom" : "ipad", "size" : "29x29", diff --git a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/Main.storyboard b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/Main.storyboard index be35d3b9..a8181893 100644 --- a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/Main.storyboard +++ b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/Main.storyboard @@ -1,175 +1,198 @@ - - + + + + + - + + - + - + - - + + - - + + - - + + - - + + - - - + + + - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - + + + + - + - - - - - + + + + + - - - - - - + + + + + + + + - + - + + + + + + diff --git a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/NativeAppInstallAdView.xib b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/NativeAppInstallAdView.xib index 1abe3d28..a707e3e4 100644 --- a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/NativeAppInstallAdView.xib +++ b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/NativeAppInstallAdView.xib @@ -1,100 +1,111 @@ - - + + + + + - + + - + - - + + - - + + - - + + - - + + - - - - - - - - - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - + + + + + + diff --git a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/NativeContentAdView.xib b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/NativeContentAdView.xib index 01ce9d07..43588f14 100644 --- a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/NativeContentAdView.xib +++ b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/NativeContentAdView.xib @@ -1,91 +1,94 @@ - - + + + + + - + + - + - - - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - + + + + + + - + + + + + + diff --git a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/SimpleCustomNativeAdView.xib b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/SimpleCustomNativeAdView.xib index 30022847..66e6d172 100644 --- a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/SimpleCustomNativeAdView.xib +++ b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/Base.lproj/SimpleCustomNativeAdView.xib @@ -1,57 +1,63 @@ - - + + + + + - + + - - + + - - - + - - - - - - - - + + + + + + + + - - - + + + - + + + + + + diff --git a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/MySimpleNativeAdView.swift b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/MySimpleNativeAdView.swift index 7b44b7e1..5ff3db25 100644 --- a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/MySimpleNativeAdView.swift +++ b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/MySimpleNativeAdView.swift @@ -35,7 +35,7 @@ class MySimpleNativeAdView: UIView { /// Weak references to this ad's asset views. @IBOutlet weak var headlineView: UILabel! - @IBOutlet weak var mainImageView: UIImageView! + @IBOutlet weak var mainPlaceholder: UIView! @IBOutlet weak var captionView: UILabel! /// The custom native ad that populated this view. @@ -45,35 +45,65 @@ class MySimpleNativeAdView: UIView { super.awakeFromNib() // Enable clicks on the main image. - mainImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, + mainPlaceholder.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(MySimpleNativeAdView.performClickOnMainImage(_:)))) - mainImageView.isUserInteractionEnabled = true + mainPlaceholder.isUserInteractionEnabled = true } func performClickOnMainImage(_ sender: UIImage!) { + customNativeAd.performClickOnAsset( + withKey: MySimpleNativeAdViewTypeProperties.MySimpleNativeAdViewMainImageKey) + } + + /// Populates the ad view with the custom native ad object. + func populate(withCustomNativeAd customNativeAd: GADNativeCustomTemplateAd) { + self.customNativeAd = customNativeAd // The custom click handler closure overrides the normal click action defined by the ad. - let customClickHandler: ()->() = { + customNativeAd.customClickHandler = { assetID in let alertView = UIAlertView(title: "Custom Click", message: "You just clicked on the image!", delegate: self, cancelButtonTitle: "OK") alertView.alertViewStyle = .default alertView.show() } - customNativeAd.performClickOnAsset( - withKey: MySimpleNativeAdViewTypeProperties.MySimpleNativeAdViewMainImageKey, - customClickHandler: customClickHandler) + + // Populate the custom native ad assets. + let headlineKey = MySimpleNativeAdViewTypeProperties.MySimpleNativeAdViewHeadlineKey + headlineView.text = customNativeAd.string(forKey: headlineKey) + let captionKey = MySimpleNativeAdViewTypeProperties.MySimpleNativeAdViewCaptionKey + captionView.text = customNativeAd.string(forKey: captionKey) + + let mainView: UIView = self.mainView(forCustomNativeAd: customNativeAd) + updateMainView(mainView) } - /// Populates the ad view with the custom native ad object. - func populateWithCustomNativeAd(_ customNativeAd: GADNativeCustomTemplateAd) { - self.customNativeAd = customNativeAd + /// This custom native ad also has a both a video and image associated with it. We'll use the + /// video asset if available, and otherwise fallback to the image asset. + private func mainView(forCustomNativeAd customNativeAd:GADNativeCustomTemplateAd) -> UIView { + if customNativeAd.videoController.hasVideoContent(), + let mediaView = customNativeAd.mediaView { + return mediaView + } else { + let imageKey = MySimpleNativeAdViewTypeProperties.MySimpleNativeAdViewMainImageKey + let image: UIImage? = customNativeAd.image(forKey: imageKey)?.image + return UIImageView(image: image) + } + } - // Populate the custom native ad assets. - headlineView.text = customNativeAd.string( - forKey: MySimpleNativeAdViewTypeProperties.MySimpleNativeAdViewHeadlineKey) - mainImageView.image = customNativeAd.image( - forKey: MySimpleNativeAdViewTypeProperties.MySimpleNativeAdViewMainImageKey)?.image - captionView.text = customNativeAd.string( - forKey: MySimpleNativeAdViewTypeProperties.MySimpleNativeAdViewCaptionKey) + private func updateMainView(_ mainView:UIView) { + // Remove all the media placeholder's subviews. + for subview: UIView in mainPlaceholder.subviews { + subview.removeFromSuperview() + } + mainPlaceholder.addSubview(mainView) + // Size the media view to fill our container size. + mainView.translatesAutoresizingMaskIntoConstraints = false + let viewDictionary: [AnyHashable: Any] = ["mainView":mainView] + mainPlaceholder.addConstraints(NSLayoutConstraint.constraints( + withVisualFormat: "H:|[mainView]|", options: [], metrics: nil, + views: viewDictionary as? [String : Any] ?? [String : Any]())) + mainPlaceholder.addConstraints(NSLayoutConstraint.constraints( + withVisualFormat: "V:|[mainView]|", options: [], metrics: nil, + views: viewDictionary as? [String : Any] ?? [String : Any]())) } } diff --git a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/ViewController.swift b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/ViewController.swift index c9600a26..9b124beb 100644 --- a/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/ViewController.swift +++ b/Swift/doubleclick/DFPCustomRenderingExample/DFPCustomRenderingExample/ViewController.swift @@ -17,12 +17,14 @@ import GoogleMobileAds import UIKit -class ViewController: UIViewController, GADNativeAppInstallAdLoaderDelegate, - GADNativeContentAdLoaderDelegate, GADNativeCustomTemplateAdLoaderDelegate { +class ViewController: UIViewController { // The view that holds the native ad. @IBOutlet weak var nativeAdPlaceholder: UIView! + // Displays status messages about presence of video assets. + @IBOutlet weak var videoStatusLabel: UILabel! + // The app install ad switch. @IBOutlet weak var appInstallAdSwitch: UISwitch! @@ -38,6 +40,9 @@ class ViewController: UIViewController, GADNativeAppInstallAdLoaderDelegate, // The SDK version label. @IBOutlet weak var versionLabel: UILabel! + // Switch to indicate if video ads should start muted. + @IBOutlet weak var startMutedSwitch: UISwitch! + /// The ad loader. You must keep a strong reference to the GADAdLoader during the ad loading /// process. var adLoader: GADAdLoader! @@ -48,6 +53,9 @@ class ViewController: UIViewController, GADNativeAppInstallAdLoaderDelegate, /// The ad unit ID. let adUnitID = "/6499/example/native" + /// The native custom template id + let nativeCustomTemplateId = "10104090" + override func viewDidLoad() { super.viewDidLoad() versionLabel.text = GADRequest.sdkVersion() @@ -92,147 +100,177 @@ class ViewController: UIViewController, GADNativeAppInstallAdLoaderDelegate, alertView.show() } else { refreshAdButton.isEnabled = false + let videoOptions = GADVideoOptions() + videoOptions.startMuted = startMutedSwitch.isOn adLoader = GADAdLoader(adUnitID: adUnitID, rootViewController: self, - adTypes: adTypes, options: nil) + adTypes: adTypes, options: [videoOptions]) adLoader.delegate = self adLoader.load(GADRequest()) + videoStatusLabel.text = "" } } - // MARK: - GADAdLoaderDelegate + /// Returns a `UIImage` representing the number of stars from the given star rating; returns `nil` + /// if the star rating is less than 3.5 stars. + func imageOfStars(fromStarRating starRating: NSDecimalNumber) -> UIImage? { + let rating = starRating.doubleValue + if rating >= 5 { + return UIImage(named: "stars_5") + } else if rating >= 4.5 { + return UIImage(named: "stars_4_5") + } else if rating >= 4 { + return UIImage(named: "stars_4") + } else if rating >= 3.5 { + return UIImage(named: "stars_3_5") + } else { + return nil + } + } + /// Updates the videoController's delegate and viewController's UI according to videoController 'hasVideoContent()' value. + /// Some content ads will include a video asset, while others do not. Apps can use the + /// GADVideoController's hasVideoContent property to determine if one is present, and adjust their + /// UI accordingly. + func updateVideoStatusLabel(forAdsVideoController videoController: GADVideoController) { + if videoController.hasVideoContent() { + // By acting as the delegate to the GADVideoController, this ViewController receives messages + // about events in the video lifecycle. + videoStatusLabel.text = "Ad contains a video asset." + } + else { + videoStatusLabel.text = "Ad does not contain a video." + } + } + +} + +// MARK: - GADAdLoaderDelegate +extension ViewController : GADAdLoaderDelegate { func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: GADRequestError) { print("\(adLoader) failed with error: \(error.localizedDescription)") refreshAdButton.isEnabled = true } +} - // MARK: - GADNativeAppInstallAdLoaderDelegate - +// MARK: - GADNativeAppInstallAdLoaderDelegate +extension ViewController : GADNativeAppInstallAdLoaderDelegate { func adLoader(_ adLoader: GADAdLoader, didReceive nativeAppInstallAd: GADNativeAppInstallAd) { print("Received native app install ad: \(nativeAppInstallAd)") refreshAdButton.isEnabled = true - - // Create and place the ad in the view hierarchy. - let appInstallAdView = Bundle.main.loadNibNamed("NativeAppInstallAdView", owner: nil, - options: nil)?.first as! GADNativeAppInstallAdView + // Create and place ad in view hierarchy. + guard let appInstallAdView: GADNativeAppInstallAdView = Bundle.main.loadNibNamed("NativeAppInstallAdView", owner: nil, options: nil)?.first as? GADNativeAppInstallAdView else { + return + } setAdView(appInstallAdView) - - // Associate the app install ad view with the app install ad object. This is required to make - // the ad clickable. + // Associate the app install ad view with the app install ad object. This is required to make the + // ad clickable. appInstallAdView.nativeAppInstallAd = nativeAppInstallAd - // Populate the app install ad view with the app install ad assets. // Some assets are guaranteed to be present in every app install ad. (appInstallAdView.headlineView as! UILabel).text = nativeAppInstallAd.headline (appInstallAdView.iconView as! UIImageView).image = nativeAppInstallAd.icon?.image (appInstallAdView.bodyView as! UILabel).text = nativeAppInstallAd.body - (appInstallAdView.imageView as! UIImageView).image = - (nativeAppInstallAd.images?.first as! GADNativeAdImage).image - (appInstallAdView.callToActionView as! UIButton).setTitle( - nativeAppInstallAd.callToAction, for: UIControlState.normal) + (appInstallAdView.callToActionView as! UIButton).setTitle(nativeAppInstallAd.callToAction, for: .normal) - // Other assets are not, however, and should be checked first. - let starRatingView = appInstallAdView.starRatingView + // Update the ViewController for video content. + updateVideoStatusLabel(forAdsVideoController: nativeAppInstallAd.videoController) + if (nativeAppInstallAd.videoController.hasVideoContent()) { + nativeAppInstallAd.videoController.delegate = self + } + // These assets are not guaranteed to be present, and should be checked first. if let starRating = nativeAppInstallAd.starRating { - (starRatingView as! UIImageView).image = imageOfStarsFromStarRating(starRating) - starRatingView?.isHidden = false - } else { - starRatingView?.isHidden = true + (appInstallAdView.starRatingView as? UIImageView)?.image = imageOfStars(fromStarRating:starRating) + appInstallAdView.starRatingView?.isHidden = false + } + else { + appInstallAdView.starRatingView?.isHidden = true } - - let storeView = appInstallAdView.storeView if let store = nativeAppInstallAd.store { - (storeView as! UILabel).text = store - storeView?.isHidden = false - } else { - storeView?.isHidden = true + (appInstallAdView.storeView as? UILabel)?.text = store + appInstallAdView.storeView?.isHidden = false + } + else { + appInstallAdView.storeView?.isHidden = true } - - let priceView = appInstallAdView.priceView if let price = nativeAppInstallAd.price { - (priceView as! UILabel).text = price - priceView?.isHidden = false - } else { - priceView?.isHidden = true + (appInstallAdView.priceView as? UILabel)?.text = price + appInstallAdView.priceView?.isHidden = false } - - // In order for the SDK to process touch events properly, user interaction should be disabled. - (appInstallAdView.callToActionView as! UIButton).isUserInteractionEnabled = false - } - - /// Returns a `UIImage` representing the number of stars from the given star rating; returns `nil` - /// if the star rating is less than 3.5 stars. - func imageOfStarsFromStarRating(_ starRating: NSDecimalNumber) -> UIImage? { - let rating = starRating.doubleValue - if rating >= 5 { - return UIImage(named: "stars_5") - } else if rating >= 4.5 { - return UIImage(named: "stars_4_5") - } else if rating >= 4 { - return UIImage(named: "stars_4") - } else if rating >= 3.5 { - return UIImage(named: "stars_3_5") - } else { - return nil + else { + appInstallAdView.priceView?.isHidden = true } + // In order for the SDK to process touch events properly, user interaction should be disabled. + appInstallAdView.callToActionView?.isUserInteractionEnabled = false } +} - // MARK: - GADNativeContentAdLoaderDelegate +// MARK: - GADNativeContentAdLoaderDelegate implementation +extension ViewController : GADNativeContentAdLoaderDelegate { func adLoader(_ adLoader: GADAdLoader, didReceive nativeContentAd: GADNativeContentAd) { print("Received native content ad: \(nativeContentAd)") refreshAdButton.isEnabled = true - - // Create and place the ad in the view hierarchy. - let contentAdView = Bundle.main.loadNibNamed( - "NativeContentAdView", owner: nil, options: nil)?.first as! GADNativeContentAdView + // Create and place ad in view hierarchy. + guard let contentAdView: GADNativeContentAdView = Bundle.main.loadNibNamed("NativeContentAdView", owner: nil, options: nil)?.first as? GADNativeContentAdView else { + return + } setAdView(contentAdView) - // Associate the content ad view with the content ad object. This is required to make the ad // clickable. contentAdView.nativeContentAd = nativeContentAd - // Populate the content ad view with the content ad assets. // Some assets are guaranteed to be present in every content ad. - (contentAdView.headlineView as! UILabel).text = nativeContentAd.headline - (contentAdView.bodyView as! UILabel).text = nativeContentAd.body - (contentAdView.imageView as! UIImageView).image = - (nativeContentAd.images?.first as! GADNativeAdImage).image - (contentAdView.advertiserView as! UILabel).text = nativeContentAd.advertiser - (contentAdView.callToActionView as! UIButton).setTitle( - nativeContentAd.callToAction, for: UIControlState.normal) - - // Other assets are not, however, and should be checked first. - let logoView = contentAdView.logoView - if let logoImage = nativeContentAd.logo?.image { - (logoView as! UIImageView).image = logoImage - logoView?.isHidden = false - } else { - logoView?.isHidden = true + (contentAdView.headlineView as? UILabel)?.text = nativeContentAd.headline + (contentAdView.bodyView as? UILabel)?.text = nativeContentAd.body + (contentAdView.advertiserView as? UILabel)?.text = nativeContentAd.advertiser + (contentAdView.callToActionView as? UIButton)?.setTitle(nativeContentAd.callToAction, for: .normal) + + // Update the ViewController for video content. + updateVideoStatusLabel(forAdsVideoController: nativeContentAd.videoController) + if (nativeContentAd.videoController.hasVideoContent()) { + nativeContentAd.videoController.delegate = self + } + // These assets are not guaranteed to be present, and should be checked first. + if let image = nativeContentAd.logo?.image { + (contentAdView.logoView as? UIImageView)?.image = image + contentAdView.logoView?.isHidden = false + } + else { + contentAdView.logoView?.isHidden = true } - // In order for the SDK to process touch events properly, user interaction should be disabled. - (contentAdView.callToActionView as! UIButton).isUserInteractionEnabled = false + contentAdView.callToActionView?.isUserInteractionEnabled = false } +} - // MARK: - GADNativeCustomTemplateAdLoaderDelegate +// MARK: - GADNativeCustomTemplateAdLoaderDelegate +extension ViewController : GADNativeCustomTemplateAdLoaderDelegate { + func nativeCustomTemplateIDs(for adLoader: GADAdLoader) -> [Any] { + return [ nativeCustomTemplateId ] + } func adLoader(_ adLoader: GADAdLoader, - didReceive nativeCustomTemplateAd: GADNativeCustomTemplateAd) { + didReceive nativeCustomTemplateAd: GADNativeCustomTemplateAd) { print("Received custom native ad: \(nativeCustomTemplateAd)") refreshAdButton.isEnabled = true - // Create and place the ad in the view hierarchy. let customNativeAdView = Bundle.main.loadNibNamed( - "SimpleCustomNativeAdView", owner: nil, options: nil)!.first as! MySimpleNativeAdView + "SimpleCustomNativeAdView", owner: nil, options: nil)!.first as! MySimpleNativeAdView setAdView(customNativeAdView) - + // Update the ViewController for video content. + updateVideoStatusLabel(forAdsVideoController: nativeCustomTemplateAd.videoController) + if (nativeCustomTemplateAd.videoController.hasVideoContent()) { + nativeCustomTemplateAd.videoController.delegate = self + } // Populate the custom native ad view with the custom native ad assets. - customNativeAdView.populateWithCustomNativeAd(nativeCustomTemplateAd) + customNativeAdView.populate(withCustomNativeAd:nativeCustomTemplateAd) } +} - func nativeCustomTemplateIDs(for adLoader: GADAdLoader) -> [Any] { - return [ "10063170" ] - } +// MARK: - GADVideoControllerDelegate implementation +extension ViewController : GADVideoControllerDelegate { + func videoControllerDidEndVideoPlayback(_ videoController: GADVideoController) { + videoStatusLabel.text = "Video playback has ended." + } }