diff --git a/BinaryProjects/ANSDK.xcodeproj/project.pbxproj b/BinaryProjects/ANSDK.xcodeproj/project.pbxproj index 9862b5485..715536bf0 100644 --- a/BinaryProjects/ANSDK.xcodeproj/project.pbxproj +++ b/BinaryProjects/ANSDK.xcodeproj/project.pbxproj @@ -6,75 +6,48 @@ objectVersion = 46; objects = { -/* Begin PBXAggregateTarget section */ - 8A6BE73919D5EEE500498F77 /* BuildANSDKFramework */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 8A6BE73A19D5EEE500498F77 /* Build configuration list for PBXAggregateTarget "BuildANSDKFramework" */; - buildPhases = ( - 8A6BE73D19D5EF1600498F77 /* Run Script */, - ); - dependencies = ( - 8A6BE74419D5F19800498F77 /* PBXTargetDependency */, - ); - name = BuildANSDKFramework; - productName = Framework; - }; -/* End PBXAggregateTarget section */ - /* Begin PBXBuildFile section */ + 8A2F48241A2E255600B0EA05 /* ANOpenInExternalBrowserActivity.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A2F48211A2E255600B0EA05 /* ANOpenInExternalBrowserActivity.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8A2F48251A2E255600B0EA05 /* ANOpenInExternalBrowserActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2F48221A2E255600B0EA05 /* ANOpenInExternalBrowserActivity.m */; }; + 8A2F48261A2E255600B0EA05 /* ANOpenInExternalBrowserActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2F48221A2E255600B0EA05 /* ANOpenInExternalBrowserActivity.m */; }; + 8A2F483D1A2E33B000B0EA05 /* compass.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A2F483C1A2E33B000B0EA05 /* compass.png */; }; 8A3B378119D623C300CE24A5 /* ANSDKResources.bundle in Resources */ = {isa = PBXBuildFile; fileRef = EC48177B1845046A0066BBFE /* ANSDKResources.bundle */; }; 8A3EC16E19B8FD9A0049CD29 /* ANBannerAdView+ANContentViewTransitions.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A3EC16D19B8FD9A0049CD29 /* ANBannerAdView+ANContentViewTransitions.m */; }; 8A3EC17019B8FDCA0049CD29 /* ANMRAID.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 8A3EC16F19B8FDC70049CD29 /* ANMRAID.bundle */; }; + 8A4FF3A11A2F72D00000E4CC /* compass@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A4FF3A01A2F72D00000E4CC /* compass@2x.png */; }; + 8A4FF3A41A2F8ACC0000E4CC /* an_arrow_left@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A4FF3A31A2F8ACC0000E4CC /* an_arrow_left@3x.png */; }; + 8A4FF3A71A2F8AFE0000E4CC /* an_arrow_left@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A4FF3A51A2F8AFE0000E4CC /* an_arrow_left@2x.png */; }; + 8A4FF3A81A2F8AFE0000E4CC /* an_arrow_left.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A4FF3A61A2F8AFE0000E4CC /* an_arrow_left.png */; }; + 8A4FF3AA1A2F8CC10000E4CC /* an_arrow_right@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A4FF3A91A2F8CC10000E4CC /* an_arrow_right@3x.png */; }; + 8A4FF3AD1A2F8CE50000E4CC /* an_arrow_right@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A4FF3AB1A2F8CE50000E4CC /* an_arrow_right@2x.png */; }; + 8A4FF3AE1A2F8CE50000E4CC /* an_arrow_right.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A4FF3AC1A2F8CE50000E4CC /* an_arrow_right.png */; }; + 8A598F7F1A1E89FC009BA879 /* ANAdFetcherResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD2DAE91A1D3A5B00878CDD /* ANAdFetcherResponse.m */; }; + 8A598F801A1E89FC009BA879 /* ANAdServerResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD2DAED1A1D3A6900878CDD /* ANAdServerResponse.m */; }; + 8A598F811A1E89FC009BA879 /* ANStandardAd.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD2DAF31A1D3C2A00878CDD /* ANStandardAd.m */; }; + 8A598F831A1E8A03009BA879 /* ANAdFetcherResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD2DAE81A1D3A5B00878CDD /* ANAdFetcherResponse.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8A598F841A1E8A03009BA879 /* ANAdServerResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD2DAEC1A1D3A6900878CDD /* ANAdServerResponse.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8A598F851A1E8A03009BA879 /* ANStandardAd.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD2DAF21A1D3C2A00878CDD /* ANStandardAd.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8A598F8B1A1EA061009BA879 /* ANNativeStandardAdResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A598F881A1EA061009BA879 /* ANNativeStandardAdResponse.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8A598F8C1A1EA061009BA879 /* ANNativeStandardAdResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A598F891A1EA061009BA879 /* ANNativeStandardAdResponse.m */; }; + 8A598F8D1A1EA061009BA879 /* ANNativeStandardAdResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A598F891A1EA061009BA879 /* ANNativeStandardAdResponse.m */; }; 8A6385DF1A14336000280054 /* ANNativeAdFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB8761F1A0994310022D9A5 /* ANNativeAdFetcher.m */; }; 8A6385E01A14336000280054 /* ANNativeAdImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB876211A0994310022D9A5 /* ANNativeAdImageCache.m */; }; 8A6385E11A14336000280054 /* ANNativeAdStarRating.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB876221A0994310022D9A5 /* ANNativeAdStarRating.m */; }; 8A6385E21A14336000280054 /* ANNativeAdRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB876231A0994310022D9A5 /* ANNativeAdRequest.m */; }; 8A6385E31A14336000280054 /* ANNativeAdRequestUrlBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB876251A0994310022D9A5 /* ANNativeAdRequestUrlBuilder.m */; }; 8A6385E41A14336000280054 /* ANNativeAdResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB876261A0994310022D9A5 /* ANNativeAdResponse.m */; }; - 8A6385E51A14336000280054 /* ANNativeMediatedAd.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB8762A1A0994310022D9A5 /* ANNativeMediatedAd.m */; }; 8A6385E61A14336000280054 /* ANNativeMediatedAdController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB8762C1A0994310022D9A5 /* ANNativeMediatedAdController.m */; }; 8A6385E71A14336000280054 /* ANNativeMediatedAdResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB8762E1A0994310022D9A5 /* ANNativeMediatedAdResponse.m */; }; - 8A6385E81A14336000280054 /* ANNativeAdRequest+ANBaseUrlOverride.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A6606441A0ACBA7008AB3D2 /* ANNativeAdRequest+ANBaseUrlOverride.m */; }; 8A6385E91A14336000280054 /* UIView+ANNativeAdCategory.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A6514711A12DB31003F1047 /* UIView+ANNativeAdCategory.m */; }; 8A6385F61A1433BD00280054 /* ANAdAdapterNativeFacebook.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A35B8AB19FEC9640016C81F /* ANAdAdapterNativeFacebook.m */; }; 8A6385F71A1433CB00280054 /* ANAdAdapterNativeMoPub.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A6606331A0A9A30008AB3D2 /* ANAdAdapterNativeMoPub.m */; }; - 8A6BE74619D5F2BD00498F77 /* ANAdProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE4EA8D194B768A0069D934 /* ANAdProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A6BE74719D5F2BD00498F77 /* ANAdView.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE4EA8E194B768A0069D934 /* ANAdView.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A6BE74819D5F2BD00498F77 /* ANBannerAdView.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE4EA8F194B768A0069D934 /* ANBannerAdView.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A6BE74919D5F2BD00498F77 /* ANCustomAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE4EA90194B768A0069D934 /* ANCustomAdapter.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A6BE74A19D5F2BD00498F77 /* ANInterstitialAd.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE4EA91194B768A0069D934 /* ANInterstitialAd.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A6BE74B19D5F2BD00498F77 /* ANLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE4EA92194B768A0069D934 /* ANLocation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A6BE74C19D5F2BD00498F77 /* ANLogManager.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE4EA93194B768A0069D934 /* ANLogManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A6BE74D19D5F2BD00498F77 /* ANTargetingParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE4EA94194B768A0069D934 /* ANTargetingParameters.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A6BE78219D60C3E00498F77 /* ANSDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A6BE78019D60C3E00498F77 /* ANSDK.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A6BE78819D61EDA00498F77 /* ANBannerAdView+ANContentViewTransitions.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A3EC16C19B8FD9A0049CD29 /* ANBannerAdView+ANContentViewTransitions.h */; }; - 8A6BE78919D61EDA00498F77 /* NSString+ANCategory.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE4EA96194B768A0069D934 /* NSString+ANCategory.h */; }; - 8A6BE78A19D61EDA00498F77 /* NSTimer+ANCategory.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE4EA98194B768A0069D934 /* NSTimer+ANCategory.h */; }; - 8A6BE78B19D61EDA00498F77 /* UIView+ANCategory.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE4EA9A194B768A0069D934 /* UIView+ANCategory.h */; }; - 8A6BE78C19D61EDA00498F77 /* UIWebView+ANCategory.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE4EA9C194B768A0069D934 /* UIWebView+ANCategory.h */; }; - 8A6BE78D19D61EF900498F77 /* ANAdFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD6189E1981C11F00AC0780 /* ANAdFetcher.h */; }; - 8A6BE78E19D61EF900498F77 /* ANAdRequestUrl.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618A01981C11F00AC0780 /* ANAdRequestUrl.h */; }; - 8A6BE78F19D61EF900498F77 /* ANAdResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618A21981C11F00AC0780 /* ANAdResponse.h */; }; - 8A6BE79019D61EF900498F77 /* ANAdViewDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618A51981C11F00AC0780 /* ANAdViewDelegate.h */; }; - 8A6BE79119D61EF900498F77 /* ANAdWebViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618A61981C11F00AC0780 /* ANAdWebViewController.h */; }; - 8A6BE79219D61EF900498F77 /* ANANJAMImplementation.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618A81981C11F00AC0780 /* ANANJAMImplementation.h */; }; - 8A6BE79319D61EF900498F77 /* ANBasicConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618AB1981C11F00AC0780 /* ANBasicConfig.h */; }; - 8A6BE79419D61EF900498F77 /* ANBrowserViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618AC1981C11F00AC0780 /* ANBrowserViewController.h */; }; - 8A6BE79519D61EF900498F77 /* ANClickOverlayView.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618AE1981C11F00AC0780 /* ANClickOverlayView.h */; }; - 8A6BE79619D61EF900498F77 /* ANGlobal.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618B01981C11F00AC0780 /* ANGlobal.h */; }; - 8A6BE79719D61EF900498F77 /* ANInterstitialAdViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618B31981C11F00AC0780 /* ANInterstitialAdViewController.h */; }; - 8A6BE79819D61EF900498F77 /* ANLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618B61981C11F00AC0780 /* ANLogging.h */; }; - 8A6BE79919D61EF900498F77 /* ANMediatedAd.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618B91981C11F00AC0780 /* ANMediatedAd.h */; }; - 8A6BE79A19D61EF900498F77 /* ANMediationAdViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618BB1981C11F00AC0780 /* ANMediationAdViewController.h */; }; - 8A6BE79B19D61EF900498F77 /* ANMediationContainerView.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618BD1981C11F00AC0780 /* ANMediationContainerView.h */; }; - 8A6BE79C19D61EF900498F77 /* ANMRAIDProperties.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618BF1981C11F00AC0780 /* ANMRAIDProperties.h */; }; - 8A6BE79D19D61EF900498F77 /* ANMRAIDViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618C01981C11F00AC0780 /* ANMRAIDViewController.h */; }; - 8A6BE79E19D61EF900498F77 /* ANPBBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618C21981C11F00AC0780 /* ANPBBuffer.h */; }; - 8A6BE79F19D61EF900498F77 /* ANPBContainerView.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618C41981C11F00AC0780 /* ANPBContainerView.h */; }; - 8A6BE7A019D61EF900498F77 /* ANReachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618C61981C11F00AC0780 /* ANReachability.h */; }; - 8A6BE7A119D61EF900498F77 /* ANWebView.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618C91981C11F00AC0780 /* ANWebView.h */; }; + 8A6CD9271A96B2FD0060BCF4 /* compass@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A6CD9261A96B2FD0060BCF4 /* compass@3x.png */; }; + 8A6D2E8D1A44A751003CE77A /* interstitial_flat_closebox@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A6D2E841A44A5D3003CE77A /* interstitial_flat_closebox@3x.png */; }; + 8A6D2E8E1A44A751003CE77A /* interstitial_flat_closebox@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A6D2E871A44A62A003CE77A /* interstitial_flat_closebox@2x.png */; }; + 8A6D2E8F1A44A751003CE77A /* interstitial_flat_closebox.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A6D2E881A44A62A003CE77A /* interstitial_flat_closebox.png */; }; + 8A82FDF61A30F36C00A267A0 /* ANNativeImpressionTrackerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A82FDF41A30F36B00A267A0 /* ANNativeImpressionTrackerManager.m */; }; + 8A84E42E1A25350800C60EAB /* ANNativeAdResponse+PrivateMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A84E42A1A2534F300C60EAB /* ANNativeAdResponse+PrivateMethods.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AED201A1BAD2700C58BDA /* ANAdConstants.h in Copy Files */ = {isa = PBXBuildFile; fileRef = 8ABB76691A00385C00FEAD9D /* ANAdConstants.h */; }; - 8A9AED211A1BAD6000C58BDA /* ANAdConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 8ABB76691A00385C00FEAD9D /* ANAdConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8A9AED221A1BAD7700C58BDA /* ANNativeAdDelegate.h in Copy Files */ = {isa = PBXBuildFile; fileRef = 8AEA6BE91A0BF43E009DB71B /* ANNativeAdDelegate.h */; }; 8A9AED231A1BAD7700C58BDA /* ANNativeAdRequest.h in Copy Files */ = {isa = PBXBuildFile; fileRef = 8A35B89619FEB5EC0016C81F /* ANNativeAdRequest.h */; }; 8A9AED241A1BAD7700C58BDA /* ANNativeAdResponse.h in Copy Files */ = {isa = PBXBuildFile; fileRef = 8A35B89919FEB8A40016C81F /* ANNativeAdResponse.h */; }; @@ -82,21 +55,7 @@ 8A9AED261A1BAD7700C58BDA /* ANNativeAdTargetingProtocol.h in Copy Files */ = {isa = PBXBuildFile; fileRef = 8AEA6BE71A0BEEF5009DB71B /* ANNativeAdTargetingProtocol.h */; }; 8A9AED271A1BAD7700C58BDA /* ANNativeCustomAdapter.h in Copy Files */ = {isa = PBXBuildFile; fileRef = 8A35B8A219FEBEBD0016C81F /* ANNativeCustomAdapter.h */; }; 8A9AED281A1BAD7700C58BDA /* ANNativeMediatedAdResponse.h in Copy Files */ = {isa = PBXBuildFile; fileRef = 8AB8762D1A0994310022D9A5 /* ANNativeMediatedAdResponse.h */; }; - 8A9AED291A1BAD7A00C58BDA /* ANNativeAdDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AEA6BE91A0BF43E009DB71B /* ANNativeAdDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A9AED2A1A1BAD7A00C58BDA /* ANNativeAdRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A35B89619FEB5EC0016C81F /* ANNativeAdRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A9AED2B1A1BAD7A00C58BDA /* ANNativeAdResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A35B89919FEB8A40016C81F /* ANNativeAdResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A9AED2C1A1BAD7A00C58BDA /* ANNativeAdStarRating.h in Headers */ = {isa = PBXBuildFile; fileRef = 8ABB766D1A004DBD00FEAD9D /* ANNativeAdStarRating.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A9AED2D1A1BAD7A00C58BDA /* ANNativeCustomAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A35B8A219FEBEBD0016C81F /* ANNativeCustomAdapter.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A9AED2E1A1BAD7A00C58BDA /* ANNativeMediatedAdResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AB8762D1A0994310022D9A5 /* ANNativeMediatedAdResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A9AED2F1A1BAD9300C58BDA /* ANNativeAdFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AB8761E1A0994310022D9A5 /* ANNativeAdFetcher.h */; }; - 8A9AED301A1BAD9300C58BDA /* ANNativeAdImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AB876201A0994310022D9A5 /* ANNativeAdImageCache.h */; }; - 8A9AED311A1BAD9300C58BDA /* ANNativeAdRequest+ANBaseUrlOverride.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A6606431A0ACBA7008AB3D2 /* ANNativeAdRequest+ANBaseUrlOverride.h */; }; - 8A9AED321A1BAD9300C58BDA /* ANNativeAdRequestUrlBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AB876241A0994310022D9A5 /* ANNativeAdRequestUrlBuilder.h */; }; - 8A9AED331A1BAD9300C58BDA /* ANNativeMediatedAd.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AB876291A0994310022D9A5 /* ANNativeMediatedAd.h */; }; - 8A9AED341A1BAD9300C58BDA /* ANNativeMediatedAdController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AB8762B1A0994310022D9A5 /* ANNativeMediatedAdController.h */; }; - 8A9AED351A1BAD9300C58BDA /* UIView+ANNativeAdCategory.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A6514701A12DB31003F1047 /* UIView+ANNativeAdCategory.h */; }; 8A9AED911A1BE84F00C58BDA /* AppNexusSDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A9AED901A1BE84F00C58BDA /* AppNexusSDK.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A9AEDAF1A1BE8AF00C58BDA /* ANSDKResources.bundle in Resources */ = {isa = PBXBuildFile; fileRef = EC48177B1845046A0066BBFE /* ANSDKResources.bundle */; }; 8A9AEDB11A1BE8C200C58BDA /* ANAdConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 8ABB76691A00385C00FEAD9D /* ANAdConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8A9AEDB21A1BE8C200C58BDA /* ANAdProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE4EA8D194B768A0069D934 /* ANAdProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8A9AEDB31A1BE8C200C58BDA /* ANAdView.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE4EA8E194B768A0069D934 /* ANAdView.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -121,8 +80,7 @@ 8A9AEDCB1A1BF88200C58BDA /* ANAdFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD6189E1981C11F00AC0780 /* ANAdFetcher.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDCC1A1BF88200C58BDA /* ANAdRequestUrl.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618A01981C11F00AC0780 /* ANAdRequestUrl.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDCD1A1BF88200C58BDA /* ANAdResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618A21981C11F00AC0780 /* ANAdResponse.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 8A9AEDCE1A1BF88200C58BDA /* ANAdViewDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618A51981C11F00AC0780 /* ANAdViewDelegate.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 8A9AEDCF1A1BF88200C58BDA /* ANAdWebViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618A61981C11F00AC0780 /* ANAdWebViewController.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8A9AEDCE1A1BF88200C58BDA /* ANAdViewInternalDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618A51981C11F00AC0780 /* ANAdViewInternalDelegate.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDD01A1BF88200C58BDA /* ANANJAMImplementation.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618A81981C11F00AC0780 /* ANANJAMImplementation.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDD11A1BF88200C58BDA /* ANBasicConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618AB1981C11F00AC0780 /* ANBasicConfig.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDD21A1BF88200C58BDA /* ANBrowserViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618AC1981C11F00AC0780 /* ANBrowserViewController.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -133,17 +91,12 @@ 8A9AEDD71A1BF88200C58BDA /* ANMediatedAd.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618B91981C11F00AC0780 /* ANMediatedAd.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDD81A1BF88200C58BDA /* ANMediationAdViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618BB1981C11F00AC0780 /* ANMediationAdViewController.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDD91A1BF88200C58BDA /* ANMediationContainerView.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618BD1981C11F00AC0780 /* ANMediationContainerView.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 8A9AEDDA1A1BF88200C58BDA /* ANMRAIDProperties.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618BF1981C11F00AC0780 /* ANMRAIDProperties.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 8A9AEDDB1A1BF88200C58BDA /* ANMRAIDViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618C01981C11F00AC0780 /* ANMRAIDViewController.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDDC1A1BF88200C58BDA /* ANPBBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618C21981C11F00AC0780 /* ANPBBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDDD1A1BF88300C58BDA /* ANPBContainerView.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618C41981C11F00AC0780 /* ANPBContainerView.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDDE1A1BF88300C58BDA /* ANReachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618C61981C11F00AC0780 /* ANReachability.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 8A9AEDDF1A1BF88300C58BDA /* ANWebView.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AD618C91981C11F00AC0780 /* ANWebView.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDE01A1BF88300C58BDA /* ANNativeAdFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AB8761E1A0994310022D9A5 /* ANNativeAdFetcher.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDE11A1BF88300C58BDA /* ANNativeAdImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AB876201A0994310022D9A5 /* ANNativeAdImageCache.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 8A9AEDE21A1BF88300C58BDA /* ANNativeAdRequest+ANBaseUrlOverride.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A6606431A0ACBA7008AB3D2 /* ANNativeAdRequest+ANBaseUrlOverride.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDE31A1BF88300C58BDA /* ANNativeAdRequestUrlBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AB876241A0994310022D9A5 /* ANNativeAdRequestUrlBuilder.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 8A9AEDE41A1BF88300C58BDA /* ANNativeMediatedAd.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AB876291A0994310022D9A5 /* ANNativeMediatedAd.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDE51A1BF88300C58BDA /* ANNativeMediatedAdController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AB8762B1A0994310022D9A5 /* ANNativeMediatedAdController.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDE61A1BF88300C58BDA /* UIView+ANNativeAdCategory.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A6514701A12DB31003F1047 /* UIView+ANNativeAdCategory.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8A9AEDE81A1BF99D00C58BDA /* ANBannerAdView+ANContentViewTransitions.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A3EC16D19B8FD9A0049CD29 /* ANBannerAdView+ANContentViewTransitions.m */; }; @@ -155,7 +108,6 @@ 8A9AEDEE1A1BF99D00C58BDA /* ANAdRequestUrl.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618A11981C11F00AC0780 /* ANAdRequestUrl.m */; }; 8A9AEDEF1A1BF99D00C58BDA /* ANAdResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618A31981C11F00AC0780 /* ANAdResponse.m */; }; 8A9AEDF01A1BF99D00C58BDA /* ANAdView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618A41981C11F00AC0780 /* ANAdView.m */; }; - 8A9AEDF11A1BF99D00C58BDA /* ANAdWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618A71981C11F00AC0780 /* ANAdWebViewController.m */; }; 8A9AEDF21A1BF99D00C58BDA /* ANANJAMImplementation.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618A91981C11F00AC0780 /* ANANJAMImplementation.m */; }; 8A9AEDF31A1BF99D00C58BDA /* ANBannerAdView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618AA1981C11F00AC0780 /* ANBannerAdView.m */; }; 8A9AEDF41A1BF99D00C58BDA /* ANBrowserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618AD1981C11F00AC0780 /* ANBrowserViewController.m */; }; @@ -169,23 +121,53 @@ 8A9AEDFC1A1BF99D00C58BDA /* ANMediatedAd.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618BA1981C11F00AC0780 /* ANMediatedAd.m */; }; 8A9AEDFD1A1BF99D00C58BDA /* ANMediationAdViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618BC1981C11F00AC0780 /* ANMediationAdViewController.m */; }; 8A9AEDFE1A1BF99D00C58BDA /* ANMediationContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618BE1981C11F00AC0780 /* ANMediationContainerView.m */; }; - 8A9AEDFF1A1BF99D00C58BDA /* ANMRAIDViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618C11981C11F00AC0780 /* ANMRAIDViewController.m */; }; 8A9AEE001A1BF99D00C58BDA /* ANPBBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618C31981C11F00AC0780 /* ANPBBuffer.m */; }; 8A9AEE011A1BF99D00C58BDA /* ANPBContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618C51981C11F00AC0780 /* ANPBContainerView.m */; }; 8A9AEE021A1BF99D00C58BDA /* ANReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618C71981C11F00AC0780 /* ANReachability.m */; }; 8A9AEE031A1BF99D00C58BDA /* ANTargetingParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618C81981C11F00AC0780 /* ANTargetingParameters.m */; }; - 8A9AEE041A1BF99D00C58BDA /* ANWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618CA1981C11F00AC0780 /* ANWebView.m */; }; 8A9AEE051A1BF99D00C58BDA /* ANNativeAdFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB8761F1A0994310022D9A5 /* ANNativeAdFetcher.m */; }; 8A9AEE061A1BF99D00C58BDA /* ANNativeAdImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB876211A0994310022D9A5 /* ANNativeAdImageCache.m */; }; 8A9AEE071A1BF99D00C58BDA /* ANNativeAdRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB876231A0994310022D9A5 /* ANNativeAdRequest.m */; }; - 8A9AEE081A1BF99D00C58BDA /* ANNativeAdRequest+ANBaseUrlOverride.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A6606441A0ACBA7008AB3D2 /* ANNativeAdRequest+ANBaseUrlOverride.m */; }; 8A9AEE091A1BF99D00C58BDA /* ANNativeAdRequestUrlBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB876251A0994310022D9A5 /* ANNativeAdRequestUrlBuilder.m */; }; 8A9AEE0A1A1BF99D00C58BDA /* ANNativeAdResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB876261A0994310022D9A5 /* ANNativeAdResponse.m */; }; 8A9AEE0B1A1BF99D00C58BDA /* ANNativeAdStarRating.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB876221A0994310022D9A5 /* ANNativeAdStarRating.m */; }; - 8A9AEE0C1A1BF99D00C58BDA /* ANNativeMediatedAd.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB8762A1A0994310022D9A5 /* ANNativeMediatedAd.m */; }; 8A9AEE0D1A1BF99D00C58BDA /* ANNativeMediatedAdController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB8762C1A0994310022D9A5 /* ANNativeMediatedAdController.m */; }; 8A9AEE0E1A1BF99D00C58BDA /* ANNativeMediatedAdResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB8762E1A0994310022D9A5 /* ANNativeMediatedAdResponse.m */; }; 8A9AEE0F1A1BF99D00C58BDA /* UIView+ANNativeAdCategory.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A6514711A12DB31003F1047 /* UIView+ANNativeAdCategory.m */; }; + 8AC65F4C1A40DE63006BCF39 /* ANMRAIDCalendarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F381A40DE63006BCF39 /* ANMRAIDCalendarManager.m */; }; + 8AC65F4E1A40DE63006BCF39 /* ANMRAIDContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F3A1A40DE63006BCF39 /* ANMRAIDContainerView.m */; }; + 8AC65F501A40DE63006BCF39 /* ANMRAIDExpandProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F3C1A40DE63006BCF39 /* ANMRAIDExpandProperties.m */; }; + 8AC65F521A40DE63006BCF39 /* ANMRAIDExpandViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F3E1A40DE63006BCF39 /* ANMRAIDExpandViewController.m */; }; + 8AC65F541A40DE63006BCF39 /* ANMRAIDJavascriptUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F401A40DE63006BCF39 /* ANMRAIDJavascriptUtil.m */; }; + 8AC65F561A40DE63006BCF39 /* ANMRAIDOrientationProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F421A40DE63006BCF39 /* ANMRAIDOrientationProperties.m */; }; + 8AC65F581A40DE63006BCF39 /* ANMRAIDResizeProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F441A40DE63006BCF39 /* ANMRAIDResizeProperties.m */; }; + 8AC65F5A1A40DE63006BCF39 /* ANMRAIDResizeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F461A40DE63006BCF39 /* ANMRAIDResizeView.m */; }; + 8AC65F5C1A40DE63006BCF39 /* ANMRAIDResizeViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F481A40DE63006BCF39 /* ANMRAIDResizeViewManager.m */; }; + 8AC65F5E1A40DE63006BCF39 /* ANMRAIDUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F4A1A40DE63006BCF39 /* ANMRAIDUtil.m */; }; + 8AC65F5F1A40DE74006BCF39 /* ANMRAIDCalendarManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AC65F371A40DE63006BCF39 /* ANMRAIDCalendarManager.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8AC65F601A40DE74006BCF39 /* ANMRAIDCalendarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F381A40DE63006BCF39 /* ANMRAIDCalendarManager.m */; }; + 8AC65F611A40DE74006BCF39 /* ANMRAIDContainerView.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AC65F391A40DE63006BCF39 /* ANMRAIDContainerView.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8AC65F621A40DE74006BCF39 /* ANMRAIDContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F3A1A40DE63006BCF39 /* ANMRAIDContainerView.m */; }; + 8AC65F631A40DE74006BCF39 /* ANMRAIDExpandProperties.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AC65F3B1A40DE63006BCF39 /* ANMRAIDExpandProperties.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8AC65F641A40DE74006BCF39 /* ANMRAIDExpandProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F3C1A40DE63006BCF39 /* ANMRAIDExpandProperties.m */; }; + 8AC65F651A40DE74006BCF39 /* ANMRAIDExpandViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AC65F3D1A40DE63006BCF39 /* ANMRAIDExpandViewController.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8AC65F661A40DE74006BCF39 /* ANMRAIDExpandViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F3E1A40DE63006BCF39 /* ANMRAIDExpandViewController.m */; }; + 8AC65F671A40DE74006BCF39 /* ANMRAIDJavascriptUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AC65F3F1A40DE63006BCF39 /* ANMRAIDJavascriptUtil.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8AC65F681A40DE74006BCF39 /* ANMRAIDJavascriptUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F401A40DE63006BCF39 /* ANMRAIDJavascriptUtil.m */; }; + 8AC65F691A40DE74006BCF39 /* ANMRAIDOrientationProperties.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AC65F411A40DE63006BCF39 /* ANMRAIDOrientationProperties.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8AC65F6A1A40DE74006BCF39 /* ANMRAIDOrientationProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F421A40DE63006BCF39 /* ANMRAIDOrientationProperties.m */; }; + 8AC65F6B1A40DE74006BCF39 /* ANMRAIDResizeProperties.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AC65F431A40DE63006BCF39 /* ANMRAIDResizeProperties.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8AC65F6C1A40DE74006BCF39 /* ANMRAIDResizeProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F441A40DE63006BCF39 /* ANMRAIDResizeProperties.m */; }; + 8AC65F6D1A40DE74006BCF39 /* ANMRAIDResizeView.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AC65F451A40DE63006BCF39 /* ANMRAIDResizeView.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8AC65F6E1A40DE74006BCF39 /* ANMRAIDResizeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F461A40DE63006BCF39 /* ANMRAIDResizeView.m */; }; + 8AC65F6F1A40DE74006BCF39 /* ANMRAIDResizeViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AC65F471A40DE63006BCF39 /* ANMRAIDResizeViewManager.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8AC65F701A40DE74006BCF39 /* ANMRAIDResizeViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F481A40DE63006BCF39 /* ANMRAIDResizeViewManager.m */; }; + 8AC65F711A40DE74006BCF39 /* ANMRAIDUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AC65F491A40DE63006BCF39 /* ANMRAIDUtil.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8AC65F721A40DE74006BCF39 /* ANMRAIDUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC65F4A1A40DE63006BCF39 /* ANMRAIDUtil.m */; }; + 8AC7C5391A3B5CEF00AA5548 /* ANAdWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC7C5371A3B5CEF00AA5548 /* ANAdWebViewController.m */; }; + 8AD2DAEB1A1D3A5B00878CDD /* ANAdFetcherResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD2DAE91A1D3A5B00878CDD /* ANAdFetcherResponse.m */; }; + 8AD2DAEF1A1D3A6900878CDD /* ANAdServerResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD2DAED1A1D3A6900878CDD /* ANAdServerResponse.m */; }; + 8AD2DAF51A1D3C2A00878CDD /* ANStandardAd.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD2DAF31A1D3C2A00878CDD /* ANStandardAd.m */; }; 8AD5155D19D216E6002E53D6 /* ANAdAdapterBannerAmazon.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD5155619D216E6002E53D6 /* ANAdAdapterBannerAmazon.m */; }; 8AD5155E19D216E6002E53D6 /* ANAdAdapterBaseAmazon.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD5155819D216E6002E53D6 /* ANAdAdapterBaseAmazon.m */; }; 8AD5155F19D216E6002E53D6 /* ANAdAdapterInterstitialAmazon.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD5155A19D216E6002E53D6 /* ANAdAdapterInterstitialAmazon.m */; }; @@ -193,7 +175,6 @@ 8AD618CC1981C11F00AC0780 /* ANAdRequestUrl.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618A11981C11F00AC0780 /* ANAdRequestUrl.m */; }; 8AD618CD1981C11F00AC0780 /* ANAdResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618A31981C11F00AC0780 /* ANAdResponse.m */; }; 8AD618CE1981C11F00AC0780 /* ANAdView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618A41981C11F00AC0780 /* ANAdView.m */; }; - 8AD618CF1981C11F00AC0780 /* ANAdWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618A71981C11F00AC0780 /* ANAdWebViewController.m */; }; 8AD618D01981C11F00AC0780 /* ANANJAMImplementation.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618A91981C11F00AC0780 /* ANANJAMImplementation.m */; }; 8AD618D11981C11F00AC0780 /* ANBannerAdView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618AA1981C11F00AC0780 /* ANBannerAdView.m */; }; 8AD618D21981C11F00AC0780 /* ANBrowserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618AD1981C11F00AC0780 /* ANBrowserViewController.m */; }; @@ -207,14 +188,13 @@ 8AD618DA1981C11F00AC0780 /* ANMediatedAd.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618BA1981C11F00AC0780 /* ANMediatedAd.m */; }; 8AD618DB1981C11F00AC0780 /* ANMediationAdViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618BC1981C11F00AC0780 /* ANMediationAdViewController.m */; }; 8AD618DC1981C11F00AC0780 /* ANMediationContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618BE1981C11F00AC0780 /* ANMediationContainerView.m */; }; - 8AD618DD1981C11F00AC0780 /* ANMRAIDViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618C11981C11F00AC0780 /* ANMRAIDViewController.m */; }; 8AD618DE1981C11F00AC0780 /* ANPBBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618C31981C11F00AC0780 /* ANPBBuffer.m */; }; 8AD618DF1981C11F00AC0780 /* ANPBContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618C51981C11F00AC0780 /* ANPBContainerView.m */; }; 8AD618E01981C11F00AC0780 /* ANReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618C71981C11F00AC0780 /* ANReachability.m */; }; 8AD618E11981C11F00AC0780 /* ANTargetingParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618C81981C11F00AC0780 /* ANTargetingParameters.m */; }; - 8AD618E21981C11F00AC0780 /* ANWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD618CA1981C11F00AC0780 /* ANWebView.m */; }; 8AD618E31981C19100AC0780 /* appnexus_logo_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 8AD618991981C10700AC0780 /* appnexus_logo_icon.png */; }; 8AD618E41981C19500AC0780 /* appnexus_logo_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8AD6189A1981C10700AC0780 /* appnexus_logo_icon@2x.png */; }; + 8ADA36201A82A8D700AF65AA /* ANSDKResources.bundle in Resources */ = {isa = PBXBuildFile; fileRef = EC48177B1845046A0066BBFE /* ANSDKResources.bundle */; }; 8AE2D79C19CC881D00001B70 /* ANAdAdapterBannerFacebook.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AE2D79719CC880D00001B70 /* ANAdAdapterBannerFacebook.m */; }; 8AE2D79D19CC881D00001B70 /* ANAdAdapterInterstitialFacebook.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AE2D79919CC880D00001B70 /* ANAdAdapterInterstitialFacebook.m */; }; 8AE2D7C519CC885600001B70 /* ANAdAdapterBannerMoPub.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AE2D7A219CC885600001B70 /* ANAdAdapterBannerMoPub.m */; }; @@ -233,9 +213,24 @@ 8AE2D86719CC9B3A00001B70 /* ANGADCustomInterstitialAd.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AE2D86519CC9B3A00001B70 /* ANGADCustomInterstitialAd.m */; }; 8AE2D86F19CC9B7300001B70 /* ANMoPubMediationBanner.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AE2D86C19CC9B7300001B70 /* ANMoPubMediationBanner.m */; }; 8AE2D87019CC9B7300001B70 /* ANMoPubMediationInterstitial.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AE2D86E19CC9B7300001B70 /* ANMoPubMediationInterstitial.m */; }; - 8AEA6BE81A0BEEF5009DB71B /* ANNativeAdTargetingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AEA6BE71A0BEEF5009DB71B /* ANNativeAdTargetingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8AE5E11E1A2FDC7700FDE858 /* ANAdView+PrivateMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AE5E11C1A2FDC7700FDE858 /* ANAdView+PrivateMethods.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8AE7AD9E1A7AC4E5009E2F2F /* EventKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AE7AD9D1A7AC4E5009E2F2F /* EventKitUI.framework */; }; + 8AE7AD9F1A7AC4F6009E2F2F /* ANAdWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AC7C5371A3B5CEF00AA5548 /* ANAdWebViewController.m */; }; 8AF366BD19D492F30097019F /* ANSDKResources.bundle in Copy Files */ = {isa = PBXBuildFile; fileRef = EC48177B1845046A0066BBFE /* ANSDKResources.bundle */; }; + 8AF3C19D1A361CC30018FB6A /* ANNativeImpressionTrackerInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AF3C19B1A361CC30018FB6A /* ANNativeImpressionTrackerInfo.m */; }; + 8AF3C19F1A3631460018FB6A /* ANNativeImpressionTrackerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A82FDF41A30F36B00A267A0 /* ANNativeImpressionTrackerManager.m */; }; + 8AF3C1A01A3631490018FB6A /* ANNativeImpressionTrackerInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AF3C19B1A361CC30018FB6A /* ANNativeImpressionTrackerInfo.m */; }; 8AF9F08D19DA131F00758111 /* ANAdAdapterBaseAmazon.h in Copy Files */ = {isa = PBXBuildFile; fileRef = 8AD5155719D216E6002E53D6 /* ANAdAdapterBaseAmazon.h */; }; + 8AFC045F1A2E74AC00BEA485 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AFC045E1A2E74AC00BEA485 /* UIKit.framework */; }; + 8AFC04611A2E74C800BEA485 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AFC04601A2E74C800BEA485 /* CoreGraphics.framework */; }; + 8AFC04631A2E74F500BEA485 /* EventKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AFC04621A2E74F500BEA485 /* EventKit.framework */; }; + 8AFC04651A2E751200BEA485 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AFC04641A2E751200BEA485 /* CoreTelephony.framework */; }; + 8AFC04671A2E752E00BEA485 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AFC04661A2E752E00BEA485 /* SystemConfiguration.framework */; }; + 8AFC046B1A2E757900BEA485 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AFC046A1A2E757900BEA485 /* QuartzCore.framework */; }; + 8AFC046D1A2E75A300BEA485 /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AFC046C1A2E75A300BEA485 /* MediaPlayer.framework */; }; + 8AFC046F1A2E75AE00BEA485 /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AFC046E1A2E75AE00BEA485 /* AdSupport.framework */; }; + 8AFC04711A2E760800BEA485 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AFC04701A2E760800BEA485 /* MessageUI.framework */; }; + 8AFC04731A2E78E400BEA485 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AFC04721A2E78E400BEA485 /* StoreKit.framework */; }; ECE4EADA194B768A0069D934 /* NSString+ANCategory.m in Sources */ = {isa = PBXBuildFile; fileRef = ECE4EA97194B768A0069D934 /* NSString+ANCategory.m */; }; ECE4EADB194B768A0069D934 /* NSTimer+ANCategory.m in Sources */ = {isa = PBXBuildFile; fileRef = ECE4EA99194B768A0069D934 /* NSTimer+ANCategory.m */; }; ECE4EADC194B768A0069D934 /* UIView+ANCategory.m in Sources */ = {isa = PBXBuildFile; fileRef = ECE4EA9B194B768A0069D934 /* UIView+ANCategory.m */; }; @@ -244,8 +239,6 @@ ECE4EB04194B76960069D934 /* ANInterstitialAdViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = ECE4EACC194B768A0069D934 /* ANInterstitialAdViewController.xib */; }; ECE4EB05194B76960069D934 /* anjam.js in Resources */ = {isa = PBXBuildFile; fileRef = ECE4EACD194B768A0069D934 /* anjam.js */; }; ECE4EB06194B76960069D934 /* errors.strings in Resources */ = {isa = PBXBuildFile; fileRef = ECE4EACE194B768A0069D934 /* errors.strings */; }; - ECE4EB07194B76960069D934 /* interstitial_closebox-down.png in Resources */ = {isa = PBXBuildFile; fileRef = ECE4EAD0194B768A0069D934 /* interstitial_closebox-down.png */; }; - ECE4EB08194B76960069D934 /* interstitial_closebox-down@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = ECE4EAD1194B768A0069D934 /* interstitial_closebox-down@2x.png */; }; ECE4EB09194B76960069D934 /* interstitial_closebox.png in Resources */ = {isa = PBXBuildFile; fileRef = ECE4EAD2194B768A0069D934 /* interstitial_closebox.png */; }; ECE4EB0A194B76960069D934 /* interstitial_closebox@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = ECE4EAD3194B768A0069D934 /* interstitial_closebox@2x.png */; }; ECE4EB0B194B76960069D934 /* UIButtonBarArrowLeft.png in Resources */ = {isa = PBXBuildFile; fileRef = ECE4EAD4194B768A0069D934 /* UIButtonBarArrowLeft.png */; }; @@ -264,13 +257,6 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 8A6BE74319D5F19800498F77 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = EC3E5CD41843C6D50070315E /* Project object */; - proxyType = 1; - remoteGlobalIDString = EC3E5CDB1843C6D50070315E; - remoteInfo = ANSDK; - }; 8A9AEDAD1A1BE8AA00C58BDA /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = EC3E5CD41843C6D50070315E /* Project object */; @@ -455,6 +441,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 8A2F48211A2E255600B0EA05 /* ANOpenInExternalBrowserActivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANOpenInExternalBrowserActivity.h; sourceTree = ""; }; + 8A2F48221A2E255600B0EA05 /* ANOpenInExternalBrowserActivity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANOpenInExternalBrowserActivity.m; sourceTree = ""; }; + 8A2F483C1A2E33B000B0EA05 /* compass.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = compass.png; sourceTree = ""; }; 8A35B89619FEB5EC0016C81F /* ANNativeAdRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ANNativeAdRequest.h; path = native/ANNativeAdRequest.h; sourceTree = ""; }; 8A35B89919FEB8A40016C81F /* ANNativeAdResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ANNativeAdResponse.h; path = native/ANNativeAdResponse.h; sourceTree = ""; }; 8A35B8A219FEBEBD0016C81F /* ANNativeCustomAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ANNativeCustomAdapter.h; path = native/ANNativeCustomAdapter.h; sourceTree = ""; }; @@ -463,49 +452,35 @@ 8A3EC16C19B8FD9A0049CD29 /* ANBannerAdView+ANContentViewTransitions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ANBannerAdView+ANContentViewTransitions.h"; sourceTree = ""; }; 8A3EC16D19B8FD9A0049CD29 /* ANBannerAdView+ANContentViewTransitions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ANBannerAdView+ANContentViewTransitions.m"; sourceTree = ""; }; 8A3EC16F19B8FDC70049CD29 /* ANMRAID.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = ANMRAID.bundle; sourceTree = ""; }; + 8A4018191A95213200D56208 /* GoogleMobileAds.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = GoogleMobileAds.framework; sourceTree = ""; }; + 8A40181F1A95224800D56208 /* MPCloseButtonX@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MPCloseButtonX@3x.png"; sourceTree = ""; }; + 8A4FF3A01A2F72D00000E4CC /* compass@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "compass@2x.png"; sourceTree = ""; }; + 8A4FF3A31A2F8ACC0000E4CC /* an_arrow_left@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "an_arrow_left@3x.png"; sourceTree = ""; }; + 8A4FF3A51A2F8AFE0000E4CC /* an_arrow_left@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "an_arrow_left@2x.png"; sourceTree = ""; }; + 8A4FF3A61A2F8AFE0000E4CC /* an_arrow_left.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = an_arrow_left.png; sourceTree = ""; }; + 8A4FF3A91A2F8CC10000E4CC /* an_arrow_right@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "an_arrow_right@3x.png"; sourceTree = ""; }; + 8A4FF3AB1A2F8CE50000E4CC /* an_arrow_right@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "an_arrow_right@2x.png"; sourceTree = ""; }; + 8A4FF3AC1A2F8CE50000E4CC /* an_arrow_right.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = an_arrow_right.png; sourceTree = ""; }; + 8A598F881A1EA061009BA879 /* ANNativeStandardAdResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANNativeStandardAdResponse.h; sourceTree = ""; }; + 8A598F891A1EA061009BA879 /* ANNativeStandardAdResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANNativeStandardAdResponse.m; sourceTree = ""; }; 8A6514701A12DB31003F1047 /* UIView+ANNativeAdCategory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+ANNativeAdCategory.h"; sourceTree = ""; }; 8A6514711A12DB31003F1047 /* UIView+ANNativeAdCategory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+ANNativeAdCategory.m"; sourceTree = ""; }; 8A6606321A0A9A30008AB3D2 /* ANAdAdapterNativeMoPub.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANAdAdapterNativeMoPub.h; sourceTree = ""; }; 8A6606331A0A9A30008AB3D2 /* ANAdAdapterNativeMoPub.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANAdAdapterNativeMoPub.m; sourceTree = ""; }; - 8A6606431A0ACBA7008AB3D2 /* ANNativeAdRequest+ANBaseUrlOverride.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ANNativeAdRequest+ANBaseUrlOverride.h"; sourceTree = ""; }; - 8A6606441A0ACBA7008AB3D2 /* ANNativeAdRequest+ANBaseUrlOverride.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ANNativeAdRequest+ANBaseUrlOverride.m"; sourceTree = ""; }; 8A6BE78019D60C3E00498F77 /* ANSDK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANSDK.h; sourceTree = ""; }; + 8A6CD9261A96B2FD0060BCF4 /* compass@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "compass@3x.png"; sourceTree = ""; }; + 8A6D2E841A44A5D3003CE77A /* interstitial_flat_closebox@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "interstitial_flat_closebox@3x.png"; sourceTree = ""; }; + 8A6D2E871A44A62A003CE77A /* interstitial_flat_closebox@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "interstitial_flat_closebox@2x.png"; sourceTree = ""; }; + 8A6D2E881A44A62A003CE77A /* interstitial_flat_closebox.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = interstitial_flat_closebox.png; sourceTree = ""; }; + 8A82FDF31A30F36B00A267A0 /* ANNativeImpressionTrackerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANNativeImpressionTrackerManager.h; sourceTree = ""; }; + 8A82FDF41A30F36B00A267A0 /* ANNativeImpressionTrackerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANNativeImpressionTrackerManager.m; sourceTree = ""; }; + 8A84E42A1A2534F300C60EAB /* ANNativeAdResponse+PrivateMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ANNativeAdResponse+PrivateMethods.h"; sourceTree = ""; }; 8A944DDE19D5AF8C007AAAB0 /* AmazonAd.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = AmazonAd.framework; sourceTree = ""; }; 8A944DDF19D5AF8C007AAAB0 /* NOTICE-AMAZON.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "NOTICE-AMAZON.txt"; sourceTree = ""; }; 8A944DE119D5AF94007AAAB0 /* FBAudienceNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FBAudienceNetwork.framework; sourceTree = ""; }; - 8A944DE519D5AFAB007AAAB0 /* DFPBannerView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DFPBannerView.h; sourceTree = ""; }; - 8A944DE619D5AFAB007AAAB0 /* DFPExtras.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DFPExtras.h; sourceTree = ""; }; - 8A944DE719D5AFAB007AAAB0 /* DFPInterstitial.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DFPInterstitial.h; sourceTree = ""; }; - 8A944DE819D5AFAB007AAAB0 /* DFPSwipeableBannerView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DFPSwipeableBannerView.h; sourceTree = ""; }; - 8A944DE919D5AFAB007AAAB0 /* GADAdSizeDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADAdSizeDelegate.h; sourceTree = ""; }; - 8A944DEA19D5AFAB007AAAB0 /* GADAppEventDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADAppEventDelegate.h; sourceTree = ""; }; - 8A944DEB19D5AFAB007AAAB0 /* GADSwipeableBannerViewDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADSwipeableBannerViewDelegate.h; sourceTree = ""; }; - 8A944DED19D5AFAB007AAAB0 /* GADCustomEventBanner.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADCustomEventBanner.h; sourceTree = ""; }; - 8A944DEE19D5AFAB007AAAB0 /* GADCustomEventBannerDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADCustomEventBannerDelegate.h; sourceTree = ""; }; - 8A944DEF19D5AFAB007AAAB0 /* GADCustomEventExtras.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADCustomEventExtras.h; sourceTree = ""; }; - 8A944DF019D5AFAB007AAAB0 /* GADCustomEventInterstitial.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADCustomEventInterstitial.h; sourceTree = ""; }; - 8A944DF119D5AFAB007AAAB0 /* GADCustomEventInterstitialDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADCustomEventInterstitialDelegate.h; sourceTree = ""; }; - 8A944DF219D5AFAB007AAAB0 /* GADCustomEventRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADCustomEventRequest.h; sourceTree = ""; }; - 8A944DF419D5AFAB007AAAB0 /* GADSearchBannerView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADSearchBannerView.h; sourceTree = ""; }; - 8A944DF519D5AFAB007AAAB0 /* GADSearchRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADSearchRequest.h; sourceTree = ""; }; - 8A944DF619D5AFAB007AAAB0 /* GADAdMobExtras.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADAdMobExtras.h; sourceTree = ""; }; - 8A944DF719D5AFAB007AAAB0 /* GADAdNetworkExtras.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADAdNetworkExtras.h; sourceTree = ""; }; - 8A944DF819D5AFAB007AAAB0 /* GADAdSize.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADAdSize.h; sourceTree = ""; }; - 8A944DF919D5AFAB007AAAB0 /* GADBannerView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADBannerView.h; sourceTree = ""; }; - 8A944DFA19D5AFAB007AAAB0 /* GADBannerViewDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADBannerViewDelegate.h; sourceTree = ""; }; - 8A944DFB19D5AFAB007AAAB0 /* GADInAppPurchase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADInAppPurchase.h; sourceTree = ""; }; - 8A944DFC19D5AFAB007AAAB0 /* GADInAppPurchaseDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADInAppPurchaseDelegate.h; sourceTree = ""; }; - 8A944DFD19D5AFAB007AAAB0 /* GADInterstitial.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADInterstitial.h; sourceTree = ""; }; - 8A944DFE19D5AFAB007AAAB0 /* GADInterstitialDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADInterstitialDelegate.h; sourceTree = ""; }; - 8A944DFF19D5AFAB007AAAB0 /* GADModules.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADModules.h; sourceTree = ""; }; - 8A944E0019D5AFAB007AAAB0 /* GADRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADRequest.h; sourceTree = ""; }; - 8A944E0119D5AFAB007AAAB0 /* GADRequestError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GADRequestError.h; sourceTree = ""; }; - 8A944E0219D5AFAB007AAAB0 /* GoogleAdMobSDKReadme.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = GoogleAdMobSDKReadme.txt; sourceTree = ""; }; - 8A944E0319D5AFAB007AAAB0 /* libGoogleAdMobAds.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libGoogleAdMobAds.a; sourceTree = ""; }; 8A944E0519D5AFBB007AAAB0 /* LICENSE-MILLENNIAL MEDIA.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "LICENSE-MILLENNIAL MEDIA.txt"; sourceTree = ""; }; 8A944E0619D5AFBB007AAAB0 /* MillennialMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = MillennialMedia.framework; sourceTree = ""; }; 8A944E0819D5AFCD007AAAB0 /* libMoPubSDK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libMoPubSDK.a; sourceTree = ""; }; - 8A944E0919D5AFCD007AAAB0 /* LICENSE-MOPUB */ = {isa = PBXFileReference; lastKnownFileType = text; path = "LICENSE-MOPUB"; sourceTree = ""; }; 8A944E0A19D5AFCD007AAAB0 /* MPAdBrowserController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MPAdBrowserController.xib; sourceTree = ""; }; 8A944E0B19D5AFCD007AAAB0 /* MPAdConversionTracker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPAdConversionTracker.h; sourceTree = ""; }; 8A944E0C19D5AFCD007AAAB0 /* MPAdPositioning.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPAdPositioning.h; sourceTree = ""; }; @@ -549,16 +524,42 @@ 8AB876241A0994310022D9A5 /* ANNativeAdRequestUrlBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANNativeAdRequestUrlBuilder.h; sourceTree = ""; }; 8AB876251A0994310022D9A5 /* ANNativeAdRequestUrlBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANNativeAdRequestUrlBuilder.m; sourceTree = ""; }; 8AB876261A0994310022D9A5 /* ANNativeAdResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANNativeAdResponse.m; sourceTree = ""; }; - 8AB876291A0994310022D9A5 /* ANNativeMediatedAd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANNativeMediatedAd.h; sourceTree = ""; }; - 8AB8762A1A0994310022D9A5 /* ANNativeMediatedAd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANNativeMediatedAd.m; sourceTree = ""; }; 8AB8762B1A0994310022D9A5 /* ANNativeMediatedAdController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANNativeMediatedAdController.h; sourceTree = ""; }; 8AB8762C1A0994310022D9A5 /* ANNativeMediatedAdController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANNativeMediatedAdController.m; sourceTree = ""; }; 8AB8762D1A0994310022D9A5 /* ANNativeMediatedAdResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ANNativeMediatedAdResponse.h; path = native/ANNativeMediatedAdResponse.h; sourceTree = ""; }; 8AB8762E1A0994310022D9A5 /* ANNativeMediatedAdResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANNativeMediatedAdResponse.m; sourceTree = ""; }; 8ABB76691A00385C00FEAD9D /* ANAdConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANAdConstants.h; sourceTree = ""; }; 8ABB766D1A004DBD00FEAD9D /* ANNativeAdStarRating.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ANNativeAdStarRating.h; path = native/ANNativeAdStarRating.h; sourceTree = ""; }; + 8AC65F371A40DE63006BCF39 /* ANMRAIDCalendarManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANMRAIDCalendarManager.h; sourceTree = ""; }; + 8AC65F381A40DE63006BCF39 /* ANMRAIDCalendarManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMRAIDCalendarManager.m; sourceTree = ""; }; + 8AC65F391A40DE63006BCF39 /* ANMRAIDContainerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANMRAIDContainerView.h; sourceTree = ""; }; + 8AC65F3A1A40DE63006BCF39 /* ANMRAIDContainerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMRAIDContainerView.m; sourceTree = ""; }; + 8AC65F3B1A40DE63006BCF39 /* ANMRAIDExpandProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANMRAIDExpandProperties.h; sourceTree = ""; }; + 8AC65F3C1A40DE63006BCF39 /* ANMRAIDExpandProperties.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMRAIDExpandProperties.m; sourceTree = ""; }; + 8AC65F3D1A40DE63006BCF39 /* ANMRAIDExpandViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANMRAIDExpandViewController.h; sourceTree = ""; }; + 8AC65F3E1A40DE63006BCF39 /* ANMRAIDExpandViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMRAIDExpandViewController.m; sourceTree = ""; }; + 8AC65F3F1A40DE63006BCF39 /* ANMRAIDJavascriptUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANMRAIDJavascriptUtil.h; sourceTree = ""; }; + 8AC65F401A40DE63006BCF39 /* ANMRAIDJavascriptUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMRAIDJavascriptUtil.m; sourceTree = ""; }; + 8AC65F411A40DE63006BCF39 /* ANMRAIDOrientationProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANMRAIDOrientationProperties.h; sourceTree = ""; }; + 8AC65F421A40DE63006BCF39 /* ANMRAIDOrientationProperties.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMRAIDOrientationProperties.m; sourceTree = ""; }; + 8AC65F431A40DE63006BCF39 /* ANMRAIDResizeProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANMRAIDResizeProperties.h; sourceTree = ""; }; + 8AC65F441A40DE63006BCF39 /* ANMRAIDResizeProperties.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMRAIDResizeProperties.m; sourceTree = ""; }; + 8AC65F451A40DE63006BCF39 /* ANMRAIDResizeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANMRAIDResizeView.h; sourceTree = ""; }; + 8AC65F461A40DE63006BCF39 /* ANMRAIDResizeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMRAIDResizeView.m; sourceTree = ""; }; + 8AC65F471A40DE63006BCF39 /* ANMRAIDResizeViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANMRAIDResizeViewManager.h; sourceTree = ""; }; + 8AC65F481A40DE63006BCF39 /* ANMRAIDResizeViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMRAIDResizeViewManager.m; sourceTree = ""; }; + 8AC65F491A40DE63006BCF39 /* ANMRAIDUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANMRAIDUtil.h; sourceTree = ""; }; + 8AC65F4A1A40DE63006BCF39 /* ANMRAIDUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMRAIDUtil.m; sourceTree = ""; }; 8AC662A219DC9DDA004025D5 /* MPServerAdPositioning.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPServerAdPositioning.h; sourceTree = ""; }; 8AC662A319DC9E07004025D5 /* MoPub-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MoPub-Bridging-Header.h"; sourceTree = ""; }; + 8AC7C5361A3B5CEF00AA5548 /* ANAdWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANAdWebViewController.h; sourceTree = ""; }; + 8AC7C5371A3B5CEF00AA5548 /* ANAdWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANAdWebViewController.m; sourceTree = ""; }; + 8AD2DAE81A1D3A5B00878CDD /* ANAdFetcherResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANAdFetcherResponse.h; sourceTree = ""; }; + 8AD2DAE91A1D3A5B00878CDD /* ANAdFetcherResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANAdFetcherResponse.m; sourceTree = ""; }; + 8AD2DAEC1A1D3A6900878CDD /* ANAdServerResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANAdServerResponse.h; sourceTree = ""; }; + 8AD2DAED1A1D3A6900878CDD /* ANAdServerResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANAdServerResponse.m; sourceTree = ""; }; + 8AD2DAF21A1D3C2A00878CDD /* ANStandardAd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANStandardAd.h; sourceTree = ""; }; + 8AD2DAF31A1D3C2A00878CDD /* ANStandardAd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANStandardAd.m; sourceTree = ""; }; 8AD5154019D214CA002E53D6 /* libANSDKAmazonAdapter.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libANSDKAmazonAdapter.a; sourceTree = BUILT_PRODUCTS_DIR; }; 8AD5155519D216E6002E53D6 /* ANAdAdapterBannerAmazon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANAdAdapterBannerAmazon.h; sourceTree = ""; }; 8AD5155619D216E6002E53D6 /* ANAdAdapterBannerAmazon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANAdAdapterBannerAmazon.m; sourceTree = ""; }; @@ -576,9 +577,7 @@ 8AD618A21981C11F00AC0780 /* ANAdResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANAdResponse.h; sourceTree = ""; }; 8AD618A31981C11F00AC0780 /* ANAdResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANAdResponse.m; sourceTree = ""; }; 8AD618A41981C11F00AC0780 /* ANAdView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANAdView.m; sourceTree = ""; }; - 8AD618A51981C11F00AC0780 /* ANAdViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANAdViewDelegate.h; sourceTree = ""; }; - 8AD618A61981C11F00AC0780 /* ANAdWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANAdWebViewController.h; sourceTree = ""; }; - 8AD618A71981C11F00AC0780 /* ANAdWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANAdWebViewController.m; sourceTree = ""; }; + 8AD618A51981C11F00AC0780 /* ANAdViewInternalDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANAdViewInternalDelegate.h; sourceTree = ""; }; 8AD618A81981C11F00AC0780 /* ANANJAMImplementation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANANJAMImplementation.h; sourceTree = ""; }; 8AD618A91981C11F00AC0780 /* ANANJAMImplementation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANANJAMImplementation.m; sourceTree = ""; }; 8AD618AA1981C11F00AC0780 /* ANBannerAdView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANBannerAdView.m; sourceTree = ""; }; @@ -602,9 +601,6 @@ 8AD618BC1981C11F00AC0780 /* ANMediationAdViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMediationAdViewController.m; sourceTree = ""; }; 8AD618BD1981C11F00AC0780 /* ANMediationContainerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANMediationContainerView.h; sourceTree = ""; }; 8AD618BE1981C11F00AC0780 /* ANMediationContainerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMediationContainerView.m; sourceTree = ""; }; - 8AD618BF1981C11F00AC0780 /* ANMRAIDProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANMRAIDProperties.h; sourceTree = ""; }; - 8AD618C01981C11F00AC0780 /* ANMRAIDViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANMRAIDViewController.h; sourceTree = ""; }; - 8AD618C11981C11F00AC0780 /* ANMRAIDViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMRAIDViewController.m; sourceTree = ""; }; 8AD618C21981C11F00AC0780 /* ANPBBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANPBBuffer.h; sourceTree = ""; }; 8AD618C31981C11F00AC0780 /* ANPBBuffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANPBBuffer.m; sourceTree = ""; }; 8AD618C41981C11F00AC0780 /* ANPBContainerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANPBContainerView.h; sourceTree = ""; }; @@ -612,8 +608,6 @@ 8AD618C61981C11F00AC0780 /* ANReachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANReachability.h; sourceTree = ""; }; 8AD618C71981C11F00AC0780 /* ANReachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANReachability.m; sourceTree = ""; }; 8AD618C81981C11F00AC0780 /* ANTargetingParameters.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANTargetingParameters.m; sourceTree = ""; }; - 8AD618C91981C11F00AC0780 /* ANWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANWebView.h; sourceTree = ""; }; - 8AD618CA1981C11F00AC0780 /* ANWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANWebView.m; sourceTree = ""; }; 8AE2D6D119CC874B00001B70 /* libANSDKGoogleAdMobAdapter.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libANSDKGoogleAdMobAdapter.a; sourceTree = BUILT_PRODUCTS_DIR; }; 8AE2D70219CC878300001B70 /* libANSDKiAdAdapter.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libANSDKiAdAdapter.a; sourceTree = BUILT_PRODUCTS_DIR; }; 8AE2D73319CC879900001B70 /* libANSDKMillennialMediaAdapter.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libANSDKMillennialMediaAdapter.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -657,8 +651,23 @@ 8AE2D86C19CC9B7300001B70 /* ANMoPubMediationBanner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ANMoPubMediationBanner.m; path = ../mediation/mediating/MoPub/ANMoPubMediationBanner.m; sourceTree = ""; }; 8AE2D86D19CC9B7300001B70 /* ANMoPubMediationInterstitial.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ANMoPubMediationInterstitial.h; path = ../mediation/mediating/MoPub/ANMoPubMediationInterstitial.h; sourceTree = ""; }; 8AE2D86E19CC9B7300001B70 /* ANMoPubMediationInterstitial.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ANMoPubMediationInterstitial.m; path = ../mediation/mediating/MoPub/ANMoPubMediationInterstitial.m; sourceTree = ""; }; + 8AE5E11C1A2FDC7700FDE858 /* ANAdView+PrivateMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ANAdView+PrivateMethods.h"; sourceTree = ""; }; + 8AE7AD9D1A7AC4E5009E2F2F /* EventKitUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = EventKitUI.framework; path = System/Library/Frameworks/EventKitUI.framework; sourceTree = SDKROOT; }; 8AEA6BE71A0BEEF5009DB71B /* ANNativeAdTargetingProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ANNativeAdTargetingProtocol.h; path = native/ANNativeAdTargetingProtocol.h; sourceTree = ""; }; 8AEA6BE91A0BF43E009DB71B /* ANNativeAdDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ANNativeAdDelegate.h; path = native/ANNativeAdDelegate.h; sourceTree = ""; }; + 8AF3C19A1A361CC30018FB6A /* ANNativeImpressionTrackerInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANNativeImpressionTrackerInfo.h; sourceTree = ""; }; + 8AF3C19B1A361CC30018FB6A /* ANNativeImpressionTrackerInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANNativeImpressionTrackerInfo.m; sourceTree = ""; }; + 8AFC045E1A2E74AC00BEA485 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 8AFC04601A2E74C800BEA485 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 8AFC04621A2E74F500BEA485 /* EventKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = EventKit.framework; path = System/Library/Frameworks/EventKit.framework; sourceTree = SDKROOT; }; + 8AFC04641A2E751200BEA485 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; + 8AFC04661A2E752E00BEA485 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + 8AFC04681A2E754700BEA485 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 8AFC046A1A2E757900BEA485 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 8AFC046C1A2E75A300BEA485 /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; + 8AFC046E1A2E75AE00BEA485 /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; }; + 8AFC04701A2E760800BEA485 /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; + 8AFC04721A2E78E400BEA485 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; EC3E5CDC1843C6D50070315E /* libANSDK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libANSDK.a; sourceTree = BUILT_PRODUCTS_DIR; }; EC48177B1845046A0066BBFE /* ANSDKResources.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ANSDKResources.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; ECE4EA8D194B768A0069D934 /* ANAdProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANAdProtocol.h; sourceTree = ""; }; @@ -681,8 +690,6 @@ ECE4EACC194B768A0069D934 /* ANInterstitialAdViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ANInterstitialAdViewController.xib; sourceTree = ""; }; ECE4EACD194B768A0069D934 /* anjam.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = anjam.js; sourceTree = ""; }; ECE4EACE194B768A0069D934 /* errors.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = errors.strings; sourceTree = ""; }; - ECE4EAD0194B768A0069D934 /* interstitial_closebox-down.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "interstitial_closebox-down.png"; sourceTree = ""; }; - ECE4EAD1194B768A0069D934 /* interstitial_closebox-down@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "interstitial_closebox-down@2x.png"; sourceTree = ""; }; ECE4EAD2194B768A0069D934 /* interstitial_closebox.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = interstitial_closebox.png; sourceTree = ""; }; ECE4EAD3194B768A0069D934 /* interstitial_closebox@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "interstitial_closebox@2x.png"; sourceTree = ""; }; ECE4EAD4194B768A0069D934 /* UIButtonBarArrowLeft.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = UIButtonBarArrowLeft.png; sourceTree = ""; }; @@ -749,6 +756,24 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 8AFC045D1A2E745C00BEA485 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8AE7AD9E1A7AC4E5009E2F2F /* EventKitUI.framework in Frameworks */, + 8AFC04731A2E78E400BEA485 /* StoreKit.framework in Frameworks */, + 8AFC04711A2E760800BEA485 /* MessageUI.framework in Frameworks */, + 8AFC046F1A2E75AE00BEA485 /* AdSupport.framework in Frameworks */, + 8AFC046D1A2E75A300BEA485 /* MediaPlayer.framework in Frameworks */, + 8AFC046B1A2E757900BEA485 /* QuartzCore.framework in Frameworks */, + 8AFC04671A2E752E00BEA485 /* SystemConfiguration.framework in Frameworks */, + 8AFC04651A2E751200BEA485 /* CoreTelephony.framework in Frameworks */, + 8AFC04631A2E74F500BEA485 /* EventKit.framework in Frameworks */, + 8AFC04611A2E74C800BEA485 /* CoreGraphics.framework in Frameworks */, + 8AFC045F1A2E74AC00BEA485 /* UIKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; EC3E5CD91843C6D50070315E /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -781,6 +806,15 @@ name = native; sourceTree = ""; }; + 8A4018181A95213200D56208 /* GoogleAdMobSDK */ = { + isa = PBXGroup; + children = ( + 8A4018191A95213200D56208 /* GoogleMobileAds.framework */, + ); + name = GoogleAdMobSDK; + path = ../mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK; + sourceTree = ""; + }; 8A944DDD19D5AF8C007AAAB0 /* AmazonSDK */ = { isa = PBXGroup; children = ( @@ -799,75 +833,6 @@ path = ../mediation/mediatedviews/Facebook/FacebookSDK; sourceTree = ""; }; - 8A944DE219D5AFAB007AAAB0 /* GoogleAdMobSDK */ = { - isa = PBXGroup; - children = ( - 8A944DE319D5AFAB007AAAB0 /* Add-ons */, - 8A944DF619D5AFAB007AAAB0 /* GADAdMobExtras.h */, - 8A944DF719D5AFAB007AAAB0 /* GADAdNetworkExtras.h */, - 8A944DF819D5AFAB007AAAB0 /* GADAdSize.h */, - 8A944DF919D5AFAB007AAAB0 /* GADBannerView.h */, - 8A944DFA19D5AFAB007AAAB0 /* GADBannerViewDelegate.h */, - 8A944DFB19D5AFAB007AAAB0 /* GADInAppPurchase.h */, - 8A944DFC19D5AFAB007AAAB0 /* GADInAppPurchaseDelegate.h */, - 8A944DFD19D5AFAB007AAAB0 /* GADInterstitial.h */, - 8A944DFE19D5AFAB007AAAB0 /* GADInterstitialDelegate.h */, - 8A944DFF19D5AFAB007AAAB0 /* GADModules.h */, - 8A944E0019D5AFAB007AAAB0 /* GADRequest.h */, - 8A944E0119D5AFAB007AAAB0 /* GADRequestError.h */, - 8A944E0219D5AFAB007AAAB0 /* GoogleAdMobSDKReadme.txt */, - 8A944E0319D5AFAB007AAAB0 /* libGoogleAdMobAds.a */, - ); - name = GoogleAdMobSDK; - path = ../mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK; - sourceTree = ""; - }; - 8A944DE319D5AFAB007AAAB0 /* Add-ons */ = { - isa = PBXGroup; - children = ( - 8A944DE419D5AFAB007AAAB0 /* DoubleClick */, - 8A944DEC19D5AFAB007AAAB0 /* Mediation */, - 8A944DF319D5AFAB007AAAB0 /* Search */, - ); - path = "Add-ons"; - sourceTree = ""; - }; - 8A944DE419D5AFAB007AAAB0 /* DoubleClick */ = { - isa = PBXGroup; - children = ( - 8A944DE519D5AFAB007AAAB0 /* DFPBannerView.h */, - 8A944DE619D5AFAB007AAAB0 /* DFPExtras.h */, - 8A944DE719D5AFAB007AAAB0 /* DFPInterstitial.h */, - 8A944DE819D5AFAB007AAAB0 /* DFPSwipeableBannerView.h */, - 8A944DE919D5AFAB007AAAB0 /* GADAdSizeDelegate.h */, - 8A944DEA19D5AFAB007AAAB0 /* GADAppEventDelegate.h */, - 8A944DEB19D5AFAB007AAAB0 /* GADSwipeableBannerViewDelegate.h */, - ); - path = DoubleClick; - sourceTree = ""; - }; - 8A944DEC19D5AFAB007AAAB0 /* Mediation */ = { - isa = PBXGroup; - children = ( - 8A944DED19D5AFAB007AAAB0 /* GADCustomEventBanner.h */, - 8A944DEE19D5AFAB007AAAB0 /* GADCustomEventBannerDelegate.h */, - 8A944DEF19D5AFAB007AAAB0 /* GADCustomEventExtras.h */, - 8A944DF019D5AFAB007AAAB0 /* GADCustomEventInterstitial.h */, - 8A944DF119D5AFAB007AAAB0 /* GADCustomEventInterstitialDelegate.h */, - 8A944DF219D5AFAB007AAAB0 /* GADCustomEventRequest.h */, - ); - path = Mediation; - sourceTree = ""; - }; - 8A944DF319D5AFAB007AAAB0 /* Search */ = { - isa = PBXGroup; - children = ( - 8A944DF419D5AFAB007AAAB0 /* GADSearchBannerView.h */, - 8A944DF519D5AFAB007AAAB0 /* GADSearchRequest.h */, - ); - path = Search; - sourceTree = ""; - }; 8A944E0419D5AFBB007AAAB0 /* MillennialMediaSDK */ = { isa = PBXGroup; children = ( @@ -882,7 +847,6 @@ isa = PBXGroup; children = ( 8A944E0819D5AFCD007AAAB0 /* libMoPubSDK.a */, - 8A944E0919D5AFCD007AAAB0 /* LICENSE-MOPUB */, 8AC662A319DC9E07004025D5 /* MoPub-Bridging-Header.h */, 8A944E0A19D5AFCD007AAAB0 /* MPAdBrowserController.xib */, 8A944E0B19D5AFCD007AAAB0 /* MPAdConversionTracker.h */, @@ -893,6 +857,7 @@ 8A944E1019D5AFCD007AAAB0 /* MPClientAdPositioning.h */, 8A944E1119D5AFCD007AAAB0 /* MPCloseButtonX.png */, 8A944E1219D5AFCD007AAAB0 /* MPCloseButtonX@2x.png */, + 8A40181F1A95224800D56208 /* MPCloseButtonX@3x.png */, 8A944E1319D5AFCD007AAAB0 /* MPCollectionViewAdPlacer.h */, 8A944E1419D5AFCD007AAAB0 /* MPConstants.h */, 8A944E1519D5AFCD007AAAB0 /* MPInterstitialAdController.h */, @@ -940,29 +905,65 @@ 8AB8761B1A0994310022D9A5 /* internal */ = { isa = PBXGroup; children = ( + 8AD2DAE81A1D3A5B00878CDD /* ANAdFetcherResponse.h */, + 8AD2DAE91A1D3A5B00878CDD /* ANAdFetcherResponse.m */, + 8AD2DAEC1A1D3A6900878CDD /* ANAdServerResponse.h */, + 8AD2DAED1A1D3A6900878CDD /* ANAdServerResponse.m */, 8AB8761E1A0994310022D9A5 /* ANNativeAdFetcher.h */, 8AB8761F1A0994310022D9A5 /* ANNativeAdFetcher.m */, 8AB876201A0994310022D9A5 /* ANNativeAdImageCache.h */, 8AB876211A0994310022D9A5 /* ANNativeAdImageCache.m */, 8AB876231A0994310022D9A5 /* ANNativeAdRequest.m */, - 8A6606431A0ACBA7008AB3D2 /* ANNativeAdRequest+ANBaseUrlOverride.h */, - 8A6606441A0ACBA7008AB3D2 /* ANNativeAdRequest+ANBaseUrlOverride.m */, 8AB876241A0994310022D9A5 /* ANNativeAdRequestUrlBuilder.h */, 8AB876251A0994310022D9A5 /* ANNativeAdRequestUrlBuilder.m */, 8AB876261A0994310022D9A5 /* ANNativeAdResponse.m */, 8AB876221A0994310022D9A5 /* ANNativeAdStarRating.m */, - 8AB876291A0994310022D9A5 /* ANNativeMediatedAd.h */, - 8AB8762A1A0994310022D9A5 /* ANNativeMediatedAd.m */, + 8A82FDF31A30F36B00A267A0 /* ANNativeImpressionTrackerManager.h */, + 8A82FDF41A30F36B00A267A0 /* ANNativeImpressionTrackerManager.m */, + 8AF3C19A1A361CC30018FB6A /* ANNativeImpressionTrackerInfo.h */, + 8AF3C19B1A361CC30018FB6A /* ANNativeImpressionTrackerInfo.m */, 8AB8762B1A0994310022D9A5 /* ANNativeMediatedAdController.h */, 8AB8762C1A0994310022D9A5 /* ANNativeMediatedAdController.m */, 8AB8762E1A0994310022D9A5 /* ANNativeMediatedAdResponse.m */, + 8A598F881A1EA061009BA879 /* ANNativeStandardAdResponse.h */, + 8A598F891A1EA061009BA879 /* ANNativeStandardAdResponse.m */, + 8AD2DAF21A1D3C2A00878CDD /* ANStandardAd.h */, + 8AD2DAF31A1D3C2A00878CDD /* ANStandardAd.m */, 8A6514701A12DB31003F1047 /* UIView+ANNativeAdCategory.h */, 8A6514711A12DB31003F1047 /* UIView+ANNativeAdCategory.m */, + 8A84E42A1A2534F300C60EAB /* ANNativeAdResponse+PrivateMethods.h */, ); name = internal; path = native/internal; sourceTree = ""; }; + 8AC65F361A40DE63006BCF39 /* MRAID */ = { + isa = PBXGroup; + children = ( + 8AC65F371A40DE63006BCF39 /* ANMRAIDCalendarManager.h */, + 8AC65F381A40DE63006BCF39 /* ANMRAIDCalendarManager.m */, + 8AC65F391A40DE63006BCF39 /* ANMRAIDContainerView.h */, + 8AC65F3A1A40DE63006BCF39 /* ANMRAIDContainerView.m */, + 8AC65F3B1A40DE63006BCF39 /* ANMRAIDExpandProperties.h */, + 8AC65F3C1A40DE63006BCF39 /* ANMRAIDExpandProperties.m */, + 8AC65F3D1A40DE63006BCF39 /* ANMRAIDExpandViewController.h */, + 8AC65F3E1A40DE63006BCF39 /* ANMRAIDExpandViewController.m */, + 8AC65F3F1A40DE63006BCF39 /* ANMRAIDJavascriptUtil.h */, + 8AC65F401A40DE63006BCF39 /* ANMRAIDJavascriptUtil.m */, + 8AC65F411A40DE63006BCF39 /* ANMRAIDOrientationProperties.h */, + 8AC65F421A40DE63006BCF39 /* ANMRAIDOrientationProperties.m */, + 8AC65F431A40DE63006BCF39 /* ANMRAIDResizeProperties.h */, + 8AC65F441A40DE63006BCF39 /* ANMRAIDResizeProperties.m */, + 8AC65F451A40DE63006BCF39 /* ANMRAIDResizeView.h */, + 8AC65F461A40DE63006BCF39 /* ANMRAIDResizeView.m */, + 8AC65F471A40DE63006BCF39 /* ANMRAIDResizeViewManager.h */, + 8AC65F481A40DE63006BCF39 /* ANMRAIDResizeViewManager.m */, + 8AC65F491A40DE63006BCF39 /* ANMRAIDUtil.h */, + 8AC65F4A1A40DE63006BCF39 /* ANMRAIDUtil.m */, + ); + path = MRAID; + sourceTree = ""; + }; 8AD5155119D216E6002E53D6 /* Amazon */ = { isa = PBXGroup; children = ( @@ -989,9 +990,9 @@ 8AD618A21981C11F00AC0780 /* ANAdResponse.h */, 8AD618A31981C11F00AC0780 /* ANAdResponse.m */, 8AD618A41981C11F00AC0780 /* ANAdView.m */, - 8AD618A51981C11F00AC0780 /* ANAdViewDelegate.h */, - 8AD618A61981C11F00AC0780 /* ANAdWebViewController.h */, - 8AD618A71981C11F00AC0780 /* ANAdWebViewController.m */, + 8AD618A51981C11F00AC0780 /* ANAdViewInternalDelegate.h */, + 8AC7C5361A3B5CEF00AA5548 /* ANAdWebViewController.h */, + 8AC7C5371A3B5CEF00AA5548 /* ANAdWebViewController.m */, 8AD618A81981C11F00AC0780 /* ANANJAMImplementation.h */, 8AD618A91981C11F00AC0780 /* ANANJAMImplementation.m */, 8AD618AA1981C11F00AC0780 /* ANBannerAdView.m */, @@ -1015,9 +1016,8 @@ 8AD618BC1981C11F00AC0780 /* ANMediationAdViewController.m */, 8AD618BD1981C11F00AC0780 /* ANMediationContainerView.h */, 8AD618BE1981C11F00AC0780 /* ANMediationContainerView.m */, - 8AD618BF1981C11F00AC0780 /* ANMRAIDProperties.h */, - 8AD618C01981C11F00AC0780 /* ANMRAIDViewController.h */, - 8AD618C11981C11F00AC0780 /* ANMRAIDViewController.m */, + 8A2F48211A2E255600B0EA05 /* ANOpenInExternalBrowserActivity.h */, + 8A2F48221A2E255600B0EA05 /* ANOpenInExternalBrowserActivity.m */, 8AD618C21981C11F00AC0780 /* ANPBBuffer.h */, 8AD618C31981C11F00AC0780 /* ANPBBuffer.m */, 8AD618C41981C11F00AC0780 /* ANPBContainerView.h */, @@ -1025,8 +1025,7 @@ 8AD618C61981C11F00AC0780 /* ANReachability.h */, 8AD618C71981C11F00AC0780 /* ANReachability.m */, 8AD618C81981C11F00AC0780 /* ANTargetingParameters.m */, - 8AD618C91981C11F00AC0780 /* ANWebView.h */, - 8AD618CA1981C11F00AC0780 /* ANWebView.m */, + 8AC65F361A40DE63006BCF39 /* MRAID */, ); path = internal; sourceTree = ""; @@ -1098,7 +1097,7 @@ 8AE2D7EC19CC891B00001B70 /* ANAdAdapterInterstitialAdMob.m */, 8AE2D7ED19CC891B00001B70 /* ANAdAdapterInterstitialDFP.h */, 8AE2D7EE19CC891B00001B70 /* ANAdAdapterInterstitialDFP.m */, - 8A944DE219D5AFAB007AAAB0 /* GoogleAdMobSDK */, + 8A4018181A95213200D56208 /* GoogleAdMobSDK */, ); name = "Google AdMob"; sourceTree = ""; @@ -1147,14 +1146,34 @@ name = "Mediated By AppNexus"; sourceTree = ""; }; + 8AE5E11F1A2FDCDB00FDE858 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 8AE7AD9D1A7AC4E5009E2F2F /* EventKitUI.framework */, + 8AFC04721A2E78E400BEA485 /* StoreKit.framework */, + 8AFC04701A2E760800BEA485 /* MessageUI.framework */, + 8AFC046E1A2E75AE00BEA485 /* AdSupport.framework */, + 8AFC046C1A2E75A300BEA485 /* MediaPlayer.framework */, + 8AFC046A1A2E757900BEA485 /* QuartzCore.framework */, + 8AFC04681A2E754700BEA485 /* CoreFoundation.framework */, + 8AFC04661A2E752E00BEA485 /* SystemConfiguration.framework */, + 8AFC04641A2E751200BEA485 /* CoreTelephony.framework */, + 8AFC04621A2E74F500BEA485 /* EventKit.framework */, + 8AFC04601A2E74C800BEA485 /* CoreGraphics.framework */, + 8AFC045E1A2E74AC00BEA485 /* UIKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; EC3E5CD31843C6D50070315E = { isa = PBXGroup; children = ( ECE4EA8C194B768A0069D934 /* ANSDK */, 8A6BE78019D60C3E00498F77 /* ANSDK.h */, + 8A9AED8D1A1BE84F00C58BDA /* AppNexusSDK */, + 8AE5E11F1A2FDCDB00FDE858 /* Frameworks */, 8AE2D87419CC9D9B00001B70 /* Mediated By AppNexus */, 8AE2D87319CC9D7400001B70 /* Mediating AppNexus */, - 8A9AED8D1A1BE84F00C58BDA /* AppNexusSDK */, EC3E5CDD1843C6D50070315E /* Products */, ); sourceTree = ""; @@ -1211,6 +1230,7 @@ ECE4EA9B194B768A0069D934 /* UIView+ANCategory.m */, ECE4EA9C194B768A0069D934 /* UIWebView+ANCategory.h */, ECE4EA9D194B768A0069D934 /* UIWebView+ANCategory.m */, + 8AE5E11C1A2FDC7700FDE858 /* ANAdView+PrivateMethods.h */, ); path = Categories; sourceTree = ""; @@ -1234,14 +1254,24 @@ children = ( 8AD618991981C10700AC0780 /* appnexus_logo_icon.png */, 8AD6189A1981C10700AC0780 /* appnexus_logo_icon@2x.png */, - ECE4EAD0194B768A0069D934 /* interstitial_closebox-down.png */, - ECE4EAD1194B768A0069D934 /* interstitial_closebox-down@2x.png */, + 8A4FF3A61A2F8AFE0000E4CC /* an_arrow_left.png */, + 8A4FF3A51A2F8AFE0000E4CC /* an_arrow_left@2x.png */, + 8A4FF3A31A2F8ACC0000E4CC /* an_arrow_left@3x.png */, + 8A4FF3AC1A2F8CE50000E4CC /* an_arrow_right.png */, + 8A4FF3AB1A2F8CE50000E4CC /* an_arrow_right@2x.png */, + 8A4FF3A91A2F8CC10000E4CC /* an_arrow_right@3x.png */, + 8A2F483C1A2E33B000B0EA05 /* compass.png */, + 8A4FF3A01A2F72D00000E4CC /* compass@2x.png */, + 8A6CD9261A96B2FD0060BCF4 /* compass@3x.png */, ECE4EAD2194B768A0069D934 /* interstitial_closebox.png */, ECE4EAD3194B768A0069D934 /* interstitial_closebox@2x.png */, ECE4EAD4194B768A0069D934 /* UIButtonBarArrowLeft.png */, - ECE4EAD6194B768A0069D934 /* UIButtonBarArrowRight.png */, ECE4EAD5194B768A0069D934 /* UIButtonBarArrowLeft@2x.png */, + ECE4EAD6194B768A0069D934 /* UIButtonBarArrowRight.png */, ECE4EAD7194B768A0069D934 /* UIButtonBarArrowRight@2x.png */, + 8A6D2E841A44A5D3003CE77A /* interstitial_flat_closebox@3x.png */, + 8A6D2E871A44A62A003CE77A /* interstitial_flat_closebox@2x.png */, + 8A6D2E881A44A62A003CE77A /* interstitial_flat_closebox.png */, ); path = images; sourceTree = ""; @@ -1249,68 +1279,12 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 8A6BE74519D5F2B500498F77 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 8A6BE78219D60C3E00498F77 /* ANSDK.h in Headers */, - 8A6BE74619D5F2BD00498F77 /* ANAdProtocol.h in Headers */, - 8A6BE74719D5F2BD00498F77 /* ANAdView.h in Headers */, - 8A6BE74819D5F2BD00498F77 /* ANBannerAdView.h in Headers */, - 8A6BE74919D5F2BD00498F77 /* ANCustomAdapter.h in Headers */, - 8A6BE74A19D5F2BD00498F77 /* ANInterstitialAd.h in Headers */, - 8A6BE74B19D5F2BD00498F77 /* ANLocation.h in Headers */, - 8A6BE74C19D5F2BD00498F77 /* ANLogManager.h in Headers */, - 8A6BE74D19D5F2BD00498F77 /* ANTargetingParameters.h in Headers */, - 8A9AED211A1BAD6000C58BDA /* ANAdConstants.h in Headers */, - 8A9AED291A1BAD7A00C58BDA /* ANNativeAdDelegate.h in Headers */, - 8A9AED2A1A1BAD7A00C58BDA /* ANNativeAdRequest.h in Headers */, - 8A9AED2B1A1BAD7A00C58BDA /* ANNativeAdResponse.h in Headers */, - 8A9AED2C1A1BAD7A00C58BDA /* ANNativeAdStarRating.h in Headers */, - 8AEA6BE81A0BEEF5009DB71B /* ANNativeAdTargetingProtocol.h in Headers */, - 8A9AED2D1A1BAD7A00C58BDA /* ANNativeCustomAdapter.h in Headers */, - 8A9AED2E1A1BAD7A00C58BDA /* ANNativeMediatedAdResponse.h in Headers */, - 8A9AED2F1A1BAD9300C58BDA /* ANNativeAdFetcher.h in Headers */, - 8A9AED301A1BAD9300C58BDA /* ANNativeAdImageCache.h in Headers */, - 8A9AED311A1BAD9300C58BDA /* ANNativeAdRequest+ANBaseUrlOverride.h in Headers */, - 8A9AED321A1BAD9300C58BDA /* ANNativeAdRequestUrlBuilder.h in Headers */, - 8A9AED331A1BAD9300C58BDA /* ANNativeMediatedAd.h in Headers */, - 8A9AED341A1BAD9300C58BDA /* ANNativeMediatedAdController.h in Headers */, - 8A9AED351A1BAD9300C58BDA /* UIView+ANNativeAdCategory.h in Headers */, - 8A6BE78819D61EDA00498F77 /* ANBannerAdView+ANContentViewTransitions.h in Headers */, - 8A6BE78919D61EDA00498F77 /* NSString+ANCategory.h in Headers */, - 8A6BE78A19D61EDA00498F77 /* NSTimer+ANCategory.h in Headers */, - 8A6BE78B19D61EDA00498F77 /* UIView+ANCategory.h in Headers */, - 8A6BE78C19D61EDA00498F77 /* UIWebView+ANCategory.h in Headers */, - 8A6BE78D19D61EF900498F77 /* ANAdFetcher.h in Headers */, - 8A6BE78E19D61EF900498F77 /* ANAdRequestUrl.h in Headers */, - 8A6BE78F19D61EF900498F77 /* ANAdResponse.h in Headers */, - 8A6BE79019D61EF900498F77 /* ANAdViewDelegate.h in Headers */, - 8A6BE79119D61EF900498F77 /* ANAdWebViewController.h in Headers */, - 8A6BE79219D61EF900498F77 /* ANANJAMImplementation.h in Headers */, - 8A6BE79319D61EF900498F77 /* ANBasicConfig.h in Headers */, - 8A6BE79419D61EF900498F77 /* ANBrowserViewController.h in Headers */, - 8A6BE79519D61EF900498F77 /* ANClickOverlayView.h in Headers */, - 8A6BE79619D61EF900498F77 /* ANGlobal.h in Headers */, - 8A6BE79719D61EF900498F77 /* ANInterstitialAdViewController.h in Headers */, - 8A6BE79819D61EF900498F77 /* ANLogging.h in Headers */, - 8A6BE79919D61EF900498F77 /* ANMediatedAd.h in Headers */, - 8A6BE79A19D61EF900498F77 /* ANMediationAdViewController.h in Headers */, - 8A6BE79B19D61EF900498F77 /* ANMediationContainerView.h in Headers */, - 8A6BE79C19D61EF900498F77 /* ANMRAIDProperties.h in Headers */, - 8A6BE79D19D61EF900498F77 /* ANMRAIDViewController.h in Headers */, - 8A6BE79E19D61EF900498F77 /* ANPBBuffer.h in Headers */, - 8A6BE79F19D61EF900498F77 /* ANPBContainerView.h in Headers */, - 8A6BE7A019D61EF900498F77 /* ANReachability.h in Headers */, - 8A6BE7A119D61EF900498F77 /* ANWebView.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 8A9AED891A1BE84F00C58BDA /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 8A9AED911A1BE84F00C58BDA /* AppNexusSDK.h in Headers */, + 8A598F831A1E8A03009BA879 /* ANAdFetcherResponse.h in Headers */, 8A9AEDB11A1BE8C200C58BDA /* ANAdConstants.h in Headers */, 8A9AEDB21A1BE8C200C58BDA /* ANAdProtocol.h in Headers */, 8A9AEDB31A1BE8C200C58BDA /* ANAdView.h in Headers */, @@ -1318,6 +1292,7 @@ 8A9AEDB51A1BE8C200C58BDA /* ANCustomAdapter.h in Headers */, 8A9AEDB61A1BE8C200C58BDA /* ANInterstitialAd.h in Headers */, 8A9AEDB71A1BE8C200C58BDA /* ANLocation.h in Headers */, + 8A598F851A1E8A03009BA879 /* ANStandardAd.h in Headers */, 8A9AEDB81A1BE8C200C58BDA /* ANLogManager.h in Headers */, 8A9AEDB91A1BE8C200C58BDA /* ANTargetingParameters.h in Headers */, 8A9AEDBA1A1BE8CE00C58BDA /* ANNativeAdDelegate.h in Headers */, @@ -1325,6 +1300,7 @@ 8A9AEDBC1A1BE8CE00C58BDA /* ANNativeAdResponse.h in Headers */, 8A9AEDBD1A1BE8CE00C58BDA /* ANNativeAdStarRating.h in Headers */, 8A9AEDBE1A1BE8CE00C58BDA /* ANNativeAdTargetingProtocol.h in Headers */, + 8A598F841A1E8A03009BA879 /* ANAdServerResponse.h in Headers */, 8A9AEDBF1A1BE8CE00C58BDA /* ANNativeCustomAdapter.h in Headers */, 8A9AEDC01A1BE8CE00C58BDA /* ANNativeMediatedAdResponse.h in Headers */, 8A9AEDC61A1BF88200C58BDA /* ANBannerAdView+ANContentViewTransitions.h in Headers */, @@ -1335,8 +1311,7 @@ 8A9AEDCB1A1BF88200C58BDA /* ANAdFetcher.h in Headers */, 8A9AEDCC1A1BF88200C58BDA /* ANAdRequestUrl.h in Headers */, 8A9AEDCD1A1BF88200C58BDA /* ANAdResponse.h in Headers */, - 8A9AEDCE1A1BF88200C58BDA /* ANAdViewDelegate.h in Headers */, - 8A9AEDCF1A1BF88200C58BDA /* ANAdWebViewController.h in Headers */, + 8A9AEDCE1A1BF88200C58BDA /* ANAdViewInternalDelegate.h in Headers */, 8A9AEDD01A1BF88200C58BDA /* ANANJAMImplementation.h in Headers */, 8A9AEDD11A1BF88200C58BDA /* ANBasicConfig.h in Headers */, 8A9AEDD21A1BF88200C58BDA /* ANBrowserViewController.h in Headers */, @@ -1347,17 +1322,26 @@ 8A9AEDD71A1BF88200C58BDA /* ANMediatedAd.h in Headers */, 8A9AEDD81A1BF88200C58BDA /* ANMediationAdViewController.h in Headers */, 8A9AEDD91A1BF88200C58BDA /* ANMediationContainerView.h in Headers */, - 8A9AEDDA1A1BF88200C58BDA /* ANMRAIDProperties.h in Headers */, - 8A9AEDDB1A1BF88200C58BDA /* ANMRAIDViewController.h in Headers */, + 8A84E42E1A25350800C60EAB /* ANNativeAdResponse+PrivateMethods.h in Headers */, + 8AC65F611A40DE74006BCF39 /* ANMRAIDContainerView.h in Headers */, + 8AC65F711A40DE74006BCF39 /* ANMRAIDUtil.h in Headers */, + 8AC65F631A40DE74006BCF39 /* ANMRAIDExpandProperties.h in Headers */, + 8AC65F6B1A40DE74006BCF39 /* ANMRAIDResizeProperties.h in Headers */, + 8AC65F6F1A40DE74006BCF39 /* ANMRAIDResizeViewManager.h in Headers */, + 8AE5E11E1A2FDC7700FDE858 /* ANAdView+PrivateMethods.h in Headers */, + 8AC65F5F1A40DE74006BCF39 /* ANMRAIDCalendarManager.h in Headers */, + 8AC65F691A40DE74006BCF39 /* ANMRAIDOrientationProperties.h in Headers */, + 8A2F48241A2E255600B0EA05 /* ANOpenInExternalBrowserActivity.h in Headers */, + 8AC65F671A40DE74006BCF39 /* ANMRAIDJavascriptUtil.h in Headers */, + 8AC65F651A40DE74006BCF39 /* ANMRAIDExpandViewController.h in Headers */, + 8AC65F6D1A40DE74006BCF39 /* ANMRAIDResizeView.h in Headers */, 8A9AEDDC1A1BF88200C58BDA /* ANPBBuffer.h in Headers */, 8A9AEDDD1A1BF88300C58BDA /* ANPBContainerView.h in Headers */, 8A9AEDDE1A1BF88300C58BDA /* ANReachability.h in Headers */, - 8A9AEDDF1A1BF88300C58BDA /* ANWebView.h in Headers */, 8A9AEDE01A1BF88300C58BDA /* ANNativeAdFetcher.h in Headers */, 8A9AEDE11A1BF88300C58BDA /* ANNativeAdImageCache.h in Headers */, - 8A9AEDE21A1BF88300C58BDA /* ANNativeAdRequest+ANBaseUrlOverride.h in Headers */, 8A9AEDE31A1BF88300C58BDA /* ANNativeAdRequestUrlBuilder.h in Headers */, - 8A9AEDE41A1BF88300C58BDA /* ANNativeMediatedAd.h in Headers */, + 8A598F8B1A1EA061009BA879 /* ANNativeStandardAdResponse.h in Headers */, 8A9AEDE51A1BF88300C58BDA /* ANNativeMediatedAdController.h in Headers */, 8A9AEDE61A1BF88300C58BDA /* UIView+ANNativeAdCategory.h in Headers */, ); @@ -1373,6 +1357,7 @@ 8A9AED891A1BE84F00C58BDA /* Headers */, 8A9AEDE71A1BF98600C58BDA /* Sources */, 8A9AED8A1A1BE84F00C58BDA /* Resources */, + 8AFC045D1A2E745C00BEA485 /* Frameworks */, ); buildRules = ( ); @@ -1544,8 +1529,6 @@ EC3E5CD91843C6D50070315E /* Frameworks */, EC3E5CDA1843C6D50070315E /* Copy Files */, EC84778B18440F2200A8BC80 /* Resources */, - 8A6BE74519D5F2B500498F77 /* Headers */, - 8A6BE76819D5F34500498F77 /* Build Framework Script */, ); buildRules = ( ); @@ -1583,9 +1566,6 @@ LastUpgradeCheck = 0510; ORGANIZATIONNAME = AppNexus; TargetAttributes = { - 8A6BE73919D5EEE500498F77 = { - CreatedOnToolsVersion = 6.0.1; - }; 8A9AED8B1A1BE84F00C58BDA = { CreatedOnToolsVersion = 6.1; }; @@ -1613,7 +1593,6 @@ 8AE2D84519CC9A6F00001B70 /* ANAdapterForGoogleAdMobSDK */, 8AE2D85519CC9B0F00001B70 /* ANAdapterForMoPubSDK */, 8AD5153219D214CA002E53D6 /* ANSDKAmazonAdapter */, - 8A6BE73919D5EEE500498F77 /* BuildANSDKFramework */, 8A9AED8B1A1BE84F00C58BDA /* AppNexusSDK */, ); }; @@ -1624,7 +1603,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8A9AEDAF1A1BE8AF00C58BDA /* ANSDKResources.bundle in Resources */, + 8ADA36201A82A8D700AF65AA /* ANSDKResources.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1688,21 +1667,31 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 8A6D2E8E1A44A751003CE77A /* interstitial_flat_closebox@2x.png in Resources */, 8AD618E41981C19500AC0780 /* appnexus_logo_icon@2x.png in Resources */, 8AD618E31981C19100AC0780 /* appnexus_logo_icon.png in Resources */, + 8A6D2E8D1A44A751003CE77A /* interstitial_flat_closebox@3x.png in Resources */, + 8A4FF3AA1A2F8CC10000E4CC /* an_arrow_right@3x.png in Resources */, ECE4EB03194B76960069D934 /* ANBrowserViewController.xib in Resources */, ECE4EB04194B76960069D934 /* ANInterstitialAdViewController.xib in Resources */, - ECE4EB07194B76960069D934 /* interstitial_closebox-down.png in Resources */, - ECE4EB08194B76960069D934 /* interstitial_closebox-down@2x.png in Resources */, + 8A4FF3A41A2F8ACC0000E4CC /* an_arrow_left@3x.png in Resources */, + 8A4FF3A81A2F8AFE0000E4CC /* an_arrow_left.png in Resources */, ECE4EB09194B76960069D934 /* interstitial_closebox.png in Resources */, + 8A4FF3AE1A2F8CE50000E4CC /* an_arrow_right.png in Resources */, ECE4EB0A194B76960069D934 /* interstitial_closebox@2x.png in Resources */, + 8A4FF3AD1A2F8CE50000E4CC /* an_arrow_right@2x.png in Resources */, ECE4EB0B194B76960069D934 /* UIButtonBarArrowLeft.png in Resources */, ECE4EB0C194B76960069D934 /* UIButtonBarArrowLeft@2x.png in Resources */, + 8A4FF3A71A2F8AFE0000E4CC /* an_arrow_left@2x.png in Resources */, ECE4EB0D194B76960069D934 /* UIButtonBarArrowRight.png in Resources */, + 8A4FF3A11A2F72D00000E4CC /* compass@2x.png in Resources */, ECE4EB0E194B76960069D934 /* UIButtonBarArrowRight@2x.png in Resources */, + 8A6D2E8F1A44A751003CE77A /* interstitial_flat_closebox.png in Resources */, ECE4EB05194B76960069D934 /* anjam.js in Resources */, ECE4EB10194B76960069D934 /* sdkjs.js in Resources */, ECE4EB06194B76960069D934 /* errors.strings in Resources */, + 8A2F483D1A2E33B000B0EA05 /* compass.png in Resources */, + 8A6CD9271A96B2FD0060BCF4 /* compass@3x.png in Resources */, 8A3EC17019B8FDCA0049CD29 /* ANMRAID.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1717,84 +1706,64 @@ }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 8A6BE73D19D5EF1600498F77 /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "set -e\n\n# If we're already inside this script then die\nif [ -n \"$RW_MULTIPLATFORM_BUILD_IN_PROGRESS\" ]; then\nexit 0\nfi\nexport RW_MULTIPLATFORM_BUILD_IN_PROGRESS=1\n\nRW_FRAMEWORK_NAME=${PROJECT_NAME}\nRW_INPUT_STATIC_LIB=\"lib${PROJECT_NAME}.a\"\nRW_FRAMEWORK_LOCATION=\"${BUILT_PRODUCTS_DIR}/${RW_FRAMEWORK_NAME}.framework\"\n\nfunction build_static_library {\n # Will rebuild the static library as specified\n # build_static_library sdk\n xcrun xcodebuild -project \"${PROJECT_FILE_PATH}\" \\\n -target \"${TARGET_NAME}\" \\\n -configuration \"${CONFIGURATION}\" \\\n -sdk \"${1}\" \\\n ONLY_ACTIVE_ARCH=NO \\\n BUILD_DIR=\"${BUILD_DIR}\" \\\n OBJROOT=\"${OBJROOT}\" \\\n BUILD_ROOT=\"${BUILD_ROOT}\" \\\n SYMROOT=\"${SYMROOT}\" $ACTION\n}\n\nfunction make_fat_library {\n # Will smash 2 static libs together\n # make_fat_library in1 in2 out\n xcrun lipo -create \"${1}\" \"${2}\" -output \"${3}\"\n}\n\n# 1 - Extract the platform (iphoneos/iphonesimulator) from the SDK name\nif [[ \"$SDK_NAME\" =~ ([A-Za-z]+) ]]; then\nRW_SDK_PLATFORM=${BASH_REMATCH[1]}\nelse\necho \"Could not find platform name from SDK_NAME: $SDK_NAME\"\nexit 1\nfi\n\n# 2 - Extract the version from the SDK\nif [[ \"$SDK_NAME\" =~ ([0-9]+.*$) ]]; then\nRW_SDK_VERSION=${BASH_REMATCH[1]}\nelse\necho \"Could not find sdk version from SDK_NAME: $SDK_NAME\"\nexit 1\nfi\n\n# 3 - Determine the other platform\nif [ \"$RW_SDK_PLATFORM\" == \"iphoneos\" ]; then\nRW_OTHER_PLATFORM=iphonesimulator\nelse\nRW_OTHER_PLATFORM=iphoneos\nfi\n\n# 4 - Find the build directory\nif [[ \"$BUILT_PRODUCTS_DIR\" =~ (.*)$RW_SDK_PLATFORM$ ]]; then\nRW_OTHER_BUILT_PRODUCTS_DIR=\"${BASH_REMATCH[1]}${RW_OTHER_PLATFORM}\"\nelse\necho \"Could not find other platform build directory.\"\nexit 1\nfi\n\n# Build the other platform.\nbuild_static_library \"${RW_OTHER_PLATFORM}${RW_SDK_VERSION}\"\n\n# If we're currently building for iphonesimulator, then need to rebuild\n# to ensure that we get both i386 and x86_64\nif [ \"$RW_SDK_PLATFORM\" == \"iphonesimulator\" ]; then\nbuild_static_library \"${SDK_NAME}\"\nfi\n\n# Join the 2 static libs into 1 and push into the .framework\nmake_fat_library \"${BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}\" \\\n\"${RW_OTHER_BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}\" \\\n\"${RW_FRAMEWORK_LOCATION}/Versions/A/${RW_FRAMEWORK_NAME}\"\n\n# Ensure that the framework is present in both platform's build directories\ncp -a \"${RW_FRAMEWORK_LOCATION}/Versions/A/${RW_FRAMEWORK_NAME}\" \\\n\"${RW_OTHER_BUILT_PRODUCTS_DIR}/${RW_FRAMEWORK_NAME}.framework/Versions/A/${RW_FRAMEWORK_NAME}\"\n\n# Copy the framework to the user's desktop\nditto \"${RW_FRAMEWORK_LOCATION}\" \"${PROJECT_DIR}/Products/${RW_FRAMEWORK_NAME}.framework\""; - showEnvVarsInLog = 0; - }; - 8A6BE76819D5F34500498F77 /* Build Framework Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 12; - files = ( - ); - inputPaths = ( - ); - name = "Build Framework Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "#set -e\n\n#export FRAMEWORK_LOCN=\"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework\"\n\n#if [ -d ${FRAMEWORK_LOCN} ];\n#then\n# rm -rf ${FRAMEWORK_LOCN}\n#fi\n#\n# Create the path to the real Headers die\n#mkdir -p \"${FRAMEWORK_LOCN}/Versions/A/Headers\"\n#\n# Create the required symlinks\n#/bin/ln -sfh A \"${FRAMEWORK_LOCN}/Versions/Current\"\n#/bin/ln -sfh Versions/Current/Headers \"${FRAMEWORK_LOCN}/Headers\"\n#/bin/ln -sfh \"Versions/Current/${PRODUCT_NAME}\" \\\n#\"${FRAMEWORK_LOCN}/${PRODUCT_NAME}\"\n#\n# Copy the public headers into the framework\n#/bin/cp -a \"${TARGET_BUILD_DIR}/${PUBLIC_HEADERS_FOLDER_PATH}/\" \\\n#\"${FRAMEWORK_LOCN}/Versions/A/Headers\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 8A9AEDE71A1BF98600C58BDA /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 8AE7AD9F1A7AC4F6009E2F2F /* ANAdWebViewController.m in Sources */, 8A9AEDE81A1BF99D00C58BDA /* ANBannerAdView+ANContentViewTransitions.m in Sources */, 8A9AEDE91A1BF99D00C58BDA /* NSString+ANCategory.m in Sources */, 8A9AEDEA1A1BF99D00C58BDA /* NSTimer+ANCategory.m in Sources */, + 8AC65F6E1A40DE74006BCF39 /* ANMRAIDResizeView.m in Sources */, 8A9AEDEB1A1BF99D00C58BDA /* UIView+ANCategory.m in Sources */, + 8A2F48261A2E255600B0EA05 /* ANOpenInExternalBrowserActivity.m in Sources */, 8A9AEDEC1A1BF99D00C58BDA /* UIWebView+ANCategory.m in Sources */, 8A9AEDED1A1BF99D00C58BDA /* ANAdFetcher.m in Sources */, + 8A598F8D1A1EA061009BA879 /* ANNativeStandardAdResponse.m in Sources */, + 8A598F811A1E89FC009BA879 /* ANStandardAd.m in Sources */, 8A9AEDEE1A1BF99D00C58BDA /* ANAdRequestUrl.m in Sources */, + 8AC65F601A40DE74006BCF39 /* ANMRAIDCalendarManager.m in Sources */, 8A9AEDEF1A1BF99D00C58BDA /* ANAdResponse.m in Sources */, 8A9AEDF01A1BF99D00C58BDA /* ANAdView.m in Sources */, - 8A9AEDF11A1BF99D00C58BDA /* ANAdWebViewController.m in Sources */, + 8AC65F721A40DE74006BCF39 /* ANMRAIDUtil.m in Sources */, + 8AC65F6C1A40DE74006BCF39 /* ANMRAIDResizeProperties.m in Sources */, 8A9AEDF21A1BF99D00C58BDA /* ANANJAMImplementation.m in Sources */, + 8AC65F6A1A40DE74006BCF39 /* ANMRAIDOrientationProperties.m in Sources */, 8A9AEDF31A1BF99D00C58BDA /* ANBannerAdView.m in Sources */, 8A9AEDF41A1BF99D00C58BDA /* ANBrowserViewController.m in Sources */, + 8AC65F641A40DE74006BCF39 /* ANMRAIDExpandProperties.m in Sources */, + 8AF3C1A01A3631490018FB6A /* ANNativeImpressionTrackerInfo.m in Sources */, 8A9AEDF51A1BF99D00C58BDA /* ANClickOverlayView.m in Sources */, 8A9AEDF61A1BF99D00C58BDA /* ANGlobal.m in Sources */, 8A9AEDF71A1BF99D00C58BDA /* ANInterstitialAd.m in Sources */, 8A9AEDF81A1BF99D00C58BDA /* ANInterstitialAdViewController.m in Sources */, 8A9AEDF91A1BF99D00C58BDA /* ANLocation.m in Sources */, + 8AC65F661A40DE74006BCF39 /* ANMRAIDExpandViewController.m in Sources */, + 8AC65F681A40DE74006BCF39 /* ANMRAIDJavascriptUtil.m in Sources */, 8A9AEDFA1A1BF99D00C58BDA /* ANLogging.m in Sources */, 8A9AEDFB1A1BF99D00C58BDA /* ANLogManager.m in Sources */, + 8AC65F701A40DE74006BCF39 /* ANMRAIDResizeViewManager.m in Sources */, 8A9AEDFC1A1BF99D00C58BDA /* ANMediatedAd.m in Sources */, 8A9AEDFD1A1BF99D00C58BDA /* ANMediationAdViewController.m in Sources */, 8A9AEDFE1A1BF99D00C58BDA /* ANMediationContainerView.m in Sources */, - 8A9AEDFF1A1BF99D00C58BDA /* ANMRAIDViewController.m in Sources */, + 8A598F801A1E89FC009BA879 /* ANAdServerResponse.m in Sources */, 8A9AEE001A1BF99D00C58BDA /* ANPBBuffer.m in Sources */, 8A9AEE011A1BF99D00C58BDA /* ANPBContainerView.m in Sources */, 8A9AEE021A1BF99D00C58BDA /* ANReachability.m in Sources */, 8A9AEE031A1BF99D00C58BDA /* ANTargetingParameters.m in Sources */, - 8A9AEE041A1BF99D00C58BDA /* ANWebView.m in Sources */, 8A9AEE051A1BF99D00C58BDA /* ANNativeAdFetcher.m in Sources */, 8A9AEE061A1BF99D00C58BDA /* ANNativeAdImageCache.m in Sources */, + 8AF3C19F1A3631460018FB6A /* ANNativeImpressionTrackerManager.m in Sources */, 8A9AEE071A1BF99D00C58BDA /* ANNativeAdRequest.m in Sources */, - 8A9AEE081A1BF99D00C58BDA /* ANNativeAdRequest+ANBaseUrlOverride.m in Sources */, 8A9AEE091A1BF99D00C58BDA /* ANNativeAdRequestUrlBuilder.m in Sources */, 8A9AEE0A1A1BF99D00C58BDA /* ANNativeAdResponse.m in Sources */, 8A9AEE0B1A1BF99D00C58BDA /* ANNativeAdStarRating.m in Sources */, - 8A9AEE0C1A1BF99D00C58BDA /* ANNativeMediatedAd.m in Sources */, + 8A598F7F1A1E89FC009BA879 /* ANAdFetcherResponse.m in Sources */, 8A9AEE0D1A1BF99D00C58BDA /* ANNativeMediatedAdController.m in Sources */, 8A9AEE0E1A1BF99D00C58BDA /* ANNativeMediatedAdResponse.m in Sources */, 8A9AEE0F1A1BF99D00C58BDA /* UIView+ANNativeAdCategory.m in Sources */, + 8AC65F621A40DE74006BCF39 /* ANMRAIDContainerView.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1882,39 +1851,52 @@ buildActionMask = 2147483647; files = ( 8AD618D51981C11F00AC0780 /* ANInterstitialAd.m in Sources */, - 8AD618CF1981C11F00AC0780 /* ANAdWebViewController.m in Sources */, 8AD618DA1981C11F00AC0780 /* ANMediatedAd.m in Sources */, + 8AD2DAF51A1D3C2A00878CDD /* ANStandardAd.m in Sources */, + 8AC65F5A1A40DE63006BCF39 /* ANMRAIDResizeView.m in Sources */, + 8AC65F561A40DE63006BCF39 /* ANMRAIDOrientationProperties.m in Sources */, + 8AC65F501A40DE63006BCF39 /* ANMRAIDExpandProperties.m in Sources */, + 8A2F48251A2E255600B0EA05 /* ANOpenInExternalBrowserActivity.m in Sources */, ECE4EADA194B768A0069D934 /* NSString+ANCategory.m in Sources */, 8AD618E11981C11F00AC0780 /* ANTargetingParameters.m in Sources */, + 8AC65F5C1A40DE63006BCF39 /* ANMRAIDResizeViewManager.m in Sources */, + 8A598F8C1A1EA061009BA879 /* ANNativeStandardAdResponse.m in Sources */, 8AD618CB1981C11F00AC0780 /* ANAdFetcher.m in Sources */, - 8AD618E21981C11F00AC0780 /* ANWebView.m in Sources */, 8AD618D61981C11F00AC0780 /* ANInterstitialAdViewController.m in Sources */, + 8A82FDF61A30F36C00A267A0 /* ANNativeImpressionTrackerManager.m in Sources */, 8A6385E31A14336000280054 /* ANNativeAdRequestUrlBuilder.m in Sources */, + 8AC65F521A40DE63006BCF39 /* ANMRAIDExpandViewController.m in Sources */, ECE4EADB194B768A0069D934 /* NSTimer+ANCategory.m in Sources */, 8AD618D01981C11F00AC0780 /* ANANJAMImplementation.m in Sources */, 8AD618DC1981C11F00AC0780 /* ANMediationContainerView.m in Sources */, 8A6385E61A14336000280054 /* ANNativeMediatedAdController.m in Sources */, 8A6385E11A14336000280054 /* ANNativeAdStarRating.m in Sources */, 8AD618CD1981C11F00AC0780 /* ANAdResponse.m in Sources */, + 8AC65F541A40DE63006BCF39 /* ANMRAIDJavascriptUtil.m in Sources */, 8AD618DE1981C11F00AC0780 /* ANPBBuffer.m in Sources */, - 8A6385E51A14336000280054 /* ANNativeMediatedAd.m in Sources */, + 8AD2DAEF1A1D3A6900878CDD /* ANAdServerResponse.m in Sources */, 8AD618D21981C11F00AC0780 /* ANBrowserViewController.m in Sources */, + 8AC7C5391A3B5CEF00AA5548 /* ANAdWebViewController.m in Sources */, 8AD618CE1981C11F00AC0780 /* ANAdView.m in Sources */, 8AD618D81981C11F00AC0780 /* ANLogging.m in Sources */, 8AD618CC1981C11F00AC0780 /* ANAdRequestUrl.m in Sources */, 8AD618DB1981C11F00AC0780 /* ANMediationAdViewController.m in Sources */, 8AD618D11981C11F00AC0780 /* ANBannerAdView.m in Sources */, - 8AD618DD1981C11F00AC0780 /* ANMRAIDViewController.m in Sources */, 8AD618D31981C11F00AC0780 /* ANClickOverlayView.m in Sources */, 8AD618DF1981C11F00AC0780 /* ANPBContainerView.m in Sources */, + 8AF3C19D1A361CC30018FB6A /* ANNativeImpressionTrackerInfo.m in Sources */, + 8AD2DAEB1A1D3A5B00878CDD /* ANAdFetcherResponse.m in Sources */, 8A3EC16E19B8FD9A0049CD29 /* ANBannerAdView+ANContentViewTransitions.m in Sources */, 8A6385E91A14336000280054 /* UIView+ANNativeAdCategory.m in Sources */, 8A6385E21A14336000280054 /* ANNativeAdRequest.m in Sources */, + 8AC65F581A40DE63006BCF39 /* ANMRAIDResizeProperties.m in Sources */, ECE4EADD194B768A0069D934 /* UIWebView+ANCategory.m in Sources */, 8AD618E01981C11F00AC0780 /* ANReachability.m in Sources */, 8A6385E01A14336000280054 /* ANNativeAdImageCache.m in Sources */, + 8AC65F4C1A40DE63006BCF39 /* ANMRAIDCalendarManager.m in Sources */, ECE4EADC194B768A0069D934 /* UIView+ANCategory.m in Sources */, - 8A6385E81A14336000280054 /* ANNativeAdRequest+ANBaseUrlOverride.m in Sources */, + 8AC65F5E1A40DE63006BCF39 /* ANMRAIDUtil.m in Sources */, + 8AC65F4E1A40DE63006BCF39 /* ANMRAIDContainerView.m in Sources */, 8A6385DF1A14336000280054 /* ANNativeAdFetcher.m in Sources */, 8AD618D71981C11F00AC0780 /* ANLocation.m in Sources */, 8A6385E71A14336000280054 /* ANNativeMediatedAdResponse.m in Sources */, @@ -1934,11 +1916,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 8A6BE74419D5F19800498F77 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = EC3E5CDB1843C6D50070315E /* ANSDK */; - targetProxy = 8A6BE74319D5F19800498F77 /* PBXContainerItemProxy */; - }; 8A9AEDAE1A1BE8AA00C58BDA /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = EC48177A1845046A0066BBFE /* ANSDKResources */; @@ -1992,23 +1969,10 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 8A6BE73B19D5EEE500498F77 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 8A6BE73C19D5EEE500498F77 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; 8A9AED9F1A1BE84F00C58BDA /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_MODULES_AUTOLINK = NO; CLANG_WARN_UNREACHABLE_CODE = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CURRENT_PROJECT_VERSION = 1; @@ -2027,6 +1991,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; @@ -2038,6 +2003,7 @@ 8A9AEDA01A1BE84F00C58BDA /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_MODULES_AUTOLINK = NO; CLANG_WARN_UNREACHABLE_CODE = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; @@ -2091,6 +2057,7 @@ isa = XCBuildConfiguration; buildSettings = { DSTROOT = /tmp/ANSDK.dst; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK"; GCC_PRECOMPILE_PREFIX_HEADER = YES; HEADER_SEARCH_PATHS = ( "$(inherited)", @@ -2108,6 +2075,7 @@ isa = XCBuildConfiguration; buildSettings = { DSTROOT = /tmp/ANSDK.dst; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK"; GCC_PRECOMPILE_PREFIX_HEADER = YES; HEADER_SEARCH_PATHS = ( "$(inherited)", @@ -2235,7 +2203,7 @@ isa = XCBuildConfiguration; buildSettings = { DSTROOT = /tmp/ANSDK.dst; - FRAMEWORK_SEARCH_PATHS = ""; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK"; GCC_PRECOMPILE_PREFIX_HEADER = YES; HEADER_SEARCH_PATHS = ( "$(inherited)", @@ -2252,7 +2220,7 @@ isa = XCBuildConfiguration; buildSettings = { DSTROOT = /tmp/ANSDK.dst; - FRAMEWORK_SEARCH_PATHS = ""; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK"; GCC_PRECOMPILE_PREFIX_HEADER = YES; HEADER_SEARCH_PATHS = ( "$(inherited)", @@ -2396,6 +2364,7 @@ DSTROOT = /tmp/ANSDK.dst; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; + ONLY_ACTIVE_ARCH = NO; OTHER_LDFLAGS = "-ObjC"; PRIVATE_HEADERS_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)/PrivateHeaders"; PRODUCT_NAME = ANSDK; @@ -2458,15 +2427,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 8A6BE73A19D5EEE500498F77 /* Build configuration list for PBXAggregateTarget "BuildANSDKFramework" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 8A6BE73B19D5EEE500498F77 /* Debug */, - 8A6BE73C19D5EEE500498F77 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 8A9AEDA31A1BE84F00C58BDA /* Build configuration list for PBXNativeTarget "AppNexusSDK" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/BinaryProjects/AppNexusSDK/AppNexusSDK.h b/BinaryProjects/AppNexusSDK/AppNexusSDK.h index dc6371bb3..ff94e127a 100644 --- a/BinaryProjects/AppNexusSDK/AppNexusSDK.h +++ b/BinaryProjects/AppNexusSDK/AppNexusSDK.h @@ -15,14 +15,9 @@ #import -//! Project version number for AppNexusSDK. FOUNDATION_EXPORT double AppNexusSDKVersionNumber; - -//! Project version string for AppNexusSDK. FOUNDATION_EXPORT const unsigned char AppNexusSDKVersionString[]; -// In this header, you should import all the public headers of your framework using statements like #import - #import #import #import diff --git a/BinaryProjects/buildANSDKCocoaTouchFramework.sh b/BinaryProjects/buildANSDKCocoaTouchFramework.sh new file mode 100755 index 000000000..2dcb5e699 --- /dev/null +++ b/BinaryProjects/buildANSDKCocoaTouchFramework.sh @@ -0,0 +1,53 @@ +OUTDIR=`pwd`/out +OUTDIR_DEVICE=`pwd`/out_device +OUTDIR_SIMULATOR=`pwd`/out_simulator +LOGDIR=$OUTDIR/log +BUILDDIR=$OUTDIR/build +SCHEMENAME="AppNexusSDK" + +rm -fr $OUTDIR > /dev/null 2>&1 +rm -fr $OUTDIR_DEVICE > /dev/null 2>&1 +rm -fr $OUTDIR_SIMULATOR > /dev/null 2>&1 + +function buildDevice { + echo "Building framework for device:" $1 + LOGFILE=$LOGDIR/$1.log + xcodebuild -project "ANSDK.xcodeproj" -scheme $1 -configuration "Release" -sdk "iphoneos" CONFIGURATION_BUILD_DIR=$OUTDIR SYMROOT=$BUILDDIR OBJROOT=$BUILDDIR > $LOGFILE 2>&1 || { echo "Error in build check log $LOGFILE"; exit;} + mkdir -p $OUTDIR/$1 + mv $OUTDIR/$1.framework $OUTDIR/$1/$1.framework +} + +function buildSim { + echo "Building framework for simulator:" $1 + LOGFILE=$LOGDIR/$1.log + xcodebuild -project "ANSDK.xcodeproj" -scheme $1 -configuration "Release" -sdk "iphonesimulator" CONFIGURATION_BUILD_DIR=$OUTDIR SYMROOT=$BUILDDIR OBJROOT=$BUILDDIR > $LOGFILE 2>&1 || { echo "Error in build check log $LOGFILE"; exit;} + mkdir -p $OUTDIR/$1 + mv $OUTDIR/$1.framework $OUTDIR/$1/$1.framework +} + +### device +mkdir -p $LOGDIR +buildDevice $SCHEMENAME +rm -rf $OUTDIR/Intermediates +rm -rf $BUILDDIR +mv $OUTDIR $OUTDIR_DEVICE + +### simulator + +mkdir -p $LOGDIR +buildSim $SCHEMENAME +rm -rf $OUTDIR/Intermediates +rm -rf $BUILDDIR +mv $OUTDIR $OUTDIR_SIMULATOR + +### combine +echo 'Combining framework architectures' + +mkdir -p $OUTDIR/$SCHEMENAME +cp -a $OUTDIR_DEVICE/$SCHEMENAME/$SCHEMENAME.framework $OUTDIR/$SCHEMENAME +lipo -create $OUTDIR_DEVICE/$SCHEMENAME/$SCHEMENAME.framework/$SCHEMENAME $OUTDIR_SIMULATOR/$SCHEMENAME/$SCHEMENAME.framework/$SCHEMENAME -output $OUTDIR/$SCHEMENAME/$SCHEMENAME.framework/$SCHEMENAME +rm -rf $OUTDIR_DEVICE/$SCHEMENAME/$SCHEMENAME.framework + +rm -fr $OUTDIR_DEVICE > /dev/null 2>&1 +rm -fr $OUTDIR_SIMULATOR > /dev/null 2>&1 +rm -rf `pwd`/build diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 84d5e8c75..2291e2aae 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,4 +1,43 @@ -## RC 1.21 +## RC 2.1 + ++ MS-856, MS-868, MS-875, MS-916, MS-918, MS-925 Implemented AppNexus Native Ad Console Support. + ++ MS-932 Introduced namespaced `ANGender` enum values (e.g. `ANGenderMale`). Deprecated existing values (e.g. `MALE`). + ++ Updated to meet MRAID 2.0 compliance standards + +### Other Feature Additions: + ++ MS-868 Added dependency on StoreKit framework, App Store URLs will open directly in the app instead of opening in the AppStore app when `opensInNativeBrowser` is set to NO on the ad view. + ++ MS-900 Added dependency on EventKitUI framework, user will be presented with a calendar event edit screen if an ad calls `mraid.createCalendarEvent` + ++ UIWebView performance enhancements + +### Bug fixes: + ++ MS-888 Clear AmazonAdView delegate on dealloc + ++ MS-902 Fixed malformed URL issue caused by mediated networks not present in app + ++ MS-934 Allow background color for banner to be set from .nib file or storyboard + +### Includes the following mediated network SDKs: + ++ Google SDK Version 7.0.0 + ++ Amazon SDK Version 2.1.9 + ++ Facebook SDK Version 3.23 + ++ Millennial Media SDK Version 5.4.1 + ++ MoPub SDK Version 3.4.0 + +Note: The AdMob and DFP mediation adapters have been updated to work with the new framework distribution mechanism for the Google Ads SDK (in version 7.0.0). + + +## RC 1.21 (2.0) + AppNexus Native API 1.0, with support for MoPub and Facebook mediation. @@ -96,4 +135,4 @@ To enable Amazon monetization, your app must register itself with Amazon when yo ... - [ANAdapaterBaseAmazone setAmazonAppKey: "YOUR APP KEY"]; + [ANAdAdapterBaseAmazon setAmazonAppKey: "YOUR APP KEY"]; diff --git a/mediation/mediatedviews/Amazon/ANAdAdapterBannerAmazon.m b/mediation/mediatedviews/Amazon/ANAdAdapterBannerAmazon.m index 388ef838b..2d7aa8464 100644 --- a/mediation/mediatedviews/Amazon/ANAdAdapterBannerAmazon.m +++ b/mediation/mediatedviews/Amazon/ANAdAdapterBannerAmazon.m @@ -77,4 +77,8 @@ - (BOOL)willHandleAdViewResize:(AmazonAdView *)view toFrame:(CGRect)frame { return NO; } +- (void)dealloc { + self.adView.delegate = nil; // clearing unsafe_unretained property +} + @end diff --git a/mediation/mediatedviews/Amazon/ANAdAdapterBaseAmazon.m b/mediation/mediatedviews/Amazon/ANAdAdapterBaseAmazon.m index 69021658a..21cebd48e 100644 --- a/mediation/mediatedviews/Amazon/ANAdAdapterBaseAmazon.m +++ b/mediation/mediatedviews/Amazon/ANAdAdapterBaseAmazon.m @@ -41,19 +41,21 @@ - (AmazonAdOptions *)adOptionsForTargetingParameters:(ANTargetingParameters *)ta options.usesGeoLocation = YES; } switch (targetingParameters.gender) { - case MALE: + case ANGenderMale: [options setAdvancedOption:kANAdAdapterBaseAmazonGenderMaleValue forKey:kANAdAdapterBaseAmazonGenderKey]; break; - case FEMALE: + case ANGenderFemale: [options setAdvancedOption:kANAdAdapterBaseAmazonGenderFemaleValue forKey:kANAdAdapterBaseAmazonGenderKey]; break; default: break; } - [options setAdvancedOption:targetingParameters.age - forKey:kANAdAdapterBaseAmazonAgeKey]; + if (targetingParameters.age) { + [options setAdvancedOption:targetingParameters.age + forKey:kANAdAdapterBaseAmazonAgeKey]; + } return options; } diff --git a/mediation/mediatedviews/Amazon/AmazonSDK/AmazonAd.framework/Versions/A/AmazonAd b/mediation/mediatedviews/Amazon/AmazonSDK/AmazonAd.framework/Versions/A/AmazonAd index f564a092d..df4d39bdd 100644 Binary files a/mediation/mediatedviews/Amazon/AmazonSDK/AmazonAd.framework/Versions/A/AmazonAd and b/mediation/mediatedviews/Amazon/AmazonSDK/AmazonAd.framework/Versions/A/AmazonAd differ diff --git a/mediation/mediatedviews/Amazon/AmazonSDK/AmazonAd.framework/Versions/A/Headers/AmazonAdOptions.h b/mediation/mediatedviews/Amazon/AmazonSDK/AmazonAd.framework/Versions/A/Headers/AmazonAdOptions.h index 3128836b1..9b99281e4 100644 --- a/mediation/mediatedviews/Amazon/AmazonSDK/AmazonAd.framework/Versions/A/Headers/AmazonAdOptions.h +++ b/mediation/mediatedviews/Amazon/AmazonSDK/AmazonAd.framework/Versions/A/Headers/AmazonAdOptions.h @@ -9,7 +9,6 @@ // Standard Amazon Ad Sizes for phones. extern const CGSize AmazonAdSize_320x50; -extern const CGSize AmazonAdSize_300x50; extern const CGSize AmazonAdSize_300x250; // Standard Amazon Ad Sizes for tablets. diff --git a/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.README.txt b/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.README.txt new file mode 100644 index 000000000..e44eace04 --- /dev/null +++ b/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.README.txt @@ -0,0 +1,5 @@ + +Facebook Audience Network for iOS +================================= + +Documentation is available at https://developers.facebook.com/docs/audience-network. diff --git a/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/DeprecatedHeaders/FBAdView.h b/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/DeprecatedHeaders/FBAdView.h index fd2884a7f..5973e3735 100644 --- a/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/DeprecatedHeaders/FBAdView.h +++ b/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/DeprecatedHeaders/FBAdView.h @@ -51,12 +51,18 @@ extern FBAdSize const kFBAdSizeHeight90Banner; */ extern FBAdSize const kFBAdSizeInterstital; +/*! + @abstract Represents the flexible rectangle ad size, where width depends on + its container width, and height is fixed as 250pt. + */ +extern FBAdSize const kFBAdSizeHeight250Rectangle; + /*! @class FBAdView @abstract A customized UIView to represent a Facebook ad (a.k.a. banner ad). */ -@interface FBAdView : UIView +@interface FBAdView : UIView /*! @method diff --git a/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/DeprecatedHeaders/FBAudienceNetwork.h b/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/DeprecatedHeaders/FBAudienceNetwork.h index 3e60e6de7..b9c6e25d3 100644 --- a/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/DeprecatedHeaders/FBAudienceNetwork.h +++ b/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/DeprecatedHeaders/FBAudienceNetwork.h @@ -20,4 +20,4 @@ #import "FBNativeAd.h" #import "FBAdImage.h" -#define FB_AD_SDK_VERSION @"3.20.0" +#define FB_AD_SDK_VERSION @"3.23.0" diff --git a/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/FBAudienceNetwork b/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/FBAudienceNetwork index 14c8bbeb8..baa71e181 100644 Binary files a/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/FBAudienceNetwork and b/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/FBAudienceNetwork differ diff --git a/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/Headers/FBAdView.h b/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/Headers/FBAdView.h index fd2884a7f..5973e3735 100644 --- a/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/Headers/FBAdView.h +++ b/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/Headers/FBAdView.h @@ -51,12 +51,18 @@ extern FBAdSize const kFBAdSizeHeight90Banner; */ extern FBAdSize const kFBAdSizeInterstital; +/*! + @abstract Represents the flexible rectangle ad size, where width depends on + its container width, and height is fixed as 250pt. + */ +extern FBAdSize const kFBAdSizeHeight250Rectangle; + /*! @class FBAdView @abstract A customized UIView to represent a Facebook ad (a.k.a. banner ad). */ -@interface FBAdView : UIView +@interface FBAdView : UIView /*! @method diff --git a/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/Headers/FBAudienceNetwork.h b/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/Headers/FBAudienceNetwork.h index 3e60e6de7..b9c6e25d3 100644 --- a/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/Headers/FBAudienceNetwork.h +++ b/mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework/Versions/A/Headers/FBAudienceNetwork.h @@ -20,4 +20,4 @@ #import "FBNativeAd.h" #import "FBAdImage.h" -#define FB_AD_SDK_VERSION @"3.20.0" +#define FB_AD_SDK_VERSION @"3.23.0" diff --git a/mediation/mediatedviews/Facebook/FacebookSDK/README-FACEBOOK.txt b/mediation/mediatedviews/Facebook/FacebookSDK/README-FACEBOOK.txt new file mode 100644 index 000000000..0c4b1cf40 --- /dev/null +++ b/mediation/mediatedviews/Facebook/FacebookSDK/README-FACEBOOK.txt @@ -0,0 +1,45 @@ +Facebook SDK for iOS +==================== + +This open-source library allows you to integrate Facebook into your iOS app. + +Learn more about the provided samples, documentation, integrating the SDK into your app, accessing source code, and more at https://developers.facebook.com/ios + +NOTE: By default, the Facebook SDK for iOS is installed in ~/Documents/FacebookSDK + +TRY IT OUT +---------- +1. Download the SDK at https://developers.facebook.com/ios or via Cocoapods by adding the 'Facebook-iOS-SDK' pod. +2. Test your install: build and run the project at ~/Documents/FacebookSDK/Samples/HelloFacebookSample/HelloFacebookSample.xcodeproj +3. Check-out the tutorials available online at: https://developers.facebook.com/docs/getting-started/getting-started-with-the-ios-sdk +4. Start coding! Visit https://developers.facebook.com/ios for tutorials and reference documentation. + +FEATURES +-------- +* Login - https://developers.facebook.com/docs/facebook-login +* Sharing - https://developers.facebook.com/docs/sharing +* App Links - https://developers.facebook.com/docs/applinks +* Graph API - https://developers.facebook.com/docs/ios/graph + +GIVE FEEDBACK +------------- +Please report bugs or issues to https://developers.facebook.com/bugs/ + +You can also join the Facebook Developers Group on Facebook (https://www.facebook.com/groups/fbdevelopers/) or ask questions on Stack Overflow (http://facebook.stackoverflow.com) + +LICENSE +------- +Except as otherwise noted, the Facebook SDK for iOS is licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0.html). + +DEVELOPER TERMS +--------------- + +- By enabling Facebook integrations, including through this SDK, you can share information with Facebook, including information about people’s use of your app. Facebook will use information received in accordance with our Data Use Policy [https://www.facebook.com/about/privacy/], including to provide you with insights about the effectiveness of your ads and the use of your app. These integrations also enable us and our partners to serve ads on and off Facebook. + +- You may limit your sharing of information with us by updating the Insights control in the developer tool [https://developers.facebook.com/apps/{app_id}/advanced]. + +- If you use a Facebook integration, including to share information with us, you agree and confirm that you have provided appropriate and sufficiently prominent notice to and obtained the appropriate consent from your users regarding such collection, use, and disclosure (including, at a minimum, through your privacy policy). You further agree that you will not share information with us about children under the age of 13. + +- You agree to comply with all applicable laws and regulations and also agree to our Terms , including our Platform Policies .and Advertising Guidelines, as applicable . + +By using the Facebook SDK for iOS you agree to these terms. diff --git a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerAdMob.h b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerAdMob.h index a95a4d445..c1fcdd86c 100644 --- a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerAdMob.h +++ b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerAdMob.h @@ -15,7 +15,7 @@ #import "ANBasicConfig.h" #import ANCUSTOMADAPTERHEADER -#import "GADBannerView.h" +#import @interface ANAdAdapterBannerAdMob : NSObject diff --git a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerAdMob.m b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerAdMob.m index 40f9e93cf..01e9446b7 100644 --- a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerAdMob.m +++ b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerAdMob.m @@ -16,8 +16,6 @@ #import "ANAdAdapterBannerAdMob.h" #import "ANLogging.h" -#import "GADAdMobExtras.h" - @interface ANAdAdapterBannerAdMob () @property (nonatomic, readwrite, strong) GADBannerView *bannerView; @end @@ -79,13 +77,13 @@ - (GADRequest *)createRequestFromTargetingParameters:(ANTARGETINGPARAMETERS *)ta ANGENDER gender = targetingParameters.gender; switch (gender) { - case MALE: + case ANGenderMale: request.gender = kGADGenderMale; break; - case FEMALE: + case ANGenderFemale: request.gender = kGADGenderFemale; break; - case UNKNOWN: + case ANGenderUnknown: request.gender = kGADGenderUnknown; default: break; @@ -98,7 +96,7 @@ - (GADRequest *)createRequestFromTargetingParameters:(ANTARGETINGPARAMETERS *)ta accuracy:location.horizontalAccuracy]; } - GADAdMobExtras *extras = [GADAdMobExtras new]; + GADExtras *extras = [[GADExtras alloc] init]; extras.additionalParameters = targetingParameters.customKeywords; [request registerAdNetworkExtras:extras]; diff --git a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerDFP.h b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerDFP.h index eabae1ce9..4a75d703a 100644 --- a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerDFP.h +++ b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerDFP.h @@ -15,9 +15,7 @@ #import "ANBasicConfig.h" #import ANCUSTOMADAPTERHEADER -#import "DFPBannerView.h" -#import "DFPSwipeableBannerView.h" -#import "GADBannerViewDelegate.h" +#import @interface ANAdAdapterBannerDFP : NSObject diff --git a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerDFP.m b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerDFP.m index 7d0665b1a..5eea51ae7 100644 --- a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerDFP.m +++ b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterBannerDFP.m @@ -15,7 +15,6 @@ #import "ANAdAdapterBannerDFP.h" #import "ANLogging.h" -#import "DFPExtras.h" @interface ANAdAdapterBannerDFP () @property (nonatomic, readwrite, strong) DFPBannerView *dfpBanner; @@ -79,13 +78,13 @@ - (GADRequest *)createRequestFromTargetingParameters:(ANTARGETINGPARAMETERS *)ta ANGENDER gender = targetingParameters.gender; switch (gender) { - case MALE: + case ANGenderMale: request.gender = kGADGenderMale; break; - case FEMALE: + case ANGenderFemale: request.gender = kGADGenderFemale; break; - case UNKNOWN: + case ANGenderUnknown: request.gender = kGADGenderUnknown; default: break; @@ -98,7 +97,7 @@ - (GADRequest *)createRequestFromTargetingParameters:(ANTARGETINGPARAMETERS *)ta accuracy:location.horizontalAccuracy]; } - DFPExtras *extras = [DFPExtras new]; + GADExtras *extras = [[GADExtras alloc] init]; NSMutableDictionary *extrasDictionary = [targetingParameters.customKeywords mutableCopy]; NSString *age = targetingParameters.age; diff --git a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialAdMob.h b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialAdMob.h index f24831c16..00e059ed4 100644 --- a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialAdMob.h +++ b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialAdMob.h @@ -15,7 +15,7 @@ #import "ANBasicConfig.h" #import ANCUSTOMADAPTERHEADER -#import "GADInterstitial.h" +#import @interface ANAdAdapterInterstitialAdMob : NSObject diff --git a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialAdMob.m b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialAdMob.m index 00ff17bde..eed7e0984 100644 --- a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialAdMob.m +++ b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialAdMob.m @@ -15,7 +15,6 @@ #import "ANAdAdapterInterstitialAdMob.h" #import "ANLogging.h" -#import "GADAdMobExtras.h" @interface ANAdAdapterInterstitialAdMob () @@ -61,13 +60,13 @@ - (GADRequest *)createRequestFromTargetingParameters:(ANTARGETINGPARAMETERS *)ta ANGENDER gender = targetingParameters.gender; switch (gender) { - case MALE: + case ANGenderMale: request.gender = kGADGenderMale; break; - case FEMALE: + case ANGenderFemale: request.gender = kGADGenderFemale; break; - case UNKNOWN: + case ANGenderUnknown: request.gender = kGADGenderUnknown; default: break; @@ -80,7 +79,7 @@ - (GADRequest *)createRequestFromTargetingParameters:(ANTARGETINGPARAMETERS *)ta accuracy:location.horizontalAccuracy]; } - GADAdMobExtras *extras = [GADAdMobExtras new]; + GADExtras *extras = [[GADExtras alloc] init]; extras.additionalParameters = targetingParameters.customKeywords; [request registerAdNetworkExtras:extras]; diff --git a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialDFP.h b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialDFP.h index 75bc2f7ae..3b6e77476 100644 --- a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialDFP.h +++ b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialDFP.h @@ -15,7 +15,7 @@ #import "ANBasicConfig.h" #import ANCUSTOMADAPTERHEADER -#import "DFPInterstitial.h" +#import @interface ANAdAdapterInterstitialDFP : NSObject diff --git a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialDFP.m b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialDFP.m index 3e24e1c28..576d8a9f2 100644 --- a/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialDFP.m +++ b/mediation/mediatedviews/GoogleAdMob/ANAdAdapterInterstitialDFP.m @@ -15,7 +15,6 @@ #import "ANAdAdapterInterstitialDFP.h" #import "ANLogging.h" -#import "DFPExtras.h" @interface ANAdAdapterInterstitialDFP () @@ -61,13 +60,13 @@ - (GADRequest *)createRequestFromTargetingParameters:(ANTARGETINGPARAMETERS *)ta ANGENDER gender = targetingParameters.gender; switch (gender) { - case MALE: + case ANGenderMale: request.gender = kGADGenderMale; break; - case FEMALE: + case ANGenderFemale: request.gender = kGADGenderFemale; break; - case UNKNOWN: + case ANGenderUnknown: request.gender = kGADGenderUnknown; default: break; @@ -80,7 +79,7 @@ - (GADRequest *)createRequestFromTargetingParameters:(ANTARGETINGPARAMETERS *)ta accuracy:location.horizontalAccuracy]; } - DFPExtras *extras = [DFPExtras new]; + GADExtras *extras = [[GADExtras alloc] init]; NSMutableDictionary *extrasDictionary = [targetingParameters.customKeywords mutableCopy]; NSString *age = targetingParameters.age; diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/DFPExtras.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/DFPExtras.h deleted file mode 100644 index d89a35ede..000000000 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/DFPExtras.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// DFPExtras.h -// Google Mobile Ads SDK -// -// Copyright 2012 Google Inc. All rights reserved. -// -// To add DFP extras to an ad request: -// DFPExtras *extras = [[[DFPExtras alloc] init] autorelease]; -// extras.additionalParameters = @{ -// @"key" : @"value" -// }; -// GADRequest *request = [GADRequest request]; -// [request registerAdNetworkExtras:extras]; -// - -#import "GADAdMobExtras.h" - -@interface DFPExtras : GADAdMobExtras - -/// Publisher provided user ID. -@property(nonatomic, copy) NSString *publisherProvidedID; - -@end diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/DFPInterstitial.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/DFPInterstitial.h deleted file mode 100644 index 7cec238da..000000000 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/DFPInterstitial.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// DFPInterstitial.h -// Google Mobile Ads SDK -// -// Copyright 2012 Google Inc. All rights reserved. -// - -#import "GADInterstitial.h" - -@protocol GADAppEventDelegate; - -@interface DFPInterstitial : GADInterstitial - -@property(nonatomic, weak) id appEventDelegate; - -@end diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/DFPSwipeableBannerView.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/DFPSwipeableBannerView.h deleted file mode 100644 index 571ca2e0f..000000000 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/DFPSwipeableBannerView.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// DFPSwipeableBannerView.h -// Google Mobile Ads SDK -// -// Copyright 2012 Google Inc. All rights reserved. -// - -#import "DFPBannerView.h" - -/// Deprecated swipeable banner view. Use DFPBannerView. -__attribute__((deprecated("Use DFPBannerView."))) -@interface DFPSwipeableBannerView : DFPBannerView - -/// Set a delegate to be notified when the user activates and deactivates an ad. Remember to nil out -/// the delegate before releasing this banner. -@property(nonatomic, weak) id swipeDelegate __attribute__((deprecated("Use DFPBannerView."))); - -@end diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/GADAdSizeDelegate.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/GADAdSizeDelegate.h deleted file mode 100644 index 6bdb38342..000000000 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/GADAdSizeDelegate.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// GADAdSizeDelegate.h -// Google Mobile Ads SDK -// -// Copyright 2012 Google Inc. All rights reserved. -// -// The class implementing this protocol will be notified when the DFPBannerView -// changes ad size. Any views that may be affected by the banner size change -// will have time to adjust. -// - -#import - -#import "GADAdSize.h" - -@class GADBannerView; - -@protocol GADAdSizeDelegate - -- (void)adView:(GADBannerView *)view willChangeAdSizeTo:(GADAdSize)size; - -@end diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/GADSwipeableBannerViewDelegate.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/GADSwipeableBannerViewDelegate.h deleted file mode 100644 index 817a3dd3f..000000000 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/GADSwipeableBannerViewDelegate.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// GADSwipeableBannerViewDelegate.h -// Google Mobile Ads SDK -// -// Copyright 2012 Google Inc. All rights reserved. -// - -#import - -@class GADBannerView; - -// The delegate will be notified when a user activates and deactivates an ad. If the -// DFPSwipeableBannerView is contained within a UIScrollView, make sure to set scrollEnabled to NO -// when -adViewDidActivateAd: is called and to set back to YES when -adViewDidDeactivateAd: is -// called. -@protocol GADSwipeableBannerViewDelegate - -@optional - -- (void)adViewDidActivateAd:(GADBannerView *)banner; - -- (void)adViewDidDeactivateAd:(GADBannerView *)banner; - -@end diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADAdMobExtras.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADAdMobExtras.h deleted file mode 100644 index 4337d8323..000000000 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADAdMobExtras.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// GADAdMobExtras.h -// Google Mobile Ads SDK -// -// Copyright 2012 Google Inc. All rights reserved. -// - -#import - -#import "GADAdNetworkExtras.h" -#import "GADModules.h" - -@interface GADAdMobExtras : NSObject - -/// The additional parameters publishers may send to the AdMob network. -@property(nonatomic, copy) NSDictionary *additionalParameters; - -@end diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADModules.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADModules.h deleted file mode 100644 index c19e11994..000000000 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADModules.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// GADModules.h -// Google Mobile Ads SDK -// -// Copyright 2014 Google Inc. All rights reserved. -// - -// If your target uses modules, importing this file will automatically link the frameworks used by -// the Google Mobile Ads library. - -#if __has_feature(objc_modules) -@import AdSupport; -@import AudioToolbox; -@import AVFoundation; -@import CoreGraphics; -@import CoreTelephony; -@import EventKit; -@import EventKitUI; -@import Foundation; -@import MessageUI; -@import StoreKit; -@import SystemConfiguration; -@import UIKit; -#endif diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/GoogleMobileAds b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/GoogleMobileAds new file mode 120000 index 000000000..95e839f2a --- /dev/null +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/GoogleMobileAds @@ -0,0 +1 @@ +Versions/Current/GoogleMobileAds \ No newline at end of file diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Headers b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Headers new file mode 120000 index 000000000..a177d2a6b --- /dev/null +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Modules/module.modulemap b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Modules/module.modulemap new file mode 100755 index 000000000..6b54fb685 --- /dev/null +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Modules/module.modulemap @@ -0,0 +1,19 @@ +framework module GoogleMobileAds { + umbrella header "GoogleMobileAds.h" + + export * + module * { export * } + + link framework "AdSupport" + link framework "AudioToolbox" + link framework "AVFoundation" + link framework "CoreGraphics" + link framework "CoreTelephony" + link framework "EventKit" + link framework "EventKitUI" + link framework "Foundation" + link framework "MessageUI" + link framework "StoreKit" + link framework "SystemConfiguration" + link framework "UIKit" +} diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/libGoogleAdMobAds.a b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/GoogleMobileAds old mode 100644 new mode 100755 similarity index 61% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/libGoogleAdMobAds.a rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/GoogleMobileAds index a5cf594a2..ce37f9c30 Binary files a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/libGoogleAdMobAds.a and b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/GoogleMobileAds differ diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/DFPBannerView.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPBannerView.h old mode 100644 new mode 100755 similarity index 67% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/DFPBannerView.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPBannerView.h index 79344771b..8a39206bc --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/DFPBannerView.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPBannerView.h @@ -5,23 +5,29 @@ // Copyright 2012 Google Inc. All rights reserved. // -#import "GADBannerView.h" +#import +@protocol DFPCustomRenderedBannerViewDelegate; @protocol GADAdSizeDelegate; @protocol GADAppEventDelegate; /// The view that displays DoubleClick For Publishers banner ads. @interface DFPBannerView : GADBannerView -/// Optional delegate that is notified when creatives send app events. To avoid crashing the app, -/// remember to nil this property before releasing the object that implements the -/// GADAppEventDelegate protocol. -@property(nonatomic, weak) id appEventDelegate; +/// Required value created on the DFP website. Create a new ad unit for every unique placement of an +/// ad in your application. Set this to the ID assigned for this placement. Ad units are important +/// for targeting and statistics. +/// +/// Example DFP ad unit ID: @"/6499/example/banner" +@property(nonatomic, copy) NSString *adUnitID; + +/// Optional delegate that is notified when creatives send app events. +@property(nonatomic, weak) IBOutlet id appEventDelegate; /// Optional delegate that is notified when creatives cause the banner to change size. To avoid /// crashing the app, remember to nil this property before releasing the object that implements the /// GADAdSizeDelegate protocol. -@property(nonatomic, weak) id adSizeDelegate; +@property(nonatomic, weak) IBOutlet id adSizeDelegate; /// Optional array of NSValue encoded GADAdSize structs, specifying all valid sizes that are /// appropriate for this slot. Never create your own GADAdSize directly. Use one of the predefined @@ -32,21 +38,23 @@ /// /// Example: /// \code -/// GADAdSize size1 = kGADAdSizeBanner; -/// GADAdSize size2 = kGADAdSizeLargeBanner; /// NSArray *validSizes = @[ -/// [NSValue valueWithBytes:&size1 objCType:@encode(GADAdSize)], -/// [NSValue valueWithBytes:&size2 objCType:@encode(GADAdSize)] +/// NSValueFromGADAdSize(kGADAdSizeBanner), +/// NSValueFromGADAdSize(kGADAdSizeLargeBanner) /// ]; /// /// bannerView.validAdSizes = validSizes; /// \endcode -@property(nonatomic, strong) NSArray *validAdSizes; +@property(nonatomic, copy) NSArray *validAdSizes; /// Indicates that the publisher will record impressions manually when the ad becomes visible to the /// user. @property(nonatomic, assign) BOOL enableManualImpressions; +/// Optional delegate object for custom rendered ads. +@property(nonatomic, weak) + IBOutlet id customRenderedBannerViewDelegate; + /// If you've set enableManualImpressions to YES, call this method when the ad is visible. - (void)recordImpression; diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPCustomRenderedAd.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPCustomRenderedAd.h new file mode 100755 index 000000000..c4543cc86 --- /dev/null +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPCustomRenderedAd.h @@ -0,0 +1,28 @@ +// +// DFPCustomRenderedAd.h +// Google Mobile Ads SDK +// +// Copyright 2014 Google Inc. All rights reserved. +// + +#import + +/// Custom rendered ad. Your application renders the ad. +@interface DFPCustomRenderedAd : NSObject + +/// The ad's HTML. +@property(nonatomic, copy, readonly) NSString *adHTML; + +/// The base URL of the ad's HTML. +@property(nonatomic, copy, readonly) NSURL *adBaseURL; + +/// Call this method when the user clicks the ad. +- (void)recordClick; + +/// Call this method when the ad is visible to the user. +- (void)recordImpression; + +/// Call this method after the ad has been rendered in a UIView object. +- (void)finishedRenderingAdView:(UIView *)view; + +@end diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPCustomRenderedBannerViewDelegate.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPCustomRenderedBannerViewDelegate.h new file mode 100755 index 000000000..59f1965ef --- /dev/null +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPCustomRenderedBannerViewDelegate.h @@ -0,0 +1,20 @@ +// +// DFPCustomRenderedBannerViewDelegate.h +// Google Mobile Ads SDK +// +// Copyright 2014 Google Inc. All rights reserved. +// + +#import + +@class DFPBannerView; +@class DFPCustomRenderedAd; + +@protocol DFPCustomRenderedBannerViewDelegate + +/// Called after ad data has been received. You must construct a banner from |customRenderedAd| and +/// call the |customRenderedAd| object's finishedRenderingAdView: when the ad is rendered. +- (void)bannerView:(DFPBannerView *)bannerView + didReceiveCustomRenderedAd:(DFPCustomRenderedAd *)customRenderedAd; + +@end diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPCustomRenderedInterstitialDelegate.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPCustomRenderedInterstitialDelegate.h new file mode 100755 index 000000000..fda75a2e2 --- /dev/null +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPCustomRenderedInterstitialDelegate.h @@ -0,0 +1,21 @@ +// +// DFPCustomRenderedInterstitialDelegate.h +// Google Mobile Ads SDK +// +// Copyright 2014 Google Inc. All rights reserved. +// + +#import + +@class DFPCustomRenderedAd; +@class DFPInterstitial; + +@protocol DFPCustomRenderedInterstitialDelegate + +/// Called after ad data has been received. You must construct an interstitial from +/// |customRenderedAd| and call the |customRenderedAd| object's finishedRenderingAdView: method when +/// the ad has been rendered. +- (void)interstitial:(DFPInterstitial *)interstitial + didReceiveCustomRenderedAd:(DFPCustomRenderedAd *)customRenderedAd; + +@end diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPInterstitial.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPInterstitial.h new file mode 100755 index 000000000..64a1c1a80 --- /dev/null +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPInterstitial.h @@ -0,0 +1,29 @@ +// +// DFPInterstitial.h +// Google Mobile Ads SDK +// +// Copyright 2012 Google Inc. All rights reserved. +// + +#import + +@protocol DFPCustomRenderedInterstitialDelegate; +@protocol GADAppEventDelegate; + +@interface DFPInterstitial : GADInterstitial + +/// Required value created on the DFP website. Create a new ad unit for every unique placement of an +/// ad in your application. Set this to the ID assigned for this placement. Ad units are important +/// for targeting and stats. +/// +/// Example DFP ad unit ID: @"/6499/example/interstitial" +@property(nonatomic, copy) NSString *adUnitID; + +/// Optional delegate that is notified when creatives send app events. +@property(nonatomic, weak) id appEventDelegate; + +/// Optional delegate object for custom rendered ads. +@property(nonatomic, weak) + id customRenderedInterstitialDelegate; + +@end diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPRequest.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPRequest.h new file mode 100755 index 000000000..248a6cc87 --- /dev/null +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/DFPRequest.h @@ -0,0 +1,31 @@ +// +// DFPRequest.h +// Google Mobile Ads SDK +// +// Copyright 2014 Google Inc. All rights reserved. +// + +#import + +#import + +/// Add this constant to the testDevices property's array to receive test ads on the simulator. +extern const id kDFPSimulatorID; + +/// Specifies optional parameters for ad requests. +@interface DFPRequest : GADRequest + +/// Publisher provided user ID. +@property(nonatomic, copy) NSString *publisherProvidedID; + +/// Array of strings used to exclude specified categories in ad results. +@property(nonatomic, copy) NSArray *categoryExclusions; + +/// Key-value pairs used for custom targeting. +@property(nonatomic, copy) NSDictionary *customTargeting; + +/// Update the ad correlator. Ad slots with the same correlation value are grouped for roadblocking. +/// After updating the correlator, load new requests in all DFP ads. ++ (void)updateCorrelator; + +@end diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADAdNetworkExtras.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADAdNetworkExtras.h old mode 100644 new mode 100755 similarity index 94% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADAdNetworkExtras.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADAdNetworkExtras.h index 64cc5b98a..d33de74b2 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADAdNetworkExtras.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADAdNetworkExtras.h @@ -7,8 +7,6 @@ #import -#import "GADModules.h" - /// An object implementing this protocol contains information set by the publisher on the client /// device for a particular ad network. /// diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADAdSize.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADAdSize.h old mode 100644 new mode 100755 similarity index 82% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADAdSize.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADAdSize.h index b1328b6fd..570bc7645 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADAdSize.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADAdSize.h @@ -4,19 +4,17 @@ // // Copyright 2012 Google Inc. All rights reserved. // -// A valid GADAdSize is considered to be one of the predefined GADAdSize -// constants or a GADAdSize constructed by GADAdSizeFromCGSize, -// GADAdSizeFullWidthPortraitWithHeight, GADAdSizeFullWidthLandscapeWithHeight. -// #import #import -#import "GADModules.h" - -/// Do not create a GADAdSize manually. Use one of the kGADAdSize constants. -/// Treat GADAdSize as an opaque type. Do not access any fields directly. To -/// obtain a concrete CGSize, use the function CGSizeFromGADAdSize(). +/// A valid GADAdSize is considered to be one of the predefined GADAdSize constants or a GADAdSize +/// constructed by GADAdSizeFromCGSize, GADAdSizeFullWidthPortraitWithHeight, +/// GADAdSizeFullWidthLandscapeWithHeight. +/// +/// Do not create a GADAdSize manually. Use one of the kGADAdSize constants. Treat GADAdSize as an +/// opaque type. Do not access any fields directly. To obtain a concrete CGSize, use the function +/// CGSizeFromGADAdSize(). typedef struct GADAdSize { CGSize size; NSUInteger flags; @@ -58,7 +56,7 @@ extern GADAdSize const kGADAdSizeInvalid; #pragma mark Custom Sizes /// Returns a custom GADAdSize for the provided CGSize. Use this only if you require a non-standard -/// size, otherwise, use one of the standard size constants above. +/// size. Otherwise, use one of the standard size constants above. GADAdSize GADAdSizeFromCGSize(CGSize size); /// Returns a custom GADAdSize that spans the full width of the application in portrait orientation @@ -85,6 +83,12 @@ BOOL IsGADAdSizeValid(GADAdSize size); /// Returns a NSString describing the provided GADAdSize. NSString *NSStringFromGADAdSize(GADAdSize size); +/// Returns an NSValue representing the GADAdSize. +NSValue *NSValueFromGADAdSize(GADAdSize size); + +/// Returns a GADAdSize from an NSValue. Returns kGADAdSizeInvalid if the value is not a GADAdSize. +GADAdSize GADAdSizeFromNSValue(NSValue *value); + #pragma mark Deprecated Macros #define GAD_SIZE_320x50 CGSizeFromGADAdSize(kGADAdSizeBanner) diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADAdSizeDelegate.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADAdSizeDelegate.h new file mode 100755 index 000000000..324a571f4 --- /dev/null +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADAdSizeDelegate.h @@ -0,0 +1,21 @@ +// +// GADAdSizeDelegate.h +// Google Mobile Ads SDK +// +// Copyright 2012 Google Inc. All rights reserved. +// + +#import + +#import + +@class GADBannerView; + +/// The class implementing this protocol will be notified when the DFPBannerView changes ad size. +/// Any views that may be affected by the banner size change will have time to adjust. +@protocol GADAdSizeDelegate + +/// Called before the ad view changes to the new size. +- (void)adView:(GADBannerView *)bannerView willChangeAdSizeTo:(GADAdSize)size; + +@end diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/GADAppEventDelegate.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADAppEventDelegate.h old mode 100644 new mode 100755 similarity index 67% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/GADAppEventDelegate.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADAppEventDelegate.h index d1f0e201c..34fbccece --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/DoubleClick/GADAppEventDelegate.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADAppEventDelegate.h @@ -10,16 +10,18 @@ @class GADBannerView; @class GADInterstitial; +/// Implement your app event within these methods. The delegate will be notified when the SDK +/// receives an app event message from the ad. @protocol GADAppEventDelegate -// Implement your app event within these methods. The delegate will be notified when the SDK -// receives an app event message from the ad. @optional +/// Called when the banner receives an app event. - (void)adView:(GADBannerView *)banner didReceiveAppEvent:(NSString *)name withInfo:(NSString *)info; +/// Called when the interstitial receives an app event. - (void)interstitial:(GADInterstitial *)interstitial didReceiveAppEvent:(NSString *)name withInfo:(NSString *)info; diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADBannerView.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADBannerView.h old mode 100644 new mode 100755 similarity index 55% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADBannerView.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADBannerView.h index 4b6757625..e0539919f --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADBannerView.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADBannerView.h @@ -7,28 +7,30 @@ #import -#import "GADAdSize.h" -#import "GADBannerViewDelegate.h" -#import "GADInAppPurchaseDelegate.h" -#import "GADModules.h" -#import "GADRequest.h" -#import "GADRequestError.h" - -/// The view that displays banner ads. A minimum implementation to get an ad -/// from within a UIViewController class is: +#import +#import +#import +#import +#import + +#ifndef IBInspectable +#define IBInspectable +#endif + +/// The view that displays banner ads. A minimum implementation to get an ad from within a +/// UIViewController class is: /// /// \code /// // Create and setup the ad view, specifying the size and origin at {0, 0}. /// GADBannerView *adView = [[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner]; /// adView.rootViewController = self; -/// adView.adUnitID = @"ID created when registering my app"; +/// adView.adUnitID = @"ID created when registering your app"; /// /// // Place the ad view onto the screen. /// [self.view addSubview:adView]; -/// [adView release]; /// /// // Request an ad without any additional targeting information. -/// [adView loadRequest:nil]; +/// [adView loadRequest:[GADRequest request]]; /// \endcode /// @interface GADBannerView : UIView @@ -45,20 +47,17 @@ #pragma mark Pre-Request -/// Required value created in the AdSense website. Create a new ad unit for every unique placement -/// of an ad in your application. Set this to the ID assigned for this placement. Ad units are -/// important for targeting and stats. -/// Example values for different request types: +/// Required value created on the AdMob website. Create a new ad unit for every unique placement of +/// an ad in your application. Set this to the ID assigned for this placement. Ad units are +/// important for targeting and statistics. /// -/// AdMob: a0123456789ABCD -/// DFP: /0123/ca-pub-0123456789012345/my-ad-identifier -/// AdSense: ca-mb-app-pub-0123456789012345/my-ad-identifier -/// Mediation: AB123456789ABCDE -@property(nonatomic, copy) NSString *adUnitID; +/// Example AdMob ad unit ID: @"ca-app-pub-0123456789012345/0123456789" +@property(nonatomic, copy) IBInspectable NSString *adUnitID; /// Required reference to the current root view controller. For example the root view controller in -/// tab-based application would be the UITabViewController. -@property(nonatomic, weak) UIViewController *rootViewController; +/// tab-based application would be the UITabViewController. Remember to nil or update this property +/// before deallocating the view controller. +@property(nonatomic, weak) IBOutlet UIViewController *rootViewController; /// Required to set this banner view to a proper size. Never create your own GADAdSize directly. Use /// one of the predefined standard ad sizes (such as kGADAdSizeBanner), or create one using the @@ -68,48 +67,23 @@ @property(nonatomic, assign) GADAdSize adSize; /// Optional delegate object that receives state change notifications from this GADBannerView. -/// Typically this is a UIViewController, however, if you are unfamiliar with the delegate pattern -/// it is recommended you subclass this GADBannerView and make it the delegate. That avoids any -/// chance of your application crashing if you forget to nil out the delegate. For example: -/// -/// \code -/// @interface MyAdView : GADBannerView -/// @end -/// -/// @implementation MyAdView -/// - (id)initWithFrame:(CGRect)frame { -/// self = [super initWithFrame:frame]; -/// if (self) { -/// self.delegate = self; -/// } -/// return self; -/// } -/// -/// - (void)dealloc { -/// self.delegate = nil; -/// [super dealloc]; -/// } -/// -/// @end -/// \endcode -@property(nonatomic, weak) id delegate; +/// Typically this is a UIViewController. Remember to nil this property before deallocating the +/// delegate. +@property(nonatomic, weak) IBOutlet id delegate; /// Optional delegate object that receives in-app purchase notifications from this ad. Required for /// the custom in-app purchase flow, but ignored when using the default in-app purchase flow. -/// Remember to nil the delegate before deallocating this object. -@property(nonatomic, weak) id inAppPurchaseDelegate; +/// Remember to nil this property before deallocating the delegate. +@property(nonatomic, weak) IBOutlet id inAppPurchaseDelegate; #pragma mark Making an Ad Request -/// Makes an ad request. Additional targeting options can be supplied with a request object. Refresh -/// the ad by calling this method again. +/// Makes an ad request. The request object supplies targeting information. - (void)loadRequest:(GADRequest *)request; -#pragma mark Ad Request - -/// Indicates if the currently displayed ad (or most recent failure) was a result of auto refreshing -/// as specified on server. This property is set to NO after each loadRequest: method. -@property(nonatomic, readonly, assign) BOOL hasAutoRefreshed; +/// A Boolean value that determines whether autoloading of ads in the receiver is enabled. If +/// enabled, you do not need to call the loadRequest: method to load ads. +@property(nonatomic, assign, getter=isAutoloadEnabled) IBInspectable BOOL autoloadEnabled; #pragma mark Mediation @@ -119,8 +93,15 @@ /// events, this method returns @"GADMAdapterCustomEvents". @property(nonatomic, readonly, weak) NSString *adNetworkClassName; -/// The underlying ad view of the mediated ad network. You may use this to find out the actual -/// size of the ad and adjust GADBannerView to fit the underlying ad view. +#pragma mark Deprecated + +/// Indicates if the currently displayed ad (or most recent failure) was a result of auto refreshing +/// as specified on server. This property is set to NO after each loadRequest: method. +@property(nonatomic, readonly, assign) BOOL hasAutoRefreshed __attribute__((deprecated)); + +/// The mediated ad network's underlying ad view. You may use this property to read the ad's actual +/// size and adjust this banner view's frame origin. However, modifying the banner view's frame size +/// triggers the Mobile Ads SDK to request a new ad. Only update the banner view's frame origin. @property(nonatomic, readonly, weak) UIView *mediatedAdView __attribute__((deprecated("Use adNetworkClassName."))); diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADBannerViewDelegate.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADBannerViewDelegate.h old mode 100644 new mode 100755 similarity index 99% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADBannerViewDelegate.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADBannerViewDelegate.h index f0b66bb61..933967c9a --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADBannerViewDelegate.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADBannerViewDelegate.h @@ -7,10 +7,8 @@ #import -#import "GADModules.h" - -@class GADRequestError; @class GADBannerView; +@class GADRequestError; /// Delegate for receiving state change messages from a GADBannerView such as ad requests /// succeeding/failing or when an ad has been clicked. diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADExtras.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADExtras.h new file mode 100755 index 000000000..80a354a46 --- /dev/null +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADExtras.h @@ -0,0 +1,17 @@ +// +// GADExtras.h +// Google Mobile Ads SDK +// +// Copyright 2012 Google Inc. All rights reserved. +// + +#import + +#import + +@interface GADExtras : NSObject + +/// Additional parameters to be sent to Google networks. +@property(nonatomic, copy) NSDictionary *additionalParameters; + +@end diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADInAppPurchase.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADInAppPurchase.h old mode 100644 new mode 100755 similarity index 99% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADInAppPurchase.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADInAppPurchase.h index 91ca8559b..7806f2977 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADInAppPurchase.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADInAppPurchase.h @@ -8,8 +8,6 @@ #import #import -#import "GADModules.h" - @protocol GADDefaultInAppPurchaseDelegate; #pragma mark - Default Purchase Flow diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADInAppPurchaseDelegate.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADInAppPurchaseDelegate.h old mode 100644 new mode 100755 similarity index 98% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADInAppPurchaseDelegate.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADInAppPurchaseDelegate.h index 51da58d36..6dee2442d --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADInAppPurchaseDelegate.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADInAppPurchaseDelegate.h @@ -7,8 +7,6 @@ #import -#import "GADModules.h" - @class GADDefaultInAppPurchase; @class GADInAppPurchase; diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADInterstitial.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADInterstitial.h old mode 100644 new mode 100755 similarity index 73% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADInterstitial.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADInterstitial.h index 211a7c60d..e0b190e42 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADInterstitial.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADInterstitial.h @@ -7,11 +7,10 @@ #import -#import "GADInAppPurchaseDelegate.h" -#import "GADInterstitialDelegate.h" -#import "GADModules.h" -#import "GADRequest.h" -#import "GADRequestError.h" +#import +#import +#import +#import /// An interstitial ad. This is a full-screen advertisement shown at natural transition points in /// your application such as between game levels or news stories. @@ -21,22 +20,20 @@ #pragma mark Pre-Request -/// Required value created in the AdSense website. Create a new ad unit for every unique placement -/// of an ad in your application. Set this to the ID assigned for this placement. Ad units are -/// important for targeting and stats. -/// Example values for different request types: -/// AdMob: a0123456789ABCD -/// DFP: /0123/ca-pub-0123456789012345/my-ad-identifier -/// AdSense: ca-mb-app-pub-0123456789012345/my-ad-identifier +/// Required value created on the AdMob website. Create a new ad unit for every unique placement of +/// an ad in your application. Set this to the ID assigned for this placement. Ad units are +/// important for targeting and statistics. +/// +/// Example AdMob ad unit ID: @"ca-app-pub-0123456789012345/0123456789" @property(nonatomic, copy) NSString *adUnitID; /// Optional delegate object that receives state change notifications from this GADInterstitalAd. -/// Remember to nil the delegate before deallocating this object. +/// Remember to nil this property before deallocating the delegate. @property(nonatomic, weak) id delegate; /// Optional delegate object that receives in-app purchase notifications from this ad. Required for /// the custom in-app purchase flow, but ignored when using the default in-app purchase flow. -/// Remember to nil the delegate before deallocating this object. +/// Remember to nil this property before deallocating the delegate. @property(nonatomic, weak) id inAppPurchaseDelegate; #pragma mark Making an Ad Request @@ -52,11 +49,11 @@ #pragma mark Post-Request /// Returns YES if the interstitial is ready to be displayed. The delegate's -/// interstitialAdDidReceiveAd: will be called when this switches from NO to YES. +/// interstitialAdDidReceiveAd: will be called after this property switches from NO to YES. @property(nonatomic, readonly, assign) BOOL isReady; -/// Returns YES if the interstitial object has already shown an interstitial. Note that an -/// interstitial object can only be used once even with different requests. +/// Returns YES if this object has already been presented. Interstitial objects can only be used +/// once even with different requests. @property(nonatomic, readonly, assign) BOOL hasBeenUsed; /// Returns the ad network class name that fetched the current ad. Returns nil while the latest ad diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADInterstitialDelegate.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADInterstitialDelegate.h old mode 100644 new mode 100755 similarity index 98% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADInterstitialDelegate.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADInterstitialDelegate.h index c7677bdf9..fe436aae8 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADInterstitialDelegate.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADInterstitialDelegate.h @@ -7,8 +7,6 @@ #import -#import "GADModules.h" - @class GADInterstitial; @class GADRequestError; diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADRequest.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADRequest.h old mode 100644 new mode 100755 similarity index 72% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADRequest.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADRequest.h index bf11028f3..00c446fcb --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADRequest.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADRequest.h @@ -8,13 +8,8 @@ #import #import -#import "GADModules.h" - @protocol GADAdNetworkExtras; -/// Add this constant to the testDevices property's array to receive test ads on the simulator. -#define GAD_SIMULATOR_ID @"Simulator" - /// Genders to help deliver more relevant ads. typedef NS_ENUM(NSInteger, GADGender) { kGADGenderUnknown, ///< Unknown gender. @@ -25,7 +20,7 @@ typedef NS_ENUM(NSInteger, GADGender) { /// Specifies optional parameters for ad requests. @interface GADRequest : NSObject -/// Creates an autoreleased GADRequest. +/// Returns a default request. + (instancetype)request; #pragma mark Additional Parameters For Ad Networks @@ -45,9 +40,6 @@ typedef NS_ENUM(NSInteger, GADGender) { /// extras type. - (void)removeAdNetworkExtrasFor:(Class)aClass; -/// Extras sent to the mediation server if using mediation. For future use. -@property(nonatomic, copy) NSDictionary *mediationExtras; - #pragma mark Collecting SDK Information /// Returns the version of the SDK. @@ -60,12 +52,11 @@ typedef NS_ENUM(NSInteger, GADGender) { #pragma mark User Information -/// The user's gender may be used to deliver more relevant ads. +/// Provide the user's gender to increase ad relevancy. @property(nonatomic, assign) GADGender gender; -/// The user's birthday may be used to deliver more relevant ads. -@property(nonatomic, strong) NSDate *birthday; -- (void)setBirthdayWithMonth:(NSInteger)m day:(NSInteger)d year:(NSInteger)y; +/// Provide the user's birthday to increase ad relevancy. +@property(nonatomic, copy) NSDate *birthday; /// The user's current location may be used to deliver more relevant ads. However do not use Core /// Location just for advertising, make sure it is used for more beneficial reasons as well. It is @@ -100,27 +91,28 @@ typedef NS_ENUM(NSInteger, GADGender) { #pragma mark Contextual Information -/// A keyword is a word or phrase describing the current activity of the user such as @"Sports -/// Scores". Each keyword is an NSString in the NSArray. To clear the keywords set this to nil. -@property(nonatomic, strong) NSMutableArray *keywords; - -/// Convenience method for adding keywords one at a time such as @"Sports Scores" and then -/// @"Football". -- (void)addKeyword:(NSString *)keyword; +/// Array of keyword strings. Keywords are words or phrases describing the current user activity +/// such as @"Sports Scores" or @"Football". Set this property to nil to clear the keywords. +@property(nonatomic, copy) NSArray *keywords; /// URL string for a webpage whose content matches the app content. This webpage content is used for /// targeting purposes. @property(nonatomic, copy) NSString *contentURL; -#pragma mark - Deprecated Methods +#pragma mark - Request Agent Information + +/// String that identifies the ad request's origin. Third party libraries that reference the Mobile +/// Ads SDK should set this property to denote the platform from which the ad request originated. +/// For example, a third party ad network called "CoolAds network" that is mediating requests to the +/// Mobile Ads SDK should set this property as "CoolAds". +@property(nonatomic, copy) NSString *requestAgent; -/// Accesses the additionalParameters for the "GoogleAdmob" ad network. Please use -/// -registerAdNetworkExtras: method above and pass an instance of GADAdMobExtras instead. -@property(nonatomic, copy) NSDictionary *additionalParameters __attribute__(( - deprecated(" use registerAdNetworkExtras: and pass an instance of GADAdMobExtras."))); +#pragma mark - Deprecated Methods -/// This property has been deprecated with the latest SDK releases. Please use testDevices. -@property(nonatomic, assign, getter=isTesting) BOOL testing - __attribute__((deprecated(" use the testDevices property."))); +/// Provide the user's birthday to increase ad relevancy. +- (void)setBirthdayWithMonth:(NSInteger)month + day:(NSInteger)day + year:(NSInteger)year + __attribute__((deprecated(" use the birthday property."))); @end diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADRequestError.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADRequestError.h old mode 100644 new mode 100755 similarity index 98% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADRequestError.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADRequestError.h index 6dcb06d70..0e10b9f9b --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GADRequestError.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GADRequestError.h @@ -7,8 +7,6 @@ #import -#import "GADModules.h" - @class GADRequest; /// Google AdMob Ads error domain. diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GoogleMobileAds.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GoogleMobileAds.h new file mode 100755 index 000000000..ca8f45921 --- /dev/null +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/GoogleMobileAds.h @@ -0,0 +1,42 @@ +// +// GoogleMobileAds.h +// Google Mobile Ads SDK +// +// Copyright 2014 Google Inc. All rights reserved. + +#import +#import + +//! Project version string for GoogleMobileAds. +FOUNDATION_EXPORT const unsigned char GoogleMobileAdsVersionString[]; + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import + +#import +#import diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventBanner.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventBanner.h old mode 100644 new mode 100755 similarity index 97% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventBanner.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventBanner.h index 25b4f1e1d..3c67f4795 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventBanner.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventBanner.h @@ -6,7 +6,9 @@ // #import -#import "GADAdSize.h" + +#import + #import "GADCustomEventBannerDelegate.h" #import "GADCustomEventRequest.h" diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventBannerDelegate.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventBannerDelegate.h old mode 100644 new mode 100755 similarity index 99% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventBannerDelegate.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventBannerDelegate.h index fef463fd8..5a9be5ee9 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventBannerDelegate.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventBannerDelegate.h @@ -6,6 +6,7 @@ // #import +#import @protocol GADCustomEventBanner; diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventExtras.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventExtras.h old mode 100644 new mode 100755 similarity index 95% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventExtras.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventExtras.h index b51f2764f..3ebe81e16 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventExtras.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventExtras.h @@ -7,7 +7,7 @@ #import -#import "GADAdNetworkExtras.h" +#import /// Create an instance of this class to set additional parameters for each custom event object. The /// additional parameters for a custom event are keyed by the custom event label. These extras are diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventInterstitial.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventInterstitial.h old mode 100644 new mode 100755 similarity index 99% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventInterstitial.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventInterstitial.h index 6679c8f9a..ba974ceca --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventInterstitial.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventInterstitial.h @@ -6,6 +6,7 @@ // #import + #import "GADCustomEventInterstitialDelegate.h" #import "GADCustomEventRequest.h" diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventInterstitialDelegate.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventInterstitialDelegate.h old mode 100644 new mode 100755 similarity index 100% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventInterstitialDelegate.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventInterstitialDelegate.h diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventRequest.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventRequest.h old mode 100644 new mode 100755 similarity index 98% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventRequest.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventRequest.h index 217ba83ce..75fe69b46 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Mediation/GADCustomEventRequest.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Mediation/GADCustomEventRequest.h @@ -7,7 +7,7 @@ #import -#import "GADRequest.h" +#import @class GADCustomEventExtras; diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Search/GADSearchBannerView.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Search/GADSearchBannerView.h old mode 100644 new mode 100755 similarity index 94% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Search/GADSearchBannerView.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Search/GADSearchBannerView.h index b74d7be2b..cb6e06019 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Search/GADSearchBannerView.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Search/GADSearchBannerView.h @@ -5,7 +5,7 @@ // Copyright 2011 Google Inc. All rights reserved. // -#import "GADBannerView.h" +#import "../GADBannerView.h" // A view that displays search ads. // To show search ads: diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Search/GADSearchRequest.h b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Search/GADSearchRequest.h old mode 100644 new mode 100755 similarity index 68% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Search/GADSearchRequest.h rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Search/GADSearchRequest.h index 8e6dca339..461852ae3 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/Add-ons/Search/GADSearchRequest.h +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/A/Headers/Search/GADSearchRequest.h @@ -5,11 +5,12 @@ // Copyright 2011 Google Inc. All rights reserved. // +#import #import -@class GADRequest; +#import -// Types of borders for search ads. +/// Search ad border types. typedef NS_ENUM(NSUInteger, GADSearchBorderType) { kGADSearchBorderTypeNone, kGADSearchBorderTypeDashed, @@ -23,28 +24,24 @@ typedef NS_ENUM(NSUInteger, GADSearchCallButtonColor) { kGADSearchCallButtonDark }; -// Specifies parameters and controls for search ads. -@interface GADSearchRequest : NSObject +// Specifies parameters for search ads. +@interface GADSearchRequest : GADRequest @property(nonatomic, copy) NSString *query; -@property(nonatomic, strong, readonly) UIColor *backgroundColor; -@property(nonatomic, strong, readonly) UIColor *gradientFrom; -@property(nonatomic, strong, readonly) UIColor *gradientTo; -@property(nonatomic, strong) UIColor *headerColor; -@property(nonatomic, strong) UIColor *descriptionTextColor; -@property(nonatomic, strong) UIColor *anchorTextColor; +@property(nonatomic, copy, readonly) UIColor *backgroundColor; +@property(nonatomic, copy, readonly) UIColor *gradientFrom; +@property(nonatomic, copy, readonly) UIColor *gradientTo; +@property(nonatomic, copy) UIColor *headerColor; +@property(nonatomic, copy) UIColor *descriptionTextColor; +@property(nonatomic, copy) UIColor *anchorTextColor; @property(nonatomic, copy) NSString *fontFamily; @property(nonatomic, assign) NSUInteger headerTextSize; -@property(nonatomic, strong) UIColor *borderColor; +@property(nonatomic, copy) UIColor *borderColor; @property(nonatomic, assign) GADSearchBorderType borderType; @property(nonatomic, assign) NSUInteger borderThickness; @property(nonatomic, copy) NSString *customChannels; @property(nonatomic, assign) GADSearchCallButtonColor callButtonColor; -// The request object used to request ad. Pass the value returned by the method -// to GADSearchBannerView to get the ad in the format specified. -- (GADRequest *)request; - // A solid background color for rendering the ad. The background of the ad // can either be a solid color, or a gradient, which can be specified through // setBackgroundGradientFrom:toColor: method. If both solid and gradient diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/Current b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/Current new file mode 120000 index 000000000..8c7e5a667 --- /dev/null +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleAdMobSDKReadme.txt b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/README-GOOGLE.txt old mode 100644 new mode 100755 similarity index 62% rename from mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleAdMobSDKReadme.txt rename to mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/README-GOOGLE.txt index 0f0f73f45..e54ebd229 --- a/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleAdMobSDKReadme.txt +++ b/mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/README-GOOGLE.txt @@ -5,9 +5,8 @@ Google Mobile Ads SDK for iOS This is the Google Mobile Ads SDK for iOS. Requirements: -- An AdMob site ID or DoubleClick for Publishers account. - Xcode 5.1 or later. -- Runtime of iOS 5.0 or later. +- iOS deployment target of iOS 6.0 or later. The latest documentation and code samples are available at: -https://developers.google.com/mobile-ads-sdk/docs/ +https://developers.google.com/mobile-ads-sdk/ diff --git a/mediation/mediatedviews/MillennialMedia/ANAdAdapterMillennialMediaBase.m b/mediation/mediatedviews/MillennialMedia/ANAdAdapterMillennialMediaBase.m index ad2f361a5..1556e0c9d 100644 --- a/mediation/mediatedviews/MillennialMedia/ANAdAdapterMillennialMediaBase.m +++ b/mediation/mediatedviews/MillennialMedia/ANAdAdapterMillennialMediaBase.m @@ -67,13 +67,13 @@ - (MMRequest *)createRequestFromTargetingParameters:(ANTARGETINGPARAMETERS *)tar ANGENDER gender = targetingParameters.gender; switch (gender) { - case MALE: + case ANGenderMale: request.gender = MMGenderMale; break; - case FEMALE: + case ANGenderFemale: request.gender = MMGenderFemale; break; - case UNKNOWN: + case ANGenderUnknown: request.gender = MMGenderOther; default: break; diff --git a/mediation/mediatedviews/MoPub/ANAdAdapterMoPubBase.m b/mediation/mediatedviews/MoPub/ANAdAdapterMoPubBase.m index 79ef7535e..f236b72b5 100644 --- a/mediation/mediatedviews/MoPub/ANAdAdapterMoPubBase.m +++ b/mediation/mediatedviews/MoPub/ANAdAdapterMoPubBase.m @@ -24,10 +24,10 @@ - (NSString *)keywordsFromTargetingParameters:(ANTARGETINGPARAMETERS *)targeting ANGENDER gender = targetingParameters.gender; switch (gender) { - case MALE: + case ANGenderMale: [keywordArray addObject:@"m_gender:male"]; break; - case FEMALE: + case ANGenderFemale: [keywordArray addObject:@"m_gender:female"]; break; default: diff --git a/mediation/mediatedviews/MoPub/ANAdAdapterNativeMoPub.m b/mediation/mediatedviews/MoPub/ANAdAdapterNativeMoPub.m index 73ed8ed2a..b5a151f90 100644 --- a/mediation/mediatedviews/MoPub/ANAdAdapterNativeMoPub.m +++ b/mediation/mediatedviews/MoPub/ANAdAdapterNativeMoPub.m @@ -74,10 +74,10 @@ - (NSString *)keywordsFromTargetingParameters:(ANTargetingParameters *)targeting ANGender gender = targetingParameters.gender; switch (gender) { - case MALE: + case ANGenderMale: [keywordArray addObject:@"m_gender:male"]; break; - case FEMALE: + case ANGenderFemale: [keywordArray addObject:@"m_gender:female"]; break; default: @@ -115,6 +115,7 @@ - (UIViewController *)viewControllerForPresentingModalView { } - (void)handleClickFromRootViewController:(UIViewController *)rvc { + [self.nativeAdDelegate adWasClicked]; [self.nativeAdDelegate willPresentAd]; [self.nativeAdDelegate didPresentAd]; self.rootViewController = rvc; diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/LICENSE-MOPUB b/mediation/mediatedviews/MoPub/MoPubSDK/LICENSE-MOPUB deleted file mode 100644 index cdafd75b1..000000000 --- a/mediation/mediatedviews/MoPub/MoPubSDK/LICENSE-MOPUB +++ /dev/null @@ -1,10 +0,0 @@ -Copyright (c) 2013 MoPub Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -* Neither the name of MoPub nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/LICENSE-MOPUB.txt b/mediation/mediatedviews/MoPub/MoPubSDK/LICENSE-MOPUB.txt new file mode 100755 index 000000000..dbbea5c1f --- /dev/null +++ b/mediation/mediatedviews/MoPub/MoPubSDK/LICENSE-MOPUB.txt @@ -0,0 +1 @@ +The MoPub SDK License can be found at http://www.mopub.com/legal/sdk-license-agreement/ \ No newline at end of file diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPAdBrowserController.xib b/mediation/mediatedviews/MoPub/MoPubSDK/MPAdBrowserController.xib old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPAdConversionTracker.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPAdConversionTracker.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPAdPositioning.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPAdPositioning.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPAdView.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPAdView.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPBannerCustomEvent.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPBannerCustomEvent.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPBannerCustomEventDelegate.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPBannerCustomEventDelegate.h old mode 100644 new mode 100755 index f2596de2c..f7b7be5f3 --- a/mediation/mediatedviews/MoPub/MoPubSDK/MPBannerCustomEventDelegate.h +++ b/mediation/mediatedviews/MoPub/MoPubSDK/MPBannerCustomEventDelegate.h @@ -25,7 +25,7 @@ /** * The view controller instance to use when presenting modals. * - * @return `viewControllerForPresentingModalView` returns theMP same view controller that you + * @return `viewControllerForPresentingModalView` returns the same view controller that you * specify when implementing the `MPAdViewDelegate` protocol. */ - (UIViewController *)viewControllerForPresentingModalView; diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPClientAdPositioning.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPClientAdPositioning.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPCloseButtonX.png b/mediation/mediatedviews/MoPub/MoPubSDK/MPCloseButtonX.png old mode 100644 new mode 100755 index 2e9dcee7a..ca4fa2981 Binary files a/mediation/mediatedviews/MoPub/MoPubSDK/MPCloseButtonX.png and b/mediation/mediatedviews/MoPub/MoPubSDK/MPCloseButtonX.png differ diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPCloseButtonX@2x.png b/mediation/mediatedviews/MoPub/MoPubSDK/MPCloseButtonX@2x.png old mode 100644 new mode 100755 index 9177ab237..85e39a31b Binary files a/mediation/mediatedviews/MoPub/MoPubSDK/MPCloseButtonX@2x.png and b/mediation/mediatedviews/MoPub/MoPubSDK/MPCloseButtonX@2x.png differ diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPCloseButtonX@3x.png b/mediation/mediatedviews/MoPub/MoPubSDK/MPCloseButtonX@3x.png new file mode 100755 index 000000000..c6e5df439 Binary files /dev/null and b/mediation/mediatedviews/MoPub/MoPubSDK/MPCloseButtonX@3x.png differ diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPCollectionViewAdPlacer.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPCollectionViewAdPlacer.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPConstants.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPConstants.h old mode 100644 new mode 100755 index a8a3e982e..ce4630e8a --- a/mediation/mediatedviews/MoPub/MoPubSDK/MPConstants.h +++ b/mediation/mediatedviews/MoPub/MoPubSDK/MPConstants.h @@ -13,7 +13,13 @@ #define HOSTNAME_FOR_TESTING @"testing.ads.mopub.com" #define DEFAULT_PUB_ID @"agltb3B1Yi1pbmNyDAsSBFNpdGUYkaoMDA" #define MP_SERVER_VERSION @"8" -#define MP_SDK_VERSION @"3.2.0" +#define MP_BUNDLE_IDENTIFIER @"com.mopub.mopub" + +#ifdef MP_FABRIC + #define MP_SDK_VERSION @"3.4.0+kit" +#else + #define MP_SDK_VERSION @"3.4.0" +#endif // Sizing constants. extern CGSize const MOPUB_BANNER_SIZE; diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPInterstitialAdController.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPInterstitialAdController.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPInterstitialCustomEvent.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPInterstitialCustomEvent.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPInterstitialCustomEventDelegate.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPInterstitialCustomEventDelegate.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAd.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAd.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdAdapter.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdAdapter.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdConstants.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdConstants.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdData.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdData.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdDelegate.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdDelegate.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdError.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdError.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdRendering.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdRendering.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdRequest.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdRequest.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdRequestTargeting.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdRequestTargeting.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdSource.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdSource.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdSourceDelegate.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeAdSourceDelegate.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeCustomEvent.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeCustomEvent.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeCustomEventDelegate.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPNativeCustomEventDelegate.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPServerAdPositioning.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPServerAdPositioning.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPStreamAdPlacementData.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPStreamAdPlacementData.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPStreamAdPlacer.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPStreamAdPlacer.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPTableViewAdManager.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPTableViewAdManager.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MPTableViewAdPlacer.h b/mediation/mediatedviews/MoPub/MoPubSDK/MPTableViewAdPlacer.h old mode 100644 new mode 100755 diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MRAID.bundle/mraid.js b/mediation/mediatedviews/MoPub/MoPubSDK/MRAID.bundle/mraid.js index 386e260e4..16fac0471 100755 --- a/mediation/mediatedviews/MoPub/MoPubSDK/MRAID.bundle/mraid.js +++ b/mediation/mediatedviews/MoPub/MoPubSDK/MRAID.bundle/mraid.js @@ -1,3 +1,7 @@ +/* +Do not modify this version of the file. It will be copied over when any of the project's targets are built. +If you wish to modify mraid.js, modify the version located at mopub-sdk-common/mraid/mraid.js. +*/ (function() { var isIOS = (/iphone|ipad|ipod/i).test(window.navigator.userAgent.toLowerCase()); if (isIOS) { @@ -13,74 +17,59 @@ } }()); -(function() { - // Establish the root mraidbridge object. - var mraidbridge = window.mraidbridge = {}; - - // native SDK is ready to process mraid commands. - var nativeSDKFiredReady = false; - - // Listeners for bridge events. - var listeners = {}; - // Queue to track pending calls to the native SDK. - var nativeCallQueue = []; - - // Whether a native call is currently in progress. - var nativeCallInFlight = false; +(function() { + var mraid = window.mraid = {}; ////////////////////////////////////////////////////////////////////////////////////////////////// - mraidbridge.fireReadyEvent = function() { - nativeSDKFiredReady = true; - mraidbridge.fireEvent('ready'); - }; + // Bridge interface to SDK - mraidbridge.fireChangeEvent = function(properties) { - mraidbridge.fireEvent('change', properties); + var bridge = window.mraidbridge = { + nativeSDKFiredReady: false, + nativeCallQueue: [], + nativeCallInFlight: false, + lastSizeChangeProperties: null }; - mraidbridge.fireErrorEvent = function(message, action) { - mraidbridge.fireEvent('error', message, action); - }; - mraidbridge.fireEvent = function(type) { - var ls = listeners[type]; - if (ls) { - var args = Array.prototype.slice.call(arguments); - args.shift(); - var l = ls.length; - for (var i = 0; i < l; i++) { - ls[i].apply(null, args); + bridge.fireChangeEvent = function(properties) { + for (var p in properties) { + if (properties.hasOwnProperty(p)) { + // Change handlers defined by MRAID below + var handler = changeHandlers[p]; + handler(properties[p]); } } }; - mraidbridge.nativeCallComplete = function(command) { - if (nativeCallQueue.length === 0) { - nativeCallInFlight = false; + bridge.nativeCallComplete = function(command) { + if (this.nativeCallQueue.length === 0) { + this.nativeCallInFlight = false; return; } - var nextCall = nativeCallQueue.pop(); + var nextCall = this.nativeCallQueue.pop(); window.location = nextCall; }; - mraidbridge.executeNativeCall = function(command) { - if (!nativeSDKFiredReady) { + bridge.executeNativeCall = function(args) { + var command = args.shift(); + + if (!this.nativeSDKFiredReady) { console.log('rejecting ' + command + ' because mraid is not ready'); - mraidbridge.fireErrorEvent('mraid is not ready', command); + bridge.notifyErrorEvent('mraid is not ready', command); return; } - + var call = 'mraid://' + command; var key, value; var isFirstArgument = true; - for (var i = 1; i < arguments.length; i += 2) { - key = arguments[i]; - value = arguments[i + 1]; + for (var i = 0; i < args.length; i += 2) { + key = args[i]; + value = args[i + 1]; if (value === null) continue; @@ -94,55 +83,133 @@ call += encodeURIComponent(key) + '=' + encodeURIComponent(value); } - if (nativeCallInFlight) { - nativeCallQueue.push(call); + if (this.nativeCallInFlight) { + this.nativeCallQueue.push(call); } else { - nativeCallInFlight = true; + this.nativeCallInFlight = true; window.location = call; } }; - ////////////////////////////////////////////////////////////////////////////////////////////////// - mraidbridge.addEventListener = function(event, listener) { - var eventListeners; - listeners[event] = listeners[event] || []; - eventListeners = listeners[event]; + bridge.setCurrentPosition = function(x, y, width, height) { + currentPosition = { + x: x, + y: y, + width: width, + height: height + }; + broadcastEvent(EVENTS.INFO, 'Set current position to ' + stringify(currentPosition)); + }; - for (var l in eventListeners) { - // Listener already registered, so no need to add it. - if (listener === l) return; + bridge.setDefaultPosition = function(x, y, width, height) { + defaultPosition = { + x: x, + y: y, + width: width, + height: height + }; + broadcastEvent(EVENTS.INFO, 'Set default position to ' + stringify(defaultPosition)); + }; + + bridge.setMaxSize = function(width, height) { + maxSize = { + width: width, + height: height + }; + + expandProperties.width = width; + expandProperties.height = height; + + broadcastEvent(EVENTS.INFO, 'Set max size to ' + stringify(maxSize)); + }; + + bridge.setPlacementType = function(_placementType) { + placementType = _placementType; + broadcastEvent(EVENTS.INFO, 'Set placement type to ' + stringify(placementType)); + }; + + bridge.setScreenSize = function(width, height) { + screenSize = { + width: width, + height: height + }; + broadcastEvent(EVENTS.INFO, 'Set screen size to ' + stringify(screenSize)); + }; + + bridge.setState = function(_state) { + state = _state; + broadcastEvent(EVENTS.INFO, 'Set state to ' + stringify(state)); + broadcastEvent(EVENTS.STATECHANGE, state); + }; + + bridge.setIsViewable = function(_isViewable) { + isViewable = _isViewable; + broadcastEvent(EVENTS.INFO, 'Set isViewable to ' + stringify(isViewable)); + broadcastEvent(EVENTS.VIEWABLECHANGE, isViewable); + }; + + bridge.setSupports = function(sms, tel, calendar, storePicture, inlineVideo) { + supportProperties = { + sms: sms, + tel: tel, + calendar: calendar, + storePicture: storePicture, + inlineVideo: inlineVideo + }; + }; + + bridge.notifyReadyEvent = function() { + this.nativeSDKFiredReady = true; + broadcastEvent(EVENTS.READY); + }; + + bridge.notifyErrorEvent = function(message, action) { + broadcastEvent(EVENTS.ERROR, message, action); + }; + + // Temporary aliases while we migrate to the new API + bridge.fireReadyEvent = bridge.notifyReadyEvent; + bridge.fireErrorEvent = bridge.notifyErrorEvent; + + bridge.notifySizeChangeEvent = function(width, height) { + if (this.lastSizeChangeProperties && + width == this.lastSizeChangeProperties.width && height == this.lastSizeChangeProperties.height) { + return; } - eventListeners.push(listener); + this.lastSizeChangeProperties = { + width: width, + height: height + }; + broadcastEvent(EVENTS.SIZECHANGE, width, height); }; - mraidbridge.removeEventListener = function(event, listener) { - if (listeners.hasOwnProperty(event)) { - var eventListeners = listeners[event]; - if (eventListeners) { - var idx = eventListeners.indexOf(listener); - if (idx !== -1) { - eventListeners.splice(idx, 1); - } - } + bridge.notifyStateChangeEvent = function() { + if (state === STATES.LOADING) { + broadcastEvent(EVENTS.INFO, 'Native SDK initialized.'); } + + broadcastEvent(EVENTS.INFO, 'Set state to ' + stringify(state)); + broadcastEvent(EVENTS.STATECHANGE, state); + }; + + bridge.notifyViewableChangeEvent = function() { + broadcastEvent(EVENTS.INFO, 'Set isViewable to ' + stringify(isViewable)); + broadcastEvent(EVENTS.VIEWABLECHANGE, isViewable); }; -}()); -(function() { - var mraid = window.mraid = {}; - var bridge = window.mraidbridge; // Constants. //////////////////////////////////////////////////////////////////////////////////// - var VERSION = mraid.VERSION = '1.0'; + var VERSION = mraid.VERSION = '2.0'; var STATES = mraid.STATES = { - LOADING: 'loading', // Initial state. + LOADING: 'loading', DEFAULT: 'default', EXPANDED: 'expanded', - HIDDEN: 'hidden' + HIDDEN: 'hidden', + RESIZED: 'resized' }; var EVENTS = mraid.EVENTS = { @@ -150,7 +217,8 @@ INFO: 'info', READY: 'ready', STATECHANGE: 'stateChange', - VIEWABLECHANGE: 'viewableChange' + VIEWABLECHANGE: 'viewableChange', + SIZECHANGE: 'sizeChange' }; var PLACEMENT_TYPES = mraid.PLACEMENT_TYPES = { @@ -163,14 +231,44 @@ // Properties which define the behavior of an expandable ad. var expandProperties = { - width: -1, - height: -1, + width: false, + height: false, useCustomClose: false, - isModal: true, - lockOrientation: false + isModal: true + }; + + var resizeProperties = { + width: false, + height: false, + offsetX: false, + offsetY: false, + customClosePosition: 'top-right', + allowOffscreen: true + }; + + var orientationProperties = { + allowOrientationChange: true, + forceOrientation: "none" }; - var hasSetCustomSize = false; + var supportProperties = { + sms: false, + tel: false, + calendar: false, + storePicture: false, + inlineVideo: false + }; + + // default is undefined so that notifySizeChangeEvent can track changes + var lastSizeChangeProperties; + + var maxSize = {}; + + var currentPosition = {}; + + var defaultPosition = {}; + + var screenSize = {}; var hasSetCustomClose = false; @@ -182,18 +280,8 @@ var isViewable = false; - var screenSize = { width: -1, height: -1 }; - var placementType = PLACEMENT_TYPES.UNKNOWN; - var supports = { - sms: false, - tel: false, - calendar: false, - storePicture: false, - inlineVideo: false - }; - ////////////////////////////////////////////////////////////////////////////////////////////////// var EventListeners = function(event) { @@ -229,7 +317,7 @@ this.broadcast = function(args) { for (var id in listeners) { - if (listeners.hasOwnProperty(id)) listeners[id].apply({}, args); + if (listeners.hasOwnProperty(id)) listeners[id].apply(mraid, args); } }; @@ -305,29 +393,17 @@ placementType = val; }, - screenSize: function(val) { + sizeChange: function(val) { broadcastEvent(EVENTS.INFO, 'Set screenSize to ' + stringify(val)); for (var key in val) { if (val.hasOwnProperty(key)) screenSize[key] = val[key]; } - - if (!hasSetCustomSize) { - expandProperties['width'] = screenSize['width']; - expandProperties['height'] = screenSize['height']; - } - }, - - expandProperties: function(val) { - broadcastEvent(EVENTS.INFO, 'Merging expandProperties with ' + stringify(val)); - for (var key in val) { - if (val.hasOwnProperty(key)) expandProperties[key] = val[key]; - } }, supports: function(val) { broadcastEvent(EVENTS.INFO, 'Set supports to ' + stringify(val)); - supports = val; - }, + supportProperties = val; + } }; var validate = function(obj, validators, action, merge) { @@ -339,7 +415,7 @@ } else { for (var i in validators) { if (validators.hasOwnProperty(i) && obj[i] === undefined) { - broadcastEvent(EVENTS.ERROR, 'Object is missing required property: ' + i + '.', action); + broadcastEvent(EVENTS.ERROR, 'Object is missing required property: ' + i, action); return false; } } @@ -351,8 +427,7 @@ var value = obj[prop]; if (validator && !validator(value)) { // Failed validation. - broadcastEvent(EVENTS.ERROR, 'Value of property ' + prop + ' is invalid.', - action); + broadcastEvent(EVENTS.ERROR, 'Value of property ' + prop + ' is invalid: ' + value, action); return false; } } @@ -360,40 +435,20 @@ }; var expandPropertyValidators = { - width: function(v) { return !isNaN(v) && v >= 0; }, - height: function(v) { return !isNaN(v) && v >= 0; }, useCustomClose: function(v) { return (typeof v === 'boolean'); }, - lockOrientation: function(v) { return (typeof v === 'boolean'); } }; ////////////////////////////////////////////////////////////////////////////////////////////////// - bridge.addEventListener('change', function(properties) { - for (var p in properties) { - if (properties.hasOwnProperty(p)) { - var handler = changeHandlers[p]; - handler(properties[p]); - } - } - }); - - bridge.addEventListener('error', function(message, action) { - broadcastEvent(EVENTS.ERROR, message, action); - }); - - bridge.addEventListener('ready', function() { - broadcastEvent(EVENTS.READY); - }); - - ////////////////////////////////////////////////////////////////////////////////////////////////// - mraid.addEventListener = function(event, listener) { if (!event || !listener) { broadcastEvent(EVENTS.ERROR, 'Both event and listener are required.', 'addEventListener'); } else if (!contains(event, EVENTS)) { broadcastEvent(EVENTS.ERROR, 'Unknown MRAID event: ' + event, 'addEventListener'); } else { - if (!listeners[event]) listeners[event] = new EventListeners(event); + if (!listeners[event]) { + listeners[event] = new EventListeners(event); + } listeners[event].add(listener); } }; @@ -402,45 +457,25 @@ if (state === STATES.HIDDEN) { broadcastEvent(EVENTS.ERROR, 'Ad cannot be closed when it is already hidden.', 'close'); - } else bridge.executeNativeCall('close'); + } else bridge.executeNativeCall(['close']); }; mraid.expand = function(URL) { - if (this.getState() !== STATES.DEFAULT) { - broadcastEvent(EVENTS.ERROR, 'Ad can only be expanded from the default state.', 'expand'); + if (!(this.getState() === STATES.DEFAULT || this.getState() === STATES.RESIZED)) { + broadcastEvent(EVENTS.ERROR, 'Ad can only be expanded from the default or resized state.', 'expand'); } else { - var args = ['expand']; - - if (this.getHasSetCustomClose()) { - args = args.concat(['shouldUseCustomClose', expandProperties.useCustomClose ? 'true' : 'false']); - } - - if (this.getHasSetCustomSize()) { - if (expandProperties.width >= 0 && expandProperties.height >= 0) { - args = args.concat(['w', expandProperties.width, 'h', expandProperties.height]); - } - } - - if (typeof expandProperties.lockOrientation !== 'undefined') { - args = args.concat(['lockOrientation', expandProperties.lockOrientation]); - } + var args = ['expand', + 'shouldUseCustomClose', expandProperties.useCustomClose + ]; if (URL) { args = args.concat(['url', URL]); } - bridge.executeNativeCall.apply(this, args); + bridge.executeNativeCall(args); } }; - mraid.getHasSetCustomClose = function() { - return hasSetCustomClose; - }; - - mraid.getHasSetCustomSize = function() { - return hasSetCustomSize; - }; - mraid.getExpandProperties = function() { var properties = { width: expandProperties.width, @@ -451,25 +486,58 @@ return properties; }; + + mraid.getCurrentPosition = function() { + return { + x: currentPosition.x, + y: currentPosition.y, + width: currentPosition.width, + height: currentPosition.height + }; + }; + + mraid.getDefaultPosition = function() { + return { + x: defaultPosition.x, + y: defaultPosition.y, + width: defaultPosition.width, + height: defaultPosition.height + }; + }; + + mraid.getMaxSize = function() { + return { + width: maxSize.width, + height: maxSize.height + }; + }; + mraid.getPlacementType = function() { return placementType; }; - mraid.getState = function() { - return state; + mraid.getScreenSize = function() { + return { + width: screenSize.width, + height: screenSize.height + }; }; - mraid.getVersion = function() { - return mraid.VERSION; + mraid.getState = function() { + return state; }; mraid.isViewable = function() { return isViewable; }; + mraid.getVersion = function() { + return mraid.VERSION; + }; + mraid.open = function(URL) { if (!URL) broadcastEvent(EVENTS.ERROR, 'URL is required.', 'open'); - else bridge.executeNativeCall('open', 'url', URL); + else bridge.executeNativeCall(['open', 'url', URL]); }; mraid.removeEventListener = function(event, listener) { @@ -490,7 +558,7 @@ broadcastEvent(EVENTS.ERROR, 'Listener not currently registered for event.', 'removeEventListener'); return; } - + } else if (!listener && listeners[event]) { listeners[event].removeAll(); } @@ -499,22 +567,12 @@ listeners[event] = null; delete listeners[event]; } - }; mraid.setExpandProperties = function(properties) { if (validate(properties, expandPropertyValidators, 'setExpandProperties', true)) { - if (properties.hasOwnProperty('width') || properties.hasOwnProperty('height')) { - hasSetCustomSize = true; - } - - if (properties.hasOwnProperty('useCustomClose')) hasSetCustomClose = true; - - var desiredProperties = ['width', 'height', 'useCustomClose', 'lockOrientation']; - var length = desiredProperties.length; - for (var i = 0; i < length; i++) { - var propname = desiredProperties[i]; - if (properties.hasOwnProperty(propname)) expandProperties[propname] = properties[propname]; + if (properties.hasOwnProperty('useCustomClose')) { + expandProperties.useCustomClose = properties.useCustomClose; } } }; @@ -522,7 +580,7 @@ mraid.useCustomClose = function(shouldUseCustomClose) { expandProperties.useCustomClose = shouldUseCustomClose; hasSetCustomClose = true; - bridge.executeNativeCall('usecustomclose', 'shouldUseCustomClose', shouldUseCustomClose); + bridge.executeNativeCall(['usecustomclose', 'shouldUseCustomClose', shouldUseCustomClose]); }; // MRAID 2.0 APIs //////////////////////////////////////////////////////////////////////////////// @@ -530,14 +588,14 @@ mraid.createCalendarEvent = function(parameters) { CalendarEventParser.initialize(parameters); if (CalendarEventParser.parse()) { - bridge.executeNativeCall.apply(this, CalendarEventParser.arguments); + bridge.executeNativeCall(CalendarEventParser.arguments); } else { broadcastEvent(EVENTS.ERROR, CalendarEventParser.errors[0], 'createCalendarEvent'); } }; mraid.supports = function(feature) { - return supports[feature]; + return supportProperties[feature]; }; mraid.playVideo = function(uri) { @@ -549,7 +607,7 @@ if (!uri) { broadcastEvent(EVENTS.ERROR, 'playVideo must be called with a valid URI', 'playVideo'); } else { - bridge.executeNativeCall.apply(this, ['playVideo', 'uri', uri]); + bridge.executeNativeCall(['playVideo', 'uri', uri]); } }; @@ -562,36 +620,102 @@ if (!uri) { broadcastEvent(EVENTS.ERROR, 'storePicture must be called with a valid URI', 'storePicture'); } else { - bridge.executeNativeCall.apply(this, ['storePicture', 'uri', uri]); + bridge.executeNativeCall(['storePicture', 'uri', uri]); } }; - mraid.resize = function() { - bridge.executeNativeCall('resize'); - }; - mraid.getResizeProperties = function() { - bridge.executeNativeCall('getResizeProperties'); + var resizePropertyValidators = { + width: function(v) { + return !isNaN(v) && v > 0; + }, + height: function(v) { + return !isNaN(v) && v > 0; + }, + offsetX: function(v) { + return !isNaN(v); + }, + offsetY: function(v) { + return !isNaN(v); + }, + customClosePosition: function(v) { + return (typeof v === 'string' && + ['top-right', 'bottom-right', 'top-left', 'bottom-left', 'center', 'top-center', 'bottom-center'].indexOf(v) > -1); + }, + allowOffscreen: function(v) { + return (typeof v === 'boolean'); + } }; - mraid.setResizeProperties = function(resizeProperties) { - bridge.executeNativeCall('setResizeProperties', 'resizeProperties', resizeProperties); + mraid.setOrientationProperties = function(properties) { + + if (properties.hasOwnProperty('allowOrientationChange')) { + orientationProperties.allowOrientationChange = properties.allowOrientationChange; + } + + if (properties.hasOwnProperty('forceOrientation')) { + orientationProperties.forceOrientation = properties.forceOrientation; + } + + var args = ['setOrientationProperties', + 'allowOrientationChange', orientationProperties.allowOrientationChange, + 'forceOrientation', orientationProperties.forceOrientation + ]; + bridge.executeNativeCall(args); }; - mraid.getCurrentPosition = function() { - bridge.executeNativeCall('getCurrentPosition'); + mraid.getOrientationProperties = function() { + return { + allowOrientationChange: orientationProperties.allowOrientationChange, + forceOrientation: orientationProperties.forceOrientation + }; }; - mraid.getDefaultPosition = function() { - bridge.executeNativeCall('getDefaultPosition'); + mraid.resize = function() { + if (!(this.getState() === STATES.DEFAULT || this.getState() === STATES.RESIZED)) { + broadcastEvent(EVENTS.ERROR, 'Ad can only be resized from the default or resized state.', 'resize'); + } else if (!resizeProperties.width || !resizeProperties.height) { + broadcastEvent(EVENTS.ERROR, 'Must set resize properties before calling resize()', 'resize'); + } else { + var args = ['resize', + 'width', resizeProperties.width, + 'height', resizeProperties.height, + 'offsetX', resizeProperties.offsetX || 0, + 'offsetY', resizeProperties.offsetY || 0, + 'customClosePosition', resizeProperties.customClosePosition, + 'allowOffscreen', !!resizeProperties.allowOffscreen + ]; + + bridge.executeNativeCall(args); + } }; - mraid.getMaxSize = function() { - bridge.executeNativeCall('getMaxSize'); + mraid.getResizeProperties = function() { + var properties = { + width: resizeProperties.width, + height: resizeProperties.height, + offsetX: resizeProperties.offsetX, + offsetY: resizeProperties.offsetY, + customClosePosition: resizeProperties.customClosePosition, + allowOffscreen: resizeProperties.allowOffscreen + }; + return properties; }; - mraid.getScreenSize = function() { - bridge.executeNativeCall('getScreenSize'); + mraid.setResizeProperties = function(properties) { + if (validate(properties, resizePropertyValidators, 'setResizeProperties', true)) { + + var desiredProperties = ['width', 'height', 'offsetX', 'offsetY', 'customClosePosition', 'allowOffscreen']; + + var length = desiredProperties.length; + + for (var i = 0; i < length; i++) { + var propname = desiredProperties[i]; + if (properties.hasOwnProperty(propname)) { + resizeProperties[propname] = properties[propname]; + } + } + } }; var CalendarEventParser = { @@ -673,7 +797,7 @@ var validValues = ['opaque', 'transparent']; if (this.parameters.hasOwnProperty('transparency')) { - var transparency = this.parameters['transparency']; + var transparency = this.parameters.transparency; if (contains(transparency, validValues)) { this.arguments.push('transparency'); this.arguments.push(transparency); @@ -698,7 +822,7 @@ parseRecurrenceInterval: function(recurrenceDict) { if (recurrenceDict.hasOwnProperty('interval')) { - var interval = recurrenceDict['interval']; + var interval = recurrenceDict.interval; if (!interval) { this.errors.push('Recurrence interval cannot be null.'); } else { @@ -714,7 +838,7 @@ parseRecurrenceFrequency: function(recurrenceDict) { if (recurrenceDict.hasOwnProperty('frequency')) { - var frequency = recurrenceDict['frequency']; + var frequency = recurrenceDict.frequency; var validFrequencies = ['daily', 'weekly', 'monthly', 'yearly']; if (contains(frequency, validFrequencies)) { this.arguments.push('frequency'); @@ -726,7 +850,7 @@ }, parseRecurrenceEndDate: function(recurrenceDict) { - var expires = recurrenceDict['expires']; + var expires = recurrenceDict.expires; if (!expires) { return; @@ -758,6 +882,6 @@ this.arguments.push(kind); this.arguments.push(dateString); } - }, + } }; }()); \ No newline at end of file diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MoPub-Bridging-Header.h b/mediation/mediatedviews/MoPub/MoPubSDK/MoPub-Bridging-Header.h old mode 100644 new mode 100755 index 7634a3390..6630f76e5 --- a/mediation/mediatedviews/MoPub/MoPubSDK/MoPub-Bridging-Header.h +++ b/mediation/mediatedviews/MoPub/MoPubSDK/MoPub-Bridging-Header.h @@ -5,6 +5,8 @@ // Copyright (c) 2014 MoPub. All rights reserved. // +#import "MoPub.h" + #import "MPAdConversionTracker.h" #import "MPAdView.h" #import "MPBannerCustomEvent.h" @@ -16,12 +18,18 @@ #import "MPNativeAd.h" #import "MPNativeAdAdapter.h" +#import "MPNativeAdConstants.h" #import "MPNativeCustomEvent.h" +#import "MPNativeCustomEventDelegate.h" +#import "MPNativeAdDelegate.h" #import "MPNativeAdError.h" #import "MPNativeAdRendering.h" #import "MPNativeAdRequest.h" #import "MPNativeAdRequestTargeting.h" #import "MPTableViewAdManager.h" +#import "MPClientAdPositioning.h" +#import "MPServerAdPositioning.h" + #import "MPCollectionViewAdPlacer.h" -#import "MPTableViewAdPlacer.h" +#import "MPTableViewAdPlacer.h" \ No newline at end of file diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/MoPub.h b/mediation/mediatedviews/MoPub/MoPubSDK/MoPub.h new file mode 100755 index 000000000..71c669519 --- /dev/null +++ b/mediation/mediatedviews/MoPub/MoPubSDK/MoPub.h @@ -0,0 +1,79 @@ +// +// MoPub.h +// MoPub +// +// Copyright (c) 2014 MoPub. All rights reserved. +// + +#if __has_include("MPNativeAdSampleTableViewCell.h") + #import "MPNativeAdSampleTableViewCell.h" +#endif + +#import "MPAdConversionTracker.h" +#import "MPAdView.h" +#import "MPBannerCustomEvent.h" +#import "MPBannerCustomEventDelegate.h" +#import "MPConstants.h" +#import "MPInterstitialAdController.h" +#import "MPInterstitialCustomEvent.h" +#import "MPInterstitialCustomEventDelegate.h" +#import "MPNativeAd.h" +#import "MPNativeAdAdapter.h" +#import "MPNativeAdConstants.h" +#import "MPNativeCustomEvent.h" +#import "MPNativeCustomEventDelegate.h" +#import "MPNativeAdError.h" +#import "MPNativeAdRendering.h" +#import "MPNativeAdRequest.h" +#import "MPNativeAdRequestTargeting.h" +#import "MPTableViewAdManager.h" +#import "MPCollectionViewAdPlacer.h" +#import "MPTableViewAdPlacer.h" +#import "MPClientAdPositioning.h" +#import "MPServerAdPositioning.h" +#import "MPNativeAdDelegate.h" + +// Import these frameworks for module support. +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#define MoPubKit [MoPub sharedInstance] + +@interface MoPub : NSObject + +/** + * Returns the MoPub singleton object. + * + * @return The MoPub singleton object. + */ ++ (MoPub *)sharedInstance; + +/** + * A Boolean value indicating whether the MoPub SDK should use Core Location APIs to automatically + * derive targeting information for location-based ads. + * + * When set to NO, the SDK will not attempt to determine device location. When set to YES, the + * SDK will periodically try to listen for location updates in order to request location-based ads. + * This only occurs if location services are enabled and the user has already authorized the use + * of location services for the application. The default value is YES. + * + * @param enabled A Boolean value indicating whether the SDK should listen for location updates. + */ +@property (nonatomic, assign) BOOL locationUpdatesEnabled; + +- (void)start; +- (NSString *)version; +- (NSString *)bundleIdentifier; + +@end diff --git a/mediation/mediatedviews/MoPub/MoPubSDK/libMoPubSDK.a b/mediation/mediatedviews/MoPub/MoPubSDK/libMoPubSDK.a index f43029048..8795d4b8f 100644 Binary files a/mediation/mediatedviews/MoPub/MoPubSDK/libMoPubSDK.a and b/mediation/mediatedviews/MoPub/MoPubSDK/libMoPubSDK.a differ diff --git a/mediation/mediatedviews/README.txt b/mediation/mediatedviews/README.txt index e5021415b..dff7072ed 100644 --- a/mediation/mediatedviews/README.txt +++ b/mediation/mediatedviews/README.txt @@ -1,6 +1,6 @@ -Update 11/17/2014 -AdMob SDK Version 6.12.2 -Amazon SDK Version 2.1.4 -Facebook SDK Version 3.20 +Update 02/18/2015 +AdMob SDK Version 7.0.0 +Amazon SDK Version 2.1.9 +Facebook SDK Version 3.23 Millennial Media SDK Version 5.4.1 -MoPub SDK Version 3.2.0 +MoPub SDK Version 3.4.0 \ No newline at end of file diff --git a/mediation/mediating/GoogleAdMob/ANGADCustomBannerAd.h b/mediation/mediating/GoogleAdMob/ANGADCustomBannerAd.h index a9e9d7759..26ca5da2b 100644 --- a/mediation/mediating/GoogleAdMob/ANGADCustomBannerAd.h +++ b/mediation/mediating/GoogleAdMob/ANGADCustomBannerAd.h @@ -13,8 +13,7 @@ limitations under the License. */ -#import "GADCustomEventBanner.h" -#import "GADCustomEventBannerDelegate.h" +#import #import "ANBannerAdView.h" @interface ANGADCustomBannerAd : NSObject diff --git a/mediation/mediating/GoogleAdMob/ANGADCustomBannerAd.m b/mediation/mediating/GoogleAdMob/ANGADCustomBannerAd.m index 3c880ab7d..2bbd5f30b 100644 --- a/mediation/mediating/GoogleAdMob/ANGADCustomBannerAd.m +++ b/mediation/mediating/GoogleAdMob/ANGADCustomBannerAd.m @@ -52,10 +52,10 @@ - (void)requestBannerAd:(GADAdSize)adSize } GADGender gadGender = [customEventRequest userGender]; - ANGENDER anGender = (ANGENDER)UNKNOWN; + ANGENDER anGender = (ANGENDER)ANGenderUnknown; if (gadGender != kGADGenderUnknown) { - if (gadGender == kGADGenderMale) anGender = (ANGENDER)MALE; - else if (gadGender == kGADGenderFemale) anGender = (ANGENDER)FEMALE; + if (gadGender == kGADGenderMale) anGender = (ANGENDER)ANGenderMale; + else if (gadGender == kGADGenderFemale) anGender = (ANGENDER)ANGenderFemale; } [self.bannerAdView setGender:anGender]; diff --git a/mediation/mediating/GoogleAdMob/ANGADCustomInterstitialAd.h b/mediation/mediating/GoogleAdMob/ANGADCustomInterstitialAd.h index ccdc162be..d0e47c578 100644 --- a/mediation/mediating/GoogleAdMob/ANGADCustomInterstitialAd.h +++ b/mediation/mediating/GoogleAdMob/ANGADCustomInterstitialAd.h @@ -13,9 +13,7 @@ limitations under the License. */ - -#import "GADCustomEventInterstitial.h" -#import "GADCustomEventInterstitialDelegate.h" +#import #import "ANInterstitialAd.h" @interface ANGADCustomInterstitialAd : NSObject diff --git a/mediation/mediating/GoogleAdMob/ANGADCustomInterstitialAd.m b/mediation/mediating/GoogleAdMob/ANGADCustomInterstitialAd.m index 4e6be22fe..b7160847a 100644 --- a/mediation/mediating/GoogleAdMob/ANGADCustomInterstitialAd.m +++ b/mediation/mediating/GoogleAdMob/ANGADCustomInterstitialAd.m @@ -43,10 +43,10 @@ - (void)requestInterstitialAdWithParameter:(NSString *)serverParameter label:(NS } GADGender gadGender = [customEventRequest userGender]; - ANGENDER anGender = (ANGENDER)UNKNOWN; + ANGENDER anGender = (ANGENDER)ANGenderUnknown; if (gadGender != kGADGenderUnknown) { - if (gadGender == kGADGenderMale) anGender = (ANGENDER)MALE; - else if (gadGender == kGADGenderFemale) anGender = (ANGENDER)FEMALE; + if (gadGender == kGADGenderMale) anGender = (ANGENDER)ANGenderMale; + else if (gadGender == kGADGenderFemale) anGender = (ANGENDER)ANGenderFemale; } [self.interstitialAd setGender:anGender]; diff --git a/sdk/ANAdConstants.h b/sdk/ANAdConstants.h index 0158127ae..b1572df87 100644 --- a/sdk/ANAdConstants.h +++ b/sdk/ANAdConstants.h @@ -30,9 +30,12 @@ typedef NS_ENUM(NSInteger, ANAdResponseCode) { }; typedef NS_ENUM(NSUInteger, ANGender) { - UNKNOWN, - MALE, - FEMALE + ANGenderUnknown, + ANGenderMale, + ANGenderFemale, + UNKNOWN __attribute__((deprecated)) = ANGenderUnknown, + MALE __attribute__((deprecated)) = ANGenderMale, + FEMALE __attribute__((deprecated)) = ANGenderFemale }; typedef NS_ENUM(NSUInteger, ANNativeAdRegisterErrorCode) { diff --git a/sdk/ANBannerAdView.h b/sdk/ANBannerAdView.h index 908351561..68a0202c5 100644 --- a/sdk/ANBannerAdView.h +++ b/sdk/ANBannerAdView.h @@ -166,7 +166,7 @@ typedef NS_ENUM(NSUInteger, ANBannerViewAdAlignment) { This allows for a class of ads known as "expandables." In order to show an expandable ad, set the animated flag to true. */ -- (void)setFrame:(CGRect)frame animated:(BOOL)animated; +- (void)setFrame:(CGRect)frame animated:(BOOL)animated __attribute((deprecated(" Use UIView animation blocks to animate a frame change."))); @end @@ -184,11 +184,11 @@ typedef NS_ENUM(NSUInteger, ANBannerViewAdAlignment) { the screen. This is in response to a user interacting with an ad that resizes itself. */ -- (void)bannerAdView:(ANBannerAdView *)adView willResizeToFrame:(CGRect)frame; +- (void)bannerAdView:(ANBannerAdView *)adView willResizeToFrame:(CGRect)frame __attribute((deprecated(" No longer called - SDK no longer resizes the banner frame."))); /** Sent after the adView has resized. */ -- (void)bannerAdViewDidResize:(ANBannerAdView *)adView; +- (void)bannerAdViewDidResize:(ANBannerAdView *)adView __attribute((deprecated(" No longer called - SDK no longer resizes the banner frame."))); @end diff --git a/sdk/Categories/ANAdView+PrivateMethods.h b/sdk/Categories/ANAdView+PrivateMethods.h new file mode 100644 index 000000000..e1a1764d2 --- /dev/null +++ b/sdk/Categories/ANAdView+PrivateMethods.h @@ -0,0 +1,31 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANAdView.h" + +@protocol ANAdFetcherDelegate; +@class ANAdFetcher; + +@interface ANAdView (PrivateMethods) + +@property (nonatomic, readwrite, strong) ANAdFetcher *adFetcher; + +- (void)initialize; +- (void)loadAd; +- (void)loadAdFromHtml:(NSString *)html + width:(int)width + height:(int)height; + +@end \ No newline at end of file diff --git a/sdk/Categories/UIView+ANCategory.h b/sdk/Categories/UIView+ANCategory.h index 13e8a5ef5..05fe2071c 100644 --- a/sdk/Categories/UIView+ANCategory.h +++ b/sdk/Categories/UIView+ANCategory.h @@ -25,6 +25,9 @@ - (void)removeSubviews; - (void)removeSubviewsWithException:(UIView *)exception; +- (BOOL)an_isViewable; +- (BOOL)an_isAtLeastHalfViewable; + #pragma mark - Autolayout - (void)constrainWithSize:(CGSize)size; diff --git a/sdk/Categories/UIView+ANCategory.m b/sdk/Categories/UIView+ANCategory.m index b46dffed1..f0afab3c1 100644 --- a/sdk/Categories/UIView+ANCategory.m +++ b/sdk/Categories/UIView+ANCategory.m @@ -75,6 +75,59 @@ - (void)removeSubviewsWithException:(UIView *)exception { } +- (BOOL)an_isViewable { + BOOL isHidden = self.hidden; + if (isHidden) return NO; + + BOOL isAttachedToWindow = self.window ? YES : NO; + if (!isAttachedToWindow) return NO; + + BOOL isInHiddenSuperview = NO; + UIView *ancestorView = self.superview; + while (ancestorView) { + if (ancestorView.hidden) { + isInHiddenSuperview = YES; + break; + } + ancestorView = ancestorView.superview; + } + if (isInHiddenSuperview) return NO; + + CGRect screenRect = [UIScreen mainScreen].bounds; + CGRect normalizedSelfRect = [self convertRect:self.bounds toView:nil]; + return CGRectIntersectsRect(normalizedSelfRect, screenRect); +} + +- (BOOL)an_isAtLeastHalfViewable { + BOOL isHidden = self.hidden; + if (isHidden) return NO; + + BOOL isAttachedToWindow = self.window ? YES : NO; + if (!isAttachedToWindow) return NO; + + BOOL isInHiddenSuperview = NO; + UIView *ancestorView = self.superview; + while (ancestorView) { + if (ancestorView.hidden) { + isInHiddenSuperview = YES; + break; + } + ancestorView = ancestorView.superview; + } + if (isInHiddenSuperview) return NO; + + CGRect screenRect = [UIScreen mainScreen].bounds; + CGRect normalizedSelfRect = [self convertRect:self.bounds toView:nil]; + CGRect intersection = CGRectIntersection(screenRect, normalizedSelfRect); + if (CGRectEqualToRect(intersection, CGRectNull)) { + return NO; + } + + CGFloat intersectionArea = CGRectGetWidth(intersection) * CGRectGetHeight(intersection); + CGFloat selfArea = CGRectGetWidth(normalizedSelfRect) * CGRectGetHeight(normalizedSelfRect); + return intersectionArea >= 0.5 * selfArea; +} + #pragma mark - Autolayout - (void)constrainWithFrameSize { diff --git a/sdk/Resources/ANBrowserViewController.xib b/sdk/Resources/ANBrowserViewController.xib index 7b977f264..b998d1680 100644 --- a/sdk/Resources/ANBrowserViewController.xib +++ b/sdk/Resources/ANBrowserViewController.xib @@ -1,80 +1,114 @@ - + - - + + + + + - + - + - - - - - - - - - - - + + + + + + + - - + + + + + - - - + + + + + + - + - + + + + + + + + + + + + + + + + + - + + + + - + + + + - - + + + + + + + + + + + + + + - - + + - - - - - diff --git a/sdk/Resources/ANInterstitialAdViewController.xib b/sdk/Resources/ANInterstitialAdViewController.xib index 6f753a44b..a38be7c59 100644 --- a/sdk/Resources/ANInterstitialAdViewController.xib +++ b/sdk/Resources/ANInterstitialAdViewController.xib @@ -1,43 +1,53 @@ - + - - + + + - + - - - - - - - + + + + + + + - - - - \ No newline at end of file + + + + + + diff --git a/sdk/Resources/ANMRAID.bundle/mraid.js b/sdk/Resources/ANMRAID.bundle/mraid.js index 2ee6647df..68dc4a45d 100644 --- a/sdk/Resources/ANMRAID.bundle/mraid.js +++ b/sdk/Resources/ANMRAID.bundle/mraid.js @@ -1,526 +1,538 @@ -/* - * Copyright 2013 APPNEXUS INC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -(function() { - var isIOS = (/iphone|ipad|ipod/i).test(window.navigator.userAgent.toLowerCase()); - if (isIOS) { - console = {}; - console.log = function(log) { - var iframe = document.createElement('iframe'); - iframe.setAttribute('src', 'anwebconsole: ' + log); - document.documentElement.appendChild(iframe); - iframe.parentNode.removeChild(iframe); - iframe = null; - }; - console.debug = console.info = console.warn = console.error = console.log; - } - }()); - -(function() { - - // Set up some variables - var mraid = window.mraid = {}; - mraid.util = {}; - var listeners = []; - listeners['ready']=[]; - listeners['error']=[]; - listeners['stateChange']=[]; - listeners['viewableChange']=[]; - listeners['sizeChange']=[]; - var state='loading'; //Can be loading, default, expanded, hidden, or resized - var placement_type='inline'; - var is_viewable=false; - var expand_properties={width:-1, height:-1, useCustomClose:false, isModal:true}; - var orientation_properties={allowOrientationChange:true, forceOrientation:"none"}; - var resize_properties={customClosePosition: 'top-right', allowOffscreen: true}; - var screen_size={}; - var max_size={}; - var default_position={}; - var current_position={}; - var size_event_width = 0; - var size_event_height = 0; - var supports = []; - supports['sms'] = false; - supports['tel'] = false; - supports['calendar'] = false; - supports['storePicture'] = false; - supports['inlineVideo'] = false; - - // constants for interaction with anjam.js - var MRAID_STATE = "state"; - var MRAID_PLACEMENT_TYPE = "placementType"; - var MRAID_VIEWABLE = "viewable"; - var MRAID_EXPAND_PROPERTIES = "expandProperties"; - var MRAID_RESIZE_PROPERTIES = "resizeProperties"; - var MRAID_ORIENTATION_PROPERTIES = "orientationProperties"; - var MRAID_SCREEN_SIZE = "screenSize"; - var MRAID_MAX_SIZE = "maxSize"; - var MRAID_DEFAULT_POSITION = "defaultPosition"; - var MRAID_CURRENT_POSITION = "currentPosition"; - - // ----- MRAID AD API FUNCTIONS ----- - - // getVersion() returns string '2.0' - mraid.getVersion=function(){ return '2.0'}; - - // getVendor() returns string 'appnexus' - mraid.getVendor=function(){ return 'appnexus'}; - - /** Adds a listener to a specific event. For example, a function onReady might be defined, and then mraid.addEventListener('ready', onReady) - * is called. When the ready event is fired, onReady will be called. - * Events 'error', 'viewableChange', 'stateChange', have parameters. - */ - mraid.addEventListener=function(event_name, method){ - if(listeners[event_name].indexOf(method) > -1) return; // Listener is already registered - listeners[event_name].push(method); - }; - - // Removes a listener from the registry - mraid.removeEventListener=function(event_name, method){ - //If no method name is given, remove all listeners from event - if(method == null){ - listeners[event_name].length=0; - return; - } - - var method_index = listeners[event_name].indexOf(method); - if(method_index > -1){ //Don't try to remove unregistered listeners - listeners[event_name].splice(method_index,1); - }else{ - mraid.util.errorEvent("An unregistered listener was requested to be removed.", "mraid.removeEventListener()") - } - }; - - //returns 'loading', 'default', 'expanded', or 'hidden' - mraid.getState=function(){ - return state; - }; - - //returns 'inline' or 'interstitial' - mraid.getPlacementType=function(){ - return placement_type; - }; - - //returns true or false - mraid.isViewable=function(){ - return is_viewable; - }; - - // ----- MRAID JS TO NATIVE FUNCTIONS ----- - - mraid.enable=function(){ - mraid.util.nativeCall("mraid://enable/"); - }; - - //Closes an expanded ad or hides an ad in default state - mraid.close=function(){ - switch(mraid.getState()){ - case 'loading': - mraid.util.errorEvent("mraid.close() called while state is 'loading'.", "mraid.close()"); - break; - case 'default': - mraid.util.nativeCall("mraid://close"); - mraid.util.stateChangeEvent('hidden'); - break; - case 'expanded': - mraid.util.nativeCall("mraid://close") - mraid.util.stateChangeEvent('default'); - break; - case 'hidden': - mraid.util.errorEvent("mraid.close() called while ad was already hidden", "mraid.close()"); - break; - case 'resized': - mraid.util.nativeCall("mraid://close/"); - mraid.util.stateChangeEvent('default'); - } - }; - - // Expands a default state ad, or unhides a hidden ad. Optionally takes a URL to load in the expanded view - mraid.expand=function(url){ - switch(mraid.getState()){ - case 'loading': - mraid.util.errorEvent("mraid.expand() called while state is 'loading'.", "mraid.expand()"); - break; - case 'default': - case 'resized': - if((expand_properties.height !== -1 && expand_properties.width !== -1) && (expand_properties.height < current_position.height || expand_properties.width < current_position.width)){ - mraid.util.errorEvent("Can't expand to a size smaller than the default size.", "mraid.expand()"); - return; - } - mraid.util.nativeCall("mraid://expand/" - +"?w="+mraid.getExpandProperties().width - +"&h="+mraid.getExpandProperties().height - +"&useCustomClose="+mraid.getExpandProperties().useCustomClose - +(url!=null ? "&url="+url:"") - +"&allow_orientation_change="+orientation_properties.allowOrientationChange - +"&force_orientation="+orientation_properties.forceOrientation); - break; - case 'expanded': - mraid.util.errorEvent("mraid.expand() called while state is 'expanded'.", "mraid.expand()"); - break; - case 'hidden': - mraid.util.errorEvent("mraid.expand() called while state is 'hidden'.", "mraid.expand()"); - break; - } - }; - - // Takes an object... {width:300, height:250, useCustomClose:false, isModal:false}; - mraid.setExpandProperties=function(properties){ - if (typeof properties === "undefined") { - mraid.util.errorEvent("Invalid expandProperties. Retaining default values.", "mraid.setExpandProperties()"); - return; - } - if (typeof properties.width !== "number") { - properties.width = -1; - } - if (typeof properties.height !== "number") { - properties.height = -1; - } - if (properties.useCustomClose === true) { - properties.useCustomClose = true; - } else { - properties.useCustomClose = false; - } - properties.isModal = true; - expand_properties = properties; - if ((typeof window.sdkjs) !== "undefined") { - window.sdkjs.mraidUpdateProperty(MRAID_EXPAND_PROPERTIES, expand_properties); - } - }; - - //returns a json object... {width:300, height:250, useCustomClose:false, isModal:false}; - mraid.getExpandProperties=function(){ - return expand_properties; - }; - - // Loads a given URL (TODO make this native ) - mraid.open=function(url){ - mraid.util.nativeCall("mraid://open/?uri="+encodeURIComponent(url)); - }; - - // MRAID 2.0 Stuff. - mraid.resize=function(){ - if(!mraid.util.validateResizeProperties(resize_properties, "mraid.resize()")){ - mraid.util.errorEvent("mraid.resize() called without properly setting setResizeProperties", "mraid.resize()"); - return; - } - switch(mraid.getState()){ - case 'loading': - mraid.util.errorEvent("mraid.resize() called while state is 'loading'.", "mraid.resize()"); - break; - case 'expanded': - mraid.util.errorEvent("mraid.resize() called while state is 'expanded'.", "mraid.resize()"); - break; - case 'resized': - case 'default': - if (resize_properties) { - mraid.util.nativeCall("mraid://resize/?w="+resize_properties.width - +"&h="+resize_properties.height - +"&offset_x="+resize_properties.offsetX - +"&offset_y="+resize_properties.offsetY - +"&custom_close_position="+resize_properties.customClosePosition - +"&allow_offscreen="+resize_properties.allowOffscreen); - } else { - mraid.util.errorEvent("mraid.resize() called with no resize_properties set", "mraid.resize()"); - } - break; - case 'hidden': - mraid.util.errorEvent("mraid.resize() called while state is 'hidden'.", "mraid.resize()"); - break; - - } - } - - mraid.setResizeProperties=function(props) { - if (mraid.util.validateResizeProperties(props, "mraid.setResizeProperties()")) { - if (typeof props.customClosePosition === "undefined") { - props.customClosePosition = 'top-right'; - } - if (typeof props.allowOffscreen === "undefined") { - props.allowOffscreen = true; - } - resize_properties = props; - if ((typeof window.sdkjs) !== "undefined") { - window.sdkjs.mraidUpdateProperty(MRAID_RESIZE_PROPERTIES, resize_properties); - } - } - } - - mraid.getResizeProperties=function(){ - return resize_properties; - } - - - //returns a json object... {allowOrientationChange:true, forceOrientation:"none"}; - mraid.getOrientationProperties=function(){ - return orientation_properties; - } - - // Takes an object... {allowOrientationChange:true, forceOrientation:"none"}; - mraid.setOrientationProperties=function(properties){ - if (typeof properties === "undefined") { - mraid.util.errorEvent("Invalid orientationProperties. Setting to default properties", "mraid.setOrientationProperties()"); - properties={allowOrientationChange:true, forceOrientation:"none"}; - } else { - if(properties.forceOrientation!=='portrait' && properties.forceOrientation!=='landscape' && properties.forceOrientation!=='none' ){ - mraid.util.errorEvent("Invalid orientationProperties forceOrientation property", "mraid.setOrientationProperties()"); - properties.forceOrientation='none'; - } - - if(typeof properties.allowOrientationChange !== "boolean"){ - mraid.util.errorEvent("Invalid orientationProperties allowOrientationChange property", "mraid.setOrientationProperties()"); - properties.allowOrientationChange=true; - } - } - - orientation_properties=properties; - if ((typeof window.sdkjs) !== "undefined") { - window.sdkjs.mraidUpdateProperty(MRAID_ORIENTATION_PROPERTIES, orientation_properties); - } - - mraid.util.nativeCall("mraid://setOrientationProperties/?allow_orientation_change="+orientation_properties.allowOrientationChange - +"&force_orientation="+orientation_properties.forceOrientation); - } - - // Creates a calendar event when passed a W3C-formatted json object - mraid.createCalendarEvent=function(event){ - mraid.util.nativeCall("mraid://createCalendarEvent/?p="+encodeURIComponent(JSON.stringify(event))); - } - - // Plays a video in the native player - mraid.playVideo=function(uri){ - mraid.util.nativeCall("mraid://playVideo/?uri="+encodeURIComponent(uri)); - } - - // Stores a picture on the device - mraid.storePicture=function(uri){ - mraid.util.nativeCall("mraid://storePicture/?uri="+encodeURIComponent(uri)); - } - - // Convenience function to modify useCustomClose attribute of expandProperties - mraid.useCustomClose=function(value){ - if (value === true) { - expand_properties.useCustomClose = true; - } else { - expand_properties.useCustomClose = false; - } - } - - // Checks if a feature is supported by this device - mraid.supports=function(feature){ - if(mraid.getState()=="loading"){ - mraid.util.errorEvent("Method 'mraid.supports()' called during loading state.", "mraid.supports()"); - return; - } - if ((typeof supports[feature]) !== "boolean") { - mraid.util.errorEvent("Unknown feature to check for support: " + feature, "mraid.supports()"); - return false; - } - return supports[feature]; - } - - // Gets the screen size of the device - mraid.getScreenSize=function(){ - if(mraid.getState()=="loading"){ - mraid.util.errorEvent("Method 'mraid.getScreenSize()' called during loading state.", "mraid.getScreenSize()"); - return; - }else{ - return screen_size; - } - } - - // Gets the max size of the ad if expanded (so it won't obscure the app's title bar) - mraid.getMaxSize=function(){ - if(mraid.getState()=="loading"){ - mraid.util.errorEvent("Method 'mraid.getMaxSize()' called during loading state.", "mraid.getMaxSize()"); - return; - }else{ - return max_size; - } - } - - // Gets the default position of the ad view, in dips offset from top left. - mraid.getDefaultPosition=function(){ - if(mraid.getState()=="loading"){ - mraid.util.errorEvent("Method 'mraid.getDefaultPosition()' called during loading state.", "mraid.getDefaultPosition()"); - return; - }else{ - return default_position; - } - } - - - // Gets the current position of the ad view, in dips offset from top left. - mraid.getCurrentPosition=function(){ - if(mraid.getState()=="loading"){ - mraid.util.errorEvent("Method 'mraid.getCurrentPosition()' called during loading state.", "mraid.getCurrentPosition()"); - return; - }else{ - return current_position; - } - } - - // ----- MRAID UTILITY FUNCTIONS ----- - // These functions are called by the native SDK to drive events and update information - - mraid.util.setPlacementType=function(type){ - placement_type=type; - if ((typeof window.sdkjs) !== "undefined") { - window.sdkjs.mraidUpdateProperty(MRAID_PLACEMENT_TYPE, placement_type); - } - }; - - mraid.util.fireEvent = function (event) { - if (!listeners[event]) { - return; - } - - var args = Array.prototype.slice.call(arguments); - args.shift(); - var length = listeners[event].length; - for (var i = 0; i < length; i++) { - if (typeof listeners[event][i] === "function") { - listeners[event][i].apply(null, args); - } - } - } - - mraid.util.readyEvent = function () { - mraid.util.fireEvent('ready'); - }; - - mraid.util.errorEvent = function (message, what_doing) { - mraid.util.fireEvent('error', message, what_doing); - }; - - mraid.util.viewableChangeEvent = function (is_viewable_now) { - if (state === 'loading') return; - is_viewable = is_viewable_now; - mraid.util.fireEvent('viewableChange', is_viewable_now); - }; - - mraid.util.setIsViewable = function (is_it_viewable) { - if (is_viewable === is_it_viewable) return; - is_viewable = is_it_viewable; - if ((typeof window.sdkjs) !== "undefined") { - window.sdkjs.mraidUpdateProperty(MRAID_VIEWABLE, is_viewable); - } - mraid.util.viewableChangeEvent(is_viewable); - }; - - mraid.util.stateChangeEvent = function (new_state) { - if (state === new_state && state != 'resized') return; - state = new_state; - if ((typeof window.sdkjs) !== "undefined") { - window.sdkjs.mraidUpdateProperty(MRAID_STATE, state); - } - if (new_state === 'hidden') { - mraid.util.setIsViewable(false); - } - mraid.util.fireEvent('stateChange', new_state); - }; - - mraid.util.sizeChangeEvent=function(width, height){ - if(state==='loading') { - size_event_width = width; - size_event_height = height; - return; - } - if(width != size_event_width || height != size_event_height) { - size_event_width = width; - size_event_height = height; - mraid.util.fireEvent('sizeChange', width, height); - } - } - - mraid.util.validateResizeProperties=function(properties, callingFunctionName) { - if (typeof properties === "undefined") { - mraid.util.errorEvent("Invalid resizeProperties", callingFunctionName); - return false; - } - if (typeof properties.width !== "number" || typeof properties.height !== "number" || typeof properties.offsetX !== "number" || typeof properties.offsetY !== "number") { - mraid.util.errorEvent("Incomplete resizeProperties. width, height, offsetX, offsetY required", callingFunctionName); - return false; - } - if (properties.width < 50) { - mraid.util.errorEvent("Resize properties width below the minimum 50 pixels", callingFunctionName); - return false; - } - if (properties.height < 50) { - mraid.util.errorEvent("Resize properties height below the minimum 50 pixels", callingFunctionName); - return false; - } - return true; - } - - var nativeCallQueue=[]; - - function dequeue() { - window.location = nativeCallQueue.shift(); - if (nativeCallQueue.length>0) setTimeout(dequeue, 0); - } - - mraid.util.nativeCall = function(uri) { - nativeCallQueue.push(uri); - if(nativeCallQueue.length == 1) setTimeout(dequeue, 0); - } - - mraid.util.setSupports = function(feature, value) { - supports[feature] = value; - if ((typeof window.sdkjs) !== "undefined") { - window.sdkjs.mraidUpdateSupports(feature, value); - } - } - - mraid.util.setScreenSize=function(width, height){ - screen_size={"width":width, - "height": height}; - if ((typeof window.sdkjs) !== "undefined") { - window.sdkjs.mraidUpdateProperty(MRAID_SCREEN_SIZE, screen_size); - } - } - - mraid.util.setMaxSize=function(width, height){ - max_size={"width":width, - "height": height}; - if ((typeof window.sdkjs) !== "undefined") { - window.sdkjs.mraidUpdateProperty(MRAID_MAX_SIZE, max_size); - } - } - - mraid.util.setDefaultPosition=function(x, y, width, height){ - default_position={"x": x, - "y": y, - "width":width, - "height": height - }; - if ((typeof window.sdkjs) !== "undefined") { - window.sdkjs.mraidUpdateProperty(MRAID_DEFAULT_POSITION, default_position); - } - } - - mraid.util.setCurrentPosition=function(x, y, width, height){ - current_position={"x": x, - "y": y, - "width":width, - "height": height - }; - if ((typeof window.sdkjs) !== "undefined") { - window.sdkjs.mraidUpdateProperty(MRAID_CURRENT_POSITION, current_position); - } - } - - }()); +/* + * Copyright 2013 APPNEXUS INC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +(function() { + var isIOS = (/iphone|ipad|ipod/i).test(window.navigator.userAgent.toLowerCase()); + if (isIOS) { + console = {}; + console.log = function(log) { + var iframe = document.createElement('iframe'); + iframe.setAttribute('src', 'anwebconsole: ' + log); + document.documentElement.appendChild(iframe); + iframe.parentNode.removeChild(iframe); + iframe = null; + }; + console.debug = console.info = console.warn = console.error = console.log; + } +}()); + +(function() { + + // Set up some variables + var mraid = window.mraid = {}; + mraid.util = {}; + var listeners = []; + listeners['ready'] = []; + listeners['error'] = []; + listeners['stateChange'] = []; + listeners['viewableChange'] = []; + listeners['sizeChange'] = []; + var state = 'loading'; //Can be loading, default, expanded, hidden, or resized + var placement_type = 'inline'; + var is_viewable = false; + var expand_properties = { + width: -1, + height: -1, + useCustomClose: false, + isModal: true + }; + var orientation_properties = { + allowOrientationChange: true, + forceOrientation: "none" + }; + var resize_properties = { + customClosePosition: 'top-right', + allowOffscreen: true + }; + var screen_size = {}; + var max_size = {}; + var default_position = {}; + var current_position = {}; + var size_event_width = 0; + var size_event_height = 0; + var supports = []; + supports['sms'] = false; + supports['tel'] = false; + supports['calendar'] = false; + supports['storePicture'] = false; + supports['inlineVideo'] = false; + + // constants for interaction with anjam.js + var MRAID_STATE = "state"; + var MRAID_PLACEMENT_TYPE = "placementType"; + var MRAID_VIEWABLE = "viewable"; + var MRAID_EXPAND_PROPERTIES = "expandProperties"; + var MRAID_RESIZE_PROPERTIES = "resizeProperties"; + var MRAID_ORIENTATION_PROPERTIES = "orientationProperties"; + var MRAID_SCREEN_SIZE = "screenSize"; + var MRAID_MAX_SIZE = "maxSize"; + var MRAID_DEFAULT_POSITION = "defaultPosition"; + var MRAID_CURRENT_POSITION = "currentPosition"; + + // ----- MRAID AD API FUNCTIONS ----- + + // getVersion() returns string '2.0' + mraid.getVersion = function() { + return '2.0' + }; + + // getVendor() returns string 'appnexus' + mraid.getVendor = function() { + return 'appnexus' + }; + + /** Adds a listener to a specific event. For example, a function onReady might be defined, and then mraid.addEventListener('ready', onReady) + * is called. When the ready event is fired, onReady will be called. + * Events 'error', 'viewableChange', 'stateChange', have parameters. + */ + mraid.addEventListener = function(event_name, method) { + if (listeners[event_name].indexOf(method) > -1) return; // Listener is already registered + listeners[event_name].push(method); + }; + + // Removes a listener from the registry + mraid.removeEventListener = function(event_name, method) { + //If no method name is given, remove all listeners from event + if (method == null) { + listeners[event_name].length = 0; + return; + } + + var method_index = listeners[event_name].indexOf(method); + if (method_index > -1) { //Don't try to remove unregistered listeners + listeners[event_name].splice(method_index, 1); + } else { + mraid.util.errorEvent("An unregistered listener was requested to be removed.", "mraid.removeEventListener()") + } + }; + + //returns 'loading', 'default', 'expanded', or 'hidden' + mraid.getState = function() { + return state; + }; + + //returns 'inline' or 'interstitial' + mraid.getPlacementType = function() { + return placement_type; + }; + + //returns true or false + mraid.isViewable = function() { + return is_viewable; + }; + + // ----- MRAID JS TO NATIVE FUNCTIONS ----- + + mraid.enable = function() { + mraid.util.nativeCall("mraid://enable/"); + }; + + //Closes an expanded ad or hides an ad in default state + mraid.close = function() { + switch (mraid.getState()) { + case 'loading': + mraid.util.errorEvent("mraid.close() called while state is 'loading'.", "mraid.close()"); + break; + case 'default': + mraid.util.nativeCall("mraid://close"); + mraid.util.stateChangeEvent('hidden'); + break; + case 'expanded': + mraid.util.nativeCall("mraid://close"); + mraid.util.stateChangeEvent('default'); + break; + case 'hidden': + mraid.util.errorEvent("mraid.close() called while ad was already hidden", "mraid.close()"); + break; + case 'resized': + mraid.util.nativeCall("mraid://close/"); + mraid.util.stateChangeEvent('default'); + } + }; + + // Expands a default state ad, or unhides a hidden ad. Optionally takes a URL to load in the expanded view + mraid.expand = function(url) { + switch (mraid.getState()) { + case 'loading': + mraid.util.errorEvent("mraid.expand() called while state is 'loading'.", "mraid.expand()"); + break; + case 'default': + case 'resized': + if (placement_type !== "inline") { + mraid.util.errorEvent("mraid.expand() cannot be called for the placement_type " + placement_type, "mraid.expand()"); + return; + } + mraid.util.nativeCall("mraid://expand/" + "?w=-1" + "&h=-1" + "&useCustomClose=" + mraid.getExpandProperties().useCustomClose + (url != null ? "&url=" + url : "") + "&allow_orientation_change=" + orientation_properties.allowOrientationChange + "&force_orientation=" + orientation_properties.forceOrientation); + break; + case 'expanded': + mraid.util.errorEvent("mraid.expand() called while state is 'expanded'.", "mraid.expand()"); + break; + case 'hidden': + mraid.util.errorEvent("mraid.expand() called while state is 'hidden'.", "mraid.expand()"); + break; + } + }; + + // Takes an object... {width:300, height:250, useCustomClose:false, isModal:false}; + mraid.setExpandProperties = function(properties) { + if (typeof properties === "undefined") { + mraid.util.errorEvent("Invalid expandProperties. Retaining default values.", "mraid.setExpandProperties()"); + return; + } + if (typeof properties.width === "number") { + expand_properties.width = properties.width; + } + if (typeof properties.height === "number") { + expand_properties.height = properties.height; + } + if (typeof properties.useCustomClose === "boolean") { + expand_properties.useCustomClose = properties.useCustomClose; + } + if ((typeof window.sdkjs) !== "undefined") { + window.sdkjs.mraidUpdateProperty(MRAID_EXPAND_PROPERTIES, expand_properties); + } + }; + + //returns a json object... {width:300, height:250, useCustomClose:false, isModal:false}; + mraid.getExpandProperties = function() { + return expand_properties; + }; + + // Loads a given URL + mraid.open = function(url) { + mraid.util.nativeCall("mraid://open/?uri=" + encodeURIComponent(url)); + }; + + // MRAID 2.0 Stuff. + mraid.resize = function() { + if (!mraid.util.validateResizeProperties(resize_properties, "mraid.resize()")) { + mraid.util.errorEvent("mraid.resize() called without properly setting setResizeProperties", "mraid.resize()"); + return; + } + switch (mraid.getState()) { + case 'loading': + mraid.util.errorEvent("mraid.resize() called while state is 'loading'.", "mraid.resize()"); + break; + case 'expanded': + mraid.util.errorEvent("mraid.resize() called while state is 'expanded'.", "mraid.resize()"); + break; + case 'resized': + case 'default': + if (placement_type !== "inline") { + mraid.util.errorEvent("mraid.resize() cannot be called for the placement_type " + placement_type, "mraid.resize()"); + return; + } + if (resize_properties) { + mraid.util.nativeCall("mraid://resize/?w=" + resize_properties.width + "&h=" + resize_properties.height + "&offset_x=" + resize_properties.offsetX + "&offset_y=" + resize_properties.offsetY + "&custom_close_position=" + resize_properties.customClosePosition + "&allow_offscreen=" + resize_properties.allowOffscreen); + } else { + mraid.util.errorEvent("mraid.resize() called with no resize_properties set", "mraid.resize()"); + } + break; + case 'hidden': + mraid.util.errorEvent("mraid.resize() called while state is 'hidden'.", "mraid.resize()"); + break; + + } + + } + + mraid.setResizeProperties = function(props) { + if (mraid.util.validateResizeProperties(props, "mraid.setResizeProperties()")) { + if (typeof props.customClosePosition === "undefined") { + props.customClosePosition = 'top-right'; + } + if (typeof props.allowOffscreen === "undefined") { + props.allowOffscreen = true; + } + resize_properties = props; + if ((typeof window.sdkjs) !== "undefined") { + window.sdkjs.mraidUpdateProperty(MRAID_RESIZE_PROPERTIES, resize_properties); + } + } + } + + mraid.getResizeProperties = function() { + return resize_properties; + } + + + //returns a json object... {allowOrientationChange:true, forceOrientation:"none"}; + mraid.getOrientationProperties = function() { + return orientation_properties; + } + + // Takes an object... {allowOrientationChange:true, forceOrientation:"none"}; + mraid.setOrientationProperties = function(properties) { + if (typeof properties === "undefined") { + mraid.util.errorEvent("Invalid orientationProperties.", "mraid.setOrientationProperties()"); + return; + } else { + + if (properties.forceOrientation === 'portrait' || properties.forceOrientation === 'landscape' || properties.forceOrientation === 'none') { + orientation_properties.forceOrientation = properties.forceOrientation; + } else { + mraid.util.errorEvent("Invalid orientationProperties forceOrientation property", "mraid.setOrientationProperties()"); + } + + if (typeof properties.allowOrientationChange === "boolean") { + orientation_properties.allowOrientationChange = properties.allowOrientationChange; + } else { + mraid.util.errorEvent("Invalid orientationProperties allowOrientationChange property", "mraid.setOrientationProperties()"); + } + } + + if ((typeof window.sdkjs) !== "undefined") { + window.sdkjs.mraidUpdateProperty(MRAID_ORIENTATION_PROPERTIES, orientation_properties); + } + + mraid.util.nativeCall("mraid://setOrientationProperties/?allow_orientation_change=" + orientation_properties.allowOrientationChange + "&force_orientation=" + orientation_properties.forceOrientation); + } + + // Creates a calendar event when passed a W3C-formatted json object + mraid.createCalendarEvent = function(event) { + mraid.util.nativeCall("mraid://createCalendarEvent/?p=" + encodeURIComponent(JSON.stringify(event))); + } + + // Plays a video in the native player + mraid.playVideo = function(uri) { + mraid.util.nativeCall("mraid://playVideo/?uri=" + encodeURIComponent(uri)); + } + + // Stores a picture on the device + mraid.storePicture = function(uri) { + mraid.util.nativeCall("mraid://storePicture/?uri=" + encodeURIComponent(uri)); + } + + // Convenience function to modify useCustomClose attribute of expandProperties + mraid.useCustomClose = function(value) { + if (value === true) { + expand_properties.useCustomClose = true; + } else { + expand_properties.useCustomClose = false; + } + mraid.util.nativeCall("mraid://setUseCustomClose/?value=" + expand_properties.useCustomClose); + } + + // Checks if a feature is supported by this device + mraid.supports = function(feature) { + if (mraid.getState() == "loading") { + mraid.util.errorEvent("Method 'mraid.supports()' called during loading state.", "mraid.supports()"); + return; + } + if ((typeof supports[feature]) !== "boolean") { + mraid.util.errorEvent("Unknown feature to check for support: " + feature, "mraid.supports()"); + return false; + } + return supports[feature]; + } + + // Gets the screen size of the device + mraid.getScreenSize = function() { + if (mraid.getState() == "loading") { + mraid.util.errorEvent("Method 'mraid.getScreenSize()' called during loading state.", "mraid.getScreenSize()"); + return; + } else { + return screen_size; + } + } + + // Gets the max size of the ad if expanded (so it won't obscure the app's title bar) + mraid.getMaxSize = function() { + if (mraid.getState() == "loading") { + mraid.util.errorEvent("Method 'mraid.getMaxSize()' called during loading state.", "mraid.getMaxSize()"); + return; + } else { + return max_size; + } + } + + // Gets the default position of the ad view, in dips offset from top left. + mraid.getDefaultPosition = function() { + if (mraid.getState() == "loading") { + mraid.util.errorEvent("Method 'mraid.getDefaultPosition()' called during loading state.", "mraid.getDefaultPosition()"); + return; + } else { + return default_position; + } + } + + + // Gets the current position of the ad view, in dips offset from top left. + mraid.getCurrentPosition = function() { + if (mraid.getState() == "loading") { + mraid.util.errorEvent("Method 'mraid.getCurrentPosition()' called during loading state.", "mraid.getCurrentPosition()"); + return; + } else { + return current_position; + } + } + + // ----- MRAID UTILITY FUNCTIONS ----- + // These functions are called by the native SDK to drive events and update information + + mraid.util.setPlacementType = function(type) { + placement_type = type; + if ((typeof window.sdkjs) !== "undefined") { + window.sdkjs.mraidUpdateProperty(MRAID_PLACEMENT_TYPE, placement_type); + } + }; + + mraid.util.fireEvent = function(event) { + if (!listeners[event]) { + return; + } + + var args = Array.prototype.slice.call(arguments); + args.shift(); + var length = listeners[event].length; + for (var i = 0; i < length; i++) { + if (typeof listeners[event][i] === "function") { + listeners[event][i].apply(null, args); + } + } + } + + mraid.util.readyEvent = function() { + mraid.util.fireEvent('ready'); + }; + + mraid.util.errorEvent = function(message, what_doing) { + mraid.util.fireEvent('error', message, what_doing); + }; + + mraid.util.viewableChangeEvent = function(is_viewable_now) { + if (state === 'loading') return; + is_viewable = is_viewable_now; + mraid.util.fireEvent('viewableChange', is_viewable_now); + }; + + mraid.util.setIsViewable = function(is_it_viewable) { + if (is_viewable === is_it_viewable) return; + is_viewable = is_it_viewable; + if ((typeof window.sdkjs) !== "undefined") { + window.sdkjs.mraidUpdateProperty(MRAID_VIEWABLE, is_viewable); + } + mraid.util.viewableChangeEvent(is_viewable); + }; + + mraid.util.stateChangeEvent = function(new_state) { + if (state === new_state && state != 'resized') return; + state = new_state; + if ((typeof window.sdkjs) !== "undefined") { + window.sdkjs.mraidUpdateProperty(MRAID_STATE, state); + } + if (new_state === 'hidden') { + mraid.util.setIsViewable(false); + } + mraid.util.fireEvent('stateChange', new_state); + }; + + mraid.util.sizeChangeEvent = function(width, height) { + if (state === 'loading') { + size_event_width = width; + size_event_height = height; + return; + } + if (width != size_event_width || height != size_event_height) { + size_event_width = width; + size_event_height = height; + mraid.util.fireEvent('sizeChange', width, height); + } + } + + mraid.util.validateResizeProperties = function(properties, callingFunctionName) { + if (typeof properties === "undefined") { + mraid.util.errorEvent("Invalid resizeProperties", callingFunctionName); + return false; + } + if (typeof properties.width !== "number" || typeof properties.height !== "number" || typeof properties.offsetX !== "number" || typeof properties.offsetY !== "number") { + mraid.util.errorEvent("Incomplete resizeProperties. width, height, offsetX, offsetY required", callingFunctionName); + return false; + } + if (properties.width < 50) { + mraid.util.errorEvent("Resize properties width below the minimum 50 pixels", callingFunctionName); + return false; + } + if (properties.height < 50) { + mraid.util.errorEvent("Resize properties height below the minimum 50 pixels", callingFunctionName); + return false; + } + return true; + } + + var nativeCallQueue = []; + + function dequeue() { + window.location = nativeCallQueue.shift(); + if (nativeCallQueue.length > 0) setTimeout(dequeue, 0); + } + + mraid.util.nativeCall = function(uri) { + nativeCallQueue.push(uri); + if (nativeCallQueue.length == 1) setTimeout(dequeue, 0); + } + + mraid.util.setSupports = function(feature, value) { + supports[feature] = value; + if ((typeof window.sdkjs) !== "undefined") { + window.sdkjs.mraidUpdateSupports(feature, value); + } + } + + mraid.util.setScreenSize = function(width, height) { + screen_size = { + "width": width, + "height": height + }; + if ((typeof window.sdkjs) !== "undefined") { + window.sdkjs.mraidUpdateProperty(MRAID_SCREEN_SIZE, screen_size); + } + } + + mraid.util.setMaxSize = function(width, height) { + max_size = { + "width": width, + "height": height + }; + if ((typeof window.sdkjs) !== "undefined") { + window.sdkjs.mraidUpdateProperty(MRAID_MAX_SIZE, max_size); + } + } + + mraid.util.setDefaultPosition = function(x, y, width, height) { + default_position = { + "x": x, + "y": y, + "width": width, + "height": height + }; + if ((typeof window.sdkjs) !== "undefined") { + window.sdkjs.mraidUpdateProperty(MRAID_DEFAULT_POSITION, default_position); + } + } + + mraid.util.setCurrentPosition = function(x, y, width, height) { + current_position = { + "x": x, + "y": y, + "width": width, + "height": height + }; + if ((typeof window.sdkjs) !== "undefined") { + window.sdkjs.mraidUpdateProperty(MRAID_CURRENT_POSITION, current_position); + } + } + +}()); diff --git a/sdk/Resources/errors.strings b/sdk/Resources/errors.strings index 76fb15ffa..66bd733c2 100644 --- a/sdk/Resources/errors.strings +++ b/sdk/Resources/errors.strings @@ -1,3 +1,4 @@ +// Keys should contain same arguments as values "fetcher_stopped"="AdFetcher stopped"; "no_placement_id"="E104: No placement ID set. onAdRequestFailed will not be called"; "already_expanded"="Cannot load a new ad while the current ad is expanded. onAdRequestFailed will not be called"; @@ -6,22 +7,28 @@ "fetcher_start_single"="AdFetcher starting in single-use mode"; "fetcher_start_auto"="AdFetcher started in auto-refresh mode"; "permissions_missing_location"="E100: Location permissions ACCESS_COARSE_LOCATION and/or ACCESS_FINE_LOCATION aren't set in the host app. This may affect demand."; -"response_error"="E301: The server replied with an error: %@"; +"response_error %@"="E301: The server replied with an error: %@"; "response_no_ads"="The server responded, but didn't return any ads."; -"response_json_error"="E300: There was an error parsing the JSON response: %@"; +"response_json_error %@"="E300: There was an error parsing the JSON response: %@"; "response_bad_format"="The server responded with ads, but in an unexpected format."; -"adsize_too_big"="E103: You requested an Ad larger than the measured ad space. Ad space size: %dx%d, request size: %dx%d"; +"adsize_too_big %d%d%d%d"="E103: You requested an Ad larger than the measured ad space. Ad space size: %dx%d, request size: %dx%d"; "blank_ad"="E302: The server returned an ad with the response, but it was blank. There is probably an issue with the creative."; -"opening_url_failed"="Failed to launch custom protocol: %@"; -"mediation_instantiation_failure"="Instantiating mediated ad failed due to %@"; -"mediation_adding_invalid"="Adding %@ to invalid networks list"; -"instantiating_class"="Instantiating %@"; -"instance_exception"="MediatedAdView is null or not an instance of %@"; +"opening_url_failed %@"="Failed to launch custom protocol: %@"; +"mediation_instantiation_failure %@"="Instantiating mediated ad failed due to %@"; +"mediation_adding_invalid %@"="Adding %@ to invalid networks list"; +"instantiating_class %@"="Instantiating %@"; +"instance_exception %@"="MediatedAdView is null or not an instance of %@"; "mediation_finish"="Mediation Controller has finished."; -"request_parameter_override_attempt"="Parameter %@ cannot be overridden by custom keywords"; +"request_parameter_override_attempt %@"="Parameter %@ cannot be overridden by custom keywords"; "mediation_timeout"="Mediation network timed out."; "bad_url_connection"="Unable to make request because of a bad URL connection."; "malformed_url"="Unable to make request because of a malformed URL."; +"ad_request_failed %@%@"="Ad request %@ failed with error %@"; +"connection_failed %d"="Ad request connection failed with status code %d"; +"no_ad_received_error %@"="No ad received. Error: %@"; +"response_received %@"="Received ad server response: %@"; +"response_received_unknown"="Received response from unknown"; +"resultcb_ignore_error %@%@"="Received resultCB response %@ with error %@"; "native_request_invalid_response"="Expected a ANNativeMediatedAdResponse."; diff --git a/sdk/Resources/images/an_arrow_left.png b/sdk/Resources/images/an_arrow_left.png new file mode 100644 index 000000000..998d1e3ca Binary files /dev/null and b/sdk/Resources/images/an_arrow_left.png differ diff --git a/sdk/Resources/images/an_arrow_left@2x.png b/sdk/Resources/images/an_arrow_left@2x.png new file mode 100644 index 000000000..7dd2f1585 Binary files /dev/null and b/sdk/Resources/images/an_arrow_left@2x.png differ diff --git a/sdk/Resources/images/an_arrow_left@3x.png b/sdk/Resources/images/an_arrow_left@3x.png new file mode 100644 index 000000000..76e3cf419 Binary files /dev/null and b/sdk/Resources/images/an_arrow_left@3x.png differ diff --git a/sdk/Resources/images/an_arrow_right.png b/sdk/Resources/images/an_arrow_right.png new file mode 100644 index 000000000..f97c92904 Binary files /dev/null and b/sdk/Resources/images/an_arrow_right.png differ diff --git a/sdk/Resources/images/an_arrow_right@2x.png b/sdk/Resources/images/an_arrow_right@2x.png new file mode 100644 index 000000000..2b876f520 Binary files /dev/null and b/sdk/Resources/images/an_arrow_right@2x.png differ diff --git a/sdk/Resources/images/an_arrow_right@3x.png b/sdk/Resources/images/an_arrow_right@3x.png new file mode 100644 index 000000000..7f6d1eb89 Binary files /dev/null and b/sdk/Resources/images/an_arrow_right@3x.png differ diff --git a/sdk/Resources/images/compass.png b/sdk/Resources/images/compass.png new file mode 100644 index 000000000..89906bcd9 Binary files /dev/null and b/sdk/Resources/images/compass.png differ diff --git a/sdk/Resources/images/compass@2x.png b/sdk/Resources/images/compass@2x.png new file mode 100644 index 000000000..65f423adf Binary files /dev/null and b/sdk/Resources/images/compass@2x.png differ diff --git a/sdk/Resources/images/compass@3x.png b/sdk/Resources/images/compass@3x.png new file mode 100644 index 000000000..36ed40093 Binary files /dev/null and b/sdk/Resources/images/compass@3x.png differ diff --git a/sdk/Resources/images/interstitial_closebox-down.png b/sdk/Resources/images/interstitial_closebox-down.png deleted file mode 100644 index 7d21ef4f9..000000000 Binary files a/sdk/Resources/images/interstitial_closebox-down.png and /dev/null differ diff --git a/sdk/Resources/images/interstitial_closebox-down@2x.png b/sdk/Resources/images/interstitial_closebox-down@2x.png deleted file mode 100644 index 4f7825582..000000000 Binary files a/sdk/Resources/images/interstitial_closebox-down@2x.png and /dev/null differ diff --git a/sdk/Resources/images/interstitial_flat_closebox.png b/sdk/Resources/images/interstitial_flat_closebox.png new file mode 100644 index 000000000..4c398daef Binary files /dev/null and b/sdk/Resources/images/interstitial_flat_closebox.png differ diff --git a/sdk/Resources/images/interstitial_flat_closebox@2x.png b/sdk/Resources/images/interstitial_flat_closebox@2x.png new file mode 100644 index 000000000..6ae8681a3 Binary files /dev/null and b/sdk/Resources/images/interstitial_flat_closebox@2x.png differ diff --git a/sdk/Resources/images/interstitial_flat_closebox@3x.png b/sdk/Resources/images/interstitial_flat_closebox@3x.png new file mode 100644 index 000000000..a39e29a7c Binary files /dev/null and b/sdk/Resources/images/interstitial_flat_closebox@3x.png differ diff --git a/sdk/internal/ANANJAMImplementation.h b/sdk/internal/ANANJAMImplementation.h index 7fc40ba5c..a4b53413f 100644 --- a/sdk/internal/ANANJAMImplementation.h +++ b/sdk/internal/ANANJAMImplementation.h @@ -13,13 +13,13 @@ limitations under the License. */ -#import "ANAdViewDelegate.h" -#import "ANBrowserViewController.h" - -#import #import +#import "ANAdViewInternalDelegate.h" +#import "ANAdWebViewController.h" + @interface ANANJAMImplementation : NSObject -+ (void)handleUrl:(NSURL *)url forWebView:(UIWebView *)webView - forDelegate:(id)delegate; -@end + ++ (void)handleURL:(NSURL *)URL withWebViewController:(ANAdWebViewController *)controller; + +@end \ No newline at end of file diff --git a/sdk/internal/ANANJAMImplementation.m b/sdk/internal/ANANJAMImplementation.m index 83247b0eb..ad1dd7bf2 100644 --- a/sdk/internal/ANANJAMImplementation.m +++ b/sdk/internal/ANANJAMImplementation.m @@ -38,24 +38,23 @@ @interface UIWebView (RecordEvent) @implementation ANANJAMImplementation -+ (void)handleUrl:(NSURL *)url forWebView:(UIWebView *)webView - forDelegate:(id)delegate { - NSString *call = [url host]; - NSDictionary *queryComponents = [[url query] queryComponents]; ++ (void)handleURL:(NSURL *)URL withWebViewController:(ANAdWebViewController *)controller { + NSString *call = [URL host]; + NSDictionary *queryComponents = [[URL query] queryComponents]; if ([call isEqualToString:kANCallMayDeepLink]) { - [ANANJAMImplementation callMayDeepLink:webView query:queryComponents]; + [ANANJAMImplementation callMayDeepLink:controller query:queryComponents]; } else if ([call isEqualToString:kANCallDeepLink]) { - [ANANJAMImplementation callDeepLink:webView query:queryComponents]; + [ANANJAMImplementation callDeepLink:controller query:queryComponents]; } else if ([call isEqualToString:kANCallExternalBrowser]) { - [ANANJAMImplementation callExternalBrowser:webView query:queryComponents]; + [ANANJAMImplementation callExternalBrowser:controller query:queryComponents]; } else if ([call isEqualToString:kANCallInternalBrowser]) { - [ANANJAMImplementation callInternalBrowser:webView query:queryComponents delegate:delegate]; + [ANANJAMImplementation callInternalBrowser:controller query:queryComponents]; } else if ([call isEqualToString:kANCallRecordEvent]) { - [ANANJAMImplementation callRecordEvent:webView query:queryComponents]; + [ANANJAMImplementation callRecordEvent:controller query:queryComponents]; } else if ([call isEqualToString:kANCallDispatchAppEvent]) { - [ANANJAMImplementation callDispatchAppEvent:webView query:queryComponents delegate:delegate]; + [ANANJAMImplementation callDispatchAppEvent:controller query:queryComponents]; } else if ([call isEqualToString:kANCallGetDeviceID]) { - [ANANJAMImplementation callGetDeviceID:webView query:queryComponents]; + [ANANJAMImplementation callGetDeviceID:controller query:queryComponents]; } else { ANLogWarn(@"ANJAM called with unsupported function: %@", call); } @@ -63,7 +62,7 @@ + (void)handleUrl:(NSURL *)url forWebView:(UIWebView *)webView // Deep Link -+ (void)callMayDeepLink:(UIWebView *)webView query:(NSDictionary *)query { ++ (void)callMayDeepLink:(ANAdWebViewController *)controller query:(NSDictionary *)query { NSString *cb = [query valueForKey:@"cb"]; NSString *urlParam = [query valueForKey:@"url"]; BOOL mayDeepLink; @@ -79,10 +78,10 @@ + (void)callMayDeepLink:(UIWebView *)webView query:(NSDictionary *)query { kANKeyCaller: kANCallMayDeepLink, @"mayDeepLink": mayDeepLink ? @"true" : @"false" }; - [ANANJAMImplementation loadResult:webView cb:cb paramsList:paramsList]; + [ANANJAMImplementation loadResult:controller cb:cb paramsList:paramsList]; } -+ (void)callDeepLink:(UIWebView *)webView query:(NSDictionary *)query { ++ (void)callDeepLink:(ANAdWebViewController *)controller query:(NSDictionary *)query { NSString *cb = [query valueForKey:@"cb"]; NSString *urlParam = [query valueForKey:@"url"]; @@ -95,13 +94,13 @@ + (void)callDeepLink:(UIWebView *)webView query:(NSDictionary *)query { NSDictionary *paramsList = @{ kANKeyCaller: kANCallDeepLink, }; - [ANANJAMImplementation loadResult:webView cb:cb paramsList:paramsList]; + [ANANJAMImplementation loadResult:controller cb:cb paramsList:paramsList]; } } // Launch Browser -+ (void)callExternalBrowser:(UIWebView *)webView query:(NSDictionary *)query { ++ (void)callExternalBrowser:(ANAdWebViewController *)controller query:(NSDictionary *)query { NSString *urlParam = [query valueForKey:@"url"]; NSURL *url = [NSURL URLWithString:urlParam]; @@ -111,19 +110,16 @@ + (void)callExternalBrowser:(UIWebView *)webView query:(NSDictionary *)query { } } -+ (void)callInternalBrowser:(UIWebView *)webView query:(NSDictionary *)query - delegate:(id)delegate { ++ (void)callInternalBrowser:(ANAdWebViewController *)controller + query:(NSDictionary *)query { NSString *urlParam = [query valueForKey:@"url"]; - NSURL *url = [NSURL URLWithString:urlParam]; - if (hasHttpPrefix([url scheme])) { - [ANBrowserViewController launchURL:url withDelegate:delegate]; - } + [controller.browserDelegate openInAppBrowserWithURL:url]; } // Record Event -+ (void)callRecordEvent:(UIWebView *)webView query:(NSDictionary *)query { ++ (void)callRecordEvent:(ANAdWebViewController *)controller query:(NSDictionary *)query { NSString *urlParam = [query valueForKey:@"url"]; NSURL *url = [NSURL URLWithString:urlParam]; @@ -133,22 +129,21 @@ + (void)callRecordEvent:(UIWebView *)webView query:(NSDictionary *)query { recordEventWebView.delegate = recordEventDelegate; [recordEventWebView setHidden:YES]; [recordEventWebView loadRequest:[NSURLRequest requestWithURL:url]]; - [webView addSubview:recordEventWebView]; + [controller.contentView addSubview:recordEventWebView]; } // Dispatch App Event -+ (void)callDispatchAppEvent:(UIWebView *)webView query:(NSDictionary *)query - delegate:(id)delegate { ++ (void)callDispatchAppEvent:(ANAdWebViewController *)controller query:(NSDictionary *)query { NSString *event = [query valueForKey:@"event"]; NSString *data = [query valueForKey:@"data"]; - [delegate adDidReceiveAppEvent:event withData:data]; + [controller.adViewDelegate adDidReceiveAppEvent:event withData:data]; } // Get Device ID -+ (void)callGetDeviceID:(UIWebView *)webView query:(NSDictionary *)query { ++ (void)callGetDeviceID:(ANAdWebViewController *)controller query:(NSDictionary *)query { NSString *cb = [query valueForKey:@"cb"]; // send idName:idfa, id: idfa value @@ -157,13 +152,13 @@ + (void)callGetDeviceID:(UIWebView *)webView query:(NSDictionary *)query { @"idname": @"idfa", @"id": ANUDID() }; - [ANANJAMImplementation loadResult:webView cb:cb paramsList:paramsList]; + [ANANJAMImplementation loadResult:controller cb:cb paramsList:paramsList]; } // Send the result back to JS -+ (void)loadResult:(UIWebView *)webView cb:(NSString *)cb paramsList:(NSDictionary *)paramsList { ++ (void)loadResult:(ANAdWebViewController *)controller cb:(NSString *)cb paramsList:(NSDictionary *)paramsList { __block NSString *params = [NSString stringWithFormat:@"cb=%@", cb ? cb : @"-1"]; [paramsList enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { @@ -176,7 +171,7 @@ + (void)loadResult:(UIWebView *)webView cb:(NSString *)cb paramsList:(NSDictiona }]; NSString *url = [NSString stringWithFormat:@"javascript:window.sdkjs.client.result(\"%@\")", params]; - [webView stringByEvaluatingJavaScriptFromString:url]; + [controller fireJavaScript:url]; } @end diff --git a/sdk/internal/ANAdFetcher.h b/sdk/internal/ANAdFetcher.h index d614dc209..d86bb662a 100644 --- a/sdk/internal/ANAdFetcher.h +++ b/sdk/internal/ANAdFetcher.h @@ -17,9 +17,7 @@ #import ANADPROTOCOLHEADER #import "ANAdResponse.h" -#import "ANAdViewDelegate.h" -#import "ANAdWebViewController.h" -#import "ANBrowserViewController.h" +#import "ANAdViewInternalDelegate.h" #import "ANGlobal.h" #import ANCUSTOMADAPTERHEADER @@ -53,16 +51,12 @@ extern NSString *const kANAdFetcherMediatedClassKey; - (void)processFinalResponse:(ANAdResponse *)response; @end -@protocol ANAdFetcherDelegate +@protocol ANAdFetcherDelegate @optional - (void)adFetcher:(ANAdFetcher *)fetcher didFinishRequestWithResponse:(ANAdResponse *)response; - (CGSize)requestedSizeForAdFetcher:(ANAdFetcher *)fetcher; - (NSTimeInterval)autoRefreshIntervalForAdFetcher:(ANAdFetcher *)fetcher; -- (void)adFetcher:(ANAdFetcher *)fetcher adShouldOpenInBrowserWithURL:(NSURL *)URL; -- (UIView *)containerView; - -// Delegate method for ANAdView subclasses to provide parameters that are specific to them. Should return an array of NSString -- (NSArray *)extraParameters; +- (NSArray *)extraParameters; // An array of NSString @end \ No newline at end of file diff --git a/sdk/internal/ANAdFetcher.m b/sdk/internal/ANAdFetcher.m index e74afeb6f..c8bdf11de 100644 --- a/sdk/internal/ANAdFetcher.m +++ b/sdk/internal/ANAdFetcher.m @@ -16,21 +16,22 @@ #import "ANAdFetcher.h" #import "ANAdRequestUrl.h" -#import "ANAdWebViewController.h" #import "ANGlobal.h" #import "ANLogging.h" #import "ANMediatedAd.h" #import "ANMediationAdViewController.h" -#import "ANWebView.h" +#import "ANMRAIDContainerView.h" + #import "NSString+ANCategory.h" #import "NSTimer+ANCategory.h" +#import "UIView+ANCategory.h" NSString *const kANAdFetcherWillRequestAdNotification = @"kANAdFetcherWillRequestAdNotification"; NSString *const kANAdFetcherAdRequestURLKey = @"kANAdFetcherAdRequestURLKey"; NSString *const kANAdFetcherWillInstantiateMediatedClassNotification = @"kANAdFetcherWillInstantiateMediatedClassKey"; NSString *const kANAdFetcherMediatedClassKey = @"kANAdFetcherMediatedClassKey"; -@interface ANAdFetcher () +@interface ANAdFetcher () @property (nonatomic, readwrite, strong) NSURLConnection *connection; @property (nonatomic, readwrite, strong) NSMutableURLRequest *request; @@ -38,7 +39,7 @@ @interface ANAdFetcher () @property (nonatomic, readwrite, strong) NSTimer *autoRefreshTimer; @property (nonatomic, readwrite, strong) NSURL *URL; @property (nonatomic, readwrite, getter = isLoading) BOOL loading; -@property (nonatomic, readwrite, strong) ANWebView *webView; +@property (nonatomic, readwrite, strong) ANMRAIDContainerView *standardAdView; @property (nonatomic, readwrite, strong) NSMutableArray *mediatedAds; @property (nonatomic, readwrite, strong) ANMediationAdViewController *mediationController; @property (nonatomic, readwrite, assign) BOOL requestShouldBePosted; @@ -110,10 +111,9 @@ - (void)requestAdWithURL:(NSURL *)URL if (!self.isLoading) { - ANLogInfo(ANErrorString(@"fetcher_start")); - - ANLogDebug(ANErrorString(([self getAutoRefreshFromDelegate] > 0.0) - ? @"fetcher_start_auto" : @"fetcher_start_single")); + ANLogInfo(@"fetcher_start"); + NSString *errorKey = [self getAutoRefreshFromDelegate] > 0.0 ? @"fetcher_start_auto" : @"fetcher_start_single"; + ANLogDebug(@"%@", errorKey); NSString *baseUrlString = [NSString stringWithFormat:@"http://%@?", self.ANMobileHostname]; self.URL = URL ? URL : [ANAdRequestUrl buildRequestUrlWithAdFetcherDelegate:self.delegate @@ -154,7 +154,7 @@ - (void)requestAdWithURL:(NSURL *)URL } else { - ANLogWarn(ANErrorString(@"moot_restart")); + ANLogWarn(@"moot_restart"); } } @@ -246,7 +246,7 @@ - (void)processAdResponse:(ANAdResponse *)response BOOL oldAdsExist = [self.mediatedAds count] > 0; if (!responseAdsExist && !oldAdsExist) { - ANLogWarn(ANErrorString(@"response_no_ads")); + ANLogWarn(@"response_no_ads"); NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: NSLocalizedString(@"Request got successful response from server, but no ads were available.", @"Error: Response was received, but it contained no ads")}; [self finishRequestWithErrorAndRefresh:errorInfo code:ANAdResponseUnableToFill]; return; @@ -278,72 +278,28 @@ - (void)handleStandardAd:(ANAdResponse *)response { CGRect requestedRect = CGRectMake(CGPointZero.x, CGPointZero.y, requestedSize.width, requestedSize.height); if (!CGRectContainsRect(requestedRect, receivedRect)) { - ANLogInfo(ANErrorString(@"adsize_too_big", - (int)receivedSize.width, (int)receivedSize.height, - (int)requestedSize.width, (int)requestedSize.height)); + ANLogInfo(@"adsize_too_big %d%d%d%d", (int)receivedSize.width, (int)receivedSize.height, + (int)requestedSize.width, (int)requestedSize.height); } CGSize sizeOfCreative = ((receivedSize.width > 0) && (receivedSize.height > 0)) ? receivedSize : requestedSize; - - /* - The old controller should not continue to fire messages to the ad fetcher. The controller maintains a weak reference to the ad fetcher delegate - in the event the web view continues to persist (in the event the banner will still show, for example), so that messages between the controller and - the ad view can proceed uninterrupted. - */ - if (self.webView) { - self.webView.controller.adFetcher = nil; - } - - // Generate a new webview to contain the HTML - self.webView = [[ANWebView alloc] initWithFrame:CGRectMake(0, 0, sizeOfCreative.width, sizeOfCreative.height)]; - - ANMRAIDAdWebViewController *webViewController = [[ANMRAIDAdWebViewController alloc] init]; - webViewController.isMRAID = response.isMraid; - webViewController.mraidDelegate = self.delegate; - webViewController.mraidDelegate.mraidEventReceiverDelegate = webViewController; - webViewController.adFetcher = self; - webViewController.webView = self.webView; - webViewController.adFetcherDelegate = self.delegate; - self.webView.delegate = webViewController; - self.webView.controller = webViewController; - NSString *contentToLoad = response.content; - contentToLoad = [self prependMRAIDJS:contentToLoad]; - contentToLoad = [self prependSDKJS:contentToLoad]; - - [self.webView loadHTMLString:contentToLoad baseURL:[NSURL URLWithString:self.ANBaseURL]]; -} - -- (NSString *)prependMRAIDJS:(NSString *)content { - NSString *mraidPath = ANMRAIDBundlePath(); - if (!mraidPath) { - ANLogError(@"Could not prepend ad content with mraid.js. MRAID will not be available to ad."); - return content; + if (self.standardAdView) { + self.standardAdView.webViewController.loadingDelegate = nil; } - NSBundle *mraidBundle = [[NSBundle alloc] initWithPath:mraidPath]; - NSData *data = [NSData dataWithContentsOfFile:[mraidBundle pathForResource:@"mraid" ofType:@"js"]]; - NSString *mraidScript = [NSString stringWithFormat:@"", - [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]]; - return [mraidScript stringByAppendingString:content]; + + self.standardAdView = [[ANMRAIDContainerView alloc] initWithSize:sizeOfCreative + HTML:response.content + webViewBaseURL:[NSURL URLWithString:self.ANBaseURL]]; + self.standardAdView.webViewController.loadingDelegate = self; } -- (NSString *)prependSDKJS:(NSString *)content { - NSString *sdkjsPath = ANPathForANResource(@"sdkjs", @"js"); - NSString *anjamPath = ANPathForANResource(@"anjam", @"js"); - if (!sdkjsPath || !anjamPath) { - ANLogError(@"Could not prepend ad content with ANJAM files. ANJAM will not be available to ad."); - return content; +- (void)didCompleteFirstLoadFromWebViewController:(ANAdWebViewController *)controller { + if (self.standardAdView.webViewController == controller) { + ANAdResponse *response = [ANAdResponse adResponseSuccessfulWithAdObject:self.standardAdView]; + [self processFinalResponse:response]; } - NSData *sdkjsData = [NSData dataWithContentsOfFile:sdkjsPath]; - NSData *anjamData = [NSData dataWithContentsOfFile:anjamPath]; - NSString *sdkjs = [[NSString alloc] initWithData:sdkjsData encoding:NSUTF8StringEncoding]; - NSString *anjam = [[NSString alloc] initWithData:anjamData encoding:NSUTF8StringEncoding]; - - NSString *sdkjsScript = [NSString stringWithFormat:@"", - sdkjs, anjam]; - return [sdkjsScript stringByAppendingString:content]; - } - (void)handleMediatedAds:(NSMutableArray *)mediatedAds { @@ -375,7 +331,7 @@ - (void)finishRequestWithErrorAndRefresh:(NSDictionary *)errorInfo code:(NSInteg - (void)startAutoRefreshTimer { if (!self.autoRefreshTimer) { - ANLogDebug(ANErrorString(@"fetcher_stopped")); + ANLogDebug(@"fetcher_stopped"); } else if ([self.autoRefreshTimer isScheduled]) { ANLogDebug(@"AutoRefresh timer already scheduled."); } else { @@ -434,7 +390,7 @@ - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)err NSString *errorMessage = [NSString stringWithFormat: @"Ad request %@ failed with error %@", connection, [error localizedDescription]]; - ANLogError(errorMessage); + ANLogError(@"%@", errorMessage); self.loading = NO; @@ -508,7 +464,7 @@ - (void)fireAndIgnoreResultCB:(NSURL *)url { ANLogInfo(@"Ignored resultCB received response with error: %@", [error localizedDescription]); } else if ([response isKindOfClass:[NSHTTPURLResponse class]]) { NSInteger status = [(NSHTTPURLResponse *)response statusCode]; - ANLogInfo(@"Ignored resultCB received response with code %ld", status); + ANLogInfo(@"Ignored resultCB received response with code %ld", (long)status); } else { ANLogInfo(@"Ignored resultCB received response."); } diff --git a/sdk/internal/ANAdRequestUrl.m b/sdk/internal/ANAdRequestUrl.m index c2fcff964..fed3e9649 100644 --- a/sdk/internal/ANAdRequestUrl.m +++ b/sdk/internal/ANAdRequestUrl.m @@ -247,9 +247,9 @@ - (NSString *)ageParameter { - (NSString *)genderParameter { ANGENDER genderValue = [self.adFetcherDelegate gender]; - if (genderValue == MALE) { + if (genderValue == ANGenderMale) { return @"&gender=m"; - } else if (genderValue == FEMALE) { + } else if (genderValue == ANGenderFemale) { return @"&gender=f"; } else { return @""; @@ -274,8 +274,8 @@ - (NSString *)customKeywordsParameter { key, [self URLEncodingFrom:value]]]; } - }else{ - ANLogWarn(ANErrorString(@"request_parameter_override_attempt", key)); + } else{ + ANLogWarn(@"request_parameter_override_attempt %@", key); } }]; @@ -296,21 +296,8 @@ - (NSString *)extraParameters { } - (NSString *)nonetParameter { - NSMutableString *nonetString = [NSMutableString stringWithString:@""]; - - NSMutableSet *nonetworks = ANInvalidNetworks(); - for (NSString *network in nonetworks) { - [nonetString appendString:network]; - [nonetString appendString:@"%2C"]; - } - - // remove trailing comma - if ([nonetString length] > 0) { - [nonetString deleteCharactersInRange: - NSMakeRange([nonetString length] - 1, 1)]; - } - - return [NSString stringWithFormat:@"&nonet=%@", nonetString]; + NSArray *invalidNetworks = [ANInvalidNetworks() allObjects]; + return invalidNetworks.count ? [NSString stringWithFormat:@"&nonet=%@", [invalidNetworks componentsJoinedByString:@"%2C"]] : @""; } - (NSString *)jsonFormatParameter { diff --git a/sdk/internal/ANAdResponse.m b/sdk/internal/ANAdResponse.m index 1e0cdd605..a8060b160 100644 --- a/sdk/internal/ANAdResponse.m +++ b/sdk/internal/ANAdResponse.m @@ -101,7 +101,7 @@ - (ANAdResponse *)processResponseData:(NSData *)data NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonParsingError]; if (jsonParsingError != nil) { - ANLogError(ANErrorString(@"response_json_error", jsonParsingError)); + ANLogError(@"response_json_error %@", jsonParsingError); return [ANAdResponse adResponseFailWithError:jsonParsingError]; } @@ -119,7 +119,7 @@ - (ANAdResponse *)processResponseData:(NSData *)data -(BOOL)checkStatusIsValid:(NSDictionary *)jsonResponse { NSString *status = jsonResponse[kResponseKeyStatus]; if (status && ([status isEqual: kResponseValueError])) { - ANLogError(ANErrorString(@"response_error", jsonResponse)); + ANLogError(@"response_error %@", jsonResponse); return NO; } return YES; @@ -140,7 +140,7 @@ - (BOOL)handleStandardAds:(NSDictionary *)jsonResponse // Grab the ad's content _content = firstAd[kResponseKeyContent]; if (!_content || ([_content length] < 1)) { - ANLogError(ANErrorString(@"blank_ad")); + ANLogError(@"blank_ad"); } else { // check for mraid.js file diff --git a/sdk/internal/ANAdView.m b/sdk/internal/ANAdView.m index 92631799d..5ba8a3115 100644 --- a/sdk/internal/ANAdView.m +++ b/sdk/internal/ANAdView.m @@ -17,39 +17,19 @@ #import ANADVIEWHEADER #import "ANAdFetcher.h" -#import "ANAdWebViewController.h" -#import "ANBrowserViewController.h" #import "ANGlobal.h" -#import ANINTERSTITIALADHEADER #import "ANLogging.h" -#import "ANMRAIDViewController.h" + #import "UIView+ANCategory.h" #import "UIWebView+ANCategory.h" -#import "ANClickOverlayView.h" #define DEFAULT_PSAS NO -#define CLOSE_BUTTON_OFFSET_X 4.0 -#define CLOSE_BUTTON_OFFSET_Y 4.0 -@interface ANADVIEW () +@interface ANADVIEW () -@property (nonatomic, readwrite, strong) UIView *contentView; -@property (nonatomic, readwrite, strong) UIButton *closeButton; @property (nonatomic, readwrite, strong) ANAdFetcher *adFetcher; - @property (nonatomic, readwrite, weak) id delegate; @property (nonatomic, readwrite, weak) id appEventDelegate; -@property (nonatomic, readwrite, assign) CGRect defaultFrame; -@property (nonatomic, readwrite, assign) CGRect defaultParentFrame; -@property (nonatomic, strong) ANMRAIDViewController *mraidController; -@property (nonatomic, readwrite, assign) BOOL isExpanded; -@property (nonatomic, readwrite) BOOL allowOrientationChange; -@property (nonatomic, readwrite) ANMRAIDOrientation forceOrientation; -@property (nonatomic, readwrite, strong) ANBrowserViewController *browserViewController; -@property (nonatomic, readwrite, assign) CGPoint resizeOffset; -@property (nonatomic, readwrite, assign) BOOL adjustFramesInResizeState; -@property (nonatomic, readwrite, strong) ANClickOverlayView *clickOverlay; @end @@ -65,26 +45,6 @@ @implementation ANADVIEW @synthesize customKeywords = __customKeywords; @synthesize landingPageLoadsInBackground = __landingPageLoadsInBackground; -// ANMRAIDEventReceiver -@synthesize mraidEventReceiverDelegate = __mraidEventReceiverDelegate; - -#pragma mark Abstract methods -/*** - * Subclasses should implement these abstract methods - ***/ - -// MRAIDAdViewDelegate methods -- (NSString *)adType { return nil; } -- (UIViewController *)displayController { return nil; } -- (void)adShouldResetToDefault {} -- (void)adShouldExpandToFrame:(CGRect)frame closeButton:(UIButton *)closeButton {} -- (void)adShouldResizeToFrame:(CGRect)frame allowOffscreen:(BOOL)allowOffscreen - closeButton:(UIButton *)closeButton - closePosition:(ANMRAIDCustomClosePosition)closePosition {} - -// AdFetcherDelegate methods -- (void)openInBrowserWithController:(ANBrowserViewController *)browserViewController {} - #pragma mark Initialization - (instancetype)init { @@ -106,10 +66,6 @@ - (void)initialize { self.clipsToBounds = YES; self.adFetcher = [[ANAdFetcher alloc] init]; self.adFetcher.delegate = self; - self.defaultParentFrame = CGRectNull; - self.defaultFrame = CGRectNull; - self.allowOrientationChange = YES; - self.forceOrientation = ANMRAIDOrientationNone; __shouldServePublicServiceAnnouncements = DEFAULT_PSAS; __location = nil; @@ -123,11 +79,6 @@ - (void)dealloc { self.adFetcher.delegate = nil; [self.adFetcher stopAd]; // MUST be called. stopAd invalidates the autoRefresh timer, which is retaining the adFetcher as well. - - if ([self.contentView respondsToSelector:@selector(setDelegate:)]) { - // If our content is a UIWebview, we want to make sure to clear out the delegate if we're destroying it - [self.contentView performSelector:@selector(setDelegate:) withObject:nil]; - } } - (void)loadAd { @@ -136,12 +87,8 @@ - (void)loadAd { errorString = ANErrorString(@"no_placement_id"); } - if (self.isExpanded) { - errorString = ANErrorString(@"already_expanded"); - } - if (errorString) { - ANLogError(errorString); + ANLogError(@"%@", errorString); NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: errorString}; NSError *error = [NSError errorWithDomain:AN_ERROR_DOMAIN code:ANAdResponseInvalidRequest userInfo:errorInfo]; [self adRequestFailedWithError:error]; @@ -152,7 +99,6 @@ - (void)loadAd { [self.adFetcher requestAd]; } - - (void)loadAdFromHtml:(NSString *)html width:(int)width height:(int)height { ANAdResponse *response = [ANAdResponse new]; @@ -165,304 +111,6 @@ - (void)loadAdFromHtml:(NSString *)html [self.adFetcher processAdResponse:response]; } -- (void)allowOrientationChange:(BOOL)allowOrientationChange - withForcedOrientation:(ANMRAIDOrientation)orientation { - self.allowOrientationChange = allowOrientationChange; - self.forceOrientation = orientation; - [self updateOrientationPropertiesOnMRAIDViewController]; -} - -- (void)updateOrientationPropertiesOnMRAIDViewController { - if (self.mraidController) { - self.mraidController.allowOrientationChange = self.allowOrientationChange; - self.mraidController.orientation = [[UIApplication sharedApplication] statusBarOrientation]; - - if (!self.isExpanded) { - switch(self.forceOrientation) { - case ANMRAIDOrientationLandscape: - if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight) { - self.mraidController.orientation = UIInterfaceOrientationLandscapeRight; - break; - } - self.mraidController.orientation = UIInterfaceOrientationLandscapeLeft; - break; - case ANMRAIDOrientationPortrait: - if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortraitUpsideDown) { - self.mraidController.orientation = UIInterfaceOrientationPortraitUpsideDown; - break; - } - self.mraidController.orientation = UIInterfaceOrientationPortrait; - break; - default: - break; - } - } - } -} - -#pragma mark MRAID expand methods - -- (void)mraidExpandAd:(CGSize)size - contentView:(UIView *)contentView - defaultParentView:(UIView *)defaultParentView - rootViewController:(UIViewController *)rootViewController { - - [self adWillPresent]; - - // set default frames for resetting later - if (CGRectIsNull(self.defaultFrame)) { - self.defaultParentFrame = defaultParentView.frame; - self.defaultFrame = contentView.frame; - } - - // expand to full screen - if ((size.width == -1) && (size.height == -1)) { - [contentView removeFromSuperview]; - - self.mraidController = [ANMRAIDViewController new]; - [self updateOrientationPropertiesOnMRAIDViewController]; - - self.mraidController.contentView = contentView; - [self.mraidController.view addSubview:contentView]; - - [rootViewController presentViewController:self.mraidController animated:NO completion:^{ - [self adDidPresent]; - }]; - } else { - CGRect orientedScreenBounds = adjustAbsoluteRectInWindowCoordinatesForOrientationGivenRect(ANPortraitScreenBounds()); - if (size.width == -1) size.width = orientedScreenBounds.size.width; - if (size.height == -1) size.height = orientedScreenBounds.size.height; - - // non-fullscreen expand - CGRect expandedContentFrame = self.defaultFrame; - expandedContentFrame.size = size; - [contentView setFrame:expandedContentFrame]; - [contentView removeFromSuperview]; - - CGRect expandedParentFrame = defaultParentView.frame; - expandedParentFrame.size = size; - [defaultParentView setFrame:expandedParentFrame]; - - [defaultParentView addSubview:contentView]; - [self adDidPresent]; - } - - self.isExpanded = YES; -} - -- (void)mraidExpandAddCloseButton:(UIButton *)closeButton - containerView:(UIView *)containerView { - // remove any existing close button - [self removeCloseButton]; - - // place the close button in the top right - CGFloat closeButtonOriginX = containerView.bounds.size.width - - closeButton.frame.size.width - CLOSE_BUTTON_OFFSET_X; - CGFloat closeButtonOriginY = CLOSE_BUTTON_OFFSET_Y; - - closeButton.frame = CGRectMake(closeButtonOriginX, closeButtonOriginY, - closeButton.frame.size.width, - closeButton.frame.size.height); - closeButton.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin; - - self.closeButton = closeButton; - - [containerView addSubview:closeButton]; -} - -#pragma mark MRAID resize methods - -- (NSString *)mraidResizeAd:(CGRect)frame - contentView:(UIView *)contentView - defaultParentView:(UIView *)defaultParentView - rootViewController:(UIViewController *)rootViewController - allowOffscreen:(BOOL)allowOffscreen { - NSString *mraidResizeErrorString = [self isResizeValid:contentView frameToResizeTo:frame]; - if ([mraidResizeErrorString length] > 0) return mraidResizeErrorString; - - // set default frames for resetting later - if (CGRectIsNull(self.defaultFrame)) { - self.defaultParentFrame = defaultParentView.frame; - self.defaultFrame = contentView.frame; - } - - self.adjustFramesInResizeState = NO; - - // resize contentView to new frame - [contentView setFrame:CGRectMake(contentView.frame.origin.x, contentView.frame.origin.y, frame.size.width, frame.size.height)]; - - /* - Adjust the parent view to fit contentView. - The parentView will realign the content view within its bounds. - */ - [defaultParentView setFrame:CGRectMake(defaultParentView.frame.origin.x + frame.origin.x, - defaultParentView.frame.origin.y + frame.origin.y, - frame.size.width, - frame.size.height)]; - - self.adjustFramesInResizeState = YES; - [self setResizeOffset:CGPointMake(frame.origin.x + self.resizeOffset.x, frame.origin.y + self.resizeOffset.y)]; - [self.mraidEventReceiverDelegate adDidChangeResizeOffset:self.resizeOffset]; - - return nil; -} - -- (NSString *)isResizeValid:(UIView *)contentView frameToResizeTo:(CGRect)frame { - // for comparing to - CGRect screenBounds = ANPortraitScreenBounds(); - CGRect orientedScreenBounds = adjustAbsoluteRectInWindowCoordinatesForOrientationGivenRect(screenBounds); - - // don't allow resizing to be larger than the screen in both directions - if (frame.size.width > orientedScreenBounds.size.width && frame.size.height > orientedScreenBounds.size.height) { - return @"Resize called with resizeProperties larger than the screen."; - } - - CGRect contentAbsoluteFrame = [contentView convertRect:contentView.bounds toView:nil]; - CGRect adjustedContentAbsoluteFrame = adjustAbsoluteRectInWindowCoordinatesForOrientationGivenRect(contentAbsoluteFrame); - - // verify that at least 50x50 pixels of the creative are onscreen - // by checking the intersection of the creative and the screen - CGFloat allowedSize = 50.0f; - CGRect contentFrame = contentView.frame; - - // the absolute x and y offset will only be changed - // by the difference of the new frame and the old frame - // the size will simply be the size given by resizeProperties - CGRect resizedFrame = CGRectMake(adjustedContentAbsoluteFrame.origin.x + (frame.origin.x - contentFrame.origin.x), - adjustedContentAbsoluteFrame.origin.y + (frame.origin.y - contentFrame.origin.y), - frame.size.width, - frame.size.height); - - // find the area of the resized creative that is on screen - // if at least 50x50 is on the screen, then the resize is valid - CGRect resizedIntersection = CGRectIntersection(orientedScreenBounds, resizedFrame); - - // if either the width or the height is smaller than the allowed size, then return an error. - if (resizedIntersection.size.width < allowedSize || resizedIntersection.size.height < allowedSize) { - return @"Resize call should keep at least 50x50 of the creative on screen"; - } - - // no errors - return nil; -} - -// returns true if position of closeEventRegion was valid, false if error -- (void)mraidResizeAddCloseEventRegion:(UIButton *)closeEventRegion - containerView:(UIView *)containerView - contentView:(UIView *)contentView - position:(ANMRAIDCustomClosePosition)position { - // remove any existing close button - [self removeCloseButton]; - - CGFloat closeEventRegionSize = 50.0f; - - CGFloat contentWidth = contentView.frame.size.width; - CGFloat contentHeight = contentView.frame.size.height; - - // different offset values for various possible closeEventRegion positions, - // relative to the origin of the contentView - CGFloat topY = 0.0f; - CGFloat bottomY = contentHeight - closeEventRegionSize; - CGFloat centerY = (contentHeight - closeEventRegionSize) / 2.0; - CGFloat leftX = 0.0f; - CGFloat rightX = contentWidth - closeEventRegionSize; - CGFloat centerX = (contentWidth - closeEventRegionSize) / 2.0; - - // closeEventRegion will be a child of the container, so it needs to be - // positioned based on contentView's origin - CGFloat closeOriginX = contentView.frame.origin.x; - CGFloat closeOriginY = contentView.frame.origin.y; - - switch (position) { - case ANMRAIDTopLeft: - closeOriginX += leftX; - closeOriginY += topY; - break; - case ANMRAIDTopCenter: - closeOriginX += centerX; - closeOriginY += topY; - break; - case ANMRAIDTopRight: - closeOriginX += rightX; - closeOriginY += topY; - break; - case ANMRAIDCenter: - closeOriginX += centerX; - closeOriginY += centerY; - break; - case ANMRAIDBottomLeft: - closeOriginX += leftX; - closeOriginY += bottomY; - break; - case ANMRAIDBottomCenter: - closeOriginX += centerX; - closeOriginY += bottomY; - break; - case ANMRAIDBottomRight: - closeOriginX += rightX; - closeOriginY += bottomY; - break; - - default: - break; - } - - // compute the absolute frame of the close event region - CGRect screenBounds = ANPortraitScreenBounds(); - CGRect orientedScreenBounds = adjustAbsoluteRectInWindowCoordinatesForOrientationGivenRect(screenBounds); - - CGRect containerAbsoluteFrame = [containerView convertRect:containerView.bounds toView:nil]; - CGRect adjustedContainerAbsoluteFrame = adjustAbsoluteRectInWindowCoordinatesForOrientationGivenRect(containerAbsoluteFrame); - - CGFloat closeAbsoluteOriginX = adjustedContainerAbsoluteFrame.origin.x + closeOriginX; - CGFloat closeAbsoluteOriginY = adjustedContainerAbsoluteFrame.origin.y + closeOriginY; - CGRect closeAbsoluteFrame = CGRectMake(closeAbsoluteOriginX, closeAbsoluteOriginY, - closeEventRegionSize, closeEventRegionSize); - - // verify that the requested close event region will be on the screen - // container frame was adjusted for orientation, so we should compare the closeAbsoluteFrame with orientedScreenBounds - BOOL isCloseEventRegionOnScreen = CGRectContainsRect(orientedScreenBounds, closeAbsoluteFrame); - - // if the requested close positioning is invalid, - // put it in the top-left of the available space - if (!isCloseEventRegionOnScreen) { - CGRect contentAbsoluteFrame = [contentView convertRect:contentView.bounds toView:nil]; - CGRect adjustedContentAbsoluteFrame = adjustAbsoluteRectInWindowCoordinatesForOrientationGivenRect(contentAbsoluteFrame); - - CGRect contentIntersection = CGRectIntersection(orientedScreenBounds, adjustedContentAbsoluteFrame); - closeOriginX = contentIntersection.origin.x - adjustedContainerAbsoluteFrame.origin.x; - closeOriginY = contentIntersection.origin.y - adjustedContainerAbsoluteFrame.origin.y; - - // add image to the region since it will be in a different - // place with no visual cue - - // Missing resources could be an issue here - UIImage *closeboxImage = [UIImage imageWithContentsOfFile:ANPathForANResource(@"interstitial_closebox", @"png")]; - UIImage *closeboxDown = [UIImage imageWithContentsOfFile:ANPathForANResource(@"interstitial_closebox_down", @"png")]; - - [closeEventRegion setImage:closeboxImage - forState:UIControlStateNormal]; - [closeEventRegion setImage:closeboxDown - forState:UIControlStateHighlighted]; - } - closeEventRegion.frame = CGRectMake(closeOriginX, closeOriginY, - closeEventRegionSize, closeEventRegionSize); - closeEventRegion.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin - | UIViewAutoresizingFlexibleLeftMargin; - - self.closeButton = closeEventRegion; - - [containerView addSubview:closeEventRegion]; -} - -- (void)removeCloseButton -{ - if (self.closeButton.superview) { - [self.closeButton removeFromSuperview]; - } - self.closeButton = nil; -} - #pragma mark Setter methods - (void)setPlacementId:(NSString *)placementId { @@ -511,34 +159,6 @@ - (void)removeCustomKeywordWithKey:(NSString *)key { [self.customKeywords removeObjectForKey:key]; } -- (void)setContentView:(UIView *)contentView { - if (contentView != _contentView) { - [self removeCloseButton]; - - if ([_contentView isKindOfClass:[UIWebView class]]) { - UIWebView *webView = (UIWebView *)_contentView; - [webView stopLoading]; - [webView setDelegate:nil]; - } - - [_contentView removeSubviews]; - [_contentView removeFromSuperview]; - [self removeSubviews]; - - if (contentView != nil) { - if ([contentView isKindOfClass:[UIWebView class]]) { - UIWebView *webView = (UIWebView *)contentView; - [webView removeDocumentPadding]; - [webView setMediaProperties]; - } - - [self addSubview:contentView]; - } - - _contentView = contentView; - } -} - #pragma mark Getter methods - (NSString *)placementId { @@ -572,7 +192,7 @@ - (NSString *)age { } - (ANGENDER)gender { - ANLogDebug(@"gender returned %d", __gender); + ANLogDebug(@"gender returned %lu", (long unsigned)__gender); return __gender; } @@ -581,138 +201,7 @@ - (NSMutableDictionary *)customKeywords { return __customKeywords; } -#pragma mark ANAdFetcherDelegate - -- (void)adFetcher:(ANAdFetcher *)fetcher adShouldOpenInBrowserWithURL:(NSURL *)URL { - [self adWasClicked]; - - if (!self.opensInNativeBrowser && hasHttpPrefix([URL scheme])) { - if (!self.browserViewController) { - self.browserViewController = [[ANBrowserViewController alloc] initWithURL:URL]; - if (!self.browserViewController) { - ANLogError(@"Browser controller did not instantiate correctly. Terminating clickthrough."); - return; - } - self.browserViewController.delegate = self; - if (self.landingPageLoadsInBackground) { - [self showClickOverlay]; - } else { - [self browserViewControllerShouldPresent:self.browserViewController]; - } - } else { - if (self.browserViewController.completedInitialLoad) { - [self browserViewControllerShouldPresent:self.browserViewController]; - } - self.browserViewController.url = URL; - } - } - else if ([[UIApplication sharedApplication] canOpenURL:URL]) { - [self adWillLeaveApplication]; - [[UIApplication sharedApplication] openURL:URL]; - } else { - ANLogWarn(ANErrorString(@"opening_url_failed", URL)); - } -} - -- (ANClickOverlayView *)clickOverlay { - if (!_clickOverlay) { - _clickOverlay = [ANClickOverlayView overlayForView:[self viewToDisplayClickOverlay]]; - _clickOverlay.alpha = 0.0; - } - return _clickOverlay; -} - -- (UIView *)viewToDisplayClickOverlay { - return nil; -} - -- (void)showClickOverlay { - [UIView animateWithDuration:0.5 - animations:^{ - [[self viewToDisplayClickOverlay] addSubview:self.clickOverlay]; - self.clickOverlay.alpha = 1.0; - }]; -} - -- (void)hideClickOverlay { - if ([self.clickOverlay superview]) { - [UIView animateWithDuration:0.5 - animations:^{ - self.clickOverlay.alpha = 0.0; - } completion:^(BOOL finished) { - [self.clickOverlay removeFromSuperview]; - }]; - } -} - -#pragma mark ANBrowserViewControllerDelegate - -- (void)browserViewControllerShouldDismiss:(ANBrowserViewController *)controller { - UIViewController *presentingViewController = controller.presentingViewController; - [presentingViewController dismissViewControllerAnimated:YES completion:^ { - self.browserViewController = nil; - }]; -} - -- (void)browserViewControllerWillLaunchExternalApplication { - [self adWillLeaveApplication]; -} - -- (void)browserViewControllerShouldPresent:(ANBrowserViewController *)controller { - if (!controller.presentingViewController) { - if (self.mraidController.presentingViewController) { - [self.mraidController presentViewController:controller - animated:YES - completion:nil]; - } else { - [self openInBrowserWithController:controller]; - } - } else { - ANLogDebug(@"In-app browser already presented - ignoring call to present"); - } -} - -- (void)browserViewController:(ANBrowserViewController *)controller browserIsLoading:(BOOL)isLoading { - if (self.landingPageLoadsInBackground) { - if (!controller.completedInitialLoad) { - isLoading ? [self showClickOverlay] : [self hideClickOverlay]; - } else { - [self hideClickOverlay]; - } - } -} - -#pragma mark ANMRAIDAdViewDelegate - -- (void)adShouldResetToDefault:(UIView *)contentView - parentView:(UIView *)parentView { - if (self.isExpanded) [self adWillClose]; - - [self removeCloseButton]; - self.adjustFramesInResizeState = NO; - - [contentView setFrame:self.defaultFrame]; - [contentView removeFromSuperview]; - [parentView setFrame:self.defaultParentFrame]; - [parentView addSubview:contentView]; - - self.defaultParentFrame = CGRectNull; - self.defaultFrame = CGRectNull; - [self setResizeOffset:CGPointZero]; - [self.mraidEventReceiverDelegate adDidChangeResizeOffset:self.resizeOffset]; - - if (self.mraidController) { - [self.mraidController dismissViewControllerAnimated:NO completion:^{ - if (self.isExpanded) [self adDidClose]; - }]; - self.mraidController = nil; - } else if (self.isExpanded) [self adDidClose]; - self.isExpanded = NO; - - [self.mraidEventReceiverDelegate adDidResetToDefault]; -} - -#pragma mark ANAdViewDelegate +#pragma mark ANAdViewInternalDelegate - (void)adWasClicked { if ([self.delegate respondsToSelector:@selector(adWasClicked:)]) { @@ -756,18 +245,6 @@ - (void)adDidReceiveAppEvent:(NSString *)name withData:(NSString *)data { } } -- (void)adFailedToDisplay { - if ([self isMemberOfClass:[ANINTERSTITIALAD class]] - && [self.delegate conformsToProtocol:@protocol(ANINTERSTITIALADDELEGATE)]) { - ANINTERSTITIALAD *interstitialAd = (ANINTERSTITIALAD *)self; - id interstitialDelegate = (id) self.delegate; - if ([interstitialDelegate respondsToSelector:@selector(adFailedToDisplay:)]) { - [interstitialDelegate adFailedToDisplay:interstitialAd]; - } - } -} - -// also helper methods for calling other selectors - (void)adDidReceiveAd { if ([self.delegate respondsToSelector:@selector(adDidReceiveAd:)]) { [self.delegate adDidReceiveAd:self]; @@ -780,4 +257,25 @@ - (void)adRequestFailedWithError:(NSError *)error { } } +- (void)adInteractionDidBegin { + ANLogDebug(@"%@", NSStringFromSelector(_cmd)); + [self.adFetcher stopAd]; +} + +- (void)adInteractionDidEnd { + ANLogDebug(@"%@", NSStringFromSelector(_cmd)); + [self.adFetcher setupAutoRefreshTimerIfNecessary]; + [self.adFetcher startAutoRefreshTimer]; +} + +- (NSString *)adType { + ANLogDebug(@"%@ is abstract, should be implemented by subclass", NSStringFromSelector(_cmd)); + return @""; +} + +- (UIViewController *)displayController { + ANLogDebug(@"%@ is abstract, should be implemented by subclass", NSStringFromSelector(_cmd)); + return nil; +} + @end diff --git a/sdk/internal/ANAdViewInternalDelegate.h b/sdk/internal/ANAdViewInternalDelegate.h new file mode 100644 index 000000000..2f1a49d0e --- /dev/null +++ b/sdk/internal/ANAdViewInternalDelegate.h @@ -0,0 +1,56 @@ +/* Copyright 2013 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +@protocol ANAdViewInternalDelegate + +- (void)adDidReceiveAd; +- (void)adRequestFailedWithError:(NSError *)error; + +- (void)adWasClicked; +- (void)adWillPresent; +- (void)adDidPresent; +- (void)adWillClose; +- (void)adDidClose; +- (void)adWillLeaveApplication; +- (void)adDidReceiveAppEvent:(NSString *)name withData:(NSString *)data; + +- (NSString *)adType; +- (UIViewController *)displayController; +- (BOOL)opensInNativeBrowser; +- (BOOL)landingPageLoadsInBackground; + +- (void)adInteractionDidBegin; +- (void)adInteractionDidEnd; + +@end + +@protocol ANBannerAdViewInternalDelegate + +- (NSNumber *)transitionInProgress; + +@end + +@class ANMRAIDOrientationProperties; + +@protocol ANInterstitialAdViewInternalDelegate + +- (void)adFailedToDisplay; +- (void)adShouldClose; +- (void)adShouldSetOrientationProperties:(ANMRAIDOrientationProperties *)orientationProperties; +- (void)adShouldUseCustomClose:(BOOL)useCustomClose; + +@end \ No newline at end of file diff --git a/sdk/internal/ANAdWebViewController.h b/sdk/internal/ANAdWebViewController.h index 8ac5ff10e..b45bf8753 100644 --- a/sdk/internal/ANAdWebViewController.h +++ b/sdk/internal/ANAdWebViewController.h @@ -1,4 +1,4 @@ -/* Copyright 2013 APPNEXUS INC +/* Copyright 2014 APPNEXUS INC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,20 +13,113 @@ limitations under the License. */ -#import "ANMRAIDProperties.h" - -#import #import +#import "ANAdViewInternalDelegate.h" +#import "ANMRAIDUtil.h" + +@class ANMRAIDExpandProperties; +@class ANMRAIDResizeProperties; +@class ANMRAIDOrientationProperties; +@class ANAdWebViewControllerConfiguration; +@protocol ANAdWebViewControllerMRAIDDelegate; +@protocol ANAdWebViewControllerPitbullDelegate; +@protocol ANAdWebViewControllerBrowserDelegate; +@protocol ANAdWebViewControllerANJAMDelegate; +@protocol ANAdWebViewControllerLoadingDelegate; + +@interface ANAdWebViewController : NSObject + +- (instancetype)initWithSize:(CGSize)size + URL:(NSURL *)URL + webViewBaseURL:(NSURL *)baseURL; + +- (instancetype)initWithSize:(CGSize)size + URL:(NSURL *)URL + webViewBaseURL:(NSURL *)baseURL + configuration:(ANAdWebViewControllerConfiguration *)configuration; + +- (instancetype)initWithSize:(CGSize)size + HTML:(NSString *)html + webViewBaseURL:(NSURL *)baseURL; + +- (instancetype)initWithSize:(CGSize)size + HTML:(NSString *)html + webViewBaseURL:(NSURL *)baseURL + configuration:(ANAdWebViewControllerConfiguration *)configuration; + +@property (nonatomic, readonly, assign) BOOL isMRAID; +@property (nonatomic, readonly, strong) UIView *contentView; +@property (nonatomic, readonly, assign) BOOL completedFirstLoad; +@property (nonatomic, readonly, strong) ANAdWebViewControllerConfiguration *configuration; + +@property (nonatomic, readwrite, weak) id adViewDelegate; + +@property (nonatomic, readwrite, weak) id loadingDelegate; +@property (nonatomic, readwrite, weak) id browserDelegate; +@property (nonatomic, readwrite, weak) id pitbullDelegate; +@property (nonatomic, readwrite, weak) id anjamDelegate; +@property (nonatomic, readwrite, weak) id mraidDelegate; + +- (void)adDidFinishExpand; +- (void)adDidFinishResize:(BOOL)success + errorString:(NSString *)errorString + isResized:(BOOL)isResized; +- (void)adDidResetToDefault; +- (void)adDidHide; +- (void)adDidFailCalendarEditWithErrorString:(NSString *)errorString; +- (void)adDidFailPhotoSaveWithErrorString:(NSString *)errorString; + +- (void)fireJavaScript:(NSString *)javascript; + +@end + +@interface ANAdWebViewControllerConfiguration : NSObject + +@property (nonatomic, readwrite, assign) BOOL scrollingEnabled; +@property (nonatomic, readwrite, assign) BOOL navigationTriggersDefaultBrowser; +@property (nonatomic, readwrite, assign) ANMRAIDState initialMRAIDState; + +@end + +@protocol ANAdWebViewControllerLoadingDelegate + +- (void)didCompleteFirstLoadFromWebViewController:(ANAdWebViewController *)controller; + +@end + +@protocol ANAdWebViewControllerBrowserDelegate + +- (void)openDefaultBrowserWithURL:(NSURL *)URL; +- (void)openInAppBrowserWithURL:(NSURL *)URL; + +@end + +@protocol ANAdWebViewControllerPitbullDelegate + +- (void)handlePitbullURL:(NSURL *)URL; + +@end + +@protocol ANAdWebViewControllerANJAMDelegate + +- (void)handleANJAMURL:(NSURL *)URL; + +@end + +@protocol ANAdWebViewControllerMRAIDDelegate -@class ANAdFetcher; -@protocol ANAdFetcherDelegate; +- (CGRect)defaultPosition; +- (CGRect)currentPosition; +- (BOOL)isViewable; -@interface ANMRAIDAdWebViewController : NSObject +- (void)adShouldExpandWithExpandProperties:(ANMRAIDExpandProperties *)expandProperties; +- (void)adShouldAttemptResizeWithResizeProperties:(ANMRAIDResizeProperties *)resizeProperties; +- (void)adShouldSetOrientationProperties:(ANMRAIDOrientationProperties *)orientationProperties; +- (void)adShouldSetUseCustomClose:(BOOL)useCustomClose; +- (void)adShouldClose; -@property (nonatomic, readwrite, weak) ANAdFetcher *adFetcher; -@property (nonatomic, readwrite, weak) id adFetcherDelegate; -@property (nonatomic, readwrite, weak) UIWebView *webView; -@property (nonatomic, readwrite, weak) id mraidDelegate; -@property (nonatomic, readwrite, assign) BOOL isMRAID; +- (void)adShouldOpenCalendarWithCalendarDict:(NSDictionary *)calendarDict; +- (void)adShouldSavePictureWithUri:(NSString *)uri; +- (void)adShouldPlayVideoWithUri:(NSString *)uri; @end \ No newline at end of file diff --git a/sdk/internal/ANAdWebViewController.m b/sdk/internal/ANAdWebViewController.m index 1ed34f5b6..4f69fbd14 100644 --- a/sdk/internal/ANAdWebViewController.m +++ b/sdk/internal/ANAdWebViewController.m @@ -1,4 +1,4 @@ -/* Copyright 2013 APPNEXUS INC +/* Copyright 2014 APPNEXUS INC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,200 +14,209 @@ */ #import "ANAdWebViewController.h" - -#import "ANAdFetcher.h" -#import "ANANJAMImplementation.h" -#import "ANBrowserViewController.h" #import "ANGlobal.h" #import "ANLogging.h" -#import "ANPBBuffer.h" -#import "ANWebView.h" +#import "ANMRAIDJavascriptUtil.h" +#import "ANMRAIDOrientationProperties.h" +#import "ANMRAIDExpandProperties.h" +#import "ANMRAIDResizeProperties.h" +#import "ANAdViewInternalDelegate.h" + #import "NSString+ANCategory.h" -#import "UIWebView+ANCategory.h" #import "NSTimer+ANCategory.h" +#import "UIWebView+ANCategory.h" +#import "UIView+ANCategory.h" -#import -#import -#import +NSString *const kANWebViewControllerMraidJSFilename = @"mraid.js"; -@interface ANAdFetcher (ANMRAIDAdWebViewController) -@property (nonatomic, readwrite, getter = isLoading) BOOL loading; -@end +@interface ANAdWebViewController () + +@property (nonatomic, readwrite, strong) UIView *contentView; +@property (nonatomic, readwrite, weak) UIWebView *legacyWebView; +@property (nonatomic, readwrite, assign) BOOL isMRAID; -@interface ANMRAIDAdWebViewController () @property (nonatomic, readwrite, assign) BOOL completedFirstLoad; -@property (nonatomic, readwrite, assign) BOOL expanded; -@property (nonatomic, readwrite, assign) BOOL resized; -@property (nonatomic, readwrite, strong) NSTimer *viewabilityTimer; -@property (nonatomic, readwrite) BOOL isViewable; -@property (nonatomic, readwrite) CGRect defaultPosition; -@property (nonatomic, readwrite) CGRect currentPosition; -@property (nonatomic, readwrite, assign) CGPoint resizeOffset; -@property (nonatomic, readwrite, strong) NSMutableArray *pitbullCaptureURLQueue; -- (void)delegateShouldOpenInBrowser:(NSURL *)URL; +@property (nonatomic, readwrite, strong) NSTimer *viewabilityTimer; +@property (nonatomic, readwrite, assign, getter=isViewable) BOOL viewable; +@property (nonatomic, readwrite, assign) CGRect defaultPosition; +@property (nonatomic, readwrite, assign) CGRect currentPosition; +@property (nonatomic, readwrite, assign) BOOL rapidTimerSet; -@property (nonatomic, readwrite, assign) BOOL isRegisteredForPitbullScreenCaptureNotifications; +@property (nonatomic, readwrite, strong) ANAdWebViewControllerConfiguration *configuration; @end -@implementation ANMRAIDAdWebViewController +@implementation ANAdWebViewController -- (void)delegateShouldOpenInBrowser:(NSURL *)URL { - if ([self.adFetcherDelegate respondsToSelector:@selector(adFetcher:adShouldOpenInBrowserWithURL:)]) { - [self.adFetcherDelegate adFetcher:self.adFetcher adShouldOpenInBrowserWithURL:URL]; +- (instancetype)initWithConfiguration:(ANAdWebViewControllerConfiguration *)configuration { + if (self = [super init]) { + if (configuration) { + _configuration = [configuration copy]; + } else { + _configuration = [[ANAdWebViewControllerConfiguration alloc] init]; + } } + return self; } -- (void)webViewDidFinishLoad:(UIWebView *)webView { - if (!self.completedFirstLoad) { - self.adFetcher.loading = NO; - - // If this is our first successful load, then send this to the delegate. Otherwise, ignore. - self.completedFirstLoad = YES; - - ANAdResponse *response = [ANAdResponse adResponseSuccessfulWithAdObject:webView]; - [self.adFetcher processFinalResponse:response]; - if (self.isMRAID) [self finishMRAIDLoad:webView]; - } -} +- (instancetype)initWithSize:(CGSize)size + URL:(NSURL *)URL + webViewBaseURL:(NSURL *)baseURL { + self = [self initWithSize:size + URL:URL + webViewBaseURL:baseURL + configuration:nil]; + return self; -- (void)finishMRAIDLoad:(UIWebView *)webView { - // set initial values for MRAID getters - [self setValuesForMRAIDSupportsFunction:webView]; - [self setScreenSizeForMRAIDGetScreenSizeFunction:webView]; - [self setMaxSizeForMRAIDGetMaxSizeFunction:webView]; - - // setup rotation detection support - [self processDidChangeStatusBarOrientationNotifications]; - - // setup viewability support - [self viewabilitySetup]; - - [webView setPlacementType:[self.mraidDelegate adType]]; - [webView fireStateChangeEvent:ANMRAIDStateDefault]; - [webView fireReadyEvent]; -} - -- (void)viewabilitySetup { - self.isViewable = [self getWebViewVisible]; - [self.webView setIsViewable:self.isViewable]; - ANLogDebug(@"%@ | viewableChange: isViewable=%d", NSStringFromSelector(_cmd), self.isViewable); - [self updatePosition]; - if (CGRectEqualToRect(self.currentPosition, CGRectZero)) { - self.currentPosition = CGRectMake(CGPointZero.x, CGPointZero.y, self.webView.bounds.size.width, self.webView.bounds.size.height); - self.defaultPosition = self.currentPosition; - [self.webView fireNewCurrentPositionEvent:self.currentPosition]; - ANLogDebug(@"%@ | current position origin (%d, %d) size %dx%d", NSStringFromSelector(_cmd), - (int)self.currentPosition.origin.x, (int)self.currentPosition.origin.y, - (int)self.currentPosition.size.width, (int)self.currentPosition.size.height); - [self.webView setDefaultPosition:self.defaultPosition]; - ANLogDebug(@"%@ | default position origin (%d, %d) size %dx%d", NSStringFromSelector(_cmd), - (int)self.defaultPosition.origin.x, (int)self.defaultPosition.origin.y, - (int)self.defaultPosition.size.width, (int)self.defaultPosition.size.height); - } - - __weak ANMRAIDAdWebViewController *weakANMRAIDAdWebViewController = self; - self.viewabilityTimer = [NSTimer scheduledTimerWithTimeInterval:kAppNexusMRAIDCheckViewableFrequency - block:^ { - ANMRAIDAdWebViewController *strongANMRAIDAdWebViewController = weakANMRAIDAdWebViewController; - [strongANMRAIDAdWebViewController checkViewability]; - } - repeats:YES]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(applicationDidEnterBackground:) - name:UIApplicationDidEnterBackgroundNotification - object:[UIApplication sharedApplication]]; } -- (void)checkViewability { - BOOL isCurrentlyViewable = [self getWebViewVisible]; - if (self.isViewable != isCurrentlyViewable) { - self.isViewable = isCurrentlyViewable; - [self.webView setIsViewable:self.isViewable]; - ANLogDebug(@"%@ | viewableChange: isViewable=%d", NSStringFromSelector(_cmd), self.isViewable); +- (instancetype)initWithSize:(CGSize)size + URL:(NSURL *)URL + webViewBaseURL:(NSURL *)baseURL + configuration:(ANAdWebViewControllerConfiguration *)configuration { + if (self = [self initWithConfiguration:configuration]) { + [self loadLegacyWebViewWithSize:size + URL:URL + baseURL:baseURL]; } - [self updatePosition]; -} - -- (void)updatePosition { - if (self.isViewable) { - CGRect newPosition = [self webViewPositionInWindowCoordinatesForWebView:self.webView]; - if (!CGRectEqualToRect(newPosition, self.currentPosition)) { - self.currentPosition = newPosition; - if (!self.expanded) { - if (self.resized) { - self.defaultPosition = CGRectMake(self.currentPosition.origin.x - self.resizeOffset.x, self.currentPosition.origin.y - self.resizeOffset.y, - self.defaultPosition.size.width, self.defaultPosition.size.height); - [self.webView setDefaultPosition:self.defaultPosition]; - } else if (!self.resized && (CGSizeEqualToSize(self.defaultPosition.size, self.currentPosition.size) || - CGRectEqualToRect(self.defaultPosition, CGRectZero))) { - self.defaultPosition = self.currentPosition; - [self.webView setDefaultPosition:self.defaultPosition]; - } - } - [self.webView fireNewCurrentPositionEvent:self.currentPosition]; - ANLogDebug(@"%@ | current position origin (%d, %d) size %dx%d", NSStringFromSelector(_cmd), - (int)self.currentPosition.origin.x, (int)self.currentPosition.origin.y, - (int)self.currentPosition.size.width, (int)self.currentPosition.size.height); - ANLogDebug(@"%@ | default position origin (%d, %d) size %dx%d", NSStringFromSelector(_cmd), - (int)self.defaultPosition.origin.x, (int)self.defaultPosition.origin.y, - (int)self.defaultPosition.size.width, (int)self.defaultPosition.size.height); + return self; +} + +- (instancetype)initWithSize:(CGSize)size + HTML:(NSString *)html + webViewBaseURL:(NSURL *)baseURL { + self = [self initWithSize:size + HTML:html + webViewBaseURL:baseURL + configuration:nil]; + return self; +} + +- (instancetype)initWithSize:(CGSize)size + HTML:(NSString *)html + webViewBaseURL:(NSURL *)baseURL + configuration:(ANAdWebViewControllerConfiguration *)configuration { + if (self = [self initWithConfiguration:configuration]) { + NSRange mraidJSRange = [html rangeOfString:kANWebViewControllerMraidJSFilename]; + _isMRAID = (mraidJSRange.location != NSNotFound); + NSURL *base = baseURL; + if (!base) { + base = [NSURL URLWithString:AN_BASE_URL]; } + NSString *htmlWithScripts = [[self class] prependScriptsToHTML:html]; + [self loadLegacyWebViewWithSize:size + HTML:htmlWithScripts + baseURL:base]; } + return self; } -- (void)applicationDidEnterBackground:(NSNotification *)notification { - self.isViewable = NO; - [self.webView setIsViewable:self.isViewable]; - ANLogDebug(@"%@ | viewableChange: isViewable=%d", NSStringFromSelector(_cmd), self.isViewable); +#pragma mark - Scripts + ++ (NSString *)mraidHTML { + return [NSString stringWithFormat:@"", + [[self class] mraidJS]]; } -- (void)dealloc { - [self unregisterFromPitbullScreenCaptureNotifications]; - [self.webView stopLoading]; - self.webView.delegate = nil; - [self.viewabilityTimer invalidate]; - [[NSNotificationCenter defaultCenter] removeObserver:self]; ++ (NSString *)anjamHTML { + return [NSString stringWithFormat:@"", + [[self class] anjamJS]]; } -- (BOOL)getWebViewVisible { - BOOL isHidden = self.webView.hidden; - if (isHidden) return NO; - - BOOL isAttachedToWindow = self.webView.window ? YES : NO; - if (!isAttachedToWindow) return NO; - - BOOL isInHiddenSuperview = NO; - UIView *ancestorView = self.webView.superview; - while (ancestorView) { - if (ancestorView.hidden) { - isInHiddenSuperview = YES; - break; - } - ancestorView = ancestorView.superview; ++ (NSString *)mraidJS { + NSString *mraidPath = ANMRAIDBundlePath(); + if (!mraidPath) { + return @""; } - if (isInHiddenSuperview) return NO; - - CGRect screenBounds = ANPortraitScreenBounds(); - CGRect newBounds = [self.webView convertRect:self.webView.bounds toView:nil]; - BOOL isOnScreen = CGRectIntersectsRect(newBounds, screenBounds); - if (!isOnScreen) return NO; + NSBundle *mraidBundle = [[NSBundle alloc] initWithPath:mraidPath]; + NSData *data = [NSData dataWithContentsOfFile:[mraidBundle pathForResource:@"mraid" ofType:@"js"]]; + return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; +} - return YES; ++ (NSString *)anjamJS { + NSString *sdkjsPath = ANPathForANResource(@"sdkjs", @"js"); + NSString *anjamPath = ANPathForANResource(@"anjam", @"js"); + if (!sdkjsPath || !anjamPath) { + return @""; + } + NSData *sdkjsData = [NSData dataWithContentsOfFile:sdkjsPath]; + NSData *anjamData = [NSData dataWithContentsOfFile:anjamPath]; + NSString *sdkjs = [[NSString alloc] initWithData:sdkjsData encoding:NSUTF8StringEncoding]; + NSString *anjam = [[NSString alloc] initWithData:anjamData encoding:NSUTF8StringEncoding]; + return [NSString stringWithFormat:@"%@ %@", sdkjs, anjam]; } -- (void)processDidChangeStatusBarOrientationNotifications { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(handleRotation:) - name:UIApplicationDidChangeStatusBarOrientationNotification - object:[UIApplication sharedApplication]]; ++ (NSString *)prependViewportToHTML:(NSString *)html { + return [NSString stringWithFormat:@"%@%@", @"", html]; +} + ++ (NSString *)prependScriptsToHTML:(NSString *)html { + return [NSString stringWithFormat:@"%@%@%@", [[self class] anjamHTML], [[self class] mraidHTML], html]; } -- (void)handleRotation:(NSNotification *)notification { - [self setMaxSizeForMRAIDGetMaxSizeFunction:self.webView]; - [self setScreenSizeForMRAIDGetScreenSizeFunction:self.webView]; +#pragma mark - UIWebView + ++ (UIWebView *)defaultLegacyWebViewWithSize:(CGSize)size + configuration:(ANAdWebViewControllerConfiguration *)configuration { + UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)]; + webView.backgroundColor = [UIColor clearColor]; + webView.opaque = NO; + if (configuration.scrollingEnabled) { + webView.scrollView.scrollEnabled = YES; + webView.scrollView.bounces = YES; + webView.scalesPageToFit = YES; + } else { + webView.scrollView.scrollEnabled = NO; + webView.scrollView.bounces = NO; + webView.scalesPageToFit = NO; + } + webView.allowsInlineMediaPlayback = YES; + webView.mediaPlaybackRequiresUserAction = NO; + return webView; +} + +- (void)loadLegacyWebViewWithSize:(CGSize)size + URL:(NSURL *)URL + baseURL:(NSURL *)baseURL { + UIWebView *webView = [[self class] defaultLegacyWebViewWithSize:size + configuration:self.configuration]; + webView.delegate = self; + self.legacyWebView = webView; + self.contentView = webView; + __weak UIWebView *weakWebView = webView; + [NSURLConnection sendAsynchronousRequest:ANBasicRequestWithURL(URL) + queue:[NSOperationQueue mainQueue] + completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { + UIWebView *strongWebView = weakWebView; + if (strongWebView) { + NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if (html.length) { + NSString *htmlWithScripts = [[self class] prependScriptsToHTML:html]; + [strongWebView loadHTMLString:htmlWithScripts baseURL:baseURL]; + } + } + }]; +} + +- (void)loadLegacyWebViewWithSize:(CGSize)size + HTML:(NSString *)html + baseURL:(NSURL *)baseURL { + UIWebView *webView = [[self class] defaultLegacyWebViewWithSize:size + configuration:self.configuration]; + webView.delegate = self; + [webView loadHTMLString:html + baseURL:baseURL]; + self.legacyWebView = webView; + self.contentView = webView; +} + +# pragma mark - UIWebViewDelegate + +- (void)webViewDidFinishLoad:(UIWebView *)webView { + [webView removeDocumentPadding]; + [self processWebViewDidFinishLoad]; } - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { @@ -216,709 +225,396 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *) NSString *scheme = [URL scheme]; if ([scheme isEqualToString:@"anwebconsole"]) { - [self printConsoleLog:URL]; + [self printConsoleLogWithURL:URL]; return NO; } - + ANLogDebug(@"Loading URL: %@", [[URL absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]); - - if ([scheme isEqualToString:@"appnexuspb"]) { - if ([self.adFetcherDelegate respondsToSelector:@selector(transitionInProgress)]) { - if ([URL.host isEqualToString:@"capture"]) { - NSNumber *transitionInProgress = [self.adFetcherDelegate performSelector:@selector(transitionInProgress)]; - if ([transitionInProgress boolValue] == YES) { - if (![self.pitbullCaptureURLQueue count]) { - [self registerForPitbullScreenCaptureNotifications]; - } - [self.pitbullCaptureURLQueue addObject:URL]; - return NO; - } - } else if ([URL.host isEqualToString:@"web"]) { - [self dispatchPitbullScreenCaptureCalls]; - [self unregisterFromPitbullScreenCaptureNotifications]; - } - } - UIView *view = self.webView; - if ([self.adFetcherDelegate respondsToSelector:@selector(containerView)]) { - view = [self.adFetcherDelegate containerView]; - } - [ANPBBuffer handleUrl:URL forView:view]; + if ([scheme isEqualToString:@"appnexuspb"]) { + [self.pitbullDelegate handlePitbullURL:URL]; return NO; } - + if (self.completedFirstLoad) { if (hasHttpPrefix(scheme)) { if (self.isMRAID) { - /* - The mainDocumentURL will be equal to the URL whenever a URL has requested to load in a new window/tab, - or move away from the existing page. This does not apply for links coming from inside an iFrame unless - window.open was explicitly written (even if these links are present inside an tag). The assumption - here is that MRAID creatives should be using mraid.open to break out of the ad. - */ - - if ([[mainDocumentURL absoluteString] isEqualToString:[URL absoluteString]]) { - [self delegateShouldOpenInBrowser:URL]; - } else { - return YES; /* Let the link load in the webView */ + if ([[mainDocumentURL absoluteString] isEqualToString:[URL absoluteString]] && self.configuration.navigationTriggersDefaultBrowser) { + [self.browserDelegate openDefaultBrowserWithURL:URL]; + return NO; } } else { - /* - The mainDocumentURL will be equal to the URL whenever a URL has requested to load in a new window/tab, - or move away from the existing page. This does not apply for links coming from inside an iFrame unless - window.open was explicitly written (even if these links are present inside an tag). However, the - assumption here is that any user clicks should break out of the ad. This fix will catch both tags - embedded in iFrames as well as asynchronous loads which occur after the first instance of webViewDidFinishLoad:. - Any creatives loading iFrames which desire clicks to continue displaying in the iFrame should be flagged as MRAID. - */ - - if ([[mainDocumentURL absoluteString] isEqualToString:[URL absoluteString]] || navigationType == UIWebViewNavigationTypeLinkClicked) { - [self delegateShouldOpenInBrowser:URL]; - } else { - return YES; /* Let the link load in the webView */ + if (([[mainDocumentURL absoluteString] isEqualToString:[URL absoluteString]] || navigationType == UIWebViewNavigationTypeLinkClicked) + && self.configuration.navigationTriggersDefaultBrowser) { + [self.browserDelegate openDefaultBrowserWithURL:URL]; + return NO; } } } else if ([scheme isEqualToString:@"mraid"]) { - // Do MRAID actions - [self dispatchNativeMRAIDURL:URL forWebView:webView]; + [self handleMRAIDURL:URL]; + return NO; } else if ([scheme isEqualToString:@"anjam"]) { - [ANANJAMImplementation handleUrl:URL forWebView:webView forDelegate:self.adFetcherDelegate]; - } else if ([[UIApplication sharedApplication] canOpenURL:URL]) { - [[UIApplication sharedApplication] openURL:URL]; + [self.anjamDelegate handleANJAMURL:URL]; + return NO; + } else if ([scheme isEqualToString:@"about"]) { + return NO; } else { - ANLogWarn(ANErrorString(@"opening_url_failed", URL)); + if (self.configuration.navigationTriggersDefaultBrowser) { + [self.browserDelegate openDefaultBrowserWithURL:URL]; + return NO; + } } - - return NO; - } else if ([scheme isEqualToString:@"mraid"] && [[URL host] isEqualToString:@"enable"]) { - [self dispatchNativeMRAIDURL:URL forWebView:webView]; + } else if ([scheme isEqualToString:@"mraid"] && [[URL host] isEqualToString:@"enable"]) { + [self handleMRAIDURL:URL]; return NO; } return YES; } -- (void)setMaxSizeForMRAIDGetMaxSizeFunction:(UIWebView*) webView{ - UIApplication *application = [UIApplication sharedApplication]; - BOOL orientationIsPortrait = UIInterfaceOrientationIsPortrait([application statusBarOrientation]); - CGSize screenSize = ANPortraitScreenBounds().size; - int orientedWidth = orientationIsPortrait ? screenSize.width : screenSize.height; - int orientedHeight = orientationIsPortrait ? screenSize.height : screenSize.width; - - if (!application.statusBarHidden) { - orientedHeight -= MIN(application.statusBarFrame.size.height, application.statusBarFrame.size.width); - } - - [webView setMaxSize:CGSizeMake(orientedWidth, orientedHeight)]; -} +# pragma mark - MRAID -- (void)setScreenSizeForMRAIDGetScreenSizeFunction:(UIWebView*)webView{ - - BOOL orientationIsPortrait = UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]); - CGSize screenSize = ANPortraitScreenBounds().size; - int orientedWidth = orientationIsPortrait ? screenSize.width : screenSize.height; - int orientedHeight = orientationIsPortrait ? screenSize.height : screenSize.width; - - [webView setScreenSize:CGSizeMake(orientedWidth, orientedHeight)]; -} - -- (CGRect)webViewPositionInWindowCoordinatesForWebView:(UIWebView *)webView { - CGRect webViewAbsoluteFrame = [webView convertRect:webView.bounds toView:nil]; - CGRect bounds = adjustAbsoluteRectInWindowCoordinatesForOrientationGivenRect(webViewAbsoluteFrame); - UIApplication *application = [UIApplication sharedApplication]; - if (!application.statusBarHidden) { - bounds.origin.y -= MIN(application.statusBarFrame.size.height, application.statusBarFrame.size.width); +- (void)processWebViewDidFinishLoad { + if (!self.completedFirstLoad) { + self.completedFirstLoad = YES; + [self.loadingDelegate didCompleteFirstLoadFromWebViewController:self]; + if (self.isMRAID) { + [self finishMRAIDLoad]; + } } - return bounds; } -- (void)setValuesForMRAIDSupportsFunction:(UIWebView*)webView{ - BOOL sms = NO; - BOOL tel = NO; - BOOL cal = NO; - BOOL inline_video = YES; - BOOL store_picture = YES; - -#ifdef __IPHONE_4_0 - //SMS - sms = [MFMessageComposeViewController canSendText]; -#else - sms = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"sms://"]]; -#endif - //TEL - tel = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"tel://"]]; - - //CAL - EKEventStore *store = [[EKEventStore alloc] init]; - if ([store respondsToSelector:@selector(requestAccessToEntityType:completion:)]) { - cal = YES; +- (void)finishMRAIDLoad { + [self fireJavaScript:[ANMRAIDJavascriptUtil feature:@"sms" + isSupported:[ANMRAIDUtil supportsSMS]]]; + [self fireJavaScript:[ANMRAIDJavascriptUtil feature:@"tel" + isSupported:[ANMRAIDUtil supportsTel]]]; + [self fireJavaScript:[ANMRAIDJavascriptUtil feature:@"calendar" + isSupported:[ANMRAIDUtil supportsCalendar]]]; + [self fireJavaScript:[ANMRAIDJavascriptUtil feature:@"inlineVideo" + isSupported:[ANMRAIDUtil supportsInlineVideo]]]; + [self fireJavaScript:[ANMRAIDJavascriptUtil feature:@"storePicture" + isSupported:[ANMRAIDUtil supportsStorePicture]]]; + + [self updateWebViewOnOrientation]; + [self updateWebViewOnPositionAndVisibilityStatus]; + if (self.configuration.initialMRAIDState == ANMRAIDStateExpanded || self.configuration.initialMRAIDState == ANMRAIDStateResized) { + [self setupRapidTimerForCheckingPositionAndViewability]; + self.rapidTimerSet = YES; + } else { + [self setupTimerForCheckingPositionAndVisibility]; } + [self setupApplicationDidEnterBackgroundNotification]; + [self setupOrientationChangeNotification]; - [webView setSupports:@"sms" isSupported:sms]; - [webView setSupports:@"tel" isSupported:tel]; - [webView setSupports:@"calendar" isSupported:cal]; - [webView setSupports:@"inlineVideo" isSupported:inline_video]; - [webView setSupports:@"storePicture" isSupported:store_picture]; + if ([self.adViewDelegate adType]) { + [self fireJavaScript:[ANMRAIDJavascriptUtil placementType:[self.adViewDelegate adType]]]; + } + [self fireJavaScript:[ANMRAIDJavascriptUtil stateChange:self.configuration.initialMRAIDState]]; + [self fireJavaScript:[ANMRAIDJavascriptUtil readyEvent]]; } -- (void)dispatchNativeMRAIDURL:(NSURL *)mraidURL forWebView:(UIWebView *)webView { - NSString *mraidCommand = [mraidURL host]; - NSString *query = [mraidURL query]; - NSDictionary *queryComponents = [query queryComponents]; +- (void)setupApplicationDidEnterBackgroundNotification { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(handleApplicationDidEnterBackground:) + name:UIApplicationDidEnterBackgroundNotification + object:[UIApplication sharedApplication]]; +} - if ([mraidCommand isEqualToString:@"expand"]) { - // hidden state handled by mraid.js - [self.adFetcherDelegate adWasClicked]; - [self expandAction:webView queryComponents:queryComponents]; - } - else if ([mraidCommand isEqualToString:@"close"]) { - // hidden state handled by mraid.js - [self closeAction:self]; - } else if([mraidCommand isEqualToString:@"resize"]) { - [self.adFetcherDelegate adWasClicked]; - [self resizeAction:webView queryComponents:queryComponents]; - } else if([mraidCommand isEqualToString:@"createCalendarEvent"]) { - [self.adFetcherDelegate adWasClicked]; - NSString *w3cEventJson = queryComponents[@"p"]; - [self createCalendarEventFromW3CCompliantJSONObject:w3cEventJson]; - } else if([mraidCommand isEqualToString:@"playVideo"]) { - [self.adFetcherDelegate adWasClicked]; - [self playVideo:queryComponents]; - } else if([mraidCommand isEqualToString:@"storePicture"]) { - [self.adFetcherDelegate adWasClicked]; - NSString *uri = queryComponents[@"uri"]; - [self storePicture:uri]; - } else if([mraidCommand isEqualToString:@"setOrientationProperties"]) { - [self setOrientationProperties:queryComponents]; - } else if([mraidCommand isEqualToString:@"open"]){ - NSString *uri = queryComponents[@"uri"]; - [self open:uri]; - } else if ([mraidCommand isEqualToString:@"enable"]) { - if (self.isMRAID) return; - self.isMRAID = YES; - if (self.completedFirstLoad) [self finishMRAIDLoad:webView]; - } +- (void)handleApplicationDidEnterBackground:(NSNotification *)notification { + self.viewable = NO; + [self fireJavaScript:[ANMRAIDJavascriptUtil isViewable:NO]]; } -- (void)open:(NSString *)url { - if ([url length] > 0) { - [self delegateShouldOpenInBrowser:[NSURL URLWithString:url]]; - } +- (void)setupOrientationChangeNotification { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(handleOrientationChange:) + name:UIApplicationDidChangeStatusBarOrientationNotification + object:[UIApplication sharedApplication]]; } -- (ANMRAIDCustomClosePosition)getCustomClosePositionFromString:(NSString *)value { - // default value is top-right - ANMRAIDCustomClosePosition position = ANMRAIDTopRight; - if ([value isEqualToString:@"top-left"]) { - position = ANMRAIDTopLeft; - } else if ([value isEqualToString:@"top-center"]) { - position = ANMRAIDTopCenter; - } else if ([value isEqualToString:@"top-right"]) { - position = ANMRAIDTopRight; - } else if ([value isEqualToString:@"center"]) { - position = ANMRAIDCenter; - } else if ([value isEqualToString:@"bottom-left"]) { - position = ANMRAIDBottomLeft; - } else if ([value isEqualToString:@"bottom-center"]) { - position = ANMRAIDBottomCenter; - } else if ([value isEqualToString:@"bottom-right"]) { - position = ANMRAIDBottomRight; - } - - return position; +- (void)handleOrientationChange:(NSNotification *)notification { + [self updateWebViewOnOrientation]; } -- (IBAction)closeAction:(id)sender { - if (self.expanded || self.resized) { - [self.mraidDelegate adShouldResetToDefault]; - - [self.webView fireStateChangeEvent:ANMRAIDStateDefault]; - self.expanded = NO; - self.resized = NO; - } - else { - // Clear the ad out - [self.webView setHidden:YES animated:YES]; - self.webView = nil; +- (void)setupTimerForCheckingPositionAndVisibility { + ANLogDebug(@"%@", NSStringFromSelector(_cmd)); + if (self.viewabilityTimer) { + [self.viewabilityTimer invalidate]; } + __weak ANAdWebViewController *weakSelf = self; + self.viewabilityTimer = [NSTimer scheduledTimerWithTimeInterval:kAppNexusMRAIDCheckViewableFrequency + block:^ { + ANAdWebViewController *strongSelf = weakSelf; + [strongSelf updateWebViewOnPositionAndVisibilityStatus]; + } + repeats:YES]; } -- (void)setExpanded:(BOOL)expanded { - if (expanded != _expanded) { - _expanded = expanded; - if (_expanded) { - [self.adFetcher stopAd]; - } - else { - [self.adFetcher setupAutoRefreshTimerIfNecessary]; - [self.adFetcher startAutoRefreshTimer]; - } +- (void)setupRapidTimerForCheckingPositionAndViewability { + ANLogDebug(@"%@", NSStringFromSelector(_cmd)); + if (self.viewabilityTimer) { + [self.viewabilityTimer invalidate]; } + __weak ANAdWebViewController *weakSelf = self; + self.viewabilityTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 + block:^ { + ANAdWebViewController *strongSelf = weakSelf; + [strongSelf updateWebViewOnPositionAndVisibilityStatus]; + } + repeats:YES]; } -- (void)expandAction:(UIWebView *)webView queryComponents:(NSDictionary *)queryComponents { - NSInteger expandedHeight = [queryComponents[@"h"] integerValue]; - NSInteger expandedWidth = [queryComponents[@"w"] integerValue]; - NSString *useCustomClose = queryComponents[@"useCustomClose"]; - NSString *url = queryComponents[@"url"]; - - [self setOrientationProperties:queryComponents]; - - BOOL needDefaultCloseButton = ![useCustomClose isEqualToString:@"true"]; - UIButton *closeButton = nil; - if (needDefaultCloseButton) { - closeButton = [self expandCloseButton]; - } else { - closeButton = [self expandCloseButtonForCustomClose]; +- (void)updateWebViewOnPositionAndVisibilityStatus { + CGRect updatedDefaultPosition = [self.mraidDelegate defaultPosition]; + if (!CGRectEqualToRect(self.defaultPosition, updatedDefaultPosition)) { + ANLogDebug(@"Default position change: %@", NSStringFromCGRect(updatedDefaultPosition)); + self.defaultPosition = updatedDefaultPosition; + [self fireJavaScript:[ANMRAIDJavascriptUtil defaultPosition:self.defaultPosition]]; } - if (!closeButton) { - ANLogError(@"Terminating MRAID expand due to invalid close button."); - return; + CGRect updatedCurrentPosition = [self.mraidDelegate currentPosition]; + if (!CGRectEqualToRect(self.currentPosition, updatedCurrentPosition)) { + ANLogDebug(@"Current position change: %@", NSStringFromCGRect(updatedCurrentPosition)); + self.currentPosition = updatedCurrentPosition; + [self fireJavaScript:[ANMRAIDJavascriptUtil currentPosition:self.currentPosition]]; } - - [self.mraidDelegate adShouldExpandToFrame:CGRectMake(0, 0, expandedWidth, expandedHeight) - closeButton:closeButton]; - self.expanded = YES; - - if ([url length] > 0) { - [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]]; + BOOL isCurrentlyViewable = [self.mraidDelegate isViewable]; + if (self.isViewable != isCurrentlyViewable) { + ANLogDebug(@"Viewable change: %d", isCurrentlyViewable); + self.viewable = isCurrentlyViewable; + [self fireJavaScript:[ANMRAIDJavascriptUtil isViewable:self.isViewable]]; } } -- (void)resizeAction:(UIWebView *)webView queryComponents:(NSDictionary *)queryComponents { - int w = [queryComponents[@"w"] intValue]; - int h = [queryComponents[@"h"] intValue]; - int offsetX = [queryComponents[@"offset_x"] intValue]; - int offsetY = [queryComponents[@"offset_y"] intValue]; - NSString* customClosePosition = queryComponents[@"custom_close_position"]; - BOOL allowOffscreen = [queryComponents[@"allow_offscreen"] boolValue]; - - ANMRAIDCustomClosePosition closePosition = [self getCustomClosePositionFromString:customClosePosition]; - - [self.mraidDelegate adShouldResizeToFrame:CGRectMake(offsetX, offsetY, w, h) - allowOffscreen:allowOffscreen - closeButton:[self resizeCloseButton] - closePosition:closePosition]; - self.resized = YES; +- (void)updateWebViewOnOrientation { + [self fireJavaScript:[ANMRAIDJavascriptUtil screenSize:[ANMRAIDUtil screenSize]]]; + [self fireJavaScript:[ANMRAIDJavascriptUtil maxSize:[ANMRAIDUtil maxSize]]]; } -- (void)playVideo:(NSDictionary *)queryComponents { - NSString *uri = queryComponents[@"uri"]; - NSURL *url = [NSURL URLWithString:uri]; - - MPMoviePlayerViewController *moviePlayerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:url]; - moviePlayerViewController.moviePlayer.fullscreen = YES; - moviePlayerViewController.moviePlayer.shouldAutoplay = YES; - moviePlayerViewController.moviePlayer.movieSourceType = MPMovieSourceTypeFile; - moviePlayerViewController.moviePlayer.view.frame = ANPortraitScreenBounds(); - moviePlayerViewController.moviePlayer.controlStyle = MPMovieControlStyleFullscreen; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(moviePlayerDidFinish:) - name:MPMoviePlayerPlaybackDidFinishNotification - object:moviePlayerViewController.moviePlayer]; - - [moviePlayerViewController.moviePlayer prepareToPlay]; - [[self.mraidDelegate displayController] presentMoviePlayerViewControllerAnimated:moviePlayerViewController]; - [moviePlayerViewController.moviePlayer play]; +- (void)fireJavaScript:(NSString *)javascript { +#if kANAdWebViewControllerWebKitEnabled + if (self.modernWebView) { + [self.modernWebView evaluateJavaScript:javascript completionHandler:nil]; + } else +#endif + { + [self.legacyWebView stringByEvaluatingJavaScriptFromString:javascript]; + } } -- (void)moviePlayerDidFinish:(NSNotification *)notification -{ - ANLogInfo(@"Movie Player finished: %@", notification); +- (void)stopWebViewLoadForDealloc { +#if kANAdWebViewControllerWebKitEnabled + if (self.modernWebView) { + [self.modernWebView stopLoading]; + self.modernWebView.navigationDelegate = nil; + } else +#endif + { + [self.legacyWebView loadHTMLString:@"" + baseURL:nil]; + [self.legacyWebView stopLoading]; + self.legacyWebView.delegate = nil; + [self.legacyWebView removeSubviews]; + [self.legacyWebView removeFromSuperview]; + } + self.contentView = nil; } -- (void)createCalendarEventFromW3CCompliantJSONObject:(NSString *)json{ - NSError* error; - NSDictionary* jsonDict = [NSJSONSerialization JSONObjectWithData:[json dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; - ANLogDebug(@"%@ | NSDictionary from JSON Calendar Object: %@", NSStringFromSelector(_cmd), jsonDict); +- (void)handleMRAIDURL:(NSURL *)URL { + ANLogDebug(@"Received MRAID query: %@", URL); - NSString* description = jsonDict[@"description"]; - NSString* location = jsonDict[@"location"]; - NSString* summary = jsonDict[@"summary"]; - NSString* start = jsonDict[@"start"]; - NSString* end = jsonDict[@"end"]; - NSString* status = jsonDict[@"status"]; - /* - * iOS Not supported - * NSString* transparency = jsonDict[@"transparency"]; - */ - NSString* reminder = jsonDict[@"reminder"]; + NSString *mraidCommand = [URL host]; + NSString *query = [URL query]; + NSDictionary *queryComponents = [query queryComponents]; - EKEventStore* store = [[EKEventStore alloc] init]; - [store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error){ - if(! granted) { - if (error != nil) { - ANLogWarn(error.localizedDescription); - } else { - ANLogWarn(@"Unable to create calendar event"); - } + ANMRAIDAction action = [ANMRAIDUtil actionForCommand:mraidCommand]; + switch (action) { + case ANMRAIDActionUnknown: + ANLogDebug(@"Unknown MRAID action requested: %@", mraidCommand); return; + case ANMRAIDActionExpand: + [self.adViewDelegate adWasClicked]; + [self forwardExpandRequestWithQueryComponents:queryComponents]; + break; + case ANMRAIDActionClose: + [self forwardCloseAction]; + break; + case ANMRAIDActionResize: + [self.adViewDelegate adWasClicked]; + [self forwardResizeRequestWithQueryComponents:queryComponents]; + break; + case ANMRAIDActionCreateCalendarEvent: { + [self.adViewDelegate adWasClicked]; + NSString *w3cEventJson = [queryComponents[@"p"] description]; + [self forwardCalendarEventRequestWithW3CJSONString:w3cEventJson]; + break; } - dispatch_async(dispatch_get_main_queue(), ^(void){ - EKEvent *event = [EKEvent eventWithEventStore:store]; - NSDateFormatter *df1 = [[NSDateFormatter alloc] init]; - NSDateFormatter *df2 = [[NSDateFormatter alloc] init]; - [df1 setDateFormat:@"yyyy-MM-dd'T'HH:mmZZZ"]; - [df2 setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZ"]; - - event.title=description; - event.notes=summary; - event.location=location; - event.calendar = [store defaultCalendarForNewEvents]; - - if (start) { - if([df1 dateFromString:start]!=nil){ - event.startDate = [df1 dateFromString:start]; - }else if([df2 dateFromString:start]!=nil){ - event.startDate = [df2 dateFromString:start]; - }else{ - event.startDate = [NSDate dateWithTimeIntervalSince1970:[start doubleValue]]; - } - - if([df1 dateFromString:end]!=nil){ - event.endDate = [df1 dateFromString:end]; - }else if([df2 dateFromString:end]!=nil){ - event.endDate = [df2 dateFromString:end]; - }else if (end) { - event.endDate = [NSDate dateWithTimeIntervalSince1970:[end doubleValue]]; - } else { - ANLogDebug(@"%@ | No end date provided, defaulting to 60 minutes", NSStringFromSelector(_cmd)); - event.endDate = [event.startDate dateByAddingTimeInterval:3600]; // default to 60 mins - } - - ANLogDebug(@"%@ | Event Start Date: %@, End Date: %@", NSStringFromSelector(_cmd), event.startDate, event.endDate); - } else { - ANLogWarn(@"%@ | Cannot create calendar event, no start date provided", NSStringFromSelector(_cmd)); - return; - } - - if([df1 dateFromString:reminder]!=nil){ - [event addAlarm:[EKAlarm alarmWithAbsoluteDate:[df1 dateFromString:reminder]]]; - }else if([df2 dateFromString:reminder]!=nil){ - [event addAlarm:[EKAlarm alarmWithAbsoluteDate:[df2 dateFromString:reminder]]]; - } else if (reminder) { - [event addAlarm:[EKAlarm alarmWithRelativeOffset: - ([reminder doubleValue] / 1000.0)]]; // milliseconds to seconds conversion - } - - if([status isEqualToString:@"pending"]){ - [event setAvailability:EKEventAvailabilityNotSupported]; - }else if([status isEqualToString:@"tentative"]){ - [event setAvailability:EKEventAvailabilityTentative]; - }else if([status isEqualToString:@"confirmed"]){ - [event setAvailability:EKEventAvailabilityBusy]; - }else if([status isEqualToString:@"cancelled"]){ - [event setAvailability:EKEventAvailabilityFree]; - } - - - NSDictionary* repeat = jsonDict[@"recurrence"]; - if ([repeat isKindOfClass:[NSDictionary class]]) { - NSString* frequency = repeat[@"frequency"]; - EKRecurrenceFrequency frequency_ios; - - if ([frequency isEqualToString:@"daily"]) frequency_ios = EKRecurrenceFrequencyDaily; - else if ([frequency isEqualToString:@"weekly"]) frequency_ios = EKRecurrenceFrequencyWeekly; - else if ([frequency isEqualToString:@"monthly"]) frequency_ios = EKRecurrenceFrequencyMonthly; - else if ([frequency isEqualToString:@"yearly"]) frequency_ios = EKRecurrenceFrequencyYearly; - else { - ANLogWarn(@"%@ | Invalid W3 frequency passed in: %@. Acceptable values are 'daily','weekly','monthly', and 'yearly'", NSStringFromSelector(_cmd), frequency); - return; - } - - int interval = [repeat[@"interval"] intValue]; - if (interval < 1) { - interval = 1; - } - - NSString* expires = repeat[@"expires"]; - //expires - EKRecurrenceEnd* end; - if([df1 dateFromString:expires]!=nil){ - end = [EKRecurrenceEnd recurrenceEndWithEndDate:[df1 dateFromString:expires]]; - }else if([df2 dateFromString:expires]!=nil){ - end = [EKRecurrenceEnd recurrenceEndWithEndDate:[df2 dateFromString:expires]]; - } else if(expires && [NSDate dateWithTimeIntervalSince1970:[expires doubleValue]]){ - end = [EKRecurrenceEnd recurrenceEndWithEndDate:[NSDate dateWithTimeIntervalSince1970:[expires doubleValue]]]; - } // default is to never expire - - /* - * iOS Not supported - * NSArray* exceptionDates = repeat[@"exceptionDates"]; - */ - - NSMutableArray* daysInWeek = [repeat[@"daysInWeek"] mutableCopy]; // Need a mutable copy of the array in order to transform NSNumber => EKRecurrenceDayOfWeek - - for (NSInteger daysInWeekIndex=0; daysInWeekIndex < [daysInWeek count]; daysInWeekIndex++) { - NSInteger dayInWeekValue = [daysInWeek[daysInWeekIndex] integerValue]; // W3 value should be between 0 and 6 inclusive. - if (dayInWeekValue >= 0 && dayInWeekValue <= 6) { - daysInWeek[daysInWeekIndex] = [EKRecurrenceDayOfWeek dayOfWeek:dayInWeekValue+1]; // Apple expects day of week value to be between 1 and 7 inclusive. - } else { - ANLogWarn(@"%@ | Invalid W3 day of week passed in: %d. Value should be between 0 and 6 inclusive.", NSStringFromSelector(_cmd), dayInWeekValue); - return; - } - } - - NSMutableArray* daysInMonth = nil; // Only valid for EKRecurrenceFrequencyMonthly - if (frequency_ios == EKRecurrenceFrequencyMonthly) { - NSMutableArray* daysInMonth = [repeat[@"daysInMonth"] mutableCopy]; - - for (NSInteger daysInMonthIndex=0; daysInMonthIndex < [daysInMonth count]; daysInMonthIndex++) { - NSInteger dayInMonthValue = [daysInMonth[daysInMonthIndex] integerValue]; // W3 value should be between -30 and 31 inclusive. - if (dayInMonthValue >= -30 && dayInMonthValue <= 31) { - if (dayInMonthValue <= 0) { // W3 reverse values from 0 to -30, Apple reverse values from -1 to -31 (0 and -1 meaning last day of month respectively) - daysInMonth[daysInMonthIndex] = @(dayInMonthValue-1); - } - } else { - ANLogWarn(@"%@ | Invalid W3 day of month passed in: %d. Value should be between -30 and 31 inclusive.", NSStringFromSelector(_cmd), dayInMonthValue); - return; - } - } - - NSArray* weeksInMonth = repeat[@"weeksInMonth"]; // Need to implement W3 weeksInMonth for monthly occurrences - NSMutableArray *updatedDaysInWeek = [[NSMutableArray alloc] init]; - - for (NSNumber* weekNumber in weeksInMonth) { - NSInteger weekNumberValue = [weekNumber integerValue]; - if (weekNumberValue >= -3 && weekNumberValue <= 4) { // W3 value should be between -3 and 4 inclusive. - for (EKRecurrenceDayOfWeek* day in daysInWeek) { - if (weekNumberValue <= 0) { // W3 reverse values from 0 to -3, Apple reverse values from -1 to -4 - weekNumberValue--; - } - ANLogDebug(@"%@ | Adding EKRecurrenceDayOfWeek object with day number %d and week number %d", NSStringFromSelector(_cmd), day.dayOfTheWeek, weekNumberValue); - [updatedDaysInWeek addObject:[EKRecurrenceDayOfWeek dayOfWeek:day.dayOfTheWeek weekNumber:weekNumberValue]]; - } - } else { - ANLogWarn(@"%@ | Invalid W3 week of month passed in: %d. Value should be between -3 and 4 inclusive.", NSStringFromSelector(_cmd), weekNumberValue); - return; - } - } - - daysInWeek = updatedDaysInWeek; - } - - NSArray *monthsInYear = nil; - NSMutableArray* daysInYear = nil; - - if (frequency_ios == EKRecurrenceFrequencyYearly) { - monthsInYear = repeat[@"monthsInYear"]; // Apple & W3 valid values from 1 to 12, inclusive. - - for (NSNumber *monthInYear in monthsInYear) { - NSInteger monthInYearValue = [monthInYear integerValue]; - if (monthInYearValue < 0 && monthInYearValue > 12) { - ANLogWarn(@"%@ | Invalid W3 month passed in: %d. Value should be between 1 and 12 inclusive.", NSStringFromSelector(_cmd), monthInYearValue); - return; - } - } - - daysInYear = [repeat[@"daysInYear"] mutableCopy]; - - for (NSInteger daysInYearIndex=0; daysInYearIndex < [daysInYear count]; daysInYearIndex++) { - NSInteger dayInYearValue = [daysInYear[daysInYearIndex] integerValue]; // W3 value should be between -364 and 365 inclusive. (W3 doesn't care about leap years?) - if (dayInYearValue >= -364 && dayInYearValue <= 365) { - if (dayInYearValue <= 0) { // W3 reverse values from 0 to -364, Apple reverse values from -1 to -366 - daysInYear[daysInYearIndex] = @(dayInYearValue-1); - } - } else { - ANLogWarn(@"%@ | Invalid W3 day of year passed in: %d. Value should be between -364 and 365 inclusive.", NSStringFromSelector(_cmd), dayInYearValue); - return; - } - } - } - - EKRecurrenceRule* rrule = [[EKRecurrenceRule alloc] initRecurrenceWithFrequency:frequency_ios - interval:interval - daysOfTheWeek:daysInWeek - daysOfTheMonth:daysInMonth - monthsOfTheYear:monthsInYear - weeksOfTheYear:nil - daysOfTheYear:daysInYear - setPositions:nil - end:end]; - - if (rrule) { // EKRecurrenceRule will return nil if invalid values are passed in - [event setRecurrenceRules:@[rrule]]; - ANLogDebug(@"%@ | Created Recurrence Rule: %@", NSStringFromSelector(_cmd), rrule); - } else { - ANLogWarn(@"%@ | Invalid EKRecurrenceRule Values Passed In.", NSStringFromSelector(_cmd)); - } - } - - NSError* error = nil; - [store saveEvent:event span:EKSpanThisEvent commit:YES error:&error]; - if (error) { - ANLogWarn(error.localizedDescription); + case ANMRAIDActionPlayVideo: { + [self.adViewDelegate adWasClicked]; + NSString *uri = [queryComponents[@"uri"] description]; + [self.mraidDelegate adShouldPlayVideoWithUri:uri]; + break; + } + case ANMRAIDActionStorePicture: { + [self.adViewDelegate adWasClicked]; + NSString *uri = [queryComponents[@"uri"] description]; + [self.mraidDelegate adShouldSavePictureWithUri:uri]; + break; + } + case ANMRAIDActionSetOrientationProperties: + [self forwardOrientationPropertiesWithQueryComponents:queryComponents]; + break; + case ANMRAIDActionSetUseCustomClose: { + NSString *value = [queryComponents[@"value"] description]; + BOOL useCustomClose = [value isEqualToString:@"true"]; + [self.mraidDelegate adShouldSetUseCustomClose:useCustomClose]; + break; + } + case ANMRAIDActionOpenURI: { + NSString *uri = [queryComponents[@"uri"] description]; + NSURL *URL = [NSURL URLWithString:uri]; + if (uri.length && URL) { + [self.browserDelegate openDefaultBrowserWithURL:URL]; } - }); - }]; + break; + } + case ANMRAIDActionEnable: + if (self.isMRAID) return; + self.isMRAID = YES; + if (self.completedFirstLoad) [self finishMRAIDLoad]; + break; + default: + ANLogError(@"Known but unhandled MRAID action: %@", mraidCommand); + break; + } } +- (void)forwardCloseAction { + [self.mraidDelegate adShouldClose]; +} +- (void)forwardResizeRequestWithQueryComponents:(NSDictionary *)queryComponents { + ANMRAIDResizeProperties *resizeProperties = [ANMRAIDResizeProperties resizePropertiesFromQueryComponents:queryComponents]; + [self.mraidDelegate adShouldAttemptResizeWithResizeProperties:resizeProperties]; +} -- (void)setOrientationProperties:(NSDictionary *)queryComponents -{ - NSString *allow = queryComponents[@"allow_orientation_change"]; - NSString *forcedOrientation = queryComponents[@"force_orientation"]; - - ANMRAIDOrientation mraidOrientation = ANMRAIDOrientationNone; - if ([forcedOrientation isEqualToString:@"none"]) { - mraidOrientation = ANMRAIDOrientationNone; - } else if ([forcedOrientation isEqualToString:@"portrait"]) { - mraidOrientation = ANMRAIDOrientationPortrait; - } else if ([forcedOrientation isEqualToString:@"landscape"]) { - mraidOrientation = ANMRAIDOrientationLandscape; +- (void)forwardExpandRequestWithQueryComponents:(NSDictionary *)queryComponents { + if (!self.rapidTimerSet) { + [self setupRapidTimerForCheckingPositionAndViewability]; + self.rapidTimerSet = YES; } - - [self.mraidDelegate allowOrientationChange:[allow boolValue] - withForcedOrientation:mraidOrientation]; -} - -- (void)storePicture:(NSString*)uri -{ - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSURL *url = [NSURL URLWithString:uri]; - NSData *data = [NSData dataWithContentsOfURL:url]; - if(data){ - dispatch_async(dispatch_get_main_queue(), ^{ - UIImage *image = [[UIImage alloc] initWithData:data]; - if (image) { - UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil); - } - }); - } - }); - + ANMRAIDExpandProperties *expandProperties = [ANMRAIDExpandProperties expandPropertiesFromQueryComponents:queryComponents]; + [self forwardOrientationPropertiesWithQueryComponents:queryComponents]; + [self.mraidDelegate adShouldExpandWithExpandProperties:expandProperties]; } -- (void)printConsoleLog:(NSURL *)URL { - NSString *decodedString = [[URL absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - ANLogDebug(decodedString); +- (void)forwardOrientationPropertiesWithQueryComponents:(NSDictionary *)queryComponents { + ANMRAIDOrientationProperties *orientationProperties = [ANMRAIDOrientationProperties orientationPropertiesFromQueryComponents:queryComponents]; + [self.mraidDelegate adShouldSetOrientationProperties:orientationProperties]; } -// expand close button for non-custom close is provided by SDK -- (UIButton *)expandCloseButton { - UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeCustom]; - [closeButton addTarget:self - action:@selector(closeAction:) - forControlEvents:UIControlEventTouchUpInside]; - - UIImage *closeboxImage = [UIImage imageWithContentsOfFile:ANPathForANResource(@"interstitial_closebox", @"png")]; - if (!closeboxImage) { - ANLogError(@"Could not create MRAID expand close button."); - return nil; +- (void)forwardCalendarEventRequestWithW3CJSONString:(NSString *)json { + NSError *error; + id jsonObject = [NSJSONSerialization JSONObjectWithData:[json dataUsingEncoding:NSUTF8StringEncoding] + options:kNilOptions + error:&error]; + if (!error && [jsonObject isKindOfClass:[NSDictionary class]]) { + [self.mraidDelegate adShouldOpenCalendarWithCalendarDict:(NSDictionary *)jsonObject]; } - [closeButton setImage:closeboxImage - forState:UIControlStateNormal]; - - UIImage *closeboxDown = [UIImage imageWithContentsOfFile:ANPathForANResource(@"interstitial_closebox_down", @"png")]; - if (closeboxDown) { - [closeButton setImage:closeboxDown - forState:UIControlStateHighlighted]; - } - - // setFrame here in order to pass the size dimensions along - [closeButton setFrame:CGRectMake(0, 0, closeboxImage.size.width, closeboxImage.size.height)]; - return closeButton; } -- (UIButton *)expandCloseButtonForCustomClose { - UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeCustom]; - [closeButton addTarget:self - action:@selector(closeAction:) - forControlEvents:UIControlEventTouchUpInside]; - [closeButton setFrame:CGRectMake(0, 0, 50.0, 50.0)]; - return closeButton; -} - -// resize close button is a transparent region -- (UIButton *)resizeCloseButton { - UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeCustom]; - [closeButton addTarget:self - action:@selector(closeAction:) - forControlEvents:UIControlEventTouchUpInside]; - return closeButton; +- (void)updatePlacementType:(NSString *)placementType { + if (self.isMRAID) { + [self fireJavaScript:[ANMRAIDJavascriptUtil placementType:placementType]]; + } } -#pragma mark ANMRAIDEventReceiver +#pragma mark - MRAID Callbacks - (void)adDidFinishExpand { - [self.webView fireStateChangeEvent:ANMRAIDStateExpanded]; + [self fireJavaScript:[ANMRAIDJavascriptUtil stateChange:ANMRAIDStateExpanded]]; } -- (void)adDidFinishResize:(BOOL)success errorString:(NSString *)errorString { +- (void)adDidFinishResize:(BOOL)success + errorString:(NSString *)errorString + isResized:(BOOL)isResized { if (success) { - [self.webView fireStateChangeEvent:ANMRAIDStateResized]; + [self fireJavaScript:[ANMRAIDJavascriptUtil stateChange:ANMRAIDStateResized]]; } else { - self.resized = NO; - [self.webView fireErrorEvent:errorString - function:@"mraid.resize()"]; + [self fireJavaScript:[ANMRAIDJavascriptUtil error:errorString + forFunction:@"mraid.resize()"]]; } } - (void)adDidResetToDefault { - [self.webView fireStateChangeEvent:ANMRAIDStateDefault]; + [self fireJavaScript:[ANMRAIDJavascriptUtil stateChange:ANMRAIDStateDefault]]; } -- (void)adDidChangeResizeOffset:(CGPoint)offset { - self.resizeOffset = offset; +- (void)adDidHide { + [self fireJavaScript:[ANMRAIDJavascriptUtil stateChange:ANMRAIDStateHidden]]; + [self stopWebViewLoadForDealloc]; } -#pragma mark - Pitbull Image Capture Transition Adjustments +- (void)adDidFailCalendarEditWithErrorString:(NSString *)errorString { + [self fireJavaScript:[ANMRAIDJavascriptUtil error:errorString + forFunction:@"mraid.createCalendarEvent()"]]; +} -- (void)observeValueForKeyPath:(NSString *)keyPath - ofObject:(id)object - change:(NSDictionary *)change - context:(void *)context { - if (object == self.adFetcherDelegate) { - NSNumber *transitionInProgress = change[NSKeyValueChangeNewKey]; - if ([transitionInProgress boolValue] == NO) { - [self unregisterFromPitbullScreenCaptureNotifications]; - [self dispatchPitbullScreenCaptureCalls]; - } - } +- (void)adDidFailPhotoSaveWithErrorString:(NSString *)errorString { + [self fireJavaScript:[ANMRAIDJavascriptUtil error:errorString + forFunction:@"mraid.storePicture()"]]; } -- (void)registerForPitbullScreenCaptureNotifications { - if (!self.isRegisteredForPitbullScreenCaptureNotifications) { - NSObject *object = self.adFetcherDelegate; - [object addObserver:self - forKeyPath:@"transitionInProgress" - options:NSKeyValueObservingOptionNew - context:nil]; - self.isRegisteredForPitbullScreenCaptureNotifications = YES; - } +#pragma mark - ANWebConsole + +- (void)printConsoleLogWithURL:(NSURL *)URL { + NSString *decodedString = [[URL absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + ANLogDebug(@"%@", decodedString); } -- (void)unregisterFromPitbullScreenCaptureNotifications { - NSObject *bannerObject = self.adFetcherDelegate; - if (self.isRegisteredForPitbullScreenCaptureNotifications) { - @try { - [bannerObject removeObserver:self - forKeyPath:@"transitionInProgress"]; - } - @catch (NSException * __unused exception) {} - self.isRegisteredForPitbullScreenCaptureNotifications = NO; +- (void)dealloc { + [self stopWebViewLoadForDealloc]; + [self.viewabilityTimer invalidate]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - ANAdViewInternalDelegate + +- (void)setAdViewDelegate:(id)adViewDelegate { + _adViewDelegate = adViewDelegate; + if (_adViewDelegate) { + [self fireJavaScript:[ANMRAIDJavascriptUtil placementType:[_adViewDelegate adType]]]; } } -- (void)dispatchPitbullScreenCaptureCalls { - for (NSURL *URL in self.pitbullCaptureURLQueue) { - UIView *view = self.webView; - if ([self.adFetcherDelegate respondsToSelector:@selector(containerView)]) { - view = [self.adFetcherDelegate containerView]; - } - [ANPBBuffer handleUrl:URL forView:view]; +@end + +#pragma mark - ANAdWebViewControllerConfiguration Implementation + +@implementation ANAdWebViewControllerConfiguration + +- (instancetype)init { + if (self = [super init]) { + _scrollingEnabled = NO; + _navigationTriggersDefaultBrowser = YES; + _initialMRAIDState = ANMRAIDStateDefault; } - self.pitbullCaptureURLQueue = nil; + return self; } -- (NSMutableArray *)pitbullCaptureURLQueue { - if (!_pitbullCaptureURLQueue) _pitbullCaptureURLQueue = [[NSMutableArray alloc] initWithCapacity:5]; - return _pitbullCaptureURLQueue; +- (id)copyWithZone:(NSZone *)zone { + ANAdWebViewControllerConfiguration *configurationCopy = [[ANAdWebViewControllerConfiguration alloc] init]; + configurationCopy.scrollingEnabled = self.scrollingEnabled; + configurationCopy.navigationTriggersDefaultBrowser = self.navigationTriggersDefaultBrowser; + configurationCopy.initialMRAIDState = self.initialMRAIDState; + return configurationCopy; } -@end +- (NSString *)description { + return [NSString stringWithFormat:@"(scrollingEnabled: %d, navigationTriggersDefaultBrowser: %d, initialMRAIDState: %lu", + self.scrollingEnabled, self.navigationTriggersDefaultBrowser, (long unsigned)self.initialMRAIDState]; +} +@end diff --git a/sdk/internal/ANBannerAdView.m b/sdk/internal/ANBannerAdView.m index f1e40ace4..38583fb27 100644 --- a/sdk/internal/ANBannerAdView.m +++ b/sdk/internal/ANBannerAdView.m @@ -17,56 +17,20 @@ #import ANBANNERADVIEWHEADER #import "ANAdFetcher.h" -#import "ANBrowserViewController.h" #import "ANGlobal.h" #import "ANLogging.h" -#import "ANMRAIDViewController.h" +#import "ANMRAIDContainerView.h" + #import "UIView+ANCategory.h" #import "UIWebView+ANCategory.h" #import "ANBannerAdView+ANContentViewTransitions.h" +#import "ANAdView+PrivateMethods.h" #define DEFAULT_ADSIZE CGSizeZero -@interface ANADVIEW (ANBANNERADVIEW) -- (void)initialize; -- (void)loadAd; -- (void)adDidReceiveAd; -- (void)adRequestFailedWithError:(NSError *)error; -- (void)mraidExpandAd:(CGSize)size - contentView:(UIView *)contentView - defaultParentView:(UIView *)defaultParentView - rootViewController:(UIViewController *)rootViewController; -- (void)mraidExpandAddCloseButton:(UIButton *)closeButton - containerView:(UIView *)containerView; -- (NSString *)mraidResizeAd:(CGRect)frame - contentView:(UIView *)contentView - defaultParentView:(UIView *)defaultParentView - rootViewController:(UIViewController *)rootViewController - allowOffscreen:(BOOL)allowOffscreen; -- (void)mraidResizeAddCloseEventRegion:(UIButton *)closeEventRegion - containerView:(UIView *)containerView - contentView:(UIView *)contentView - position:(ANMRAIDCustomClosePosition)position; -- (void)adShouldResetToDefault:(UIView *)contentView - parentView:(UIView *)parentView; - -- (void)loadAdFromHtml:(NSString *)html - width:(int)width height:(int)height; -- (void)removeCloseButton; - -@property (nonatomic, readwrite, strong) ANAdFetcher *adFetcher; -@property (nonatomic, readwrite, strong) ANMRAIDViewController *mraidController; -@property (nonatomic, readwrite, strong) UIButton *closeButton; -@property (nonatomic, readwrite, strong) ANBrowserViewController *browserViewController; -@property (nonatomic, readwrite, assign) CGRect defaultParentFrame; -@property (nonatomic, readwrite, assign) CGRect defaultFrame; -@property (nonatomic, readwrite, assign) CGPoint resizeOffset; -@property (nonatomic, readwrite, assign) BOOL adjustFramesInResizeState; -@end - -@interface ANBANNERADVIEW () +@interface ANBANNERADVIEW () @property (nonatomic, readwrite, strong) UIView *contentView; -@property (nonatomic, readwrite, strong) NSNumber *transitionInProgress; // Should be used by pitbull +@property (nonatomic, readwrite, strong) NSNumber *transitionInProgress; @end @implementation ANBANNERADVIEW @@ -79,7 +43,6 @@ @implementation ANBANNERADVIEW - (void)initialize { [super initialize]; - self.backgroundColor = [UIColor clearColor]; self.autoresizingMask = UIViewAutoresizingNone; // Set default autoRefreshInterval @@ -106,6 +69,7 @@ - (instancetype)initWithFrame:(CGRect)frame { if (self != nil) { [self initialize]; + self.backgroundColor = [UIColor clearColor]; } return self; @@ -180,42 +144,10 @@ - (NSTimeInterval)autoRefreshInterval { return __autoRefreshInterval; } -- (void)setFrame:(CGRect)frame { - if (self.adjustFramesInResizeState) { - CGRect adjustedFrame = CGRectMake(frame.origin.x + self.resizeOffset.x, frame.origin.y + self.resizeOffset.y, frame.size.width, frame.size.height); - [super setFrame:adjustedFrame]; - self.defaultParentFrame = CGRectMake(frame.origin.x, frame.origin.y, self.defaultParentFrame.size.width, self.defaultParentFrame.size.height); - CGFloat defaultContentWidth = self.defaultFrame.size.width; - CGFloat defaultContentHeight = self.defaultFrame.size.height; - CGFloat defaultCenterX = (self.defaultParentFrame.size.width - defaultContentWidth) / 2; - CGFloat defaultCenterY = (self.defaultParentFrame.size.height - defaultContentHeight) / 2; - self.defaultFrame = CGRectMake(defaultCenterX, defaultCenterY, defaultContentWidth, defaultContentHeight); - } else { - [super setFrame:frame]; - } -} - -- (void)setFrame:(CGRect)frame animated:(BOOL)animated { - if (animated) { - [self willResizeToFrame:frame]; - [UIView animateWithDuration:kAppNexusAnimationDuration animations:^{ - [self setFrame:frame]; - } completion:^(BOOL finished) { - [self bannerAdViewDidResize]; - }]; - } - else { - [self willResizeToFrame:frame]; - [self setFrame:frame]; - [self bannerAdViewDidResize]; - } -} - #pragma mark - Transitions - (void)setContentView:(UIView *)newContentView { if (newContentView != _contentView) { - [self removeCloseButton]; if ([newContentView isKindOfClass:[UIWebView class]]) { UIWebView *webView = (UIWebView *)newContentView; @@ -226,6 +158,16 @@ - (void)setContentView:(UIView *)newContentView { UIView *oldContentView = _contentView; _contentView = newContentView; + if ([newContentView isKindOfClass:[ANMRAIDContainerView class]]) { + ANMRAIDContainerView *standardAdView = (ANMRAIDContainerView *)newContentView; + standardAdView.adViewDelegate = self; + } + + if ([oldContentView isKindOfClass:[ANMRAIDContainerView class]]) { + ANMRAIDContainerView *standardAdView = (ANMRAIDContainerView *)oldContentView; + standardAdView.adViewDelegate = nil; + } + [self performTransitionFromContentView:oldContentView toContentView:newContentView]; } @@ -238,18 +180,6 @@ - (NSNumber *)transitionInProgress { #pragma mark Implementation of abstract methods from ANAdView -- (void)openInBrowserWithController:(ANBrowserViewController *)browserViewController { - BOOL rvcAttachedToWindow = self.rootViewController.view.window ? YES : NO; - if (rvcAttachedToWindow) { - [self adWillPresent]; - [self.rootViewController presentViewController:browserViewController animated:YES completion:^{ - [self adDidPresent]; - }]; - } else { - ANLogError(@"Cannot present in-app browser - rootViewController not set, or rootViewController not attached to window"); - } -} - - (void)loadAdFromHtml:(NSString *)html width:(int)width height:(int)height { self.adSize = CGSizeMake(width, height); @@ -316,107 +246,29 @@ - (CGSize)requestedSizeForAdFetcher:(ANAdFetcher *)fetcher { return self.adSize; } -- (UIView *)containerView { - return self; -} - -#pragma mark ANMRAIDAdViewDelegate +#pragma mark - ANAdViewInternalDelegate - (NSString *)adType { return @"inline"; } - (UIViewController *)displayController { - return self.mraidController ? self.mraidController : self.rootViewController; + return self.rootViewController; } -- (void)adShouldExpandToFrame:(CGRect)frame - closeButton:(UIButton *)closeButton { - [self resetContentViewForMRAID]; - - [super mraidExpandAd:frame.size - contentView:self.contentView - defaultParentView:self - rootViewController:self.rootViewController]; - - UIView *containerView = self.mraidController ? self.mraidController.view : self; - [super mraidExpandAddCloseButton:closeButton containerView:containerView]; - - [self.mraidEventReceiverDelegate adDidFinishExpand]; -} - -- (void)adShouldResizeToFrame:(CGRect)frame allowOffscreen:(BOOL)allowOffscreen - closeButton:(UIButton *)closeButton - closePosition:(ANMRAIDCustomClosePosition)closePosition { - [self resetContentViewForMRAID]; - - // resized ads are never modal - UIView *contentView = self.contentView; - - NSString *mraidResizeErrorString = [super mraidResizeAd:frame - contentView:contentView - defaultParentView:self - rootViewController:self.rootViewController - allowOffscreen:allowOffscreen]; - - if ([mraidResizeErrorString length] > 0) { - [self.mraidEventReceiverDelegate adDidFinishResize:NO errorString:mraidResizeErrorString]; - return; - } - - [super mraidResizeAddCloseEventRegion:closeButton - containerView:self - contentView:contentView - position:closePosition]; - - self.adjustFramesInResizeState = YES; - - // send mraid events - [self.mraidEventReceiverDelegate adDidFinishResize:YES errorString:nil]; -} - -- (void)adShouldResetToDefault { - self.adjustFramesInResizeState = NO; - [super adShouldResetToDefault:self.contentView parentView:self]; - [self constrainContentView]; -} - -- (void)resetContentViewForMRAID { - CGRect contentViewFrame = self.contentView.frame; - [self.contentView removeSizeConstraint]; - [self.contentView removeAlignmentConstraintsToSuperview]; - self.contentView.translatesAutoresizingMaskIntoConstraints = YES; - [self.contentView setFrame:contentViewFrame]; -} +#pragma mark - Deprecated -#pragma mark delegate selector helper method +- (void)setFrame:(CGRect)frame animated:(BOOL)animated { + if (animated) { + [UIView animateWithDuration:kAppNexusAnimationDuration animations:^{ + [self setFrame:frame]; + } completion:^(BOOL finished) { -- (void)willResizeToFrame:(CGRect)frame { - if ([self.delegate respondsToSelector:@selector(bannerAdView:willResizeToFrame:)]) { - [self.delegate bannerAdView:self willResizeToFrame:frame]; + }]; } -} - -- (void)bannerAdViewDidResize { - if ([self.delegate respondsToSelector:@selector(bannerAdViewDidResize:)]) { - [self.delegate bannerAdViewDidResize:self]; + else { + [self setFrame:frame]; } } -#pragma mark ANBrowserViewControllerDelegate - -- (void)browserViewControllerShouldDismiss:(ANBrowserViewController *)controller -{ - [self adWillClose]; - UIViewController *presentingViewController = controller.presentingViewController; - [presentingViewController dismissViewControllerAnimated:YES completion:^{ - self.browserViewController = nil; - [self adDidClose]; - }]; -} - -- (UIView *)viewToDisplayClickOverlay { - return self.contentView; -} - -@end +@end \ No newline at end of file diff --git a/sdk/internal/ANBrowserViewController.h b/sdk/internal/ANBrowserViewController.h index c824b5e76..f89ef4d07 100644 --- a/sdk/internal/ANBrowserViewController.h +++ b/sdk/internal/ANBrowserViewController.h @@ -19,33 +19,48 @@ @interface ANBrowserViewController : UIViewController +@property (nonatomic, readwrite, weak) IBOutlet UIToolbar *toolbar; @property (nonatomic, readwrite, weak) IBOutlet UIBarButtonItem *forwardButton; @property (nonatomic, readwrite, weak) IBOutlet UIBarButtonItem *backButton; @property (nonatomic, readwrite, weak) IBOutlet UIBarButtonItem *doneButton; @property (nonatomic, readwrite, weak) IBOutlet UIBarButtonItem *openInButton; -@property (nonatomic, readwrite, weak) IBOutlet UIWebView *webView; +@property (nonatomic, readwrite, strong) IBOutlet UIBarButtonItem *refreshButton; +@property (nonatomic, readwrite, weak) IBOutlet UIView *webViewContainerView; +@property (nonatomic, readwrite, weak) IBOutlet NSLayoutConstraint *containerViewSuperviewTopConstraint; - (IBAction)closeAction:(id)sender; - (IBAction)forwardAction:(id)sender; - (IBAction)backAction:(id)sender; - (IBAction)openInAction:(id)sender; -@property (nonatomic, readonly, assign) BOOL completedInitialLoad; -@property (nonatomic, readonly, assign, getter=isLoading) BOOL loading; +- (instancetype)initWithURL:(NSURL *)url + delegate:(id)delegate + delayPresentationForLoad:(BOOL)shouldDelayPresentation; + @property (nonatomic, readwrite, strong) NSURL *url; @property (nonatomic, readwrite, weak) id delegate; +@property (nonatomic, readonly, assign) BOOL delayPresentationForLoad; +@property (nonatomic, readonly, assign) BOOL completedInitialLoad; +@property (nonatomic, readonly, assign, getter=isLoading) BOOL loading; -- (instancetype)initWithURL:(NSURL *)url; -+ (void)launchURL:(NSURL *)url withDelegate:(id)delegate; +- (void)stopLoading; @end @protocol ANBrowserViewControllerDelegate +@required +- (UIViewController *)rootViewControllerForDisplayingBrowserViewController:(ANBrowserViewController *)controller; + @optional -- (void)browserViewControllerShouldDismiss:(ANBrowserViewController *)controller; -- (void)browserViewControllerShouldPresent:(ANBrowserViewController *)controller; -- (void)browserViewControllerWillLaunchExternalApplication; -- (void)browserViewController:(ANBrowserViewController *)controller browserIsLoading:(BOOL)isLoading; +- (void)browserViewController:(ANBrowserViewController *)controller + couldNotHandleInitialURL:(NSURL *)url; +- (void)browserViewController:(ANBrowserViewController *)controller + browserIsLoading:(BOOL)isLoading; +- (void)willPresentBrowserViewController:(ANBrowserViewController *)controller; +- (void)didPresentBrowserViewController:(ANBrowserViewController *)controller; +- (void)willDismissBrowserViewController:(ANBrowserViewController *)controller; +- (void)didDismissBrowserViewController:(ANBrowserViewController *)controller; +- (void)willLeaveApplicationFromBrowserViewController:(ANBrowserViewController *)controller; @end \ No newline at end of file diff --git a/sdk/internal/ANBrowserViewController.m b/sdk/internal/ANBrowserViewController.m index f17f975ae..e76aa45fe 100644 --- a/sdk/internal/ANBrowserViewController.m +++ b/sdk/internal/ANBrowserViewController.m @@ -14,190 +14,440 @@ */ #import "ANBrowserViewController.h" +#import #import "ANGlobal.h" #import "ANLogging.h" #import "UIWebView+ANCategory.h" +#import "UIView+ANCategory.h" +#import "ANOpenInExternalBrowserActivity.h" -@interface ANBrowserViewController () -@property (nonatomic, readwrite, strong) UIActionSheet *openInSheet; +@interface ANBrowserViewController () @property (nonatomic, readwrite, assign) BOOL completedInitialLoad; @property (nonatomic, readwrite, assign, getter=isLoading) BOOL loading; +@property (nonatomic, readwrite, strong) UIWebView *webView; +@property (nonatomic, readwrite, strong) UIBarButtonItem *refreshIndicatorItem; +@property (nonatomic, readwrite, strong) UIPopoverController *activityPopover; +@property (nonatomic, readwrite, strong) SKStoreProductViewController *iTunesStoreController; + +@property (nonatomic, readwrite, assign, getter=isPresented) BOOL presented; +@property (nonatomic, readwrite, assign, getter=isPresenting) BOOL presenting; +@property (nonatomic, readwrite, assign, getter=isDismissing) BOOL dismissing; +@property (nonatomic, readwrite, strong) NSOperation *postPresentingOperation; +@property (nonatomic, readwrite, strong) NSOperation *postDismissingOperation; + +@property (nonatomic, readwrite, assign) BOOL userDidDismiss; +@property (nonatomic, readwrite, assign) BOOL receivedInitialRequest; + @end @implementation ANBrowserViewController -- (instancetype)initWithURL:(NSURL *)url { +- (instancetype)initWithURL:(NSURL *)url + delegate:(id)delegate + delayPresentationForLoad:(BOOL)shouldDelayPresentation { if (!ANPathForANResource(NSStringFromClass([self class]), @"nib")) { ANLogError(@"Could not instantiate browser controller because of missing NIB file"); return nil; } - self = [super initWithNibName:NSStringFromClass([self class]) bundle:ANResourcesBundle()]; + self = [super initWithNibName:NSStringFromClass([self class]) + bundle:ANResourcesBundle()]; if (self) { _url = url; - [self.view description]; // A call to self.view is needed for the webView to be created and the load to begin + _delegate = delegate; + _delayPresentationForLoad = shouldDelayPresentation; + [self.webView loadRequest:ANBasicRequestWithURL(url)]; } - - return self; + return self; +} + +- (void)setUrl:(NSURL *)url { + if (![[url absoluteString] isEqualToString:[_url absoluteString]] || (!self.loading && !self.completedInitialLoad)) { + _url = url; + [self resetBrowser]; + [self.webView loadRequest:ANBasicRequestWithURL(url)]; + } else { + ANLogWarn(@"In-app browser ignoring request to load - request is already loading"); + } +} + +# pragma mark - Lifecycle callbacks + +- (void)viewDidLoad { + [super viewDidLoad]; + [self refreshButtons]; + [self addWebViewToContainerView]; + [self setupToolbar]; +} + +- (void)dealloc { + [self resetBrowser]; + self.webView.delegate = nil; + self.iTunesStoreController.delegate = nil; } -+ (NSURLRequest *)requestForURL:(NSURL *)URL { - NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL - cachePolicy:NSURLRequestReloadIgnoringLocalCacheData - timeoutInterval:kAppNexusRequestTimeoutInterval]; - [request setValue:ANUserAgent() forHTTPHeaderField:@"User-Agent"]; - return [request copy]; +- (void)resetBrowser { + self.completedInitialLoad = NO; + self.loading = NO; + self.receivedInitialRequest = NO; + self.webView = nil; } -+ (void)launchURL:(NSURL *)url withDelegate:(id)delegate { - ANBrowserViewController *controller = [[ANBrowserViewController alloc] initWithURL:url]; - controller.delegate = delegate; - if ([controller.delegate respondsToSelector:@selector(browserViewControllerShouldPresent:)]) { - [controller.delegate browserViewControllerShouldPresent:controller]; +- (void)setupToolbar { + if (![self respondsToSelector:@selector(modalPresentationCapturesStatusBarAppearance)]) { + UIImage *backArrow = [UIImage imageWithContentsOfFile:ANPathForANResource(@"UIButtonBarArrowLeft", @"png")]; + UIImage *forwardArrow = [UIImage imageWithContentsOfFile:ANPathForANResource(@"UIButtonBarArrowRight", @"png")]; + [self.backButton setImage:backArrow]; + [self.forwardButton setImage:forwardArrow]; + + self.backButton.tintColor = [UIColor whiteColor]; + self.forwardButton.tintColor = [UIColor whiteColor]; + self.openInButton.tintColor = [UIColor whiteColor]; + self.refreshButton.tintColor = nil; + self.doneButton.tintColor = nil; } } -- (IBAction)closeAction:(id)sender { - [self.openInSheet dismissWithClickedButtonIndex:1 animated:NO]; - if ([self.delegate respondsToSelector:@selector(browserViewControllerShouldDismiss:)]) { - [self.delegate browserViewControllerShouldDismiss:self]; +#pragma mark - Adjust for status bar + +- (void)viewWillLayoutSubviews { + CGFloat containerViewDistanceToTopOfSuperview; + if ([self respondsToSelector:@selector(modalPresentationCapturesStatusBarAppearance)]) { + CGSize statusBarFrameSize = [[UIApplication sharedApplication] statusBarFrame].size; + containerViewDistanceToTopOfSuperview = statusBarFrameSize.height; + if (statusBarFrameSize.height > statusBarFrameSize.width) { + containerViewDistanceToTopOfSuperview = statusBarFrameSize.width; + } + } else { + containerViewDistanceToTopOfSuperview = 0; } + + self.containerViewSuperviewTopConstraint.constant = containerViewDistanceToTopOfSuperview; +} + +#pragma mark - User Actions + +- (IBAction)closeAction:(id)sender { + self.userDidDismiss = YES; + [self rootViewControllerShouldDismissPresentedViewController]; } - (IBAction)forwardAction:(id)sender { - [self.webView goForward]; + [self.webView goForward]; } - (IBAction)backAction:(id)sender { - [self.webView goBack]; + [self.webView goBack]; } - (IBAction)openInAction:(id)sender { - self.openInSheet = [[UIActionSheet alloc] - initWithTitle:NSLocalizedString(@"Open In Browser", @"Title: Open in browser option") - delegate:self - cancelButtonTitle:NSLocalizedString(@"Cancel", @"Title: Cancel button") - destructiveButtonTitle:nil - otherButtonTitles:@"Open In External Browser", nil]; - - [self.openInSheet showFromBarButtonItem:sender animated:YES]; + NSURL *webViewURL = self.webView.request.URL; + if (webViewURL.absoluteString.length) { + NSArray *appActivities = @[[[ANOpenInExternalBrowserActivity alloc] init]]; + UIActivityViewController *share = [[UIActivityViewController alloc] initWithActivityItems:@[webViewURL] + applicationActivities:appActivities]; + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { + self.activityPopover = [[UIPopoverController alloc] initWithContentViewController:share]; + [self.activityPopover presentPopoverFromBarButtonItem:self.openInButton + permittedArrowDirections:UIPopoverArrowDirectionAny + animated:YES]; + } else { + [self presentViewController:share + animated:YES + completion:nil]; + } + } } -- (void)viewDidLoad { - [super viewDidLoad]; - [self refreshButtons]; - [self.webView loadRequest:[[self class] requestForURL:self.url]]; +- (IBAction)refresh:(id)sender { + [self.webView reload]; } -- (void)viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; - [self.webView stopLoading]; +- (void)refreshButtons { + self.backButton.enabled = self.webView.canGoBack; + self.forwardButton.enabled = self.webView.canGoForward; } -- (void)refreshButtons { - self.backButton.enabled = [self.webView canGoBack]; - self.forwardButton.enabled = [self.webView canGoForward]; +#pragma mark - Presentation Methods + +- (void)rootViewControllerShouldPresentBrowserViewController { + [self rootViewControllerShouldPresentViewController:self]; } -- (void)setWebView:(UIWebView *)webView { - _webView = webView; - [webView setMediaProperties]; +- (void)rootViewControllerShouldPresentStoreViewController { + [self rootViewControllerShouldPresentViewController:self.iTunesStoreController]; } -- (void)dealloc { - self.webView.delegate = nil; - [self.webView stopLoading]; +- (void)rootViewControllerShouldPresentViewController:(UIViewController *)controllerToPresent { + if (self.isPresenting || self.isPresented || self.userDidDismiss) { + return; + } + if (self.isDismissing) { + ANLogDebug(@"In-app browser dismissal in progress - will present after dismiss"); + __weak ANBrowserViewController *weakSelf = self; + self.postDismissingOperation = [NSBlockOperation blockOperationWithBlock:^{ + ANBrowserViewController *strongSelf = weakSelf; + [strongSelf rootViewControllerShouldPresentViewController:controllerToPresent]; + }]; + return; + } + + UIViewController *rvc = [self.delegate rootViewControllerForDisplayingBrowserViewController:self]; + if (!ANCanPresentFromViewController(rvc)) { + ANLogDebug(@"No root view controller provided, or root view controller view not attached to window - could not present in-app browser"); + return; + } + + self.presenting = YES; + if ([self.delegate respondsToSelector:@selector(willPresentBrowserViewController:)]) { + [self.delegate willPresentBrowserViewController:self]; + } + __weak ANBrowserViewController *weakSelf = self; + [rvc presentViewController:controllerToPresent animated:YES completion:^{ + ANBrowserViewController *strongSelf = weakSelf; + if ([strongSelf.delegate respondsToSelector:@selector(didPresentBrowserViewController:)]) { + [strongSelf.delegate didPresentBrowserViewController:strongSelf]; + } + strongSelf.presenting = NO; + strongSelf.presented = YES; + }]; } -- (void)setUrl:(NSURL *)url { - if (![[url absoluteString] isEqualToString:[_url absoluteString]] || (!self.loading && !self.completedInitialLoad)) { - _url = url; - [self.webView stopLoading]; - self.completedInitialLoad = NO; - [self.webView loadRequest:[[self class] requestForURL:url]]; - } else { - ANLogWarn(@"In-app browser ignoring request to load - request is already loading"); +- (void)rootViewControllerShouldDismissPresentedViewController { + if (self.isDismissing || (!self.isPresented && !self.isPresenting)) { + return; + } + if (self.isPresenting) { + ANLogDebug(@"In-app browser presentation in progress - will dismiss after present"); + __weak ANBrowserViewController *weakSelf = self; + self.postPresentingOperation = [NSBlockOperation blockOperationWithBlock:^{ + ANBrowserViewController *strongSelf = weakSelf; + [strongSelf rootViewControllerShouldDismissPresentedViewController]; + }]; + return; + } + + UIViewController *controllerForDismissingModalView = self.iTunesStoreController.presentingViewController; + if (self.presentingViewController) { + controllerForDismissingModalView = self.presentingViewController; + } + + if (self.activityPopover.popoverVisible) { + [self.activityPopover dismissPopoverAnimated:NO]; } + + [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; + + self.dismissing = YES; + if ([self.delegate respondsToSelector:@selector(willDismissBrowserViewController:)]) { + [self.delegate willDismissBrowserViewController:self]; + } + __weak ANBrowserViewController *weakSelf = self; + [controllerForDismissingModalView dismissViewControllerAnimated:YES completion:^{ + ANBrowserViewController *strongSelf = weakSelf; + if ([strongSelf.delegate respondsToSelector:@selector(didDismissBrowserViewController:)]) { + [strongSelf.delegate didDismissBrowserViewController:strongSelf]; + } + strongSelf.dismissing = NO; + strongSelf.presented = NO; + }]; +} + +- (void)setPresenting:(BOOL)presenting { + _presenting = presenting; + if (!_presenting && self.postPresentingOperation) { + [[NSOperationQueue mainQueue] addOperation:self.postPresentingOperation]; + self.postPresentingOperation = nil; + } +} + +- (void)setDismissing:(BOOL)dismissing { + _dismissing = dismissing; + if (!_dismissing && self.postDismissingOperation) { + [[NSOperationQueue mainQueue] addOperation:self.postDismissingOperation]; + self.postDismissingOperation = nil; + } +} + +#pragma mark - UIWebViewDelegate + +- (UIWebView *)webView { + if (!_webView) { + _webView = [[UIWebView alloc] init]; + _webView.delegate = self; + _webView.scalesPageToFit = YES; + [_webView setMediaProperties]; + } + return _webView; } -#pragma mark UIWebViewDelegate +- (void)addWebViewToContainerView { + [self.webViewContainerView addSubview:self.webView]; + self.webView.translatesAutoresizingMaskIntoConstraints = NO; + [self.webView constrainToSizeOfSuperview]; + [self.webView alignToSuperviewWithXAttribute:NSLayoutAttributeLeft + yAttribute:NSLayoutAttributeTop]; +} - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { - [self handleWebViewLoadingChange]; NSURL *URL = [request URL]; - - if (hasHttpPrefix([URL scheme])) { - return YES; + NSNumber *iTunesId = ANiTunesIDForURL(URL); + BOOL shouldStartLoadWithRequest = NO; + + if (iTunesId) { + [webView stopLoading]; + [self loadAndPresentStoreControllerWithiTunesId:iTunesId]; + } else if (hasHttpPrefix([URL scheme])) { + if (!self.presented && !self.presenting && !self.delayPresentationForLoad) { + [self rootViewControllerShouldPresentBrowserViewController]; + } + shouldStartLoadWithRequest = YES; } else if ([[UIApplication sharedApplication] canOpenURL:URL]) { - if ([self.delegate respondsToSelector:@selector(browserViewControllerShouldDismiss:)]) { - [self.delegate browserViewControllerShouldDismiss:self]; + if (!self.completedInitialLoad) { + [self rootViewControllerShouldDismissPresentedViewController]; } - if ([self.delegate respondsToSelector:@selector(browserViewControllerWillLaunchExternalApplication)]) { - [self.delegate browserViewControllerWillLaunchExternalApplication]; + if ([self.delegate respondsToSelector:@selector(willLeaveApplicationFromBrowserViewController:)]) { + [self.delegate willLeaveApplicationFromBrowserViewController:self]; } ANLogDebug(@"%@ | Opening URL in external application: %@", NSStringFromSelector(_cmd), URL); [webView stopLoading]; [[UIApplication sharedApplication] openURL:URL]; - return NO; } else { - ANLogWarn(ANErrorString(@"opening_url_failed", URL)); - return NO; + ANLogWarn(@"opening_url_failed %@", URL); + if (!self.receivedInitialRequest) { + if ([self.delegate respondsToSelector:@selector(browserViewController:couldNotHandleInitialURL:)]) { + [self.delegate browserViewController:self couldNotHandleInitialURL:URL]; + } + } } + + if (shouldStartLoadWithRequest) { + [self updateLoadingStateForStartLoad]; + } + + self.receivedInitialRequest = YES; + + return shouldStartLoadWithRequest; } - (void)webViewDidStartLoad:(UIWebView *)webView { - [self handleWebViewLoadingChange]; - [self refreshButtons]; + [self updateLoadingStateForStartLoad]; } - (void)webViewDidFinishLoad:(UIWebView *)webView { - [self handleWebViewLoadingChange]; + [self updateLoadingStateForFinishLoad]; if (!self.completedInitialLoad) { self.completedInitialLoad = YES; - if ([self.delegate respondsToSelector:@selector(browserViewControllerShouldPresent:)]) { - [self.delegate browserViewControllerShouldPresent:self]; + if (!self.presented) { + [self rootViewControllerShouldPresentBrowserViewController]; } } - [self refreshButtons]; } - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { - [self handleWebViewLoadingChange]; + ANLogWarn(@"In-app browser received error: %@", error); + [self updateLoadingStateForFinishLoad]; +} + +- (void)loadingStateDidChangeFromOldValue:(BOOL)oldValue toNewValue:(BOOL)newValue { + if (oldValue != newValue) { + if ([self.delegate respondsToSelector:@selector(browserViewController:browserIsLoading:)]) { + [self.delegate browserViewController:self + browserIsLoading:newValue]; + } + } +} + +- (void)updateLoadingStateForStartLoad { + BOOL oldValue = self.loading; + self.loading = self.webView.loading; + [self loadingStateDidChangeFromOldValue:oldValue toNewValue:self.loading]; + [self refreshToolbarActivityIndicator]; [self refreshButtons]; - ANLogWarn(@"In-app browser failed with error: %@", error); } -- (void)handleWebViewLoadingChange { +- (void)updateLoadingStateForFinishLoad { BOOL oldValue = self.loading; self.loading = self.webView.loading; - if (oldValue != self.loading && [self.delegate respondsToSelector:@selector(browserViewController:browserIsLoading:)]) { - [self.delegate browserViewController:self - browserIsLoading:self.loading]; + if (self.loading) { + NSString *readyState = [self.webView stringByEvaluatingJavaScriptFromString:@"document.readyState"]; + if ([readyState isEqualToString:@"complete"]) { + self.loading = NO; + } } + [self loadingStateDidChangeFromOldValue:oldValue toNewValue:self.loading]; + [self refreshToolbarActivityIndicator]; + [self refreshButtons]; } -#pragma mark UIActionSheetDelegate +- (void)refreshToolbarActivityIndicator { + NSMutableArray *toolbarItems = [self.toolbar.items mutableCopy]; + NSUInteger refreshItemIndex = [toolbarItems indexOfObject:self.refreshButton]; + if (refreshItemIndex == NSNotFound) { + refreshItemIndex = [toolbarItems indexOfObject:self.refreshIndicatorItem]; + } + if (refreshItemIndex != NSNotFound) { + if (self.loading) { + [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; + toolbarItems[refreshItemIndex] = self.refreshIndicatorItem; + } else { + [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; + toolbarItems[refreshItemIndex] = self.refreshButton; + } + [self.toolbar setItems:[toolbarItems copy] animated:NO]; + } +} -- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { - if (buttonIndex == 0) { - NSURL *URL = self.webView.request.URL; - - if ([[UIApplication sharedApplication] canOpenURL:URL]) { - if ([self.delegate respondsToSelector:@selector(browserViewControllerShouldDismiss:)]) { - [self.delegate browserViewControllerShouldDismiss:self]; - } - if ([self.delegate respondsToSelector:@selector(browserViewControllerWillLaunchExternalApplication)]) { - [self.delegate browserViewControllerWillLaunchExternalApplication]; - } - [[UIApplication sharedApplication] openURL:URL]; - } - } +- (UIBarButtonItem *)refreshIndicatorItem { + if (!_refreshIndicatorItem) { + UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; + [indicator startAnimating]; + _refreshIndicatorItem = [[UIBarButtonItem alloc] initWithCustomView:indicator]; + } + return _refreshIndicatorItem; } -- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex { - if (actionSheet == self.openInSheet) { - self.openInSheet = nil; - } +- (void)stopLoading { + [self.webView stopLoading]; + [self updateLoadingStateForFinishLoad]; } -@end +#pragma mark - SKStoreProductViewController + +- (void)loadAndPresentStoreControllerWithiTunesId:(NSNumber *)iTunesId { + if (iTunesId) { + self.iTunesStoreController = [[SKStoreProductViewController alloc] init]; + self.iTunesStoreController.delegate = self; + [self.iTunesStoreController loadProductWithParameters:@{SKStoreProductParameterITunesItemIdentifier:iTunesId} + completionBlock:nil]; + if (self.isPresenting) { + self.postPresentingOperation = [NSBlockOperation blockOperationWithBlock:^{ + [self presentStoreViewController]; + }]; + return; + } else if (self.isDismissing) { + self.postDismissingOperation = [NSBlockOperation blockOperationWithBlock:^{ + [self presentStoreViewController]; + }]; + return; + } + [self presentStoreViewController]; + } +} + +- (void)presentStoreViewController { + if (self.isPresented) { + [self presentViewController:self.iTunesStoreController + animated:YES + completion:nil]; + } else { + [self rootViewControllerShouldPresentStoreViewController]; + } +} + +- (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController { + self.userDidDismiss = YES; + [self rootViewControllerShouldDismissPresentedViewController]; +} + +@end \ No newline at end of file diff --git a/sdk/internal/ANClickOverlayView.h b/sdk/internal/ANClickOverlayView.h index 14db35a3c..84ee02487 100644 --- a/sdk/internal/ANClickOverlayView.h +++ b/sdk/internal/ANClickOverlayView.h @@ -25,6 +25,6 @@ typedef NS_ENUM(NSUInteger, ANClickOverlayColorOption) { @interface ANClickOverlayView : UIView -+ (ANClickOverlayView *)overlayForView:(UIView *)view; ++ (ANClickOverlayView *)addOverlayToView:(UIView *)view; @end \ No newline at end of file diff --git a/sdk/internal/ANClickOverlayView.m b/sdk/internal/ANClickOverlayView.m index 384d47e81..f994a8b38 100644 --- a/sdk/internal/ANClickOverlayView.m +++ b/sdk/internal/ANClickOverlayView.m @@ -15,6 +15,8 @@ #import "ANClickOverlayView.h" +#import "UIView+ANCategory.h" + #define OVERLAY_LARGE CGSizeMake(100.0, 70.0) #define OVERLAY_MEDIUM CGSizeMake(50.0, 35.0) @@ -28,28 +30,64 @@ - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setBackgroundColor:[UIColor clearColor]]; + [self addIndicatorView]; } return self; } -+ (ANClickOverlayView *)overlayForView:(UIView *)view { - CGSize overlaySize = OVERLAY_LARGE; - if (CGRectGetHeight(view.bounds) <= OVERLAY_LARGE.height) { - overlaySize = OVERLAY_MEDIUM; - } - CGFloat originX = CGRectGetMidX(view.bounds) - 0.5 * overlaySize.width; - CGFloat originY = CGRectGetMidY(view.bounds) - 0.5 * overlaySize.height; - ANClickOverlayView *overlay = [[ANClickOverlayView alloc] initWithFrame:CGRectMake(originX, originY, overlaySize.width, overlaySize.height)]; ++ (ANClickOverlayView *)addOverlayToView:(UIView *)view { + ANClickOverlayView *overlay = [[ANClickOverlayView alloc] init]; + [view addSubview:overlay]; + overlay.translatesAutoresizingMaskIntoConstraints = NO; + NSLayoutConstraint *heightSuperviewRelation = [NSLayoutConstraint constraintWithItem:overlay + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationLessThanOrEqual + toItem:view + attribute:NSLayoutAttributeHeight + multiplier:1.0 + constant:0.0]; + NSLayoutConstraint *maxHeight = [NSLayoutConstraint constraintWithItem:overlay + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationLessThanOrEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1.0 + constant:OVERLAY_LARGE.height]; + NSLayoutConstraint *minHeight = [NSLayoutConstraint constraintWithItem:overlay + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1.0 + constant:OVERLAY_MEDIUM.height]; + NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:overlay + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:view + attribute:NSLayoutAttributeHeight + multiplier:0.9 + constant:0.0]; + height.priority = UILayoutPriorityDefaultLow; + NSLayoutConstraint *aspectRatio = [NSLayoutConstraint constraintWithItem:overlay + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:overlay + attribute:NSLayoutAttributeHeight + multiplier:1.5 + constant:0.0]; + [view addConstraints:@[heightSuperviewRelation, maxHeight, minHeight, aspectRatio,height]]; + [overlay alignToSuperviewWithXAttribute:NSLayoutAttributeCenterX + yAttribute:NSLayoutAttributeCenterY]; return overlay; } - (void)addIndicatorView { UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; - CGFloat originX = CGRectGetMidX(self.bounds) - 0.5 * CGRectGetWidth(indicator.bounds); - CGFloat originY = CGRectGetMidY(self.bounds) - 0.5 * CGRectGetHeight(indicator.bounds); - indicator.frame = CGRectMake(originX, originY, CGRectGetWidth(indicator.bounds), CGRectGetHeight(indicator.bounds)); [indicator startAnimating]; [self addSubview:indicator]; + indicator.translatesAutoresizingMaskIntoConstraints = NO; + [indicator alignToSuperviewWithXAttribute:NSLayoutAttributeCenterX + yAttribute:NSLayoutAttributeCenterY]; } - (UIColor *)colorForColorOption:(ANClickOverlayColorOption)option withAlpha:(CGFloat)alpha { @@ -80,8 +118,6 @@ - (void)drawRect:(CGRect)rect { [bkColor setFill]; [roundedRect fillWithBlendMode:kCGBlendModeNormal alpha:1.0]; - - [self addIndicatorView]; } @end \ No newline at end of file diff --git a/sdk/internal/ANGlobal.h b/sdk/internal/ANGlobal.h index 84d95e9f1..9260ef99e 100644 --- a/sdk/internal/ANGlobal.h +++ b/sdk/internal/ANGlobal.h @@ -35,7 +35,7 @@ #define AN_ERROR_TABLE @"errors" #define AN_DEFAULT_PLACEMENT_ID @"default_placement_id" -#define AN_SDK_VERSION @"2.0" +#define AN_SDK_VERSION @"2.1" #define APPNEXUS_BANNER_SIZE CGSizeMake(320, 50) #define APPNEXUS_MEDIUM_RECT_SIZE CGSizeMake(300, 250) @@ -50,6 +50,8 @@ #define kAppNexusMRAIDCheckViewableFrequency 1.0 #define kAppNexusBannerAdTransitionDefaultDuration 1.0 #define kAppNexusNativeAdImageDownloadTimeoutInterval 10.0 +#define kAppNexusNativeAdCheckViewabilityForTrackingFrequency 0.25 +#define kAppNexusNativeAdIABShouldBeViewableForTrackingDuration 1.0 // Banner AutoRefresh @@ -85,8 +87,8 @@ NSString *ANDeviceModel(void); BOOL ANAdvertisingTrackingEnabled(void); BOOL isFirstLaunch(void); NSString *ANUDID(void); -NSString *ANErrorString(NSString *key, ...); -NSError *ANError(NSString *key, NSInteger code, ...); +NSString *ANErrorString(NSString *key); +NSError *ANError(NSString *key, NSInteger code, ...) NS_FORMAT_FUNCTION(1,3); NSBundle *ANResourcesBundle(); NSString *ANPathForANResource(NSString *name, NSString *type); NSString *convertToNSString(id value); @@ -98,3 +100,11 @@ void ANAddInvalidNetwork(NSString *network); void ANSetNotificationsEnabled(BOOL enabled); void ANPostNotifications(NSString *name, id object, NSDictionary *userInfo); CGRect ANPortraitScreenBounds(); +NSURLRequest *ANBasicRequestWithURL(NSURL *URL); +NSMutableURLRequest *ANBasicMutableRequest(); +NSNumber *ANiTunesIDForURL(NSURL *URL); +BOOL ANCanPresentFromViewController(UIViewController *viewController); + +@interface ANGlobal : NSObject + +@end diff --git a/sdk/internal/ANGlobal.m b/sdk/internal/ANGlobal.m index aeb013f52..1745d784d 100644 --- a/sdk/internal/ANGlobal.m +++ b/sdk/internal/ANGlobal.m @@ -96,23 +96,22 @@ BOOL isFirstLaunch() return udidComponent; } -NSString *ANErrorString(NSString *key, ...) { - NSString *localizedDescription = NSLocalizedStringFromTableInBundle(key, AN_ERROR_TABLE, ANResourcesBundle(), @""); - if (localizedDescription) { - va_list args; - va_start(args, key); - localizedDescription = [[NSString alloc] initWithFormat:localizedDescription - arguments:args]; - va_end(args); - } - return localizedDescription; +NSString *ANErrorString(NSString *key) { + return NSLocalizedStringFromTableInBundle(key, AN_ERROR_TABLE, ANResourcesBundle(), @""); } NSError *ANError(NSString *key, NSInteger code, ...) { NSDictionary *errorInfo = nil; va_list args; va_start(args, code); - NSString *localizedDescription = ANErrorString(key, args); + NSString *localizedDescription = ANErrorString(key); + if (localizedDescription) { + localizedDescription = [[NSString alloc] initWithFormat:localizedDescription + arguments:args]; + } else { + ANLogWarn(@"Could not find localized error string for key %@", key); + localizedDescription = @""; + } va_end(args); errorInfo = @{NSLocalizedDescriptionKey: localizedDescription}; return [NSError errorWithDomain:AN_ERROR_DOMAIN @@ -123,9 +122,11 @@ BOOL isFirstLaunch() NSBundle *ANResourcesBundle() { static dispatch_once_t resBundleToken; static NSBundle *resBundle; + static ANGlobal *globalInstance; dispatch_once(&resBundleToken, ^{ - NSString *resBundlePath = [[NSBundle mainBundle] pathForResource:AN_RESOURCE_BUNDLE ofType:@"bundle"]; - resBundle = resBundlePath ? [NSBundle bundleWithPath:resBundlePath] : [NSBundle mainBundle]; + globalInstance = [[ANGlobal alloc] init]; + NSString *resBundlePath = [[NSBundle bundleForClass:[globalInstance class]] pathForResource:AN_RESOURCE_BUNDLE ofType:@"bundle"]; + resBundle = resBundlePath ? [NSBundle bundleWithPath:resBundlePath] : [NSBundle bundleForClass:[globalInstance class]]; }); return resBundle; } @@ -246,4 +247,42 @@ CGRect ANPortraitScreenBounds() { } } return screenBounds; -} \ No newline at end of file +} + +NSURLRequest *ANBasicRequestWithURL(NSURL *URL) { + NSMutableURLRequest *request = ANBasicMutableRequest(); + request.URL = URL; + return [request copy]; +} + +NSMutableURLRequest *ANBasicMutableRequest() { + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:nil + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:kAppNexusRequestTimeoutInterval]; + [request setValue:ANUserAgent() forHTTPHeaderField:@"User-Agent"]; + return request; +} + +NSNumber *ANiTunesIDForURL(NSURL *URL) { + if ([URL.host isEqualToString:@"itunes.apple.com"]) { + NSRegularExpression *idPattern = [[NSRegularExpression alloc] initWithPattern:@"id(\\d+)" + options:0 + error:nil]; + NSRange idRange = [idPattern rangeOfFirstMatchInString:URL.absoluteString + options:0 + range:NSMakeRange(0, URL.absoluteString.length)]; + if (idRange.length != 0) { + NSString *idString = [[URL.absoluteString substringWithRange:idRange] substringFromIndex:2]; + return @([idString longLongValue]); + } + } + return nil; +} + +BOOL ANCanPresentFromViewController(UIViewController *viewController) { + return viewController.view.window != nil ? YES : NO; +} + +@implementation ANGlobal + +@end diff --git a/sdk/internal/ANInterstitialAd.m b/sdk/internal/ANInterstitialAd.m index 799d4ca21..439c661a7 100644 --- a/sdk/internal/ANInterstitialAd.m +++ b/sdk/internal/ANInterstitialAd.m @@ -17,13 +17,13 @@ #import ANINTERSTITIALADHEADER #import "ANAdFetcher.h" -#import "ANBrowserViewController.h" #import "ANGlobal.h" #import "ANInterstitialAdViewController.h" #import "ANLogging.h" -#import "ANMRAIDViewController.h" +#import "ANAdView+PrivateMethods.h" #import "ANPBBuffer.h" #import "ANPBContainerView.h" +#import "ANMRAIDContainerView.h" #define AN_INTERSTITIAL_AD_TIMEOUT 60.0 @@ -39,36 +39,7 @@ NSString *const kANInterstitialAdViewDateLoadedKey = @"kANInterstitialAdViewDateLoadedKey"; NSString *const kANInterstitialAdViewAuctionInfoKey = @"kANInterstitialAdViewAuctionInfoKey"; -@interface ANADVIEW (ANINTERSTITIALAD) -- (void)initialize; -- (void)loadAd; -- (void)adDidReceiveAd; -- (void)adRequestFailedWithError:(NSError *)error; -- (void)mraidExpandAd:(CGSize)size - contentView:(UIView *)contentView - defaultParentView:(UIView *)defaultParentView - rootViewController:(UIViewController *)rootViewController; -- (void)mraidExpandAddCloseButton:(UIButton *)closeButton - containerView:(UIView *)containerView; -- (NSString *)mraidResizeAd:(CGRect)frame - contentView:(UIView *)contentView - defaultParentView:(UIView *)defaultParentView - rootViewController:(UIViewController *)rootViewController - allowOffscreen:(BOOL)allowOffscreen; -- (void)mraidResizeAddCloseEventRegion:(UIButton *)closeEventRegion - containerView:(UIView *)containerView - contentView:contentView - position:(ANMRAIDCustomClosePosition)position; -- (void)adShouldResetToDefault:(UIView *)contentView - parentView:(UIView *)parentView; - -@property (nonatomic, readwrite, strong) ANAdFetcher *adFetcher; -@property (nonatomic, readwrite, strong) ANMRAIDViewController *mraidController; -@property (nonatomic, readwrite, strong) ANBrowserViewController *browserViewController; - -@end - -@interface ANINTERSTITIALAD () +@interface ANINTERSTITIALAD () @property (nonatomic, readwrite, strong) ANInterstitialAdViewController *controller; @property (nonatomic, readwrite, strong) NSMutableArray *precachedAdObjects; @@ -77,20 +48,15 @@ @interface ANINTERSTITIALAD () @end @implementation ANINTERSTITIALAD -@synthesize controller = __controller; -@synthesize precachedAdObjects = __precachedAdObjects; -@synthesize delegate = __delegate; -@synthesize frame = __frame; -@synthesize allowedAdSizes = __allowedAdSizes; #pragma mark Initialization - (void)initialize { [super initialize]; - __controller = [[ANInterstitialAdViewController alloc] init]; - __controller.delegate = self; - __precachedAdObjects = [NSMutableArray array]; - __allowedAdSizes = [self getDefaultAllowedAdSizes]; + _controller = [[ANInterstitialAdViewController alloc] init]; + _controller.delegate = self; + _precachedAdObjects = [NSMutableArray array]; + _allowedAdSizes = [self getDefaultAllowedAdSizes]; _closeDelay = kANInterstitialDefaultCloseButtonDelay; } @@ -116,6 +82,14 @@ - (void)displayAdFromViewController:(UIViewController *)controller { id adToShow = nil; NSString *auctionID = nil; + self.controller.orientationProperties = nil; + self.controller.useCustomClose = NO; + + if ([self.controller.contentView isKindOfClass:[ANMRAIDContainerView class]]) { + ANMRAIDContainerView *mraidContainerView = (ANMRAIDContainerView *)self.controller.contentView; + mraidContainerView.adViewDelegate = nil; + } + while ([self.precachedAdObjects count] > 0) { // Pull the first ad off NSDictionary *adDict = self.precachedAdObjects[0]; @@ -140,6 +114,12 @@ - (void)displayAdFromViewController:(UIViewController *)controller { ANLogError(@"Could not present interstitial because of a nil interstitial controller. This happens because of ANSDK resources missing from the app bundle."); return; } + if ([adToShow isKindOfClass:[ANMRAIDContainerView class]]) { + ANMRAIDContainerView *mraidContainerView = (ANMRAIDContainerView *)adToShow; + mraidContainerView.adViewDelegate = self; + mraidContainerView.embeddedInModalView = YES; + } + self.controller.contentView = adToShow; if (self.backgroundColor) { self.controller.backgroundColor = self.backgroundColor; @@ -235,17 +215,6 @@ - (void)setCloseDelay:(NSTimeInterval)closeDelay { _closeDelay = closeDelay; } -#pragma mark Implementation of Abstract methods from ANAdView - -- (void)openInBrowserWithController:(ANBrowserViewController *)browserViewController { - // Stop the countdown and enable close button immediately - [self.controller stopCountdownTimer]; - if (self.controller.presentingViewController) { - // don't open the browser if the interstitial has been closed already - [self.controller presentViewController:self.browserViewController animated:YES completion:nil]; - } -} - #pragma mark extraParameters methods - (NSString *)sizeParameter { @@ -309,94 +278,61 @@ - (CGSize)requestedSizeForAdFetcher:(ANAdFetcher *)fetcher { return self.frame.size; } -- (UIView *)containerView { - return self.controller.view; -} - -#pragma mark ANMRAIDAdViewDelegate +#pragma mark ANInterstitialAdViewControllerDelegate -- (NSString *)adType { - return @"interstitial"; +- (void)interstitialAdViewControllerShouldDismiss:(ANInterstitialAdViewController *)controller { + __weak ANINTERSTITIALAD *weakAd = self; + + [self.controller.presentingViewController dismissViewControllerAnimated:YES completion:^{ + ANINTERSTITIALAD *ad = weakAd; + ad.controller = nil; + }]; } -- (UIViewController *)displayController { - return self.mraidController ? self.mraidController : self.controller; +- (NSTimeInterval)closeDelayForController { + return self.closeDelay; } -- (void)adShouldExpandToFrame:(CGRect)frame - closeButton:(UIButton *)closeButton { - [super mraidExpandAd:frame.size - contentView:self.controller.contentView - defaultParentView:self.controller.containerView - rootViewController:self.controller]; - - UIView *containerView = self.mraidController ? self.mraidController.view : self.controller.contentView; - [super mraidExpandAddCloseButton:closeButton containerView:containerView]; - - [self.mraidEventReceiverDelegate adDidFinishExpand]; +- (void)dismissAndPresentAgainForPreferredInterfaceOrientationChange { + __weak ANInterstitialAd *weakSelf = self; + UIViewController *presentingViewController = self.controller.presentingViewController; + [presentingViewController dismissViewControllerAnimated:NO + completion:^{ + ANInterstitialAd *strongSelf = weakSelf; + [presentingViewController presentViewController:strongSelf.controller + animated:NO + completion:nil]; + }]; } -- (void)adShouldResizeToFrame:(CGRect)frame allowOffscreen:(BOOL)allowOffscreen - closeButton:(UIButton *)closeButton - closePosition:(ANMRAIDCustomClosePosition)closePosition { - // resized ads are never modal - UIView *contentView = self.controller.contentView; - UIView *containerView = self.controller.containerView; - - NSString *mraidResizeErrorString = [super mraidResizeAd:frame - contentView:contentView - defaultParentView:containerView - rootViewController:self.controller - allowOffscreen:allowOffscreen]; - - if ([mraidResizeErrorString length] > 0) { - [self.mraidEventReceiverDelegate adDidFinishResize:NO errorString:mraidResizeErrorString]; - return; - } - - [super mraidResizeAddCloseEventRegion:closeButton - containerView:containerView - contentView:contentView - position:closePosition]; - - // send mraid events - [self.mraidEventReceiverDelegate adDidFinishResize:YES errorString:nil]; +#pragma mark - ANAdViewInternalDelegate + +- (NSString *)adType { + return @"interstitial"; } -- (void)adShouldResetToDefault { - [super adShouldResetToDefault:self.controller.contentView parentView:self.controller.containerView]; +- (UIViewController *)displayController { + return self.controller; } -#pragma mark ANBrowserViewControllerDelegate +#pragma mark - ANInterstitialAdViewInternalDelegate -- (void)browserViewControllerShouldDismiss:(ANBrowserViewController *)controller { - [controller dismissViewControllerAnimated:YES completion:^{ - self.browserViewController = nil; - }]; +- (void)adFailedToDisplay { + if ([self.delegate respondsToSelector:@selector(adFailedToDisplay:)]) { + [self.delegate adFailedToDisplay:self]; + } } -- (UIView *)viewToDisplayClickOverlay { - return self.controller.contentView; +- (void)adShouldClose { + [self.controller closeAction:nil]; } -#pragma mark ANInterstitialAdViewControllerDelegate - -- (void)interstitialAdViewControllerShouldDismiss:(ANInterstitialAdViewController *)controller { - __weak ANINTERSTITIALAD *weakAd = self; - - [self.browserViewController dismissViewControllerAnimated:YES completion:^{ - ANINTERSTITIALAD *ad = weakAd; - ad.browserViewController = nil; - }]; - - [self.controller dismissViewControllerAnimated:YES completion:^{ - ANINTERSTITIALAD *ad = weakAd; - ad.controller = nil; - }]; +- (void)adShouldSetOrientationProperties:(ANMRAIDOrientationProperties *)orientationProperties { + self.controller.orientationProperties = orientationProperties; } -- (NSTimeInterval)closeDelayForController { - return self.closeDelay; +- (void)adShouldUseCustomClose:(BOOL)useCustomClose { + self.controller.useCustomClose = useCustomClose; } -@end +@end \ No newline at end of file diff --git a/sdk/internal/ANInterstitialAdViewController.h b/sdk/internal/ANInterstitialAdViewController.h index 10a38d28e..5e57c746b 100644 --- a/sdk/internal/ANInterstitialAdViewController.h +++ b/sdk/internal/ANInterstitialAdViewController.h @@ -16,16 +16,20 @@ #import @protocol ANInterstitialAdViewControllerDelegate; +@class ANMRAIDOrientationProperties; @interface ANInterstitialAdViewController : UIViewController @property (nonatomic, readwrite, weak) id delegate; -@property (nonatomic, readwrite, strong) UIView *containerView; @property (nonatomic, readwrite, strong) UIView *contentView; @property (nonatomic, readwrite, weak) IBOutlet UIButton *closeButton; @property (nonatomic, readwrite, weak) IBOutlet UIProgressView *progressView; @property (nonatomic, readwrite, strong) UIColor *backgroundColor; @property (nonatomic, readonly, assign) UIInterfaceOrientation orientation; +@property (nonatomic, readwrite, weak) IBOutlet NSLayoutConstraint *buttonTopToSuperviewConstraint; + +@property (nonatomic, readwrite, strong) ANMRAIDOrientationProperties *orientationProperties; +@property (nonatomic, readwrite, assign) BOOL useCustomClose; - (IBAction)closeAction:(id)sender; - (void)stopCountdownTimer; @@ -36,5 +40,6 @@ - (void)interstitialAdViewControllerShouldDismiss:(ANInterstitialAdViewController *)controller; - (NSTimeInterval)closeDelayForController; +- (void)dismissAndPresentAgainForPreferredInterfaceOrientationChange; -@end +@end \ No newline at end of file diff --git a/sdk/internal/ANInterstitialAdViewController.m b/sdk/internal/ANInterstitialAdViewController.m index 067bb745d..30b1e17b8 100644 --- a/sdk/internal/ANInterstitialAdViewController.m +++ b/sdk/internal/ANInterstitialAdViewController.m @@ -19,6 +19,8 @@ #import "ANLogging.h" #import "UIView+ANCategory.h" #import "UIWebView+ANCategory.h" +#import "ANMRAIDOrientationProperties.h" +#import "NSTimer+ANCategory.h" @interface ANInterstitialAdViewController () @property (nonatomic, readwrite, strong) NSTimer *progressTimer; @@ -26,11 +28,10 @@ @interface ANInterstitialAdViewController () @property (nonatomic, readwrite, assign) BOOL viewed; @property (nonatomic, readwrite, assign) BOOL originalHiddenState; @property (nonatomic, readwrite, assign) UIInterfaceOrientation orientation; +@property (nonatomic, readwrite, assign, getter=isDismissing) BOOL dismissing; @end @implementation ANInterstitialAdViewController -@synthesize contentView = __contentView; -@synthesize backgroundColor = __backgroundColor; - (instancetype)init { if (!ANPathForANResource(NSStringFromClass([self class]), @"nib")) { @@ -40,7 +41,6 @@ - (instancetype)init { self = [super initWithNibName:NSStringFromClass([self class]) bundle:ANResourcesBundle()]; self.originalHiddenState = NO; self.orientation = [[UIApplication sharedApplication] statusBarOrientation]; - self.containerView = [UIView new]; return self; } @@ -51,16 +51,36 @@ - (void)viewDidLoad { } self.progressView.hidden = YES; self.closeButton.hidden = YES; - CGRect containerFrame = adjustAbsoluteRectInWindowCoordinatesForOrientationGivenRect(self.view.frame); - [self.containerView setFrame:containerFrame]; - [self.view insertSubview:self.containerView atIndex:0]; + if (self.contentView && !self.contentView.superview) { + [self.view addSubview:self.contentView]; + [self.view insertSubview:self.contentView + belowSubview:self.progressView]; + [self.contentView alignToSuperviewWithXAttribute:NSLayoutAttributeCenterX + yAttribute:NSLayoutAttributeCenterY]; + } + [self setupCloseButtonImageWithCustomClose:self.useCustomClose]; +} + +- (void)setupCloseButtonImageWithCustomClose:(BOOL)useCustomClose { + if (useCustomClose) { + [self.closeButton setImage:nil + forState:UIControlStateNormal]; + return; + } + BOOL atLeastiOS7 = [self respondsToSelector:@selector(modalPresentationCapturesStatusBarAppearance)]; + NSString *closeboxImageName = @"interstitial_flat_closebox"; + if (!atLeastiOS7) { + closeboxImageName = @"interstitial_closebox"; + } + UIImage *closeboxImage = [UIImage imageWithContentsOfFile:ANPathForANResource(closeboxImageName, @"png")]; + [self.closeButton setImage:closeboxImage + forState:UIControlStateNormal]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.originalHiddenState = [UIApplication sharedApplication].statusBarHidden; [self setStatusBarHidden:YES]; - [self centerContentView]; } - (void)viewDidAppear:(BOOL)animated { @@ -79,23 +99,25 @@ - (void)viewWillDisappear:(BOOL)animated { [self.progressTimer invalidate]; } -- (void)startCountdownTimer -{ +- (void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + self.dismissing = NO; +} + +- (void)startCountdownTimer { self.progressView.hidden = NO; self.closeButton.hidden = YES; self.timerStartDate = [NSDate date]; self.progressTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(progressTimerDidFire:) userInfo:nil repeats:YES]; } -- (void)stopCountdownTimer -{ +- (void)stopCountdownTimer { [self.progressTimer invalidate]; - [self.progressView setHidden:YES]; - [self.closeButton setHidden:NO]; + self.progressView.hidden = YES; + self.closeButton.hidden = NO; } -- (void)progressTimerDidFire:(NSTimer *)timer -{ +- (void)progressTimerDidFire:(NSTimer *)timer { NSDate *timeNow = [NSDate date]; NSTimeInterval timeShown = [timeNow timeIntervalSinceDate:self.timerStartDate]; NSTimeInterval closeDelay = [self.delegate closeDelayForController]; @@ -106,76 +128,67 @@ - (void)progressTimerDidFire:(NSTimer *)timer } } -- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration -{ - [UIView animateWithDuration:duration animations:^{ - [self centerContentView]; - }]; -} - -- (void)centerContentView { - CGFloat contentWidth = self.contentView.frame.size.width; - CGFloat contentHeight = self.contentView.frame.size.height; - CGFloat centerX = (self.containerView.bounds.size.width - contentWidth) / 2; - CGFloat centerY = (self.containerView.bounds.size.height - contentHeight) / 2; - - self.contentView.frame = CGRectMake(centerX, centerY, contentWidth, contentHeight); -} - - (void)setContentView:(UIView *)contentView { - if (contentView != __contentView) { - if ([__contentView isKindOfClass:[UIWebView class]]) { - UIWebView *webView = (UIWebView *)__contentView; + if (contentView != _contentView) { + if ([_contentView isKindOfClass:[UIWebView class]]) { + UIWebView *webView = (UIWebView *)_contentView; [webView stopLoading]; [webView setDelegate:nil]; } - - [__contentView removeSubviews]; - [__contentView removeFromSuperview]; - [self.containerView removeSubviews]; - if (contentView != nil) { - if ([contentView isKindOfClass:[UIWebView class]]) { - UIWebView *webView = (UIWebView *)contentView; - [webView removeDocumentPadding]; - [webView setMediaProperties]; - } - - [self.containerView addSubview:contentView]; - } + [_contentView removeFromSuperview]; + _contentView = contentView; - __contentView = contentView; + [self.view insertSubview:_contentView + belowSubview:self.progressView]; + _contentView.translatesAutoresizingMaskIntoConstraints = NO; + [_contentView constrainWithFrameSize]; + [_contentView alignToSuperviewWithXAttribute:NSLayoutAttributeCenterX + yAttribute:NSLayoutAttributeCenterY]; } } --(void)setBackgroundColor:(UIColor *)backgroundColor -{ - __backgroundColor = backgroundColor; - self.view.backgroundColor = __backgroundColor; - self.containerView.backgroundColor = __backgroundColor; +- (void)setBackgroundColor:(UIColor *)backgroundColor { + _backgroundColor = backgroundColor; + self.view.backgroundColor = _backgroundColor; } -- (IBAction)closeAction:(id)sender -{ +- (IBAction)closeAction:(id)sender { + if ([self.progressTimer isScheduled]) { + return; + } + self.dismissing = YES; [self.delegate interstitialAdViewControllerShouldDismiss:self]; } -// hiding the status bar in iOS 7 - (BOOL)prefersStatusBarHidden { return YES; } -// hiding the status bar pre-iOS 7 - (void)setStatusBarHidden:(BOOL)hidden { [[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:UIStatusBarAnimationNone]; } -// locking orientation in iOS 6+ - (BOOL)shouldAutorotate { return NO; } - (NSUInteger)supportedInterfaceOrientations { + if (self.orientationProperties) { + if (self.orientationProperties.allowOrientationChange) { + return UIInterfaceOrientationMaskAll; + } else { + switch (self.orientationProperties.forceOrientation) { + case ANMRAIDOrientationPortrait: + return UIInterfaceOrientationMaskPortrait; + case ANMRAIDOrientationLandscape: + return UIInterfaceOrientationMaskLandscape; + default: + return UIInterfaceOrientationMaskAll; + } + } + } + switch (self.orientation) { case UIInterfaceOrientationLandscapeLeft: return UIInterfaceOrientationMaskLandscapeLeft; @@ -188,10 +201,67 @@ - (NSUInteger)supportedInterfaceOrientations { } } -// locking orientation in pre-iOS 6 -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { - return NO; +- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { + if (self.orientationProperties) { + switch (self.orientationProperties.forceOrientation) { + case ANMRAIDOrientationPortrait: + if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown) { + return UIInterfaceOrientationPortraitUpsideDown; + } + return UIInterfaceOrientationPortrait; + case ANMRAIDOrientationLandscape: + if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) { + return UIInterfaceOrientationLandscapeRight; + } + return UIInterfaceOrientationLandscapeLeft; + default: + break; + } + } + return self.orientation; } -@end +- (void)viewWillLayoutSubviews { + CGFloat buttonDistanceToSuperview; + if ([self respondsToSelector:@selector(modalPresentationCapturesStatusBarAppearance)]) { + CGSize statusBarFrameSize = [[UIApplication sharedApplication] statusBarFrame].size; + buttonDistanceToSuperview = statusBarFrameSize.height; + if (statusBarFrameSize.height > statusBarFrameSize.width) { + buttonDistanceToSuperview = statusBarFrameSize.width; + } + } else { + buttonDistanceToSuperview = 0; + } + + self.buttonTopToSuperviewConstraint.constant = buttonDistanceToSuperview; + + if (!self.isDismissing) { + CGRect normalizedContentViewFrame = CGRectMake(0, 0, CGRectGetWidth(self.contentView.frame), CGRectGetHeight(self.contentView.frame)); + if (!CGRectContainsRect(self.view.frame, normalizedContentViewFrame)) { + CGRect rotatedNormalizedContentViewFrame = CGRectMake(0, 0, CGRectGetHeight(self.contentView.frame), CGRectGetWidth(self.contentView.frame)); + if (CGRectContainsRect(self.view.frame, rotatedNormalizedContentViewFrame)) { + [self.contentView constrainWithSize:CGSizeMake(CGRectGetHeight(self.contentView.frame), CGRectGetWidth(self.contentView.frame))]; + } + } + } +} + +- (void)setUseCustomClose:(BOOL)useCustomClose { + if (_useCustomClose != useCustomClose) { + _useCustomClose = useCustomClose; + [self setupCloseButtonImageWithCustomClose:useCustomClose]; + } +} + +- (void)setOrientationProperties:(ANMRAIDOrientationProperties *)orientationProperties { + _orientationProperties = orientationProperties; + if ([self.view an_isViewable]) { + if (orientationProperties.allowOrientationChange && orientationProperties.forceOrientation == ANMRAIDOrientationNone) { + [UIViewController attemptRotationToDeviceOrientation]; + } else if ([UIApplication sharedApplication].statusBarOrientation != [self preferredInterfaceOrientationForPresentation]) { + [self.delegate dismissAndPresentAgainForPreferredInterfaceOrientationChange]; + } + } +} +@end \ No newline at end of file diff --git a/sdk/internal/ANLogging.h b/sdk/internal/ANLogging.h index d63ffae10..9927455be 100644 --- a/sdk/internal/ANLogging.h +++ b/sdk/internal/ANLogging.h @@ -27,7 +27,7 @@ void notifyListener(NSString *message, NSInteger messageLevel); #if AN_DEBUG_MODE -void _ANLog(ANLogLevel level, NSString *format, ...); +void _ANLog(ANLogLevel level, NSString *format, ...) NS_FORMAT_FUNCTION(2, 3); #define ANLogTrace(...) _ANLog(ANLogLevelTrace, __VA_ARGS__) #define ANLogDebug(...) _ANLog(ANLogLevelDebug, __VA_ARGS__) #define ANLogInfo(...) _ANLog(ANLogLevelInfo, __VA_ARGS__) diff --git a/sdk/internal/ANLogging.m b/sdk/internal/ANLogging.m index 3694bf888..813877085 100644 --- a/sdk/internal/ANLogging.m +++ b/sdk/internal/ANLogging.m @@ -24,6 +24,7 @@ void _ANLog(ANLogLevel level, NSString *format, ...) { if ([ANLogManager getANLogLevel] <= level) { + format = ANErrorString(format); // returns the format string if error string not found format = [NSString stringWithFormat:@"%@: %@", AN_LOG_NAME, format]; va_list args; va_start(args, format); @@ -39,4 +40,4 @@ void notifyListener(NSString *message, NSInteger messageLevel) ANPostNotifications(kANLoggingNotification, nil, @{kANLogMessageKey: message, kANLogMessageLevelKey: @(messageLevel)}); -} +} \ No newline at end of file diff --git a/sdk/internal/ANMRAIDProperties.h b/sdk/internal/ANMRAIDProperties.h deleted file mode 100644 index bd517a1c6..000000000 --- a/sdk/internal/ANMRAIDProperties.h +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright 2013 APPNEXUS INC - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#import -#import - -typedef NS_ENUM(NSUInteger, ANMRAIDOrientation) { - ANMRAIDOrientationPortrait, - ANMRAIDOrientationLandscape, - ANMRAIDOrientationNone -}; - -typedef NS_ENUM(NSUInteger, ANMRAIDCustomClosePosition) { - ANMRAIDTopLeft, - ANMRAIDTopCenter, - ANMRAIDTopRight, - ANMRAIDCenter, - ANMRAIDBottomLeft, - ANMRAIDBottomCenter, - ANMRAIDBottomRight -}; - -typedef NS_ENUM(NSUInteger, ANMRAIDState) { - ANMRAIDStateLoading, - ANMRAIDStateDefault, - ANMRAIDStateExpanded, - ANMRAIDStateHidden, - ANMRAIDStateResized -}; - -@protocol ANMRAIDEventReceiver - -- (void)adDidFinishExpand; -- (void)adDidFinishResize:(BOOL)success errorString:(NSString *)errorString; -- (void)adDidChangeResizeOffset:(CGPoint)offset; -- (void)adDidResetToDefault; - -@end - -@protocol ANMRAIDAdViewDelegate - -@property (nonatomic, readwrite, weak) id mraidEventReceiverDelegate; - -- (NSString *)adType; -- (UIViewController *)displayController; -- (void)adShouldResetToDefault; -- (void)adShouldExpandToFrame:(CGRect)frame closeButton:(UIButton *)closeButton; -- (void)adShouldResizeToFrame:(CGRect)frame allowOffscreen:(BOOL)allowOffscreen - closeButton:(UIButton *)closeButton - closePosition:(ANMRAIDCustomClosePosition)closePosition; -- (void)allowOrientationChange:(BOOL)allowOrientationChange - withForcedOrientation:(ANMRAIDOrientation)orientation; - -@end - diff --git a/sdk/internal/ANMRAIDViewController.m b/sdk/internal/ANMRAIDViewController.m deleted file mode 100644 index 719f626d6..000000000 --- a/sdk/internal/ANMRAIDViewController.m +++ /dev/null @@ -1,112 +0,0 @@ -/* Copyright 2013 APPNEXUS INC - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#import "ANMRAIDViewController.h" -#import "ANGlobal.h" - -@interface ANMRAIDViewController () -@property (nonatomic, readwrite, assign) BOOL originalHiddenState; -@end - -@implementation ANMRAIDViewController - -- (instancetype)init { - self = [super init]; - if (self) { - _allowOrientationChange = YES; - } - return self; -} - -- (void)viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; - self.originalHiddenState = [UIApplication sharedApplication].statusBarHidden; - [self setStatusBarHidden:YES]; - - [self resetViewForRotations:[[UIApplication sharedApplication] statusBarOrientation]]; -} - -- (void)viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; - [self setStatusBarHidden:self.originalHiddenState]; -} - -- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { - [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; - [self resetViewForRotations:toInterfaceOrientation]; -} - -- (void)resetViewForRotations:(UIInterfaceOrientation)orientation { - UIInterfaceOrientation orientationAfterRotation = orientation; - if (!self.allowOrientationChange) { - orientationAfterRotation = self.orientation; - } - - CGRect mainBounds = ANPortraitScreenBounds(); - if (UIInterfaceOrientationIsLandscape(orientationAfterRotation)) { - CGFloat portraitHeight = mainBounds.size.height; - CGFloat portraitWidth = mainBounds.size.width; - mainBounds.size.height = portraitWidth; - mainBounds.size.width = portraitHeight; - } - - [self.contentView setFrame:mainBounds]; -} - -// locking orientation in iOS 6+ -- (BOOL)shouldAutorotate { - return self.allowOrientationChange; -} - -- (NSUInteger)supportedInterfaceOrientations { - if (self.allowOrientationChange) { - return [[UIApplication sharedApplication] supportedInterfaceOrientationsForWindow:[self.view window]]; - } else { - switch (self.orientation) { - case UIInterfaceOrientationPortrait: - return UIInterfaceOrientationMaskPortrait; - break; - case UIInterfaceOrientationPortraitUpsideDown: - return UIInterfaceOrientationMaskPortraitUpsideDown; - break; - case UIInterfaceOrientationLandscapeLeft: - return UIInterfaceOrientationMaskLandscapeLeft; - break; - case UIInterfaceOrientationLandscapeRight: - return UIInterfaceOrientationMaskLandscapeRight; - break; - default: - return UIInterfaceOrientationMaskPortrait; - break; - } - } -} - -// locking orientation in pre-iOS 6 -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { - return self.allowOrientationChange; -} - -// hiding the status bar in iOS 7 -- (BOOL)prefersStatusBarHidden { - return YES; -} - -// hiding the status bar pre-iOS 7 -- (void)setStatusBarHidden:(BOOL)hidden { - [[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:UIStatusBarAnimationNone]; -} - -@end diff --git a/sdk/internal/ANMediationAdViewController.m b/sdk/internal/ANMediationAdViewController.m index 29ba3c3c8..2017b48f7 100644 --- a/sdk/internal/ANMediationAdViewController.m +++ b/sdk/internal/ANMediationAdViewController.m @@ -85,7 +85,7 @@ - (BOOL)requestForAd:(ANMediatedAd *)ad { ANPostNotifications(kANAdFetcherWillInstantiateMediatedClassNotification, self, @{kANAdFetcherMediatedClassKey: className}); - ANLogDebug(ANErrorString(@"instantiating_class", className)); + ANLogDebug(@"instantiating_class %@", className); // check to see if an instance of this class exists Class adClass = NSClassFromString(className); @@ -143,10 +143,10 @@ - (void)handleInstantiationFailure:(NSString *)className errorCode:(ANADRESPONSECODE)errorCode errorInfo:(NSString *)errorInfo { if ([errorInfo length] > 0) { - ANLogError(ANErrorString(@"mediation_instantiation_failure", errorInfo)); + ANLogError(@"mediation_instantiation_failure %@", errorInfo); } if ([className length] > 0) { - ANLogWarn(ANErrorString(@"mediation_adding_invalid", className)); + ANLogWarn(@"mediation_adding_invalid %@", className); ANAddInvalidNetwork(className); } @@ -167,7 +167,7 @@ - (void)clearAdapter { self.adViewDelegate = nil; self.mediatedAd = nil; [self cancelTimeout]; - ANLogInfo(ANErrorString(@"mediation_finish")); + ANLogInfo(@"mediation_finish"); } - (BOOL)requestAd:(CGSize)size @@ -199,7 +199,7 @@ - (BOOL)requestAd:(CGSize)size targetingParameters:targetingParameters]; return YES; } else { - ANLogError(ANErrorString(@"instance_exception", @"CustomAdapterBanner")); + ANLogError(@"instance_exception %@", @"CustomAdapterBanner"); } } else if ([adView isKindOfClass:[ANINTERSTITIALAD class]]) { // make sure the container and protocol match @@ -215,7 +215,7 @@ - (BOOL)requestAd:(CGSize)size targetingParameters:targetingParameters]; return YES; } else { - ANLogError(ANErrorString(@"instance_exception", @"CustomAdapterInterstitial")); + ANLogError(@"instance_exception %@", @"CustomAdapterInterstitial"); } } @@ -286,7 +286,10 @@ - (void)willLeaveApplication { - (void)failedToDisplayAd { if (self.hasFailed) return; [self runInBlock:^(void) { - [self.adViewDelegate adFailedToDisplay]; + if ([self.adViewDelegate conformsToProtocol:@protocol(ANInterstitialAdViewInternalDelegate)]) { + id interstitialDelegate = (id)self.adViewDelegate; + [interstitialDelegate adFailedToDisplay]; + } }]; } @@ -426,7 +429,7 @@ - (void)startTimeout { dispatch_get_main_queue(), ^{ ANMediationAdViewController *strongSelf = weakSelf; if (!strongSelf || strongSelf.timeoutCanceled) return; - ANLogWarn(ANErrorString(@"mediation_timeout")); + ANLogWarn(@"mediation_timeout"); [strongSelf didFailToReceiveAd:(ANADRESPONSECODE)ANAdResponseInternalError]; }); diff --git a/sdk/internal/ANMRAIDViewController.h b/sdk/internal/ANOpenInExternalBrowserActivity.h similarity index 65% rename from sdk/internal/ANMRAIDViewController.h rename to sdk/internal/ANOpenInExternalBrowserActivity.h index a48e3142b..e168eb04c 100644 --- a/sdk/internal/ANMRAIDViewController.h +++ b/sdk/internal/ANOpenInExternalBrowserActivity.h @@ -1,4 +1,4 @@ -/* Copyright 2013 APPNEXUS INC +/* Copyright 2014 APPNEXUS INC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,8 +15,6 @@ #import -@interface ANMRAIDViewController : UIViewController -@property (nonatomic, readwrite, strong) UIView *contentView; -@property (nonatomic, readwrite, assign) UIInterfaceOrientation orientation; -@property (nonatomic, assign) BOOL allowOrientationChange; // Default: YES +@interface ANOpenInExternalBrowserActivity : UIActivity + @end diff --git a/sdk/internal/ANOpenInExternalBrowserActivity.m b/sdk/internal/ANOpenInExternalBrowserActivity.m new file mode 100644 index 000000000..949abf0f6 --- /dev/null +++ b/sdk/internal/ANOpenInExternalBrowserActivity.m @@ -0,0 +1,68 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANOpenInExternalBrowserActivity.h" +#import "ANGlobal.h" +#import "ANLogging.h" + +@interface ANOpenInExternalBrowserActivity() + +@property (nonatomic, readwrite, strong) NSURL *URLToOpen; + +@end + +@implementation ANOpenInExternalBrowserActivity + +- (NSString *)activityType { + return @"AppNexus Open In Safari"; +} + +- (NSString *)activityTitle { + return @"Open In Safari"; +} + +- (UIImage *)activityImage { + NSString *iconPath = ANPathForANResource(@"compass", @"png"); + if (!iconPath) { + ANLogError(@"Could not find compass image for 'Open in Safari' sharing option"); + return nil; + } + UIImage *icon = [UIImage imageWithContentsOfFile:iconPath]; + return icon; +} + +- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems { + id firstObject = [activityItems firstObject]; + if ([firstObject isKindOfClass:[NSURL class]]) { + NSURL *URL = (NSURL *)firstObject; + return URL.absoluteString.length; + } + return NO; +} + +- (void)performActivity { + [[UIApplication sharedApplication] openURL:self.URLToOpen]; + [self activityDidFinish:YES]; +} + +- (void)prepareWithActivityItems:(NSArray *)activityItems { + self.URLToOpen = [activityItems objectAtIndex:0]; +} + ++ (UIActivityCategory)activityCategory { + return UIActivityCategoryAction; +} + +@end \ No newline at end of file diff --git a/sdk/internal/ANReachability.h b/sdk/internal/ANReachability.h index ce6a57188..75aed1af8 100644 --- a/sdk/internal/ANReachability.h +++ b/sdk/internal/ANReachability.h @@ -1,85 +1,98 @@ /* - - File: Reachability.h + File: Reachability.h Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs. + Version: 3.5 - Version: 2.2 - - Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. - ("Apple") in consideration of your agreement to the following terms, and your - use, installation, modification or redistribution of this Apple software - constitutes acceptance of these terms. If you do not agree with these terms, - please do not use, install, modify or redistribute this Apple software. + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. - In consideration of your agreement to abide by the following terms, and subject - to these terms, Apple grants you a personal, non-exclusive license, under - Apple's copyrights in this original Apple software (the "Apple Software"), to - use, reproduce, modify and redistribute the Apple Software, with or without - modifications, in source and/or binary forms; provided that if you redistribute - the Apple Software in its entirety and without modifications, you must retain - this notice and the following text and disclaimers in all such redistributions - of the Apple Software. - Neither the name, trademarks, service marks or logos of Apple Inc. may be used - to endorse or promote products derived from the Apple Software without specific - prior written permission from Apple. Except as expressly stated in this notice, - no other rights or licenses, express or implied, are granted by Apple herein, - including but not limited to any patent rights that may be infringed by your - derivative works or by other works in which the Apple Software may be - incorporated. + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. - The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO - WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED - WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN - COMBINATION WITH YOUR PRODUCTS. + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. - IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR - DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF - CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF - APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. - Copyright (C) 2010 Apple Inc. All Rights Reserved. + Copyright (C) 2014 Apple Inc. All Rights Reserved. -*/ - + */ #import #import +#import -typedef enum { + +typedef enum : NSInteger { ANNetworkStatusNotReachable = 0, ANNetworkStatusReachableViaWiFi, ANNetworkStatusReachableViaWWAN } ANNetworkStatus; -#define kReachabilityChangedNotification @"kNetworkReachabilityChangedNotification" -@interface ANReachability: NSObject -{ - BOOL localWiFiRef; - SCNetworkReachabilityRef reachabilityRef; -} -//reachabilityWithHostName- Use to check the reachability of a particular host name. -+ (ANReachability*) reachabilityWithHostName: (NSString*) hostName; +extern NSString *kANReachabilityChangedNotification; + + +@interface ANReachability : NSObject -//reachabilityForInternetConnection- checks whether the default route is available. -// Should be used by applications that do not connect to a particular host -+ (ANReachability*) reachabilityForInternetConnection; +/*! + * Use to check the reachability of a given host name. + */ ++ (instancetype)reachabilityWithHostName:(NSString *)hostName; -//reachabilityForLocalWiFi- checks whether a local wifi connection is available. -+ (ANReachability*) reachabilityForLocalWiFi; +/*! + * Use to check the reachability of a given IP address. + */ ++ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress; -//Start listening for reachability notifications on the current run loop +/*! + * Checks whether the default route is available. Should be used by applications that do not connect to a particular host. + */ ++ (instancetype)reachabilityForInternetConnection; + +/*! + * Checks whether a local WiFi connection is available. + */ ++ (instancetype)reachabilityForLocalWiFi; + +/*! + * Start listening for reachability notifications on the current run loop. + */ - (BOOL)startNotifier; - (void)stopNotifier; -- (ANNetworkStatus) currentReachabilityStatus; -//WWAN may be available, but not active until a connection has been established. -//WiFi may require a connection for VPN on Demand. -- (BOOL)connectionRequired; -@end +- (ANNetworkStatus)currentReachabilityStatus; +/*! + * WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand. + */ +- (BOOL)connectionRequired; +@end diff --git a/sdk/internal/ANReachability.m b/sdk/internal/ANReachability.m index 9b05596e6..d890e456c 100644 --- a/sdk/internal/ANReachability.m +++ b/sdk/internal/ANReachability.m @@ -1,196 +1,219 @@ /* - - File: Reachability.m + File: Reachability.m Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs. + Version: 3.5 - Version: 2.2 - - Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. - ("Apple") in consideration of your agreement to the following terms, and your - use, installation, modification or redistribution of this Apple software - constitutes acceptance of these terms. If you do not agree with these terms, - please do not use, install, modify or redistribute this Apple software. + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. - In consideration of your agreement to abide by the following terms, and subject - to these terms, Apple grants you a personal, non-exclusive license, under - Apple's copyrights in this original Apple software (the "Apple Software"), to - use, reproduce, modify and redistribute the Apple Software, with or without - modifications, in source and/or binary forms; provided that if you redistribute - the Apple Software in its entirety and without modifications, you must retain - this notice and the following text and disclaimers in all such redistributions - of the Apple Software. - Neither the name, trademarks, service marks or logos of Apple Inc. may be used - to endorse or promote products derived from the Apple Software without specific - prior written permission from Apple. Except as expressly stated in this notice, - no other rights or licenses, express or implied, are granted by Apple herein, - including but not limited to any patent rights that may be infringed by your - derivative works or by other works in which the Apple Software may be - incorporated. + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. - The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO - WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED - WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN - COMBINATION WITH YOUR PRODUCTS. + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. - IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR - DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF - CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF - APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. - Copyright (C) 2010 Apple Inc. All Rights Reserved. + Copyright (C) 2014 Apple Inc. All Rights Reserved. -*/ + */ -#import -#import -#import #import #import #import +#import #import #import "ANReachability.h" +NSString *kANReachabilityChangedNotification = @"kANNetworkReachabilityChangedNotification"; + + +#pragma mark - Supporting functions + #define kShouldPrintReachabilityFlags 0 -static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment) +static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment) { #if kShouldPrintReachabilityFlags - + NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n", - (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', - (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', - - (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', - (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', - (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', - (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', - (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', - (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', - (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-', - comment - ); + (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', + (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', + + (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', + (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', + (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', + (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-', + comment + ); #endif } - -@implementation ANReachability static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) { - #pragma unused (target, flags) +#pragma unused (target, flags) NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback"); - NSCAssert([(NSObject*) CFBridgingRelease(info) isKindOfClass: [ANReachability class]], @"info was wrong class in ReachabilityCallback"); - - ANReachability* noteObject = (__bridge ANReachability*) info; - // Post a notification to notify the client that the network reachability changed. - [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject]; -} + NSCAssert([(__bridge NSObject*) info isKindOfClass: [ANReachability class]], @"info was wrong class in ReachabilityCallback"); -- (BOOL) startNotifier -{ - BOOL retVal = NO; - SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; - if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context)) - { - if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) - { - retVal = YES; - } - } - return retVal; + ANReachability* noteObject = (__bridge ANReachability *)info; + // Post a notification to notify the client that the network reachability changed. + [[NSNotificationCenter defaultCenter] postNotificationName: kANReachabilityChangedNotification object: noteObject]; } -- (void) stopNotifier -{ - if(reachabilityRef!= NULL) - { - SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - } -} -- (void) dealloc +#pragma mark - Reachability implementation + +@implementation ANReachability { - [self stopNotifier]; - if(reachabilityRef!= NULL) - { - CFRelease(reachabilityRef); - } + BOOL _alwaysReturnLocalWiFiStatus; //default is NO + SCNetworkReachabilityRef _reachabilityRef; } -+ (ANReachability *)reachabilityWithHostName:(NSString*)hostName; ++ (instancetype)reachabilityWithHostName:(NSString *)hostName { - ANReachability* retVal = NULL; + ANReachability* returnValue = NULL; SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]); - if(reachability!= NULL) + if (reachability != NULL) { - retVal= [[self alloc] init]; - if(retVal!= NULL) + returnValue= [[self alloc] init]; + if (returnValue != NULL) { - retVal->reachabilityRef = reachability; - retVal->localWiFiRef = NO; + returnValue->_reachabilityRef = reachability; + returnValue->_alwaysReturnLocalWiFiStatus = NO; } } - return retVal; + return returnValue; } -+ (ANReachability *)reachabilityWithAddress:(const struct sockaddr_in*)hostAddress; ++ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress { - SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress); - ANReachability* retVal = NULL; - if(reachability!= NULL) + SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)hostAddress); + + ANReachability* returnValue = NULL; + + if (reachability != NULL) { - retVal= [[self alloc] init]; - if(retVal!= NULL) + returnValue = [[self alloc] init]; + if (returnValue != NULL) { - retVal->reachabilityRef = reachability; - retVal->localWiFiRef = NO; + returnValue->_reachabilityRef = reachability; + returnValue->_alwaysReturnLocalWiFiStatus = NO; } } - return retVal; + return returnValue; } -+ (ANReachability *)reachabilityForInternetConnection; ++ (instancetype)reachabilityForInternetConnection { struct sockaddr_in zeroAddress; bzero(&zeroAddress, sizeof(zeroAddress)); zeroAddress.sin_len = sizeof(zeroAddress); zeroAddress.sin_family = AF_INET; - return [self reachabilityWithAddress: &zeroAddress]; + + return [self reachabilityWithAddress:&zeroAddress]; } -+ (ANReachability *)reachabilityForLocalWiFi; ++ (instancetype)reachabilityForLocalWiFi { struct sockaddr_in localWifiAddress; bzero(&localWifiAddress, sizeof(localWifiAddress)); localWifiAddress.sin_len = sizeof(localWifiAddress); localWifiAddress.sin_family = AF_INET; - // IN_LINKLOCALNETNUM is defined in as 169.254.0.0 + + // IN_LINKLOCALNETNUM is defined in as 169.254.0.0. localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); - ANReachability* retVal = [self reachabilityWithAddress: &localWifiAddress]; - if(retVal!= NULL) + + ANReachability* returnValue = [self reachabilityWithAddress: &localWifiAddress]; + if (returnValue != NULL) { - retVal->localWiFiRef = YES; + returnValue->_alwaysReturnLocalWiFiStatus = YES; } - return retVal; + + return returnValue; } -#pragma mark Network Flag Handling -- (ANNetworkStatus)localWiFiStatusForFlags: (SCNetworkReachabilityFlags)flags +#pragma mark - Start and stop notifier + +- (BOOL)startNotifier +{ + BOOL returnValue = NO; + SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; + + if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context)) + { + if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) + { + returnValue = YES; + } + } + + return returnValue; +} + +- (void)stopNotifier +{ + if (_reachabilityRef != NULL) + { + SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + } +} + +- (void)dealloc +{ + [self stopNotifier]; + if (_reachabilityRef != NULL) + { + CFRelease(_reachabilityRef); + } +} + + +#pragma mark - Network Flag Handling + +- (ANNetworkStatus)localWiFiStatusForFlags:(SCNetworkReachabilityFlags)flags { PrintReachabilityFlags(flags, "localWiFiStatusForFlags"); + ANNetworkStatus returnValue = ANNetworkStatusNotReachable; - BOOL retVal = ANNetworkStatusNotReachable; - if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect)) + if ((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect)) { - retVal = ANNetworkStatusReachableViaWiFi; + returnValue = ANNetworkStatusReachableViaWiFi; } - return retVal; + + return returnValue; } - (ANNetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags @@ -198,69 +221,79 @@ - (ANNetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags PrintReachabilityFlags(flags, "networkStatusForFlags"); if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) { - // if target host is not reachable + // The target host is not reachable. return ANNetworkStatusNotReachable; } - BOOL retVal = ANNetworkStatusNotReachable; - + ANNetworkStatus returnValue = ANNetworkStatusNotReachable; + if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) { - // if target host is reachable and no connection is required - // then we'll assume (for now) that your on Wi-Fi - retVal = ANNetworkStatusReachableViaWiFi; + /* + If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi... + */ + returnValue = ANNetworkStatusReachableViaWiFi; } - - + if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || - (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) + (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) { - // ... and the connection is on-demand (or on-traffic) if the - // calling application is using the CFSocketStream or higher APIs - - if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) - { - // ... and no [user] intervention is needed - retVal = ANNetworkStatusReachableViaWiFi; - } - } - + /* + ... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs... + */ + + if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) + { + /* + ... and no [user] intervention is needed... + */ + returnValue = ANNetworkStatusReachableViaWiFi; + } + } + if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) { - // ... but WWAN connections are OK if the calling application - // is using the CFNetwork (CFSocketStream?) APIs. - retVal = ANNetworkStatusReachableViaWWAN; + /* + ... but WWAN connections are OK if the calling application is using the CFNetwork APIs. + */ + returnValue = ANNetworkStatusReachableViaWWAN; } - return retVal; + + return returnValue; } -- (BOOL)connectionRequired; +- (BOOL)connectionRequired { - NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef"); + NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef"); SCNetworkReachabilityFlags flags; - if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) + + if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) { return (flags & kSCNetworkReachabilityFlagsConnectionRequired); } - return NO; + + return NO; } - (ANNetworkStatus)currentReachabilityStatus { - NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef"); - ANNetworkStatus retVal = ANNetworkStatusNotReachable; + NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef"); + ANNetworkStatus returnValue = ANNetworkStatusNotReachable; SCNetworkReachabilityFlags flags; - if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) + + if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) { - if(localWiFiRef) + if (_alwaysReturnLocalWiFiStatus) { - retVal = [self localWiFiStatusForFlags: flags]; + returnValue = [self localWiFiStatusForFlags:flags]; } else { - retVal = [self networkStatusForFlags: flags]; + returnValue = [self networkStatusForFlags:flags]; } } - return retVal; + + return returnValue; } + @end diff --git a/sdk/internal/ANWebView.h b/sdk/internal/ANWebView.h deleted file mode 100644 index a283893f5..000000000 --- a/sdk/internal/ANWebView.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright 2013 APPNEXUS INC - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#import "ANMRAIDProperties.h" -#import "ANAdWebViewController.h" - -#import -#import - -@interface ANWebView : UIWebView - -@property (nonatomic, readwrite, strong) ANMRAIDAdWebViewController *controller; - -@end - -@interface UIWebView (MRAIDExtensions) -// MRAID events -- (void)fireReadyEvent; -- (void)fireStateChangeEvent:(ANMRAIDState)state; -- (void)fireNewCurrentPositionEvent:(CGRect)frame; -- (void)fireErrorEvent:(NSString *)errorString function:(NSString *)function; - -// set values for MRAID getters -- (void)setPlacementType:(NSString *)placementType; -- (void)setIsViewable:(BOOL)viewable; -- (void)setCurrentPosition:(CGRect)frame; -- (void)setDefaultPosition:(CGRect)frame; -- (void)setScreenSize:(CGSize)size; -- (void)setMaxSize:(CGSize)size; -- (void)setSupports:(NSString *)feature isSupported:(BOOL)isSupported; - -- (void)setHidden:(BOOL)hidden animated:(BOOL)animated; - -- (ANMRAIDState)getMRAIDState; - -@end diff --git a/sdk/internal/ANWebView.m b/sdk/internal/ANWebView.m deleted file mode 100644 index c761eea79..000000000 --- a/sdk/internal/ANWebView.m +++ /dev/null @@ -1,176 +0,0 @@ -/* Copyright 2013 APPNEXUS INC - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#import "ANWebView.h" - -#import "ANGlobal.h" -#import "ANLogging.h" -#import "UIWebView+ANCategory.h" - -@implementation ANWebView - --(instancetype)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if (self) { - self.backgroundColor = [UIColor clearColor]; - self.opaque = NO; - self.scrollEnabled = NO; - [self setMediaProperties]; - } - return self; -} - -- (void)dealloc { - self.delegate = nil; -} - -@end - -@implementation ANWebView (MRAIDExtensions) - -- (void)fireReadyEvent { - NSString* script = [NSString stringWithFormat:@"window.mraid.util.readyEvent();"]; - [self stringByEvaluatingJavaScriptFromString:script]; -} - -- (void)fireStateChangeEvent:(ANMRAIDState)state { - NSString *stateString = @""; - - switch (state) { - case ANMRAIDStateLoading: - stateString = @"loading"; - break; - case ANMRAIDStateDefault: - stateString = @"default"; - break; - case ANMRAIDStateExpanded: - stateString = @"expanded"; - break; - case ANMRAIDStateHidden: - stateString = @"hidden"; - break; - case ANMRAIDStateResized: - stateString = @"resized"; - break; - default: - break; - } - - NSString *script = [NSString stringWithFormat:@"window.mraid.util.stateChangeEvent('%@')", stateString]; - [self stringByEvaluatingJavaScriptFromString:script]; -} - -- (void)fireErrorEvent:(NSString *)errorString function:(NSString *)function { - NSString* script = [NSString stringWithFormat:@"mraid.util.errorEvent('%@', '%@');", errorString, function]; - [self stringByEvaluatingJavaScriptFromString:script]; -} - -- (void)fireNewCurrentPositionEvent:(CGRect)frame { - [self setCurrentSize:frame.size]; - [self setCurrentPosition:frame]; -} - -- (void)setPlacementType:(NSString *)placementType { - NSString* script = [NSString stringWithFormat:@"window.mraid.util.setPlacementType('%@');", placementType]; - [self stringByEvaluatingJavaScriptFromString:script]; -} - -- (void)setIsViewable:(BOOL)viewable { - NSString* script = [NSString stringWithFormat:@"window.mraid.util.setIsViewable(%@)", - viewable ? @"true" : @"false"]; - [self stringByEvaluatingJavaScriptFromString:script]; -} - -- (void)setCurrentSize:(CGSize)size { - int width = floorf(size.width + 0.5f); - int height = floorf(size.height + 0.5f); - - NSString *script = [NSString stringWithFormat:@"window.mraid.util.sizeChangeEvent(%i,%i);", - width, height]; - [self stringByEvaluatingJavaScriptFromString:script]; -} - -- (void)setCurrentPosition:(CGRect)frame { - int offsetX = (frame.origin.x > 0) ? floorf(frame.origin.x + 0.5f) : ceilf(frame.origin.x - 0.5f); - int offsetY = (frame.origin.y > 0) ? floorf(frame.origin.y + 0.5f) : ceilf(frame.origin.y - 0.5f); - int width = floorf(frame.size.width + 0.5f); - int height = floorf(frame.size.height + 0.5f); - - NSString *script = [NSString stringWithFormat:@"window.mraid.util.setCurrentPosition(%i, %i, %i, %i);", - offsetX, offsetY, width, height]; - [self stringByEvaluatingJavaScriptFromString:script]; -} - -- (void)setDefaultPosition:(CGRect)frame { - int offsetX = (frame.origin.x > 0) ? floorf(frame.origin.x + 0.5f) : ceilf(frame.origin.x - 0.5f); - int offsetY = (frame.origin.y > 0) ? floorf(frame.origin.y + 0.5f) : ceilf(frame.origin.y - 0.5f); - int width = floorf(frame.size.width + 0.5f); - int height = floorf(frame.size.height + 0.5f); - - NSString *script = [NSString stringWithFormat:@"window.mraid.util.setDefaultPosition(%i, %i, %i, %i);", - offsetX, offsetY, width, height]; - [self stringByEvaluatingJavaScriptFromString:script]; -} - -- (void)setScreenSize:(CGSize)size { - int width = floorf(size.width + 0.5f); - int height = floorf(size.height + 0.5f); - [self stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.mraid.util.setScreenSize(%i, %i);", width, height]]; -} - -- (void)setMaxSize:(CGSize)size { - int width = floorf(size.width + 0.5f); - int height = floorf(size.height + 0.5f); - [self stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.mraid.util.setMaxSize(%i, %i);",width, height]]; -} - -- (void)setSupports:(NSString *)feature isSupported:(BOOL)isSupported { - [self stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.mraid.util.setSupports(\'%@\', %@);", - feature, (isSupported ? @"true" : @"false")]]; -} - -- (ANMRAIDState)getMRAIDState { - NSString *state = [self stringByEvaluatingJavaScriptFromString:@"window.mraid.getState()"]; - if ([state isEqualToString:@"loading"]) { - return ANMRAIDStateLoading; - } else if ([state isEqualToString:@"default"]) { - return ANMRAIDStateDefault; - } else if ([state isEqualToString:@"expanded"]) { - return ANMRAIDStateExpanded; - } else if ([state isEqualToString:@"hidden"]) { - return ANMRAIDStateHidden; - } else if ([state isEqualToString:@"resized"]) { - return ANMRAIDStateResized; - } - - ANLogError(@"Call to mraid.getState() returned invalid state."); - return ANMRAIDStateDefault; -} - -- (void)setHidden:(BOOL)hidden animated:(BOOL)animated { - if (animated) { - [UIView animateWithDuration:kAppNexusAnimationDuration animations:^{ - self.alpha = hidden ? 0.0f : 1.0f; - } completion:^(BOOL finished) { - self.hidden = hidden; - self.alpha = 1.0f; - }]; - } - else { - self.hidden = hidden; - } -} - -@end diff --git a/sdk/internal/MRAID/ANMRAIDCalendarManager.h b/sdk/internal/MRAID/ANMRAIDCalendarManager.h new file mode 100644 index 000000000..5caf38cfe --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDCalendarManager.h @@ -0,0 +1,40 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +@protocol ANMRAIDCalendarManagerDelegate; + +@interface ANMRAIDCalendarManager : NSObject + +- (instancetype)initWithCalendarDictionary:(NSDictionary *)dict + delegate:(id)delegate; + +@property (nonatomic, readwrite, weak) id delegate; + +@end + +@protocol ANMRAIDCalendarManagerDelegate + +- (UIViewController *)rootViewControllerForPresentationForCalendarManager:(ANMRAIDCalendarManager *)calendarManager; + +@optional +- (void)willPresentCalendarEditForCalendarManager:(ANMRAIDCalendarManager *)calendarManager; +- (void)didPresentCalendarEditForCalendarManager:(ANMRAIDCalendarManager *)calendarManager; +- (void)willDismissCalendarEditForCalendarManager:(ANMRAIDCalendarManager *)calendarManager; +- (void)didDismissCalendarEditForCalendarManager:(ANMRAIDCalendarManager *)calendarManager; +- (void)calendarManager:(ANMRAIDCalendarManager *)calendarManager calendarEditFailedWithErrorString:(NSString *)errorString; + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDCalendarManager.m b/sdk/internal/MRAID/ANMRAIDCalendarManager.m new file mode 100644 index 000000000..713108c05 --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDCalendarManager.m @@ -0,0 +1,418 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANMRAIDCalendarManager.h" +#import +#import "ANLogging.h" +#import "ANGlobal.h" + +@interface ANMRAIDCalendarManager () + +@property (nonatomic, readwrite, strong) EKEventStore *eventStore; +@property (nonatomic, readwrite, strong) NSDictionary *calendarDict; +@property (nonatomic, readwrite, weak) EKEventEditViewController *eventEditController; + +@end + +@implementation ANMRAIDCalendarManager + +- (instancetype)initWithCalendarDictionary:(NSDictionary *)dict + delegate:(id)delegate { + if (self = [super init]) { + _calendarDict = dict; + _delegate = delegate; + [self requestAccessFromUserForCalendarAccess]; + } + return self; +} + +- (EKEventStore *)eventStore { + if (!_eventStore) _eventStore = [[EKEventStore alloc] init]; + return _eventStore; +} + +- (void)requestAccessFromUserForCalendarAccess { + __weak ANMRAIDCalendarManager *weakSelf = self; + [self.eventStore requestAccessToEntityType:EKEntityTypeEvent + completion:^(BOOL granted, NSError *error) { + dispatch_async(dispatch_get_main_queue(), ^{ + ANMRAIDCalendarManager *strongSelf = weakSelf; + if (granted) { + [strongSelf setupCalendarUI]; + } else if (error) { + ANLogError(@"MRAID creative requested calendar access, received error: %@", error); + } else { + ANLogError(@"MRAID creative requested calendar access, but access was denied."); + } + + if (!granted) { + if ([strongSelf.delegate respondsToSelector:@selector(calendarManager:calendarEditFailedWithErrorString:)]) { + [strongSelf.delegate calendarManager:strongSelf calendarEditFailedWithErrorString:@"User did not grant access to calendar"]; + } + } + }); + }]; +} + +- (void)setupCalendarUI { + UIViewController *rvc = [self.delegate rootViewControllerForPresentationForCalendarManager:self]; + if (!ANCanPresentFromViewController(rvc)) { + ANLogDebug(@"No root view controller provided, or root view controller view not attached to window - could not add event to calendar"); + if ([self.delegate respondsToSelector:@selector(calendarManager:calendarEditFailedWithErrorString:)]) { + [self.delegate calendarManager:self calendarEditFailedWithErrorString:@"Could not present Calendar UI"]; + } + return; + } + EKEvent *event = [[self class] eventWithEventStore:self.eventStore + jsonCalendarObject:self.calendarDict]; + EKEventEditViewController *eventEditController = [[EKEventEditViewController alloc] init]; + eventEditController.eventStore = self.eventStore; + eventEditController.editViewDelegate = self; + eventEditController.event = event; + self.eventEditController = eventEditController; + if ([self.delegate respondsToSelector:@selector(willPresentCalendarEditForCalendarManager:)]) { + [self.delegate willPresentCalendarEditForCalendarManager:self]; + } + __weak ANMRAIDCalendarManager *weakSelf = self; + [rvc presentViewController:eventEditController + animated:YES + completion:^{ + ANMRAIDCalendarManager *strongSelf = weakSelf; + if ([strongSelf.delegate respondsToSelector:@selector(didPresentCalendarEditForCalendarManager:)]) { + [strongSelf.delegate didPresentCalendarEditForCalendarManager:strongSelf]; + } + }]; +} + +- (void)dealloc { + self.eventEditController.delegate = nil; +} + +#pragma mark - EKEventEditViewDelegate + +- (void)eventEditViewController:(EKEventEditViewController *)controller didCompleteWithAction:(EKEventEditViewAction)action { + if (action != EKEventEditViewActionSaved) { + if ([self.delegate respondsToSelector:@selector(calendarManager:calendarEditFailedWithErrorString:)]) { + [self.delegate calendarManager:self calendarEditFailedWithErrorString:@"User did not save event"]; + } + } + if ([self.delegate respondsToSelector:@selector(willDismissCalendarEditForCalendarManager:)]) { + [self.delegate willDismissCalendarEditForCalendarManager:self]; + } + __weak ANMRAIDCalendarManager *weakSelf = self; + [controller dismissViewControllerAnimated:YES + completion:^{ + ANMRAIDCalendarManager *strongSelf = weakSelf; + if ([strongSelf.delegate respondsToSelector:@selector(didDismissCalendarEditForCalendarManager:)]) { + [strongSelf.delegate didDismissCalendarEditForCalendarManager:strongSelf]; + } + }]; +} + +#pragma mark - Basic Event Generation + ++ (EKEvent *)eventWithEventStore:(EKEventStore *)eventStore + jsonCalendarObject:(NSDictionary *)calendarObject { + EKEvent *event = [EKEvent eventWithEventStore:eventStore]; + + event.title = [calendarObject[@"description"] description]; + event.notes = [calendarObject[@"summary"] description]; + event.location = [calendarObject[@"location"] description]; + event.calendar = [eventStore defaultCalendarForNewEvents]; + event.startDate = [[self class] dateWithDateFormattersOrAsEpochTimestampForString:[calendarObject[@"start"] description]]; + NSDate *endDate = [[self class] dateWithDateFormattersOrAsEpochTimestampForString:[calendarObject[@"end"] description]]; + if (!endDate) { + endDate = [event.startDate dateByAddingTimeInterval:3600]; + } + event.endDate = endDate; + + ANLogDebug(@"Event start date: %@", event.startDate); + ANLogDebug(@"Event end date: %@", event.endDate); + + EKAlarm *reminder = [[self class] alarmWithReminderString:[calendarObject[@"reminder"] description]]; + if (reminder) { + [event addAlarm:reminder]; + } + + id recurrenceObject = calendarObject[@"recurrence"]; + if ([recurrenceObject isKindOfClass:[NSDictionary class]]) { + EKRecurrenceRule *recurrenceRule = [[self class] recurrenceRuleForRecurrence:(NSDictionary *)recurrenceObject]; + if (recurrenceRule) { + [event addRecurrenceRule:recurrenceRule]; + } + } + + return event; +} + +// Read-only property ++ (EKEventStatus)eventStatusForStatus:(NSString *)status { + if ([status isEqualToString:@"tentative"]) { + return EKEventStatusTentative; + } else if ([status isEqualToString:@"confirmed"]) { + return EKEventStatusConfirmed; + } else if ([status isEqualToString:@"cancelled"]) { + return EKEventStatusCanceled; + } + + return EKEventStatusNone; +} + ++ (EKAlarm *)alarmWithReminderString:(NSString *)reminder { + if (!reminder.length) { + return nil; + } + + NSDate *date = [[self class] dateWithDateFormattersForDateString:reminder]; + if (date) { + return [EKAlarm alarmWithAbsoluteDate:date]; + } else { + return [EKAlarm alarmWithRelativeOffset:([reminder doubleValue] / 1000.0)]; + } +} + +#pragma mark - Event Recurrences + ++ (EKRecurrenceRule *)recurrenceRuleForRecurrence:(NSDictionary *)recurrence { + EKRecurrenceFrequency frequency = [[self class] recurrenceFrequencyForFrequency:[recurrence[@"frequency"] description]]; + NSInteger interval = [[self class] intervalForIntervalString:[recurrence[@"interval"] description]]; + EKRecurrenceEnd *end = [[self class] recurrenceEndForExpires:[recurrence[@"expires"] description]]; + + NSArray *daysOfTheWeek = nil; + NSArray *daysOfTheMonth = nil; + NSArray *monthsOfTheYear = nil; + NSArray *daysOfTheYear = nil; + + id daysInWeekObject = recurrence[@"daysInWeek"]; + if ([daysInWeekObject isKindOfClass:[NSArray class]]) { + daysOfTheWeek = [[self class] EKRecurrenceDaysOfTheWeekArrayForDaysInWeekArray:(NSArray *)daysInWeekObject]; + } + + id daysInMonthObject = recurrence[@"daysInMonth"]; + if ([daysInMonthObject isKindOfClass:[NSArray class]]) { + daysOfTheMonth = [[self class] EKRecurrenceDaysOfTheMonthArrayForDaysInMonthArray:(NSArray *)daysInMonthObject]; + } + + id weeksInMonthObject = recurrence[@"weeksInMonth"]; + if ([weeksInMonthObject isKindOfClass:[NSArray class]]) { + NSArray *updatedDaysOfTheWeek = [[self class] updatedEKRecurrenceDaysOfTheWeekArrayForWeeksInMonthArray:(NSArray *)weeksInMonthObject + EKRecurrenceDaysOfTheWeekArray:daysOfTheWeek]; + if (updatedDaysOfTheWeek) { + daysOfTheWeek = updatedDaysOfTheWeek; + } + } + + id monthsInYearObject = recurrence[@"monthsInYear"]; + if ([monthsInYearObject isKindOfClass:[NSArray class]]) { + monthsOfTheYear = [[self class] EKRecurrenceMonthsOfTheYearArrayForMonthsInYearArray:(NSArray *)monthsInYearObject]; + } + + id daysInYearObject = recurrence[@"daysInYear"]; + if ([daysInYearObject isKindOfClass:[NSArray class]]) { + daysOfTheYear = [[self class] EKRecurrenceDaysOfTheYearArrayForDaysInYearArray:(NSArray *)daysInYearObject]; + } + + return [[EKRecurrenceRule alloc] initRecurrenceWithFrequency:frequency + interval:interval + daysOfTheWeek:daysOfTheWeek + daysOfTheMonth:daysOfTheMonth + monthsOfTheYear:monthsOfTheYear + weeksOfTheYear:nil + daysOfTheYear:daysOfTheYear + setPositions:nil + end:end]; +} + ++ (NSInteger)intervalForIntervalString:(NSString *)intervalString { + if (!intervalString.length) { + return 1; + } + NSInteger interval = [intervalString integerValue]; + if (interval < 1) { + interval = 1; + } + return interval; +} + ++ (EKRecurrenceFrequency)recurrenceFrequencyForFrequency:(NSString *)frequency { + if ([frequency isEqualToString:@"daily"]) { + return EKRecurrenceFrequencyDaily; + } else if ([frequency isEqualToString:@"weekly"]) { + return EKRecurrenceFrequencyWeekly; + } else if ([frequency isEqualToString:@"monthly"]) { + return EKRecurrenceFrequencyMonthly; + } else if ([frequency isEqualToString:@"yearly"]) { + return EKRecurrenceFrequencyYearly; + } + + return -1; +} + ++ (EKRecurrenceEnd *)recurrenceEndForExpires:(NSString *)expires { + if (!expires.length) { + return nil; + } + + NSDate *date = [[self class] dateWithDateFormattersOrAsEpochTimestampForString:expires]; + if (date) { + return [EKRecurrenceEnd recurrenceEndWithEndDate:date]; + } + return nil; +} + ++ (NSArray *)EKRecurrenceDaysOfTheWeekArrayForDaysInWeekArray:(NSArray *)daysInWeek { + if (!daysInWeek.count) { + return nil; + } + + NSMutableArray *ekRecurrenceDaysOfWeekArray = [[NSMutableArray alloc] init]; + [daysInWeek enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSInteger dayInWeek = [obj integerValue]; + if (dayInWeek >= 0 && dayInWeek <= 6) { + [ekRecurrenceDaysOfWeekArray addObject:[EKRecurrenceDayOfWeek dayOfWeek:dayInWeek+1]]; + } else { + ANLogDebug(@"MRAID creative passed invalid W3 day of week: %ld", (long)dayInWeek); + } + }]; + return [ekRecurrenceDaysOfWeekArray copy]; +} + ++ (NSArray *)EKRecurrenceDaysOfTheMonthArrayForDaysInMonthArray:(NSArray *)daysInMonth { + if (!daysInMonth.count) { + return nil; + } + + NSMutableArray *ekRecurrenceDaysOfMonthArray = [[NSMutableArray alloc] init]; + [daysInMonth enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSInteger dayInMonth = [obj integerValue]; + + if (dayInMonth >= -30 && dayInMonth <= 31) { + if (dayInMonth <= 0) { + dayInMonth = dayInMonth - 1; + } + [ekRecurrenceDaysOfMonthArray addObject:@(dayInMonth)]; + } else { + ANLogDebug(@"MRAID creative passed invalid W3 day of month: %ld", (long)dayInMonth); + return; + } + }]; + return [ekRecurrenceDaysOfMonthArray copy]; +} + ++ (NSArray *)updatedEKRecurrenceDaysOfTheWeekArrayForWeeksInMonthArray:(NSArray *)weeksInMonth + EKRecurrenceDaysOfTheWeekArray:(NSArray *)daysOfTheWeek { + if (!weeksInMonth.count) { + return daysOfTheWeek; + } + + NSMutableArray *ekRecurrenceDaysOfWeekArray = [[NSMutableArray alloc] init]; + [weeksInMonth enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + __block NSInteger weekNumber = [obj integerValue]; + if (weekNumber >= -3 && weekNumber <= 4) { + [daysOfTheWeek enumerateObjectsUsingBlock:^(EKRecurrenceDayOfWeek *dayOfWeek, NSUInteger idx, BOOL *stop) { + if (weekNumber <= 0) { + weekNumber = weekNumber - 1; + } + [ekRecurrenceDaysOfWeekArray addObject:[EKRecurrenceDayOfWeek dayOfWeek:dayOfWeek.dayOfTheWeek + weekNumber:weekNumber]]; + }]; + } else { + ANLogDebug(@"MRAID creative passed invalid W3 week in month: %ld", (long)weekNumber); + } + }]; + return [ekRecurrenceDaysOfWeekArray copy]; +} + ++ (NSArray *)EKRecurrenceDaysOfTheYearArrayForDaysInYearArray:(NSArray *)daysInYear { + if (!daysInYear.count) { + return nil; + } + + NSMutableArray *ekRecurrenceDaysOfYearArray = [[NSMutableArray alloc] init]; + [daysInYear enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSInteger dayInYear = [obj integerValue]; + if (dayInYear >= -364 && dayInYear <= 365) { + if (dayInYear <= 0) { + dayInYear = dayInYear - 1; + } + [ekRecurrenceDaysOfYearArray addObject:@(dayInYear)]; + } + }]; + return ekRecurrenceDaysOfYearArray; +} + ++ (NSArray *)EKRecurrenceMonthsOfTheYearArrayForMonthsInYearArray:(NSArray *)monthsInYear { + if (!monthsInYear.count) { + return nil; + } + + NSMutableArray *ekRecurrenceMonthsOfYearArray = [[NSMutableArray alloc] init]; + [monthsInYear enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSInteger monthInYear = [obj integerValue]; + if (monthInYear > 0 && monthInYear <= 12) { + [ekRecurrenceMonthsOfYearArray addObject:@(monthInYear)]; + } + }]; + return ekRecurrenceMonthsOfYearArray; +} + +#pragma mark - Helper methods + ++ (NSDate *)dateWithDateFormattersOrAsEpochTimestampForString:(NSString *)dateString { + if (!dateString.length) { + return nil; + } + + NSDate *date = [[self class] dateWithDateFormattersForDateString:dateString]; + if (!date) { + date = [NSDate dateWithTimeIntervalSince1970:[dateString doubleValue]]; + } + return date; +} + ++ (NSDate *)dateWithDateFormattersForDateString:(NSString *)dateString { + if (!dateString.length) { + return nil; + } + + NSDate *date = [[[self class] sharedDateFormatter1] dateFromString:dateString]; + if (!date) { + date = [[[self class] sharedDateFormatter2] dateFromString:dateString]; + } + + return date; +} + ++ (NSDateFormatter *)sharedDateFormatter1 { + static NSDateFormatter *dateFormatter1; + static dispatch_once_t dateFormatter1Token; + dispatch_once(&dateFormatter1Token, ^{ + dateFormatter1 = [[NSDateFormatter alloc] init]; + dateFormatter1.dateFormat = @"yyyy-MM-dd'T'HH:mmZZZZZ"; + }); + return dateFormatter1; +} + ++ (NSDateFormatter *)sharedDateFormatter2 { + static NSDateFormatter *dateFormatter2; + static dispatch_once_t dateFormatter2Token; + dispatch_once(&dateFormatter2Token, ^{ + dateFormatter2 = [[NSDateFormatter alloc] init]; + dateFormatter2.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZZZZZ"; + }); + return dateFormatter2; +} + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDContainerView.h b/sdk/internal/MRAID/ANMRAIDContainerView.h new file mode 100644 index 000000000..1defa92e1 --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDContainerView.h @@ -0,0 +1,33 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import +#import "ANAdWebViewController.h" + +@protocol ANAdViewInternalDelegate; + +@interface ANMRAIDContainerView : UIView + +- (instancetype)initWithSize:(CGSize)size + HTML:(NSString *)html + webViewBaseURL:(NSURL *)baseURL; + +@property (nonatomic, readonly, assign) CGSize size; +@property (nonatomic, readonly, strong) ANAdWebViewController *webViewController; + +@property (nonatomic, readwrite, weak) id adViewDelegate; +@property (nonatomic, readwrite, assign) BOOL embeddedInModalView; + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDContainerView.m b/sdk/internal/MRAID/ANMRAIDContainerView.m new file mode 100644 index 000000000..c81989524 --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDContainerView.m @@ -0,0 +1,702 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANMRAIDContainerView.h" +#import "UIView+ANCategory.h" +#import "ANGlobal.h" +#import "ANMRAIDResizeViewManager.h" +#import "ANAdViewInternalDelegate.h" +#import "ANMRAIDCalendarManager.h" +#import "ANMRAIDExpandViewController.h" +#import "ANMRAIDExpandProperties.h" +#import "ANMRAIDOrientationProperties.h" +#import "ANLogging.h" +#import "ANBrowserViewController.h" +#import "ANClickOverlayView.h" +#import "ANPBBuffer.h" +#import "ANANJAMImplementation.h" + +typedef NS_OPTIONS(NSUInteger, ANMRAIDContainerViewAdInteraction) { + ANMRAIDContainerViewAdInteractionExpandedOrResized = 1 << 0, + ANMRAIDContainerViewAdInteractionVideo = 1 << 1, + ANMRAIDContainerViewAdInteractionBrowser = 1 << 2, + ANMRAIDContainerViewAdInteractionCalendar = 1 << 3, + ANMRAIDContainerViewAdInteractionPicture = 1 << 4 +}; + +@interface ANMRAIDContainerView () + +@property (nonatomic, readwrite, assign) CGSize size; +@property (nonatomic, readwrite, strong) NSURL *baseURL; + +@property (nonatomic, readwrite, strong) ANAdWebViewController *webViewController; +@property (nonatomic, readwrite, strong) ANMRAIDResizeViewManager *resizeManager; +@property (nonatomic, readwrite, strong) ANMRAIDCalendarManager *calendarManager; +@property (nonatomic, readwrite, strong) ANBrowserViewController *browserViewController; +@property (nonatomic, readwrite, strong) ANMRAIDExpandViewController *expandController; +@property (nonatomic, readwrite, strong) ANMRAIDOrientationProperties *orientationProperties; + +@property (nonatomic, readwrite, assign) BOOL useCustomClose; +@property (nonatomic, readwrite, strong) UIButton *customCloseRegion; + +@property (nonatomic, readwrite, strong) ANClickOverlayView *clickOverlay; + +@property (nonatomic, readwrite, strong) NSMutableArray *pitbullCaptureURLQueue; +@property (nonatomic, readwrite, assign) BOOL isRegisteredForPitbullScreenCaptureNotifications; + +@property (nonatomic, readwrite, assign) BOOL adInteractionInProgress; +@property (nonatomic, readwrite, assign) NSUInteger adInteractionValue; + +@property (nonatomic, readonly, assign, getter=isExpanded) BOOL expanded; +@property (nonatomic, readonly, assign, getter=isResized) BOOL resized; + +@property (nonatomic, readwrite, assign) CGRect lastKnownDefaultPosition; +@property (nonatomic, readwrite, assign) CGRect lastKnownCurrentPosition; + +@property (nonatomic, readwrite, strong) ANAdWebViewController *expandWebViewController; + +@end + +@implementation ANMRAIDContainerView + +- (instancetype)initWithSize:(CGSize)size + HTML:(NSString *)html + webViewBaseURL:(NSURL *)baseURL { + if (self = [super initWithFrame:CGRectMake(0, 0, size.width, size.height)]) { + _size = size; + _baseURL = baseURL; + + _lastKnownCurrentPosition = CGRectMake(0, 0, size.width, size.height); + _lastKnownDefaultPosition = CGRectMake(0, 0, size.width, size.height); + + self.webViewController = [[ANAdWebViewController alloc] initWithSize:size + HTML:html + webViewBaseURL:baseURL]; + self.webViewController.mraidDelegate = self; + self.webViewController.browserDelegate = self; + self.webViewController.pitbullDelegate = self; + self.webViewController.anjamDelegate = self; + + self.backgroundColor = [UIColor clearColor]; + + UIView *contentView = self.webViewController.contentView; + contentView.translatesAutoresizingMaskIntoConstraints = NO; + [self addSubview:contentView]; + [contentView constrainToSizeOfSuperview]; + [contentView alignToSuperviewWithXAttribute:NSLayoutAttributeLeft + yAttribute:NSLayoutAttributeTop]; + } + return self; +} + +- (void)setAdViewDelegate:(id)adViewDelegate { + _adViewDelegate = adViewDelegate; + self.webViewController.adViewDelegate = adViewDelegate; + self.expandWebViewController.adViewDelegate = adViewDelegate; + if ([adViewDelegate conformsToProtocol:@protocol(ANInterstitialAdViewInternalDelegate)]) { + id interstitialDelegate = (id)adViewDelegate; + [interstitialDelegate adShouldSetOrientationProperties:self.orientationProperties]; + [interstitialDelegate adShouldUseCustomClose:self.useCustomClose]; + if (self.useCustomClose) { + [self addSupplementaryCustomCloseRegion]; + } + } +} + +- (UIViewController *)displayController { + UIViewController *presentingVC = self.isExpanded ? self.expandController : [self.adViewDelegate displayController]; + if (ANCanPresentFromViewController(presentingVC)) { + return presentingVC; + } + return nil; +} + +- (void)adInteractionBeganWithInteraction:(ANMRAIDContainerViewAdInteraction)interaction { + self.adInteractionValue = self.adInteractionValue | interaction; + self.adInteractionInProgress = self.adInteractionValue != 0; +} + +- (void)adInteractionEndedForInteraction:(ANMRAIDContainerViewAdInteraction)interaction { + self.adInteractionValue = self.adInteractionValue & ~interaction; + self.adInteractionInProgress = self.adInteractionValue != 0; +} + +- (void)setAdInteractionInProgress:(BOOL)adInteractionInProgress { + BOOL oldValue = _adInteractionInProgress; + _adInteractionInProgress = adInteractionInProgress; + BOOL newValue = _adInteractionInProgress; + if (oldValue != newValue) { + if (_adInteractionInProgress) { + [self.adViewDelegate adInteractionDidBegin]; + } else { + [self.adViewDelegate adInteractionDidEnd]; + } + } +} + +#pragma mark - ANNewAdWebViewControllerMRAIDDelegate + +- (CGRect)defaultPosition { + if (self.window) { + CGRect absoluteContentViewFrame = [self convertRect:self.bounds toView:nil]; + CGRect position = adjustAbsoluteRectInWindowCoordinatesForOrientationGivenRect(absoluteContentViewFrame); + position.origin.y -= ([ANMRAIDUtil screenSize].height - [ANMRAIDUtil maxSize].height); + self.lastKnownDefaultPosition = position; + return position; + } else { + return self.lastKnownDefaultPosition; + } +} + +- (CGRect)currentPosition { + UIView *contentView = self.webViewController.contentView; + if (self.expandWebViewController.contentView.window) { + contentView = self.expandWebViewController.contentView; + } + + if (contentView) { + CGRect absoluteContentViewFrame = [contentView convertRect:contentView.bounds toView:nil]; + CGRect position = adjustAbsoluteRectInWindowCoordinatesForOrientationGivenRect(absoluteContentViewFrame); + position.origin.y -= ([ANMRAIDUtil screenSize].height - [ANMRAIDUtil maxSize].height); + self.lastKnownCurrentPosition = position; + return position; + } else { + return self.lastKnownCurrentPosition; + } +} + +- (BOOL)isViewable { + return self.expandWebViewController ? [self.expandWebViewController.contentView an_isViewable] : [self.webViewController.contentView an_isViewable]; +} + +- (void)adShouldExpandWithExpandProperties:(ANMRAIDExpandProperties *)expandProperties { + UIViewController *presentingController = [self displayController]; + if (!presentingController) { + ANLogDebug(@"Ignoring call to mraid.expand() - no root view controller to present from"); + return; + } + + [self handleBrowserLoadingForMRAIDStateChange]; + [self adInteractionBeganWithInteraction:ANMRAIDContainerViewAdInteractionExpandedOrResized]; + + ANLogDebug(@"Expanding with expand properties: %@", [expandProperties description]); + [self.adViewDelegate adWillPresent]; + if (self.isResized) { + [self.resizeManager detachResizeView]; + self.resizeManager = nil; + } + + UIView *expandContentView = self.webViewController.contentView; + + BOOL presentWithAnimation = NO; + + if (expandProperties.URL.absoluteString.length) { + ANAdWebViewControllerConfiguration *customConfig = [[ANAdWebViewControllerConfiguration alloc] init]; + customConfig.scrollingEnabled = YES; + customConfig.navigationTriggersDefaultBrowser = NO; + customConfig.initialMRAIDState = ANMRAIDStateExpanded; + self.expandWebViewController = [[ANAdWebViewController alloc] initWithSize:[ANMRAIDUtil screenSize] + URL:expandProperties.URL + webViewBaseURL:self.baseURL + configuration:customConfig]; + self.expandWebViewController.mraidDelegate = self; + self.expandWebViewController.browserDelegate = self; + self.expandWebViewController.pitbullDelegate = self; + self.expandWebViewController.anjamDelegate = self; + self.expandWebViewController.adViewDelegate = self.adViewDelegate; + + expandContentView = self.expandWebViewController.contentView; + presentWithAnimation = YES; + } + + self.expandController = [[ANMRAIDExpandViewController alloc] initWithContentView:expandContentView + expandProperties:expandProperties]; + if (self.orientationProperties) { + [self adShouldSetOrientationProperties:self.orientationProperties]; + } + self.expandController.delegate = self; + [presentingController presentViewController:self.expandController + animated:presentWithAnimation + completion:^{ + [self.adViewDelegate adDidPresent]; + [self.webViewController adDidFinishExpand]; + }]; +} + +- (void)adShouldSetOrientationProperties:(ANMRAIDOrientationProperties *)orientationProperties { + ANLogDebug(@"Setting orientation properties: %@", [orientationProperties description]); + self.orientationProperties = orientationProperties; + if (self.expandController) { + self.expandController.orientationProperties = orientationProperties; + } else if ([self.adViewDelegate conformsToProtocol:@protocol(ANInterstitialAdViewInternalDelegate)]) { + id interstitialDelegate = (id)self.adViewDelegate; + [interstitialDelegate adShouldSetOrientationProperties:orientationProperties]; + } +} + +- (void)adShouldSetUseCustomClose:(BOOL)useCustomClose { + ANLogDebug(@"Setting useCustomClose: %d", useCustomClose); + self.useCustomClose = useCustomClose; + if ([self.adViewDelegate conformsToProtocol:@protocol(ANInterstitialAdViewInternalDelegate)]) { + id interstitialDelegate = (id)self.adViewDelegate; + [interstitialDelegate adShouldUseCustomClose:useCustomClose]; + if (useCustomClose) { + [self addSupplementaryCustomCloseRegion]; + } + } +} + +- (void)addSupplementaryCustomCloseRegion { + self.customCloseRegion = [UIButton buttonWithType:UIButtonTypeCustom]; + self.customCloseRegion.translatesAutoresizingMaskIntoConstraints = NO; + [self insertSubview:self.customCloseRegion + aboveSubview:self.webViewController.contentView]; + [self.customCloseRegion constrainWithSize:CGSizeMake(50.0, 50.0)]; + [self.customCloseRegion alignToSuperviewWithXAttribute:NSLayoutAttributeRight + yAttribute:NSLayoutAttributeTop]; + [self.customCloseRegion addTarget:self + action:@selector(closeInterstitial:) + forControlEvents:UIControlEventTouchUpInside]; +} + +- (void)closeInterstitial:(id)sender { + if ([self.adViewDelegate conformsToProtocol:@protocol(ANInterstitialAdViewInternalDelegate)]) { + id interstitialDelegate = (id)self.adViewDelegate; + [interstitialDelegate adShouldClose]; + } +} + +- (void)adShouldAttemptResizeWithResizeProperties:(ANMRAIDResizeProperties *)resizeProperties { + ANLogDebug(@"Attempting resize with resize properties: %@", [resizeProperties description]); + [self handleBrowserLoadingForMRAIDStateChange]; + [self adInteractionBeganWithInteraction:ANMRAIDContainerViewAdInteractionExpandedOrResized]; + + if (!self.resizeManager) { + self.resizeManager = [[ANMRAIDResizeViewManager alloc] initWithContentView:self.webViewController.contentView + anchorView:self]; + self.resizeManager.delegate = self; + } + + NSString *errorString; + BOOL resizeHappened = [self.resizeManager attemptResizeWithResizeProperties:resizeProperties + errorString:&errorString]; + [self.webViewController adDidFinishResize:resizeHappened + errorString:errorString + isResized:self.isResized]; + if (!self.isResized) { + [self adInteractionEndedForInteraction:ANMRAIDContainerViewAdInteractionExpandedOrResized]; + } +} + +- (void)adShouldClose { + if (self.isResized || self.isExpanded) { + [self adShouldResetToDefault]; + } else { + [self adShouldHide]; + } + + [self adInteractionEndedForInteraction:ANMRAIDContainerViewAdInteractionExpandedOrResized]; +} + +- (void)adShouldResetToDefault { + [self.resizeManager detachResizeView]; + self.resizeManager = nil; + + [self handleBrowserLoadingForMRAIDStateChange]; + + if (self.isExpanded) { + [self.adViewDelegate adWillClose]; + + BOOL dismissWithAnimation = NO; + UIView *detachedContentView = [self.expandController detachContentView]; + if (detachedContentView == self.expandWebViewController.contentView) { + dismissWithAnimation = YES; + } + + [self.expandController dismissViewControllerAnimated:dismissWithAnimation + completion:^{ + [self.adViewDelegate adDidClose]; + }]; + self.expandController = nil; + } + + self.expandWebViewController = nil; + + UIView *contentView = self.webViewController.contentView; + if (contentView.superview != self) { + [self addSubview:contentView]; + [contentView removeConstraints:contentView.constraints]; + [contentView constrainToSizeOfSuperview]; + [contentView alignToSuperviewWithXAttribute:NSLayoutAttributeLeft + yAttribute:NSLayoutAttributeTop]; + } + + [self.webViewController adDidResetToDefault]; + [self adInteractionEndedForInteraction:ANMRAIDContainerViewAdInteractionExpandedOrResized]; +} + +- (void)adShouldHide { + [self handleBrowserLoadingForMRAIDStateChange]; + + if (self.embeddedInModalView && [self.adViewDelegate conformsToProtocol:@protocol(ANInterstitialAdViewInternalDelegate)]) { + id interstitialDelegate = (id)self.adViewDelegate; + [interstitialDelegate adShouldClose]; + } else { + [UIView animateWithDuration:kAppNexusAnimationDuration + animations:^{ + self.webViewController.contentView.alpha = 0.0f; + } completion:^(BOOL finished) { + self.webViewController.contentView.hidden = YES; + }]; + [self.webViewController adDidHide]; + } + [self adInteractionEndedForInteraction:ANMRAIDContainerViewAdInteractionExpandedOrResized]; +} + +- (void)adShouldOpenCalendarWithCalendarDict:(NSDictionary *)calendarDict { + [self adInteractionBeganWithInteraction:ANMRAIDContainerViewAdInteractionCalendar]; + self.calendarManager = [[ANMRAIDCalendarManager alloc] initWithCalendarDictionary:calendarDict + delegate:self]; +} + +- (void)adShouldSavePictureWithUri:(NSString *)uri { + [self adInteractionBeganWithInteraction:ANMRAIDContainerViewAdInteractionPicture]; + [ANMRAIDUtil storePictureWithUri:uri + withCompletionTarget:self + completionSelector:@selector(image:didFinishSavingWithError:contextInfo:)]; +} + +- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { + if (error) { + [self.webViewController adDidFailPhotoSaveWithErrorString:error.localizedDescription]; + [self.expandWebViewController adDidFailPhotoSaveWithErrorString:error.localizedDescription]; + } + [self adInteractionEndedForInteraction:ANMRAIDContainerViewAdInteractionPicture]; +} + +- (void)adShouldPlayVideoWithUri:(NSString *)uri { + UIViewController *presentingViewController = [self displayController]; + if (!presentingViewController) { + ANLogDebug(@"Ignoring call to mraid.playVideo() - no root view controller to present from"); + return; + } + [self adInteractionBeganWithInteraction:ANMRAIDContainerViewAdInteractionVideo]; + self.resizeManager.resizeView.hidden = YES; + [ANMRAIDUtil playVideoWithUri:uri + fromRootViewController:presentingViewController + withCompletionTarget:self + completionSelector:@selector(moviePlayerDidFinish:)]; +} + +- (void)moviePlayerDidFinish:(NSNotification *)notification { + self.resizeManager.resizeView.hidden = NO; + [self adInteractionEndedForInteraction:ANMRAIDContainerViewAdInteractionVideo]; +} + +- (void)didMoveToWindow { + [self.resizeManager didMoveAnchorViewToWindow]; +} + +- (BOOL)isExpanded { + return self.expandController.presentingViewController ? YES : NO; +} + +- (BOOL)isResized { + return self.resizeManager.isResized; +} + +#pragma mark - ANCalendarManagerDelegate + +- (UIViewController *)rootViewControllerForPresentationForCalendarManager:(ANMRAIDCalendarManager *)calendarManager { + return [self displayController]; +} + +- (void)willDismissCalendarEditForCalendarManager:(ANMRAIDCalendarManager *)calendarManager { + if (!self.embeddedInModalView && !self.isExpanded) { + [self.adViewDelegate adWillClose]; + } + self.resizeManager.resizeView.hidden = NO; +} + +- (void)didDismissCalendarEditForCalendarManager:(ANMRAIDCalendarManager *)calendarManager { + if (!self.embeddedInModalView && !self.isExpanded) { + [self.adViewDelegate adDidClose]; + } + [self adInteractionEndedForInteraction:ANMRAIDContainerViewAdInteractionCalendar]; +} + +- (void)willPresentCalendarEditForCalendarManager:(ANMRAIDCalendarManager *)calendarManager { + if (!self.embeddedInModalView && !self.isExpanded) { + [self.adViewDelegate adWillPresent]; + } + self.resizeManager.resizeView.hidden = YES; +} + +- (void)didPresentCalendarEditForCalendarManager:(ANMRAIDCalendarManager *)calendarManager { + if (!self.embeddedInModalView && !self.isExpanded) { + [self.adViewDelegate adDidPresent]; + } +} + +- (void)calendarManager:(ANMRAIDCalendarManager *)calendarManager calendarEditFailedWithErrorString:(NSString *)errorString { + [self.webViewController adDidFailCalendarEditWithErrorString:errorString]; + [self.expandWebViewController adDidFailPhotoSaveWithErrorString:errorString]; + [self adInteractionEndedForInteraction:ANMRAIDContainerViewAdInteractionCalendar]; +} + +#pragma mark - ANResizeViewManagerDelegate + +- (void)resizeViewClosedByResizeViewManager:(ANMRAIDResizeViewManager *)manager { + [self adShouldResetToDefault]; +} + +#pragma mark - ANMRAIDExpandViewControllerDelegate + +- (void)closeButtonWasTappedOnExpandViewController:(ANMRAIDExpandViewController *)controller { + [self adShouldResetToDefault]; +} + +- (void)dismissAndPresentAgainForPreferredInterfaceOrientationChange { + __weak ANMRAIDContainerView *weakSelf = self; + UIViewController *presentingViewController = self.expandController.presentingViewController; + [presentingViewController dismissViewControllerAnimated:NO + completion:^{ + ANMRAIDContainerView *strongSelf = weakSelf; + [presentingViewController presentViewController:strongSelf.expandController + animated:NO + completion:nil]; + }]; +} + +#pragma mark - ANWebViewControllerBrowserDelegate + +- (void)openDefaultBrowserWithURL:(NSURL *)URL { + if (!self.adViewDelegate) { + ANLogDebug(@"Ignoring attempt to trigger browser on ad while not attached to a view."); + return; + } + + [self.adViewDelegate adWasClicked]; + + if (![self.adViewDelegate opensInNativeBrowser]) { + [self openInAppBrowserWithURL:URL]; + } + else if ([[UIApplication sharedApplication] canOpenURL:URL]) { + [self.adViewDelegate adWillLeaveApplication]; + [[UIApplication sharedApplication] openURL:URL]; + } else { + ANLogWarn(@"opening_url_failed %@", URL); + } +} + +- (void)openInAppBrowserWithURL:(NSURL *)URL { + [self adInteractionBeganWithInteraction:ANMRAIDContainerViewAdInteractionBrowser]; + if (!self.browserViewController) { + self.browserViewController = [[ANBrowserViewController alloc] initWithURL:URL + delegate:self + delayPresentationForLoad:[self.adViewDelegate landingPageLoadsInBackground]]; + if (!self.browserViewController) { + ANLogError(@"Browser controller did not instantiate correctly."); + return; + } + } else { + self.browserViewController.url = URL; + } +} + +#pragma mark - ANBrowserViewControllerDelegate + +- (UIViewController *)rootViewControllerForDisplayingBrowserViewController:(ANBrowserViewController *)controller { + return [self displayController]; +} + +- (void)browserViewController:(ANBrowserViewController *)controller browserIsLoading:(BOOL)isLoading { + if ([self.adViewDelegate landingPageLoadsInBackground]) { + if (!controller.completedInitialLoad) { + isLoading ? [self showClickOverlay] : [self hideClickOverlay]; + } else { + [self hideClickOverlay]; + } + } +} + +- (void)willDismissBrowserViewController:(ANBrowserViewController *)controller { + if (!self.embeddedInModalView && !self.isExpanded) { + [self.adViewDelegate adWillClose]; + } + self.resizeManager.resizeView.hidden = NO; +} + +- (void)didDismissBrowserViewController:(ANBrowserViewController *)controller { + self.browserViewController = nil; + if (!self.embeddedInModalView && !self.isExpanded) { + [self.adViewDelegate adDidClose]; + } + [self hideClickOverlay]; + [self adInteractionEndedForInteraction:ANMRAIDContainerViewAdInteractionBrowser]; +} + +- (void)willPresentBrowserViewController:(ANBrowserViewController *)controller { + if (!self.embeddedInModalView && !self.isExpanded) { + [self.adViewDelegate adWillPresent]; + } + self.resizeManager.resizeView.hidden = YES; + [self adInteractionBeganWithInteraction:ANMRAIDContainerViewAdInteractionBrowser]; +} + +- (void)didPresentBrowserViewController:(ANBrowserViewController *)controller { + if (!self.embeddedInModalView && !self.isExpanded) { + [self.adViewDelegate adDidPresent]; + } +} + +- (void)willLeaveApplicationFromBrowserViewController:(ANBrowserViewController *)controller { + [self.adViewDelegate adWillLeaveApplication]; +} + +- (void)handleBrowserLoadingForMRAIDStateChange { + [self.browserViewController stopLoading]; + [self adInteractionEndedForInteraction:ANMRAIDContainerViewAdInteractionBrowser]; +} + +- (void)browserViewController:(ANBrowserViewController *)controller + couldNotHandleInitialURL:(NSURL *)url { + [self adInteractionEndedForInteraction:ANMRAIDContainerViewAdInteractionBrowser]; +} + +# pragma mark - Click overlay + +- (UIView *)viewToDisplayClickOverlay { + if (self.isExpanded) { + return self.expandController.view; + } else if (self.isResized) { + return self.resizeManager.resizeView; + } else { + return self; + } +} + +- (void)showClickOverlay { + if (!self.clickOverlay.superview) { + self.clickOverlay = [ANClickOverlayView addOverlayToView:[self viewToDisplayClickOverlay]]; + self.clickOverlay.alpha = 0.0; + } + + self.clickOverlay.hidden = NO; + + [UIView animateWithDuration:0.5 + animations:^{ + self.clickOverlay.alpha = 1.0; + }]; +} + +- (void)hideClickOverlay { + if ([self.clickOverlay superview]) { + [UIView animateWithDuration:0.5 + animations:^{ + self.clickOverlay.alpha = 0.0; + } completion:^(BOOL finished) { + self.clickOverlay.hidden = YES; + }]; + } +} + +#pragma mark - ANWebViewControllerPitbullDelegate + +- (void)handlePitbullURL:(NSURL *)URL { + if ([URL.host isEqualToString:@"capture"]) { + BOOL transitionInProgress = NO; + if ([self.adViewDelegate conformsToProtocol:@protocol(ANBannerAdViewInternalDelegate)]) { + id bannerDelegate = (id)self.adViewDelegate; + transitionInProgress = [[bannerDelegate transitionInProgress] boolValue]; + } + if (transitionInProgress) { + if (![self.pitbullCaptureURLQueue count]) { + [self registerForPitbullScreenCaptureNotifications]; + } + [self.pitbullCaptureURLQueue addObject:URL]; + return; + } + } else if ([URL.host isEqualToString:@"web"]) { + [self dispatchPitbullScreenCaptureCalls]; + [self unregisterFromPitbullScreenCaptureNotifications]; + } + + [ANPBBuffer handleUrl:URL forView:self.webViewController.contentView]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + if (object == self.adViewDelegate) { + NSNumber *transitionInProgress = change[NSKeyValueChangeNewKey]; + if ([transitionInProgress boolValue] == NO) { + [self unregisterFromPitbullScreenCaptureNotifications]; + [self dispatchPitbullScreenCaptureCalls]; + } + } +} + +- (void)registerForPitbullScreenCaptureNotifications { + if (!self.isRegisteredForPitbullScreenCaptureNotifications) { + if ([self.adViewDelegate conformsToProtocol:@protocol(ANBannerAdViewInternalDelegate)]) { + NSObject *object = (id)self.adViewDelegate; + [object addObserver:self + forKeyPath:@"transitionInProgress" + options:NSKeyValueObservingOptionNew + context:nil]; + self.isRegisteredForPitbullScreenCaptureNotifications = YES; + } else { + ANLogDebug(@"Attempt to register for pitbull screen capture notifications on an ad view which does not conform to ANBannerAdViewInternalDelegate"); + } + } +} + +- (void)unregisterFromPitbullScreenCaptureNotifications { + NSObject *bannerObject = self.adViewDelegate; + if (self.isRegisteredForPitbullScreenCaptureNotifications) { + @try { + [bannerObject removeObserver:self + forKeyPath:@"transitionInProgress"]; + } + @catch (NSException * __unused exception) {} + self.isRegisteredForPitbullScreenCaptureNotifications = NO; + } +} + +- (void)dispatchPitbullScreenCaptureCalls { + for (NSURL *URL in self.pitbullCaptureURLQueue) { + UIView *view = self.webViewController.contentView; + [ANPBBuffer handleUrl:URL forView:view]; + } + self.pitbullCaptureURLQueue = nil; +} + +- (NSMutableArray *)pitbullCaptureURLQueue { + if (!_pitbullCaptureURLQueue) _pitbullCaptureURLQueue = [[NSMutableArray alloc] initWithCapacity:5]; + return _pitbullCaptureURLQueue; +} + +#pragma mark - ANWebViewControllerANJAMDelegate + +- (void)handleANJAMURL:(NSURL *)URL { + [ANANJAMImplementation handleURL:URL + withWebViewController:self.webViewController]; +} + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDExpandProperties.h b/sdk/internal/MRAID/ANMRAIDExpandProperties.h new file mode 100644 index 000000000..ef2759f7c --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDExpandProperties.h @@ -0,0 +1,32 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +@interface ANMRAIDExpandProperties : NSObject + ++ (ANMRAIDExpandProperties *)expandPropertiesFromQueryComponents:(NSDictionary *)queryComponents; + +- (instancetype)initWithWidth:(CGFloat)width + height:(CGFloat)height + URL:(NSURL *)URL + useCustomClose:(BOOL)useCustomClose; + +@property (nonatomic, readonly, assign) CGFloat width; +@property (nonatomic, readonly, assign) CGFloat height; +@property (nonatomic, readonly, strong) NSURL *URL; +@property (nonatomic, readonly, assign) BOOL useCustomClose; + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDExpandProperties.m b/sdk/internal/MRAID/ANMRAIDExpandProperties.m new file mode 100644 index 000000000..39ae2d036 --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDExpandProperties.m @@ -0,0 +1,55 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANMRAIDExpandProperties.h" +#import "ANMRAIDUtil.h" + +@implementation ANMRAIDExpandProperties + ++ (ANMRAIDExpandProperties *)expandPropertiesFromQueryComponents:(NSDictionary *)queryComponents { + CGFloat w = [queryComponents[@"h"] floatValue]; + CGFloat h = [queryComponents[@"w"] floatValue]; + NSString *urlString = queryComponents[@"url"]; + NSURL *URL = nil; + if (urlString.length) { + URL = [NSURL URLWithString:urlString]; + } + NSString *useCustomCloseString = queryComponents[@"useCustomClose"]; + BOOL useCustomClose = [useCustomCloseString isEqualToString:@"true"]; + + return [[ANMRAIDExpandProperties alloc] initWithWidth:w + height:h + URL:URL + useCustomClose:useCustomClose]; +} + +- (instancetype)initWithWidth:(CGFloat)width + height:(CGFloat)height + URL:(NSURL *)URL + useCustomClose:(BOOL)useCustomClose { + if (self = [super init]) { + _width = width; + _height = height; + _URL = URL; + _useCustomClose = useCustomClose; + } + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"(width %f, height %f, useCustomClose %d, url %@)", self.width, self.height, self.useCustomClose, self.URL]; +} + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDExpandViewController.h b/sdk/internal/MRAID/ANMRAIDExpandViewController.h new file mode 100644 index 000000000..e798c4d42 --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDExpandViewController.h @@ -0,0 +1,42 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import +#import "ANMRAIDUtil.h" + +@class ANMRAIDExpandProperties; +@class ANMRAIDOrientationProperties; +@protocol ANMRAIDExpandViewControllerDelegate; + +static CGFloat const kANMRAIDExpandViewControllerCloseRegionWidth = 50.0; +static CGFloat const kANMRAIDExpandViewControllerCloseRegionHeight = 50.0; + +@interface ANMRAIDExpandViewController : UIViewController + +- (instancetype)initWithContentView:(UIView *)contentView + expandProperties:(ANMRAIDExpandProperties *)expandProperties; +- (UIView *)detachContentView; + +@property (nonatomic, readwrite, weak) id delegate; +@property (nonatomic, readwrite, strong) ANMRAIDOrientationProperties *orientationProperties; + +@end + +@protocol ANMRAIDExpandViewControllerDelegate + +- (void)closeButtonWasTappedOnExpandViewController:(ANMRAIDExpandViewController *)controller; +- (void)dismissAndPresentAgainForPreferredInterfaceOrientationChange; + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDExpandViewController.m b/sdk/internal/MRAID/ANMRAIDExpandViewController.m new file mode 100644 index 000000000..8f08562b9 --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDExpandViewController.m @@ -0,0 +1,194 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANMRAIDExpandViewController.h" +#import "ANMRAIDExpandProperties.h" +#import "ANMRAIDOrientationProperties.h" +#import "ANGlobal.h" +#import "ANLogging.h" + +#import "UIView+ANCategory.h" + +@interface ANMRAIDExpandViewController () + +@property (nonatomic, readwrite, assign) BOOL originalStatusBarHiddenState; + +@property (nonatomic, readwrite, strong) UIView *contentView; +@property (nonatomic, readwrite, strong) ANMRAIDExpandProperties *expandProperties; + +@property (nonatomic, readwrite, weak) UIButton *closeButton; + +@end + +@implementation ANMRAIDExpandViewController + +- (instancetype)initWithContentView:(UIView *)contentView + expandProperties:(ANMRAIDExpandProperties *)expandProperties { + if (self = [super init]) { + _contentView = contentView; + _expandProperties = expandProperties; + _orientationProperties = [[ANMRAIDOrientationProperties alloc] initWithAllowOrientationChange:YES + forceOrientation:ANMRAIDOrientationNone]; + } + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor whiteColor]; + [self createCloseButton]; + [self attachContentView]; +} + +- (void)createCloseButton { + UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeCustom]; + closeButton.translatesAutoresizingMaskIntoConstraints = NO; + [closeButton addTarget:self + action:@selector(closeButtonWasTapped) + forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:closeButton]; + [closeButton constrainWithSize:CGSizeMake(kANMRAIDExpandViewControllerCloseRegionWidth, kANMRAIDExpandViewControllerCloseRegionHeight)]; + [closeButton alignToSuperviewWithXAttribute:NSLayoutAttributeRight + yAttribute:NSLayoutAttributeTop]; + if (!self.expandProperties.useCustomClose) { + BOOL atLeastiOS7 = [self respondsToSelector:@selector(modalPresentationCapturesStatusBarAppearance)]; + NSString *closeboxImageName = @"interstitial_flat_closebox"; + if (!atLeastiOS7) { + closeboxImageName = @"interstitial_closebox"; + } + UIImage *closeboxImage = [UIImage imageWithContentsOfFile:ANPathForANResource(closeboxImageName, @"png")]; + [closeButton setImage:closeboxImage + forState:UIControlStateNormal]; + } + self.closeButton = closeButton; +} + +- (void)closeButtonWasTapped { + [self.delegate closeButtonWasTappedOnExpandViewController:self]; +} + +- (void)attachContentView { + self.contentView.translatesAutoresizingMaskIntoConstraints = NO; + [self.contentView removeConstraints:self.contentView.constraints]; + [self.contentView removeSizeConstraintToSuperview]; + [self.contentView removeAlignmentConstraintsToSuperview]; + + [self.view insertSubview:self.contentView + belowSubview:self.closeButton]; + if (self.expandProperties.width == -1 && self.expandProperties.height == -1) { + [self.contentView constrainToSizeOfSuperview]; + } else { + CGRect orientedScreenBounds = adjustAbsoluteRectInWindowCoordinatesForOrientationGivenRect(ANPortraitScreenBounds()); + CGFloat expandedWidth = self.expandProperties.width; + CGFloat expandedHeight = self.expandProperties.height; + + if (expandedWidth == -1) { + expandedWidth = orientedScreenBounds.size.width; + } + if (expandedHeight == -1) { + expandedHeight = orientedScreenBounds.size.height; + } + [self.contentView constrainWithSize:CGSizeMake(expandedWidth, expandedHeight)]; + } + + [self.contentView alignToSuperviewWithXAttribute:NSLayoutAttributeLeft + yAttribute:NSLayoutAttributeTop]; +} + +- (UIView *)detachContentView { + UIView *contentView = self.contentView; + [contentView removeConstraints:contentView.constraints]; + [contentView removeSizeConstraintToSuperview]; + [contentView removeAlignmentConstraintsToSuperview]; + [contentView removeFromSuperview]; + self.contentView = nil; + return contentView; +} + +- (void)setOrientationProperties:(ANMRAIDOrientationProperties *)orientationProperties { + _orientationProperties = orientationProperties; + if ([self.view an_isViewable]) { + if (orientationProperties.allowOrientationChange && orientationProperties.forceOrientation == ANMRAIDOrientationNone) { + [UIViewController attemptRotationToDeviceOrientation]; + } else { + [self.delegate dismissAndPresentAgainForPreferredInterfaceOrientationChange]; + } + } +} + +- (NSUInteger)supportedInterfaceOrientations { + if (self.orientationProperties.allowOrientationChange) { + return UIInterfaceOrientationMaskAll; + } else { + switch (self.orientationProperties.forceOrientation) { + case ANMRAIDOrientationPortrait: + return UIInterfaceOrientationMaskPortrait; + case ANMRAIDOrientationLandscape: + return UIInterfaceOrientationMaskLandscape; + default: + return UIInterfaceOrientationMaskAll; + } + } +} + +- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { + switch (self.orientationProperties.forceOrientation) { + case ANMRAIDOrientationPortrait: + if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown) { + return UIInterfaceOrientationPortraitUpsideDown; + } + return UIInterfaceOrientationPortrait; + case ANMRAIDOrientationLandscape: + if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) { + return UIInterfaceOrientationLandscapeRight; + } + return UIInterfaceOrientationLandscapeLeft; + default: { + UIInterfaceOrientation currentOrientation = [UIApplication sharedApplication].statusBarOrientation; + return currentOrientation; + } + } +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + if (![self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) { + self.originalStatusBarHiddenState = [UIApplication sharedApplication].statusBarHidden; + [[UIApplication sharedApplication] setStatusBarHidden:YES + withAnimation:UIStatusBarAnimationNone]; + } +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + if (self.orientationProperties.allowOrientationChange) { + _orientationProperties = [[ANMRAIDOrientationProperties alloc] initWithAllowOrientationChange:YES + forceOrientation:ANMRAIDOrientationNone]; + } +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + if (![self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) { + [[UIApplication sharedApplication] setStatusBarHidden:self.originalStatusBarHiddenState + withAnimation:UIStatusBarAnimationNone]; + } +} + +- (BOOL)prefersStatusBarHidden { + return YES; +} + +@end diff --git a/sdk/internal/MRAID/ANMRAIDJavascriptUtil.h b/sdk/internal/MRAID/ANMRAIDJavascriptUtil.h new file mode 100644 index 000000000..d0e895885 --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDJavascriptUtil.h @@ -0,0 +1,36 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANMRAIDUtil.h" + +@interface ANMRAIDJavascriptUtil : NSObject + ++ (NSString *)readyEvent; ++ (NSString *)stateChange:(ANMRAIDState)state; ++ (NSString *)error:(NSString *)errorString + forFunction:(NSString *)function; ++ (NSString *)placementType:(NSString *)placementType; ++ (NSString *)isViewable:(BOOL)isViewable; ++ (NSString *)currentSize:(CGSize)size; ++ (NSString *)currentPosition:(CGRect)position; ++ (NSString *)defaultPosition:(CGRect)position; ++ (NSString *)screenSize:(CGSize)size; ++ (NSString *)maxSize:(CGSize)size; ++ (NSString *)feature:(NSString *)feature + isSupported:(BOOL)supported; + ++ (NSString *)getState; + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDJavascriptUtil.m b/sdk/internal/MRAID/ANMRAIDJavascriptUtil.m new file mode 100644 index 000000000..23eda65ea --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDJavascriptUtil.m @@ -0,0 +1,92 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANMRAIDJavascriptUtil.h" + +@implementation ANMRAIDJavascriptUtil + ++ (NSString *)readyEvent { + return @"window.mraid.util.readyEvent();"; +} + ++ (NSString *)stateChange:(ANMRAIDState)state { + NSString *stateString = [ANMRAIDUtil stateStringFromState:state]; + if (!stateString) { + stateString = @""; + } + return [NSString stringWithFormat:@"window.mraid.util.stateChangeEvent('%@');", stateString]; +} + ++ (NSString *)error:(NSString *)error + forFunction:(NSString *)function { + return [NSString stringWithFormat:@"window.mraid.util.errorEvent('%@', '%@');", error, function]; +} + ++ (NSString *)placementType:(NSString *)placementType { + return [NSString stringWithFormat:@"window.mraid.util.setPlacementType('%@');", placementType]; +} + ++ (NSString *)isViewable:(BOOL)isViewable { + return [NSString stringWithFormat:@"window.mraid.util.setIsViewable(%@);", + isViewable ? @"true" : @"false"]; +} + ++ (NSString *)currentSize:(CGSize)size { + int width = floorf(size.width + 0.5f); + int height = floorf(size.height + 0.5f); + return [NSString stringWithFormat:@"window.mraid.util.sizeChangeEvent(%i,%i);", width, height]; +} + ++ (NSString *)currentPosition:(CGRect)position { + int offsetX = (position.origin.x > 0) ? floorf(position.origin.x + 0.5f) : ceilf(position.origin.x - 0.5f); + int offsetY = (position.origin.y > 0) ? floorf(position.origin.y + 0.5f) : ceilf(position.origin.y - 0.5f); + int width = floorf(position.size.width + 0.5f); + int height = floorf(position.size.height + 0.5f); + return [NSString stringWithFormat:@"window.mraid.util.setCurrentPosition(%i, %i, %i, %i); %@", + offsetX, offsetY, width, height, [[self class] currentSize:CGSizeMake(width, height)]]; +} + ++ (NSString *)defaultPosition:(CGRect)position { + int offsetX = (position.origin.x > 0) ? floorf(position.origin.x + 0.5f) : ceilf(position.origin.x - 0.5f); + int offsetY = (position.origin.y > 0) ? floorf(position.origin.y + 0.5f) : ceilf(position.origin.y - 0.5f); + int width = floorf(position.size.width + 0.5f); + int height = floorf(position.size.height + 0.5f); + return [NSString stringWithFormat:@"window.mraid.util.setDefaultPosition(%i, %i, %i, %i);", + offsetX, offsetY, width, height]; +} + ++ (NSString *)screenSize:(CGSize)size { + int width = floorf(size.width + 0.5f); + int height = floorf(size.height + 0.5f); + return [NSString stringWithFormat:@"window.mraid.util.setScreenSize(%i, %i);", width, height]; +} + ++ (NSString *)maxSize:(CGSize)size { + int width = floorf(size.width + 0.5f); + int height = floorf(size.height + 0.5f); + return [NSString stringWithFormat:@"window.mraid.util.setMaxSize(%i, %i);", width, height]; +} + ++ (NSString *)feature:(NSString *)feature + isSupported:(BOOL)supported { + return [NSString stringWithFormat:@"window.mraid.util.setSupports(\'%@\', %@);", + feature, (supported ? @"true" : @"false")]; +} + ++ (NSString *)getState { + return @"window.mraid.getState()"; +} + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDOrientationProperties.h b/sdk/internal/MRAID/ANMRAIDOrientationProperties.h new file mode 100644 index 000000000..6952d8332 --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDOrientationProperties.h @@ -0,0 +1,28 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANMRAIDUtil.h" + +@interface ANMRAIDOrientationProperties : NSObject + ++ (ANMRAIDOrientationProperties *)orientationPropertiesFromQueryComponents:(NSDictionary *)queryComponents; + +- (instancetype)initWithAllowOrientationChange:(BOOL)allowOrientationChange + forceOrientation:(ANMRAIDOrientation)forceOrientation; + +@property (nonatomic, readonly, assign) BOOL allowOrientationChange; +@property (nonatomic, readonly, assign) ANMRAIDOrientation forceOrientation; + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDOrientationProperties.m b/sdk/internal/MRAID/ANMRAIDOrientationProperties.m new file mode 100644 index 000000000..b756b7384 --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDOrientationProperties.m @@ -0,0 +1,48 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANMRAIDOrientationProperties.h" + +@implementation ANMRAIDOrientationProperties + ++ (ANMRAIDOrientationProperties *)orientationPropertiesFromQueryComponents:(NSDictionary *)queryComponents { + NSString *allowOrientationChangeString = queryComponents[@"allow_orientation_change"]; + BOOL allowOrientationChange; + if (allowOrientationChangeString) { + allowOrientationChange = [allowOrientationChangeString boolValue]; + } else { + allowOrientationChange = YES; + } + + NSString *forceOrientationString = queryComponents[@"force_orientation"]; + ANMRAIDOrientation forceOrientation = [ANMRAIDUtil orientationFromForceOrientationString:forceOrientationString]; + return [[ANMRAIDOrientationProperties alloc] initWithAllowOrientationChange:allowOrientationChange + forceOrientation:forceOrientation]; +} + +- (instancetype)initWithAllowOrientationChange:(BOOL)allowOrientationChange + forceOrientation:(ANMRAIDOrientation)forceOrientation { + if (self = [super init]) { + _allowOrientationChange = allowOrientationChange; + _forceOrientation = forceOrientation; + } + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"(allowOrientationChange %d, forceOrientation: %lu)", self.allowOrientationChange, (long unsigned)self.forceOrientation]; +} + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDResizeProperties.h b/sdk/internal/MRAID/ANMRAIDResizeProperties.h new file mode 100644 index 000000000..08705ecbf --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDResizeProperties.h @@ -0,0 +1,36 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANMRAIDUtil.h" + +@interface ANMRAIDResizeProperties : NSObject + ++ (ANMRAIDResizeProperties *)resizePropertiesFromQueryComponents:(NSDictionary *)queryComponents; + +- (instancetype)initWithWidth:(CGFloat)width + height:(CGFloat)height + offsetX:(CGFloat)offsetX + offsetY:(CGFloat)offsetY + customClosePosition:(ANMRAIDCustomClosePosition)customClosePosition + allowOffscreen:(BOOL)allowOffscreen; + +@property (nonatomic, readonly, assign) CGFloat width; +@property (nonatomic, readonly, assign) CGFloat height; +@property (nonatomic, readonly, assign) CGFloat offsetX; +@property (nonatomic, readonly, assign) CGFloat offsetY; +@property (nonatomic, readonly, assign) ANMRAIDCustomClosePosition customClosePosition; +@property (nonatomic, readonly, assign) BOOL allowOffscreen; + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDResizeProperties.m b/sdk/internal/MRAID/ANMRAIDResizeProperties.m new file mode 100644 index 000000000..8212dbf99 --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDResizeProperties.m @@ -0,0 +1,65 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANMRAIDResizeProperties.h" + +@implementation ANMRAIDResizeProperties + ++ (ANMRAIDResizeProperties *)resizePropertiesFromQueryComponents:(NSDictionary *)queryComponents { + CGFloat w = [queryComponents[@"w"] floatValue]; + CGFloat h = [queryComponents[@"h"] floatValue]; + CGFloat offsetX = [queryComponents[@"offset_x"] floatValue]; + CGFloat offsetY = [queryComponents[@"offset_y"] floatValue]; + + NSString* customClosePositionString = [queryComponents[@"custom_close_position"] description]; + ANMRAIDCustomClosePosition closePosition = [ANMRAIDUtil customClosePositionFromCustomClosePositionString:customClosePositionString]; + + BOOL allowOffscreen; + if (queryComponents[@"allow_offscreen"]) { + allowOffscreen = [queryComponents[@"allow_offscreen"] boolValue]; + } else { + allowOffscreen = YES; + } + + return [[ANMRAIDResizeProperties alloc] initWithWidth:w + height:h + offsetX:offsetX + offsetY:offsetY + customClosePosition:closePosition + allowOffscreen:allowOffscreen]; +} + +- (instancetype)initWithWidth:(CGFloat)width + height:(CGFloat)height + offsetX:(CGFloat)offsetX + offsetY:(CGFloat)offsetY + customClosePosition:(ANMRAIDCustomClosePosition)customClosePosition + allowOffscreen:(BOOL)allowOffscreen { + if (self = [super init]) { + _width = width; + _height = height; + _offsetX = offsetX; + _offsetY = offsetY; + _customClosePosition = customClosePosition; + _allowOffscreen = allowOffscreen; + } + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"(width %f, height %f, offsetX %f, offsetY %f, customClosePosition %lu, allowOffscreen %d)", self.width, self.height, self.offsetX, self.offsetY, (long unsigned)self.customClosePosition, self.allowOffscreen]; +} + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDResizeView.h b/sdk/internal/MRAID/ANMRAIDResizeView.h new file mode 100644 index 000000000..57652332a --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDResizeView.h @@ -0,0 +1,39 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import +#import "ANMRAIDUtil.h" + +static CGFloat const kANResizeViewCloseRegionWidth = 50.0; +static CGFloat const kANResizeViewCloseRegionHeight = 50.0; + +@protocol ANMRAIDResizeViewDelegate; + +@interface ANMRAIDResizeView : UIView + +- (void)attachContentView:(UIView *)contentView; +- (UIView *)detachContentView; + +@property (nonatomic, readonly, weak) UIView *contentView; +@property (nonatomic, readwrite, assign) ANMRAIDCustomClosePosition closePosition; +@property (nonatomic, readwrite, weak) id delegate; + +@end + +@protocol ANMRAIDResizeViewDelegate + +- (void)closeRegionSelectedOnResizeView:(ANMRAIDResizeView *)resizeView; + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDResizeView.m b/sdk/internal/MRAID/ANMRAIDResizeView.m new file mode 100644 index 000000000..c1d227284 --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDResizeView.m @@ -0,0 +1,211 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANMRAIDResizeView.h" +#import "ANLogging.h" +#import "UIView+ANCategory.h" +#import "ANGlobal.h" + +@interface ANMRAIDResizeView () + +@property (nonatomic, readwrite, weak) UIView *contentView; + +@property (nonatomic, readwrite, strong) UIButton *closeRegion; +@property (nonatomic, readwrite, strong) UIButton *supplementaryCloseRegion; +@property (nonatomic, readwrite, strong) UIImage *closeRegionDefaultImage; + +@end + +@implementation ANMRAIDResizeView + +#pragma mark - ANResizeView Implementation + +- (instancetype)init { + if (self = [super init]) { + self.backgroundColor = [UIColor clearColor]; + [self setupCloseRegion]; + [self setupSupplementaryCloseRegion]; + } + return self; +} + +#pragma mark - Close Region + +- (void)setClosePosition:(ANMRAIDCustomClosePosition)closePosition { + _closePosition = closePosition; + [self setupCloseRegionConstraintsWithClosePosition:_closePosition]; +} + +- (void)setupCloseRegion { + UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [closeButton addTarget:self + action:@selector(closeRegionSelectedOnResizeView) + forControlEvents:UIControlEventTouchUpInside]; + _closeRegion = closeButton; + [self addSubview:_closeRegion]; +} + +- (void)setupSupplementaryCloseRegion { + UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [closeButton addTarget:self + action:@selector(closeRegionSelectedOnResizeView) + forControlEvents:UIControlEventTouchUpInside]; + [closeButton setImage:self.closeRegionDefaultImage + forState:UIControlStateNormal]; + closeButton.hidden = YES; + closeButton.translatesAutoresizingMaskIntoConstraints = NO; + [closeButton constrainWithSize:CGSizeMake(kANResizeViewCloseRegionWidth, kANResizeViewCloseRegionHeight)]; + _supplementaryCloseRegion = closeButton; + [self addSubview:_supplementaryCloseRegion]; +} + +- (void)setupCloseRegionConstraintsWithClosePosition:(ANMRAIDCustomClosePosition)position { + [self.closeRegion removeConstraints:self.closeRegion.constraints]; + self.closeRegion.translatesAutoresizingMaskIntoConstraints = NO; + NSLayoutAttribute xAttribute; + NSLayoutAttribute yAttribute; + + switch (position) { + case ANMRAIDCustomClosePositionTopLeft: + yAttribute = NSLayoutAttributeTop; + xAttribute = NSLayoutAttributeLeft; + break; + case ANMRAIDCustomClosePositionTopCenter: + yAttribute = NSLayoutAttributeTop; + xAttribute = NSLayoutAttributeCenterX; + break; + case ANMRAIDCustomClosePositionTopRight: + yAttribute = NSLayoutAttributeTop; + xAttribute = NSLayoutAttributeRight; + break; + case ANMRAIDCustomClosePositionCenter: + yAttribute = NSLayoutAttributeCenterY; + xAttribute = NSLayoutAttributeCenterX; + break; + case ANMRAIDCustomClosePositionBottomLeft: + yAttribute = NSLayoutAttributeBottom; + xAttribute = NSLayoutAttributeLeft; + break; + case ANMRAIDCustomClosePositionBottomCenter: + yAttribute = NSLayoutAttributeBottom; + xAttribute = NSLayoutAttributeCenterX; + break; + case ANMRAIDCustomClosePositionBottomRight: + yAttribute = NSLayoutAttributeBottom; + xAttribute = NSLayoutAttributeRight; + break; + default: + ANLogDebug(@"Invalid custom close position for MRAID resize event"); + yAttribute = NSLayoutAttributeTop; + xAttribute = NSLayoutAttributeRight; + break; + } + + [self.closeRegion constrainWithSize:CGSizeMake(kANResizeViewCloseRegionWidth, kANResizeViewCloseRegionHeight)]; + [self.closeRegion alignToSuperviewWithXAttribute:xAttribute + yAttribute:yAttribute]; +} + +#pragma mark - Content View + +- (void)attachContentView:(UIView *)contentView { + if (contentView != self.contentView) { + if (self.contentView) { + ANLogError(@"Error: Attempt to attach a second content view to a resize view."); + return; + } + self.contentView = contentView; + [self.contentView removeFromSuperview]; + [self insertSubview:self.contentView + belowSubview:self.closeRegion]; + [self setupContentViewConstraints]; + } +} + +- (UIView *)detachContentView { + UIView *contentView = self.contentView; + self.contentView = nil; + if (contentView.superview == self) { + [contentView removeFromSuperview]; + [contentView removeConstraints:contentView.constraints]; + return contentView; + } + if (contentView) { + ANLogError(@"Error: Attempted to detach a content view from a resize view which has already been added to another hierarchy"); + } + return nil; +} + +- (void)setupContentViewConstraints { + [self.contentView removeConstraints:self.contentView.constraints]; + self.contentView.translatesAutoresizingMaskIntoConstraints = NO; + [self.contentView constrainToSizeOfSuperview]; + [self.contentView alignToSuperviewWithXAttribute:NSLayoutAttributeLeft + yAttribute:NSLayoutAttributeTop]; +} + +#pragma mark - ANResizeViewDelegate + +- (void)closeRegionSelectedOnResizeView { + [self.delegate closeRegionSelectedOnResizeView:self]; +} + +#pragma mark - Layout + ++ (BOOL)requiresConstraintBasedLayout { + return YES; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + [self enableSupplementaryCloseRegionIfNecessary]; +} + +- (void)enableSupplementaryCloseRegionIfNecessary { + CGRect screenBounds = [UIScreen mainScreen].bounds; + CGRect closeRegionBoundsInWindowCoordinates = [self.closeRegion convertRect:self.closeRegion.bounds + toView:nil]; + if (CGRectContainsRect(screenBounds, closeRegionBoundsInWindowCoordinates)) { + self.supplementaryCloseRegion.hidden = YES; + } else { + self.supplementaryCloseRegion.hidden = NO; + + CGRect selfBoundsInWindowCoordinates = [self convertRect:self.bounds + toView:nil]; + CGRect intersection = CGRectIntersection(screenBounds, selfBoundsInWindowCoordinates); + CGRect intersectionFrameInCloseRegionCoordinates = [self convertRect:intersection + fromView:nil]; + CGFloat updatedCloseRegionOriginX = intersectionFrameInCloseRegionCoordinates.origin.x + intersectionFrameInCloseRegionCoordinates.size.width - self.supplementaryCloseRegion.frame.size.width; + CGFloat updatedCloseRegionOriginY = intersectionFrameInCloseRegionCoordinates.origin.y; + + CGRect updatedCloseRegionFrame = CGRectMake(updatedCloseRegionOriginX, updatedCloseRegionOriginY, self.supplementaryCloseRegion.frame.size.width, self.supplementaryCloseRegion.frame.size.height); + + [self.supplementaryCloseRegion setFrame:updatedCloseRegionFrame]; + } +} + +- (UIImage *)closeRegionDefaultImage { + if (!_closeRegionDefaultImage) { + BOOL atLeastiOS7 = [self respondsToSelector:@selector(tintColorDidChange)]; + NSString *closeboxImageName = @"interstitial_flat_closebox"; + if (!atLeastiOS7) { + closeboxImageName = @"interstitial_closebox"; + } + _closeRegionDefaultImage = [UIImage imageWithContentsOfFile:ANPathForANResource(closeboxImageName, @"png")]; + } + return _closeRegionDefaultImage; +} + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDResizeViewManager.h b/sdk/internal/MRAID/ANMRAIDResizeViewManager.h new file mode 100644 index 000000000..a29038eab --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDResizeViewManager.h @@ -0,0 +1,44 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import +#import "ANMRAIDResizeProperties.h" +#import "ANMRAIDResizeView.h" + +@class ANMRAIDResizeView; +@protocol ANMRAIDResizeViewManagerDelegate; + +@interface ANMRAIDResizeViewManager : NSObject + +@property (nonatomic, readonly, strong) ANMRAIDResizeView *resizeView; +@property (nonatomic, readwrite, weak) id delegate; +@property (nonatomic, readonly, assign, getter=isResized) BOOL resized; + +- (instancetype)initWithContentView:(UIView *)contentView + anchorView:(UIView *)anchorView; + +- (BOOL)attemptResizeWithResizeProperties:(ANMRAIDResizeProperties *)properties + errorString:(NSString *__autoreleasing*)errorString; +- (void)detachResizeView; + +- (void)didMoveAnchorViewToWindow; + +@end + +@protocol ANMRAIDResizeViewManagerDelegate + +- (void)resizeViewClosedByResizeViewManager:(ANMRAIDResizeViewManager *)manager; + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDResizeViewManager.m b/sdk/internal/MRAID/ANMRAIDResizeViewManager.m new file mode 100644 index 000000000..1125b03a9 --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDResizeViewManager.m @@ -0,0 +1,238 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANMRAIDResizeViewManager.h" +#import "ANLogging.h" +#import "UIView+ANCategory.h" +#import "ANMRAIDResizeView.h" + +@interface ANMRAIDResizeViewManager () + +@property (nonatomic, readwrite, strong) NSLayoutConstraint *rootViewLeftConstraint; +@property (nonatomic, readwrite, strong) NSLayoutConstraint *rootViewTopConstraint; + +@property (nonatomic, readwrite, strong) ANMRAIDResizeProperties *lastResizeProperties; + +@property (nonatomic, readwrite, strong) ANMRAIDResizeView *resizeView; +@property (nonatomic, readwrite, weak) UIView *anchorView; +@property (nonatomic, readwrite, weak) UIView *contentView; +@property (nonatomic, readwrite, assign, getter=isResized) BOOL resized; + +@end + +@implementation ANMRAIDResizeViewManager + +#pragma mark - MRAID Resize Validation + ++ (BOOL)validateMRAIDResizeFromView:(UIView *)view + withResizeProperties:(ANMRAIDResizeProperties *)properties + errorString:(NSString *__autoreleasing *)errorString { + + CGRect screenBounds = [UIScreen mainScreen].bounds; + CGRect resizedBounds; + resizedBounds.origin.x = view.bounds.origin.x + properties.offsetX; + resizedBounds.origin.y = view.bounds.origin.y + properties.offsetY; + resizedBounds.size.width = properties.width; + resizedBounds.size.height = properties.height; + + CGRect resizedBoundsInWindowCoordinates = [view convertRect:resizedBounds + toView:nil]; + CGRect resizedIntersection = CGRectIntersection(screenBounds, resizedBoundsInWindowCoordinates); + + if (resizedIntersection.size.width < kANResizeViewCloseRegionWidth + || resizedIntersection.size.height < kANResizeViewCloseRegionHeight) { + *errorString = [NSString stringWithFormat:@"Resize call should keep at least %fx%f of the creative on screen", kANResizeViewCloseRegionWidth, kANResizeViewCloseRegionHeight]; + return NO; + } else if (resizedIntersection.size.width > screenBounds.size.width + && resizedIntersection.size.height > screenBounds.size.height) { + *errorString = @"Resize called with resizeProperties larger than the screen."; + return NO; + } + + return YES; +} + +#pragma mark - ANResizeViewManager Implementation + +- (instancetype)initWithContentView:(UIView *)contentView + anchorView:(UIView *)anchorView { + if (contentView == anchorView) { + ANLogError(@"%@ Anchor view cannot be the same as the content view", NSStringFromClass([self class])); + return nil; + } + if (!contentView || !anchorView) { + ANLogError(@"%@ Content view, anchor view, and root view have to be defined", NSStringFromClass([self class])); + return nil; + } + + if (self = [super init]) { + _contentView = contentView; + _anchorView = anchorView; + _resizeView = [[ANMRAIDResizeView alloc] init]; + _resizeView.delegate = self; + _resizeView.translatesAutoresizingMaskIntoConstraints = NO; + } + return self; +} + +- (BOOL)attemptResizeWithResizeProperties:(ANMRAIDResizeProperties *)properties + errorString:(NSString *__autoreleasing*)errorString { + + BOOL allowResize = [ANMRAIDResizeViewManager validateMRAIDResizeFromView:self.anchorView + withResizeProperties:properties + errorString:errorString]; + + if (allowResize) { + self.lastResizeProperties = properties; + [self resizeWithResizeProperties:properties]; + self.resized = YES; + } + + return allowResize; +} + +- (void)resizeWithResizeProperties:(ANMRAIDResizeProperties *)properties { + self.resizeView.closePosition = properties.customClosePosition; + [self.resizeView constrainWithSize:CGSizeMake(properties.width, properties.height)]; + + if (!self.resizeView.superview) { + [self.anchorView.window addSubview:self.resizeView]; + } + + if (!self.resizeView.contentView) { + [self.resizeView attachContentView:self.contentView]; + } + + if ([[UIScreen mainScreen] respondsToSelector:@selector(coordinateSpace)]) { + if (self.rootViewLeftConstraint) { + self.rootViewLeftConstraint.constant = properties.offsetX; + } else { + self.rootViewLeftConstraint = [NSLayoutConstraint constraintWithItem:self.resizeView + attribute:NSLayoutAttributeLeft + relatedBy:NSLayoutRelationEqual + toItem:self.anchorView + attribute:NSLayoutAttributeLeft + multiplier:1.0 + constant:properties.offsetX]; + [self.anchorView.window addConstraint:self.rootViewLeftConstraint]; + } + + if (self.rootViewTopConstraint) { + self.rootViewTopConstraint.constant = properties.offsetY; + } else { + self.rootViewTopConstraint = [NSLayoutConstraint constraintWithItem:self.resizeView + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationEqual + toItem:self.anchorView + attribute:NSLayoutAttributeTop + multiplier:1.0 + constant:properties.offsetY]; + [self.anchorView.window addConstraint:self.rootViewTopConstraint]; + } + } else { + CGRect boundsToResizeTo = self.anchorView.bounds; + boundsToResizeTo.origin.x += properties.offsetX; + boundsToResizeTo.origin.y += properties.offsetY; + boundsToResizeTo.size = CGSizeMake(properties.width, properties.height); + CGRect frameToResizeToInWindowCoordinates = [self.anchorView convertRect:boundsToResizeTo + toView:nil]; + self.resizeView.frame = frameToResizeToInWindowCoordinates; + self.resizeView.transform = [self transformForOrientation]; + + [self setupRotationListener]; + } +} + +- (void)detachResizeView { + if (self.resized) { + [self.resizeView removeFromSuperview]; + self.resized = NO; + [self removeRootViewConstraints]; + self.resizeView = nil; + self.lastResizeProperties = nil; + [self unregisterFromDeviceOrientationNotification]; + } +} + +- (void)removeRootViewConstraints { + [self.anchorView.window removeConstraint:self.rootViewLeftConstraint]; + [self.anchorView.window removeConstraint:self.rootViewTopConstraint]; + self.rootViewLeftConstraint = nil; + self.rootViewTopConstraint = nil; +} + +- (void)didMoveAnchorViewToWindow { + if (self.resized) { + if (self.anchorView.window) { + [self resizeWithResizeProperties:self.lastResizeProperties]; + } else { + [self.resizeView removeFromSuperview]; + [self removeRootViewConstraints]; + } + } +} + +# pragma mark - Pre-iOS 8 resize + +- (CGAffineTransform)transformForOrientation { + CGFloat radians = 0; + switch ([UIApplication sharedApplication].statusBarOrientation) { + case UIInterfaceOrientationLandscapeLeft: + radians = -(CGFloat)M_PI_2; + break; + case UIInterfaceOrientationLandscapeRight: + radians = (CGFloat)M_PI_2; + break; + case UIInterfaceOrientationPortraitUpsideDown: + radians = (CGFloat)M_PI; + break; + default: + radians = 0.0f; + break; + } + + CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(radians); + return rotationTransform; +} + +- (void)setupRotationListener { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(handleDeviceOrientationDidChangeNotification:) + name:UIDeviceOrientationDidChangeNotification + object:nil]; +} + +- (void)handleDeviceOrientationDidChangeNotification:(NSNotification *)notification { + [self resizeWithResizeProperties:self.lastResizeProperties]; +} + +- (void)unregisterFromDeviceOrientationNotification { + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIDeviceOrientationDidChangeNotification + object:nil]; +} + +#pragma mark - ANResizeViewManagerDelegate + +- (void)closeRegionSelectedOnResizeView:(ANMRAIDResizeView *)resizeView { + [self detachResizeView]; + [self.delegate resizeViewClosedByResizeViewManager:self]; +} + +- (void)dealloc { + [self detachResizeView]; +} + +@end \ No newline at end of file diff --git a/sdk/internal/MRAID/ANMRAIDUtil.h b/sdk/internal/MRAID/ANMRAIDUtil.h new file mode 100644 index 000000000..9668fab6a --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDUtil.h @@ -0,0 +1,84 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +typedef NS_ENUM(NSUInteger, ANMRAIDOrientation) { + ANMRAIDOrientationPortrait, + ANMRAIDOrientationLandscape, + ANMRAIDOrientationNone +}; + +typedef NS_ENUM(NSUInteger, ANMRAIDCustomClosePosition) { + ANMRAIDCustomClosePositionUnknown, + ANMRAIDCustomClosePositionTopLeft, + ANMRAIDCustomClosePositionTopCenter, + ANMRAIDCustomClosePositionTopRight, + ANMRAIDCustomClosePositionCenter, + ANMRAIDCustomClosePositionBottomLeft, + ANMRAIDCustomClosePositionBottomCenter, + ANMRAIDCustomClosePositionBottomRight +}; + +typedef NS_ENUM(NSUInteger, ANMRAIDState) { + ANMRAIDStateUnknown, + ANMRAIDStateLoading, + ANMRAIDStateDefault, + ANMRAIDStateExpanded, + ANMRAIDStateHidden, + ANMRAIDStateResized +}; + +typedef NS_ENUM(NSUInteger, ANMRAIDAction) { + ANMRAIDActionUnknown, + ANMRAIDActionExpand, + ANMRAIDActionClose, + ANMRAIDActionResize, + ANMRAIDActionCreateCalendarEvent, + ANMRAIDActionPlayVideo, + ANMRAIDActionStorePicture, + ANMRAIDActionSetOrientationProperties, + ANMRAIDActionSetUseCustomClose, + ANMRAIDActionOpenURI, + ANMRAIDActionEnable +}; + +@interface ANMRAIDUtil : NSObject + ++ (BOOL)supportsSMS; ++ (BOOL)supportsTel; ++ (BOOL)supportsCalendar; ++ (BOOL)supportsInlineVideo; ++ (BOOL)supportsStorePicture; + ++ (CGSize)maxSize; ++ (CGSize)screenSize; + ++ (void)playVideoWithUri:(NSString *)uri + fromRootViewController:(UIViewController *)rootViewController + withCompletionTarget:(id)target + completionSelector:(SEL)selector; ++ (void)storePictureWithUri:(NSString *)uri + withCompletionTarget:(id)target + completionSelector:(SEL)selector; + ++ (ANMRAIDAction)actionForCommand:(NSString *)command; ++ (ANMRAIDCustomClosePosition)customClosePositionFromCustomClosePositionString:(NSString *)customClosePositionString; ++ (ANMRAIDOrientation)orientationFromForceOrientationString:(NSString *)orientationString; + ++ (ANMRAIDState)stateFromString:(NSString *)string; ++ (NSString *)stateStringFromState:(ANMRAIDState)state; + +@end diff --git a/sdk/internal/MRAID/ANMRAIDUtil.m b/sdk/internal/MRAID/ANMRAIDUtil.m new file mode 100644 index 000000000..4e15a07cb --- /dev/null +++ b/sdk/internal/MRAID/ANMRAIDUtil.m @@ -0,0 +1,181 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANMRAIDUtil.h" +#import +#import +#import "ANGlobal.h" + +@implementation ANMRAIDUtil + ++ (ANMRAIDCustomClosePosition)customClosePositionFromCustomClosePositionString:(NSString *)customClosePositionString { + if ([customClosePositionString isEqualToString:@"top-left"]) { + return ANMRAIDCustomClosePositionTopLeft; + } else if ([customClosePositionString isEqualToString:@"top-center"]) { + return ANMRAIDCustomClosePositionTopCenter; + } else if ([customClosePositionString isEqualToString:@"top-right"]) { + return ANMRAIDCustomClosePositionTopRight; + } else if ([customClosePositionString isEqualToString:@"center"]) { + return ANMRAIDCustomClosePositionCenter; + } else if ([customClosePositionString isEqualToString:@"bottom-left"]) { + return ANMRAIDCustomClosePositionBottomLeft; + } else if ([customClosePositionString isEqualToString:@"bottom-center"]) { + return ANMRAIDCustomClosePositionBottomCenter; + } else if ([customClosePositionString isEqualToString:@"bottom-right"]) { + return ANMRAIDCustomClosePositionBottomRight; + } + return ANMRAIDCustomClosePositionUnknown; +} + ++ (BOOL)supportsSMS { + return [MFMessageComposeViewController canSendText]; +} + ++ (BOOL)supportsTel { + return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"tel://"]]; +} + ++ (BOOL)supportsCalendar { + return YES; +} + ++ (BOOL)supportsInlineVideo { + return YES; +} + ++ (BOOL)supportsStorePicture { + return YES; +} + ++ (ANMRAIDAction)actionForCommand:(NSString *)command { + if ([command isEqualToString:@"expand"]) { + return ANMRAIDActionExpand; + } else if ([command isEqualToString:@"close"]) { + return ANMRAIDActionClose; + } else if ([command isEqualToString:@"resize"]) { + return ANMRAIDActionResize; + } else if ([command isEqualToString:@"createCalendarEvent"]) { + return ANMRAIDActionCreateCalendarEvent; + } else if ([command isEqualToString:@"playVideo"]) { + return ANMRAIDActionPlayVideo; + } else if ([command isEqualToString:@"storePicture"]) { + return ANMRAIDActionStorePicture; + } else if ([command isEqualToString:@"setOrientationProperties"]) { + return ANMRAIDActionSetOrientationProperties; + } else if ([command isEqualToString:@"setUseCustomClose"]) { + return ANMRAIDActionSetUseCustomClose; + } else if ([command isEqualToString:@"open"]) { + return ANMRAIDActionOpenURI; + } else if ([command isEqualToString:@"enable"]) { + return ANMRAIDActionEnable; + } + return ANMRAIDActionUnknown; +} + ++ (void)storePictureWithUri:(NSString *)uri + withCompletionTarget:(id)target + completionSelector:(SEL)selector { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSURL *url = [NSURL URLWithString:uri]; + NSData *data = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] + returningResponse:nil + error:nil]; + if(data){ + dispatch_async(dispatch_get_main_queue(), ^{ + UIImage *image = [[UIImage alloc] initWithData:data]; + if (image) { + UIImageWriteToSavedPhotosAlbum(image, target, selector, nil); + } + }); + } + }); +} + ++ (void)playVideoWithUri:(NSString *)uri + fromRootViewController:(UIViewController *)rootViewController + withCompletionTarget:(id)target + completionSelector:(SEL)selector { + NSURL *url = [NSURL URLWithString:uri]; + + MPMoviePlayerViewController *moviePlayerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:url]; + moviePlayerViewController.moviePlayer.fullscreen = YES; + moviePlayerViewController.moviePlayer.shouldAutoplay = YES; + moviePlayerViewController.moviePlayer.movieSourceType = MPMovieSourceTypeUnknown; + moviePlayerViewController.moviePlayer.view.frame = rootViewController.view.frame; + moviePlayerViewController.moviePlayer.controlStyle = MPMovieControlStyleFullscreen; + [moviePlayerViewController.moviePlayer prepareToPlay]; + [rootViewController presentMoviePlayerViewControllerAnimated:moviePlayerViewController]; + [moviePlayerViewController.moviePlayer play]; + + [[NSNotificationCenter defaultCenter] addObserver:target + selector:selector + name:MPMoviePlayerPlaybackDidFinishNotification + object:moviePlayerViewController.moviePlayer]; +} + ++ (ANMRAIDOrientation)orientationFromForceOrientationString:(NSString *)orientationString { + if ([orientationString isEqualToString:@"portrait"]) { + return ANMRAIDOrientationPortrait; + } else if ([orientationString isEqualToString:@"landscape"]) { + return ANMRAIDOrientationLandscape; + } + return ANMRAIDOrientationNone; +} + ++ (CGSize)maxSize { + return [[self class] screenSize]; +} + ++ (CGSize)screenSize { + BOOL orientationIsPortrait = UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]); + CGSize screenSize = ANPortraitScreenBounds().size; + int orientedWidth = orientationIsPortrait ? screenSize.width : screenSize.height; + int orientedHeight = orientationIsPortrait ? screenSize.height : screenSize.width; + return CGSizeMake(orientedWidth, orientedHeight); +} + ++ (ANMRAIDState)stateFromString:(NSString *)stateString { + if ([stateString isEqualToString:@"loading"]) { + return ANMRAIDStateLoading; + } else if ([stateString isEqualToString:@"default"]) { + return ANMRAIDStateDefault; + } else if ([stateString isEqualToString:@"expanded"]) { + return ANMRAIDStateExpanded; + } else if ([stateString isEqualToString:@"hidden"]) { + return ANMRAIDStateHidden; + } else if ([stateString isEqualToString:@"resized"]) { + return ANMRAIDStateResized; + } + return ANMRAIDStateUnknown; +} + ++ (NSString *)stateStringFromState:(ANMRAIDState)state { + switch (state) { + case ANMRAIDStateLoading: + return @"loading"; + case ANMRAIDStateDefault: + return @"default"; + case ANMRAIDStateExpanded: + return @"expanded"; + case ANMRAIDStateHidden: + return @"hidden"; + case ANMRAIDStateResized: + return @"resized"; + default: + return nil; + } +} + +@end \ No newline at end of file diff --git a/sdk/internal/ANAdViewDelegate.h b/sdk/native/internal/ANAdFetcherResponse.h similarity index 59% rename from sdk/internal/ANAdViewDelegate.h rename to sdk/native/internal/ANAdFetcherResponse.h index a7921ae2b..36b8aa882 100644 --- a/sdk/internal/ANAdViewDelegate.h +++ b/sdk/native/internal/ANAdFetcherResponse.h @@ -1,4 +1,4 @@ -/* Copyright 2013 APPNEXUS INC +/* Copyright 2014 APPNEXUS INC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,19 +15,13 @@ #import -@protocol ANAdViewDelegate +@interface ANAdFetcherResponse : NSObject -- (void)adWasClicked; -- (void)adWillPresent; -- (void)adDidPresent; -- (void)adWillClose; -- (void)adDidClose; -- (void)adWillLeaveApplication; -- (void)adDidReceiveAppEvent:(NSString *)name withData:(NSString *)data; +- (instancetype)initAdResponseFailWithError:(NSError *)error; +- (instancetype)initAdResponseSuccessWithAdObject:(id)adObject; -// for interstitials only -- (void)adFailedToDisplay; +@property (nonatomic, readonly, assign, getter=isSuccessful) BOOL successful; +@property (nonatomic, readonly, strong) id adObject; +@property (nonatomic, readonly, strong) NSError *error; -@optional -- (void)transitionInProgress; @end \ No newline at end of file diff --git a/sdk/native/internal/ANAdFetcherResponse.m b/sdk/native/internal/ANAdFetcherResponse.m new file mode 100644 index 000000000..56768a2c3 --- /dev/null +++ b/sdk/native/internal/ANAdFetcherResponse.m @@ -0,0 +1,44 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANAdFetcherResponse.h" + +@interface ANAdFetcherResponse () + +@property (nonatomic, readwrite, assign, getter=isSuccessful) BOOL successful; +@property (nonatomic, readwrite, strong) id adObject; +@property (nonatomic, readwrite, strong) NSError *error; + +@end + +@implementation ANAdFetcherResponse + +- (instancetype)initAdResponseFailWithError:(NSError *)error { + self = [super init]; + if (self) { + _error = error; + } + return self; +} +- (instancetype)initAdResponseSuccessWithAdObject:(id)adObject { + self = [super init]; + if (self) { + _successful = YES; + _adObject = adObject; + } + return self; +} + +@end \ No newline at end of file diff --git a/sdk/native/internal/ANAdServerResponse.h b/sdk/native/internal/ANAdServerResponse.h new file mode 100644 index 000000000..011fbee2c --- /dev/null +++ b/sdk/native/internal/ANAdServerResponse.h @@ -0,0 +1,31 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import +#import "ANStandardAd.h" +#import "ANNativeStandardAdResponse.h" + +@interface ANAdServerResponse : NSObject + +- (instancetype)initWithAdServerData:(NSData *)data; + +@property (nonatomic, readonly, assign) BOOL containsAds; +@property (nonatomic, readonly, strong) ANStandardAd *standardAd; +@property (nonatomic, readonly, strong) ANNativeStandardAdResponse *nativeAd; +@property (nonatomic, readonly, strong) NSMutableArray *standardAds; +@property (nonatomic, readonly, strong) NSMutableArray *mediatedAds; +@property (nonatomic, readonly, strong) NSMutableArray *nativeAds; + +@end \ No newline at end of file diff --git a/sdk/native/internal/ANAdServerResponse.m b/sdk/native/internal/ANAdServerResponse.m new file mode 100644 index 000000000..e96620d4a --- /dev/null +++ b/sdk/native/internal/ANAdServerResponse.m @@ -0,0 +1,336 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANAdServerResponse.h" +#import "ANLogging.h" +#import "ANGlobal.h" +#import "ANMediatedAd.h" + +static NSString *const kANAdServerResponseKeyStatus = @"status"; +static NSString *const kANAdServerResponseKeyType = @"type"; +static NSString *const kANAdServerResponseKeyAds = @"ads"; +static NSString *const kANAdServerResponseKeyMediatedAds = @"mediated"; +static NSString *const kANAdServerResponseKeyNativeAds = @"native"; +static NSString *const kANAdServerResponseValueError = @"error"; + +// Standard +static NSString *const kANAdServerResponseKeyWidth = @"width"; +static NSString *const kANAdServerResponseKeyHeight = @"height"; +static NSString *const kANAdServerResponseKeyContent = @"content"; +static NSString *const kANAdServerResponseMraidJSFilename = @"mraid.js"; + +// Mediated +static NSString *const kANAdServerResponseValueIOS = @"ios"; +static NSString *const kANAdServerResponseKeyHandler = @"handler"; +static NSString *const kANAdServerResponseKeyClass = @"class"; +static NSString *const kANAdServerResponseKeyId = @"id"; +static NSString *const kANAdServerResponseKeyParam = @"param"; +static NSString *const kANAdServerResponseKeyResultCB = @"result_cb"; +static NSString *const kANAdServerResponseKeyAuctionInfo = @"auction_info"; + +// Native +static NSString *const kANAdServerResponseKeyNativeMediaType = @"type"; +static NSString *const kANAdServerResponseKeyNativeTitle = @"title"; +static NSString *const kANAdServerResponseKeyNativeDescription = @"description"; +static NSString *const kANAdServerResponseKeyNativeFullText = @"full_text"; +static NSString *const kANAdServerResponseKeyNativeContext = @"context"; +static NSString *const kANAdServerResponseKeyNativeIconImageUrl = @"icon_img_url"; +static NSString *const kANAdServerResponseKeyNativeMainMedia = @"main_media"; +static NSString *const kANAdServerResponseKeyNativeMainMediaLabel = @"label"; +static NSString *const kANAdServerResponseKeyNativeMainMediaDefaultLabel = @"default"; +static NSString *const kANAdServerResponseKeyNativeMainMediaURL = @"url"; +static NSString *const kANAdServerResponseKeyNativeCallToAction = @"cta"; +static NSString *const kANAdServerResponseKeyNativeClickTrackArray = @"click_trackers"; +static NSString *const kANAdServerResponseKeyNativeImpTrackArray = @"impression_trackers"; +static NSString *const kANAdServerResponseKeyNativeClickUrl = @"click_url"; +static NSString *const kANAdServerResponseKeyNativeClickFallbackUrl = @"click_url_fallback"; +static NSString *const kANAdServerResponseKeyNativeRatingDict = @"rating"; +static NSString *const kANAdServerResponseKeyNativeRatingValue = @"value"; +static NSString *const kANAdServerResponseKeyNativeRatingScale = @"scale"; +static NSString *const kANAdServerResponseKeyNativeCustomKeywordsDict = @"custom"; + +static NSString *const kANAdFetcherDidReceiveResponseNotification = @"kANAdFetcherDidReceiveResponseNotification"; +static NSString *const kANAdFetcherAdResponseKey = @"kANAdFetcherAdResponseKey"; + +@interface ANAdServerResponse () + +@property (nonatomic, readwrite, assign) BOOL containsAds; +@property (nonatomic, readwrite, strong) ANStandardAd *standardAd; +@property (nonatomic, readwrite, strong) ANNativeStandardAdResponse *nativeAd; +@property (nonatomic, readwrite, strong) NSMutableArray *standardAds; +@property (nonatomic, readwrite, strong) NSMutableArray *mediatedAds; +@property (nonatomic, readwrite, strong) NSMutableArray *nativeAds; + +@end + +@implementation ANAdServerResponse + +- (instancetype)initWithAdServerData:(NSData *)data { + self = [super init]; + if (self) { + [self processResponseData:data]; + } + return self; +} + +- (void)processResponseData:(NSData *)data { + NSDictionary *jsonResponse = [[self class] jsonResponseFromData:data]; + if (jsonResponse) { + BOOL isError = [[self class] errorStatusForJSONResponse:jsonResponse]; + if (!isError) { + self.standardAds = [[self class] standardAdsFromJSONResponse:jsonResponse]; + self.standardAd = [self.standardAds firstObject]; + self.mediatedAds = [[self class] mediatedAdsFromJSONResponse:jsonResponse]; + self.nativeAds = [[self class] nativeAdsFromJSONResponse:jsonResponse]; + self.nativeAd = [self.nativeAds firstObject]; + if (self.standardAd || self.mediatedAds || self.nativeAds) { + self.containsAds = YES; + } + } + } +} + ++ (NSDictionary *)jsonResponseFromData:(NSData *)data { + NSString *responseString = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + if (!responseString || [responseString length] == 0) { + ANLogDebug(@"Received empty response from ad server"); + return nil; + } + + ANPostNotifications(kANAdFetcherDidReceiveResponseNotification, self, + @{kANAdFetcherAdResponseKey: (responseString ? responseString : @"")}); + + NSError *jsonParsingError = nil; + id jsonResponse = [NSJSONSerialization JSONObjectWithData:data + options:0 + error:&jsonParsingError]; + if (jsonParsingError) { + ANLogError(@"response_json_error %@", jsonParsingError); + return nil; + } else if (![jsonResponse isKindOfClass:[NSDictionary class]]) { + ANLogError(@"Response from ad server in an unexpected format: %@", jsonResponse); + return nil; + } + + return (NSDictionary *)jsonResponse; +} + ++ (BOOL)errorStatusForJSONResponse:(NSDictionary *)jsonResponse { + NSString *status = jsonResponse[kANAdServerResponseKeyStatus]; + if ([status isEqualToString:kANAdServerResponseValueError]) { + ANLogError(@"response_error %@", jsonResponse); + return YES; + } + return NO; +} + ++ (NSMutableArray *)mediatedAdsFromJSONResponse:(NSDictionary *)jsonResponse { + NSArray *mediatedAdDictArray = [[self class] validDictionaryArrayForKey:kANAdServerResponseKeyMediatedAds + inJSONResponse:jsonResponse]; + NSMutableArray *parsedMediatedAdObjects = [[NSMutableArray alloc] init]; + [mediatedAdDictArray enumerateObjectsUsingBlock:^(NSDictionary *mediatedAdDict, NSUInteger idx, BOOL *stop) { + ANMediatedAd *mediatedAd = [[self class] parseMediatedAdFromDictionary:mediatedAdDict]; + if (mediatedAd) { + [parsedMediatedAdObjects addObject:mediatedAd]; + } + }]; + return parsedMediatedAdObjects; +} + ++ (NSMutableArray *)standardAdsFromJSONResponse:(NSDictionary *)jsonResponse { + NSArray *standardAdDictArray = [[self class] validDictionaryArrayForKey:kANAdServerResponseKeyAds + inJSONResponse:jsonResponse]; + NSMutableArray *parsedStandardAdObjects = [[NSMutableArray alloc] init]; + [standardAdDictArray enumerateObjectsUsingBlock:^(NSDictionary *standardAdDict, NSUInteger idx, BOOL *stop) { + ANStandardAd *standardAd = [[self class] parseStandardAdFromDictionary:standardAdDict]; + if (standardAd) { + [parsedStandardAdObjects addObject:standardAd]; + } + }]; + return parsedStandardAdObjects; +} + ++ (NSMutableArray *)nativeAdsFromJSONResponse:(NSDictionary *)jsonResponse { + NSArray *nativeAdDictArray = [[self class] validDictionaryArrayForKey:kANAdServerResponseKeyNativeAds + inJSONResponse:jsonResponse]; + NSMutableArray *parsedNativeAdObjects = [[NSMutableArray alloc] init]; + [nativeAdDictArray enumerateObjectsUsingBlock:^(NSDictionary *nativeAdDict, NSUInteger idx, BOOL *stop) { + ANNativeStandardAdResponse *nativeAd = [[self class] parseNativeAdFromDictionary:nativeAdDict]; + if (nativeAd) { + [parsedNativeAdObjects addObject:nativeAd]; + } + }]; + return parsedNativeAdObjects; +} + ++ (NSMutableArray *)validDictionaryArrayForKey:(NSString *)key + inJSONResponse:(NSDictionary *)jsonResponse { + if ([jsonResponse[key] isKindOfClass:[NSArray class]]) { + NSArray *adsArray = (NSArray *)jsonResponse[key]; + NSMutableArray *validAdsArray = [[NSMutableArray alloc] initWithCapacity:[adsArray count]]; + [adsArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if ([obj isKindOfClass:[NSDictionary class]]) { + [validAdsArray addObject:obj]; + } + }]; + if (validAdsArray.count) { + return validAdsArray; + } + } + return nil; +} + ++ (ANStandardAd *)parseStandardAdFromDictionary:(NSDictionary *)standardAdDict { + if (standardAdDict) { + ANStandardAd *ad = [[ANStandardAd alloc] init]; + ad.type = [standardAdDict[kANAdServerResponseKeyType] description]; + ad.width = [standardAdDict[kANAdServerResponseKeyWidth] description]; + ad.height = [standardAdDict[kANAdServerResponseKeyHeight] description]; + ad.content = [standardAdDict[kANAdServerResponseKeyContent] description]; + if (!ad.content || [ad.content length] == 0) { + ANLogError(@"blank_ad"); + return ad; + } + NSRange mraidJSRange = [ad.content rangeOfString:kANAdServerResponseMraidJSFilename]; + if (mraidJSRange.location != NSNotFound) { + ad.mraid = YES; + } + return ad; + } + return nil; +} + ++ (ANMediatedAd *)parseMediatedAdFromDictionary:(NSDictionary *)mediatedAdDict { + if ([mediatedAdDict[kANAdServerResponseKeyHandler] isKindOfClass:[NSArray class]]) { + ANMediatedAd *mediatedAd; + NSArray *handlerArray = (NSArray *)mediatedAdDict[kANAdServerResponseKeyHandler]; + for (id handlerObject in handlerArray) { + if ([handlerObject isKindOfClass:[NSDictionary class]]) { + NSDictionary *handlerDict = (NSDictionary *)handlerObject; + NSString *type = [handlerDict[kANAdServerResponseKeyType] description]; + if ([type.lowercaseString isEqualToString:kANAdServerResponseValueIOS]) { + NSString *className = [handlerDict[kANAdServerResponseKeyClass] description]; + if ([className length] == 0) { + return nil; + } + mediatedAd = [[ANMediatedAd alloc] init]; + mediatedAd.className = className; + mediatedAd.param = [handlerDict[kANAdServerResponseKeyParam] description]; + mediatedAd.width = [handlerDict[kANAdServerResponseKeyWidth] description]; + mediatedAd.height = [handlerDict[kANAdServerResponseKeyHeight] description]; + mediatedAd.adId = [handlerDict[kANAdServerResponseKeyId] description]; + break; + } + } + } + mediatedAd.resultCB = [mediatedAdDict[kANAdServerResponseKeyResultCB] description]; + mediatedAd.auctionInfo = [mediatedAdDict[kANAdServerResponseKeyAuctionInfo] description]; + return mediatedAd; + } + return nil; +} + ++ (ANNativeStandardAdResponse *)parseNativeAdFromDictionary:(NSDictionary *)nativeAdDict { + if (nativeAdDict) { + ANNativeStandardAdResponse *nativeAd = [[ANNativeStandardAdResponse alloc] init]; + + if ([nativeAdDict[kANAdServerResponseKeyNativeMediaType] isKindOfClass:[NSString class]]) { + nativeAd.mediaType = nativeAdDict[kANAdServerResponseKeyNativeMediaType]; + } + if ([nativeAdDict[kANAdServerResponseKeyNativeTitle] isKindOfClass:[NSString class]]) { + nativeAd.title = nativeAdDict[kANAdServerResponseKeyNativeTitle]; + } + if ([nativeAdDict[kANAdServerResponseKeyNativeDescription] isKindOfClass:[NSString class]]) { + nativeAd.body = nativeAdDict[kANAdServerResponseKeyNativeDescription]; + } + if ([nativeAdDict[kANAdServerResponseKeyNativeFullText] isKindOfClass:[NSString class]]) { + nativeAd.fullText = nativeAdDict[kANAdServerResponseKeyNativeFullText]; + } + if ([nativeAdDict[kANAdServerResponseKeyNativeContext] isKindOfClass:[NSString class]]) { + nativeAd.socialContext = nativeAdDict[kANAdServerResponseKeyNativeContext]; + } + if ([nativeAdDict[kANAdServerResponseKeyNativeCallToAction] isKindOfClass:[NSString class]]) { + nativeAd.callToAction = nativeAdDict[kANAdServerResponseKeyNativeCallToAction]; + } + + NSString *iconImageURLString = [nativeAdDict[kANAdServerResponseKeyNativeIconImageUrl] description]; + NSString *clickURLString = [nativeAdDict[kANAdServerResponseKeyNativeClickUrl] description]; + NSString *clickURLFallbackString = [nativeAdDict[kANAdServerResponseKeyNativeClickFallbackUrl] description]; + + nativeAd.iconImageURL = [NSURL URLWithString:iconImageURLString]; + nativeAd.clickURL = [NSURL URLWithString:clickURLString]; + nativeAd.clickFallbackURL = [NSURL URLWithString:clickURLFallbackString]; + + if ([nativeAdDict[kANAdServerResponseKeyNativeMainMedia] isKindOfClass:[NSArray class]]) { + NSArray *mainMedia = nativeAdDict[kANAdServerResponseKeyNativeMainMedia]; + [mainMedia enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if ([obj isKindOfClass:[NSDictionary class]]) { + NSDictionary *mainImageData = obj; + NSString *labelValue = [mainImageData[kANAdServerResponseKeyNativeMainMediaLabel] description]; + if ([labelValue isEqualToString:kANAdServerResponseKeyNativeMainMediaDefaultLabel]) { + NSString *mainImageURLString = [[mainImageData objectForKey:kANAdServerResponseKeyNativeMainMediaURL] description]; + nativeAd.mainImageURL = [NSURL URLWithString:mainImageURLString]; + *stop = YES; + } + } + }]; + } + + if ([nativeAdDict[kANAdServerResponseKeyNativeClickTrackArray] isKindOfClass:[NSArray class]]) { + NSArray *clickTrackArray = nativeAdDict[kANAdServerResponseKeyNativeClickTrackArray]; + NSMutableArray *clickTrackURLs = [[NSMutableArray alloc] initWithCapacity:clickTrackArray.count]; + [clickTrackArray enumerateObjectsUsingBlock:^(id clickTrackElement, NSUInteger idx, BOOL *stop) { + NSURL *clickURL = [NSURL URLWithString:[clickTrackElement description]]; + if (clickURL) { + [clickTrackURLs addObject:clickURL]; + } + }]; + nativeAd.clickTrackers = [clickTrackURLs copy]; + } + if ([nativeAdDict[kANAdServerResponseKeyNativeImpTrackArray] isKindOfClass:[NSArray class]]) { + NSArray *impTrackerArray = nativeAdDict[kANAdServerResponseKeyNativeImpTrackArray]; + NSMutableArray *impTrackURLs = [[NSMutableArray alloc] initWithCapacity:impTrackerArray.count]; + [impTrackerArray enumerateObjectsUsingBlock:^(id impTrackerElement, NSUInteger idx, BOOL *stop) { + NSURL *impURL = [NSURL URLWithString:[impTrackerElement description]]; + if (impURL) { + [impTrackURLs addObject:impURL]; + } + }]; + nativeAd.impTrackers = [impTrackURLs copy]; + } + if ([nativeAdDict[kANAdServerResponseKeyNativeCustomKeywordsDict] isKindOfClass:[NSDictionary class]]) { + nativeAd.customElements = (NSDictionary *)nativeAdDict[kANAdServerResponseKeyNativeCustomKeywordsDict]; + } + if ([nativeAdDict[kANAdServerResponseKeyNativeRatingDict] isKindOfClass:[NSDictionary class]]) { + NSDictionary *rating = (NSDictionary *)nativeAdDict[kANAdServerResponseKeyNativeRatingDict]; + NSNumber *ratingScale = @(0); + NSNumber *ratingValue = @(0); + + if ([rating[kANAdServerResponseKeyNativeRatingScale] isKindOfClass:[NSNumber class]]) { + ratingScale = rating[kANAdServerResponseKeyNativeRatingScale]; + } + if ([rating[kANAdServerResponseKeyNativeRatingValue] isKindOfClass:[NSNumber class]]) { + ratingValue = rating[kANAdServerResponseKeyNativeRatingValue]; + } + nativeAd.rating = [[ANNativeAdStarRating alloc] initWithValue:[ratingValue floatValue] + scale:[ratingScale integerValue]]; + } + return nativeAd; + } + return nil; +} + +@end \ No newline at end of file diff --git a/sdk/native/internal/ANNativeAdFetcher.h b/sdk/native/internal/ANNativeAdFetcher.h index c3ae86af4..6fae8bd32 100644 --- a/sdk/native/internal/ANNativeAdFetcher.h +++ b/sdk/native/internal/ANNativeAdFetcher.h @@ -17,6 +17,7 @@ #import "ANAdResponse.h" #import "ANGlobal.h" #import "ANNativeAdTargetingProtocol.h" +#import "ANAdFetcherResponse.h" static NSString *const kANNativeAdFetcherDefaultBaseUrlString = @"http://mediation.adnxs.com/mob"; @@ -35,6 +36,6 @@ static NSString *const kANNativeAdFetcherDefaultBaseUrlString = @"http://mediati @protocol ANNativeAdFetcherDelegate -- (void)adFetcher:(ANNativeAdFetcher *)fetcher didFinishRequestWithResponse:(ANAdResponse *)response; +- (void)adFetcher:(ANNativeAdFetcher *)fetcher didFinishRequestWithResponse:(ANAdFetcherResponse *)response; @end \ No newline at end of file diff --git a/sdk/native/internal/ANNativeAdFetcher.m b/sdk/native/internal/ANNativeAdFetcher.m index 39e58f0ff..9ec769698 100644 --- a/sdk/native/internal/ANNativeAdFetcher.m +++ b/sdk/native/internal/ANNativeAdFetcher.m @@ -15,38 +15,34 @@ #import "ANNativeAdFetcher.h" #import "ANLogging.h" -#import "ANNativeMediatedAd.h" +#import "ANMediatedAd.h" #import "ANNativeMediatedAdController.h" #import "ANNativeAdRequestUrlBuilder.h" #import "ANNativeAdTargetingProtocol.h" +#import "ANAdServerResponse.h" @interface ANNativeAdFetcher () +@property (nonatomic, readwrite, weak) id delegate; +@property (nonatomic, readwrite, strong) NSString *baseUrlString; + @property (nonatomic, readwrite, strong) NSURLConnection *connection; -@property (nonatomic, readwrite, strong) NSMutableURLRequest *request; @property (nonatomic, readwrite, strong) NSMutableData *data; -@property (nonatomic, readwrite, strong) NSURL *URL; @property (nonatomic, readwrite, getter = isLoading) BOOL loading; -@property (nonatomic, readwrite, strong) NSMutableArray *mediatedAds; -@property (nonatomic, readwrite, strong) ANNativeMediatedAdController *mediationController; -@property (nonatomic, readwrite, assign) BOOL requestShouldBePosted; -// variables for measuring latency. @property (nonatomic, readwrite, assign) NSTimeInterval totalLatencyStart; - -@property (nonatomic, readwrite, weak) id delegate; -@property (nonatomic, readwrite, strong) NSString *baseUrlString; +@property (nonatomic, readwrite, strong) NSMutableArray *mediatedAds; +@property (nonatomic, readwrite, strong) ANNativeStandardAdResponse *nativeAd; +@property (nonatomic, readwrite, strong) ANNativeMediatedAdController *mediationController; @end @implementation ANNativeAdFetcher +#pragma mark - Initializers + - (instancetype)initWithDelegate:(id)delegate baseUrlString:(NSString *)baseUrlString { - if (!baseUrlString) { - return [self initWithDelegate:delegate]; - } - if (self = [self init]) { self.delegate = delegate; self.baseUrlString = baseUrlString; @@ -56,23 +52,20 @@ - (instancetype)initWithDelegate:(id)delegate } - (instancetype)initWithDelegate:(id)delegate { - if (self = [self init]) { - self.delegate = delegate; - [self requestAd]; - } - return self; + return [self initWithDelegate:delegate + baseUrlString:kANNativeAdFetcherDefaultBaseUrlString]; } - (instancetype)init { if (self = [super init]) { self.data = [NSMutableData data]; - self.request = [[self class] initBasicRequest]; - self.baseUrlString = kANNativeAdFetcherDefaultBaseUrlString; [NSHTTPCookieStorage sharedHTTPCookieStorage].cookieAcceptPolicy = NSHTTPCookieAcceptPolicyAlways; } return self; } +#pragma mark - Ad Server Request + + (NSMutableURLRequest *)initBasicRequest { NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:nil cachePolicy:NSURLRequestReloadIgnoringLocalCacheData @@ -81,140 +74,97 @@ + (NSMutableURLRequest *)initBasicRequest { return request; } +- (void)requestAd { + NSURL *adRequestUrl = [ANNativeAdRequestUrlBuilder requestUrlWithAdRequestDelegate:self.delegate + baseUrlString:self.baseUrlString]; + [self requestAdWithURL:adRequestUrl]; +} + - (void)requestAdWithURL:(NSURL *)URL { [self markLatencyStart]; - self.request = [[self class] initBasicRequest]; + NSMutableURLRequest *request = [[self class] initBasicRequest]; if (!self.isLoading) { - ANLogInfo(ANErrorString(@"fetcher_start")); - - self.URL = URL ? URL : [ANNativeAdRequestUrlBuilder requestUrlWithAdRequestDelegate:self.delegate - baseUrlString:self.baseUrlString]; - if (self.URL != nil) { - self.request.URL = self.URL; - self.connection = [NSURLConnection connectionWithRequest:self.request delegate:self]; - - if (self.connection != nil) { - ANLogInfo(@"Beginning loading ad from URL: %@", self.URL); - - if (self.requestShouldBePosted) { - ANLogDebug(@"self.requestShouldBePosted"); - self.requestShouldBePosted = NO; - } + ANLogInfo(@"fetcher_start"); + if (URL) { + request.URL = URL; + self.connection = [NSURLConnection connectionWithRequest:request + delegate:self]; + if (self.connection) { self.loading = YES; + } else { + [self finishRequestWithError:ANError(@"bad_url_connection", ANAdResponseBadURLConnection)]; } - else { - NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: NSLocalizedString(@"Unable to make request due to bad URL connection.", @"Error: Bad URL connection.")}; - NSError *badURLConnectionError = [NSError errorWithDomain:AN_ERROR_DOMAIN code:ANAdResponseBadURLConnection userInfo:errorInfo]; - ANAdResponse *response = [ANAdResponse adResponseFailWithError:badURLConnectionError]; - [self processFinalResponse:response]; - } - } - else { - NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: NSLocalizedString(@"Unable to make request due to malformed URL.", @"Error: Malformed URL")}; - NSError *badURLError = [NSError errorWithDomain:AN_ERROR_DOMAIN code:ANAdResponseBadURL userInfo:errorInfo]; - ANAdResponse *response = [ANAdResponse adResponseFailWithError:badURLError]; - [self processFinalResponse:response]; + } else { + [self finishRequestWithError:ANError(@"malformed_url", ANAdResponseBadURL)]; } - } - else { - ANLogWarn(ANErrorString(@"moot_restart")); + } else { + ANLogWarn(@"moot_restart"); } } -- (void)requestAd { - self.requestShouldBePosted = YES; - [self requestAdWithURL:nil]; +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [self stopAd]; } - (void)stopAd { [self.connection cancel]; self.connection = nil; - self.loading = NO; self.data = nil; -} - -- (void)sendDelegateFinishedResponse:(ANAdResponse *)response { - if ([self.delegate respondsToSelector:@selector(adFetcher:didFinishRequestWithResponse:)]) { - [self.delegate adFetcher:self didFinishRequestWithResponse:response]; - } -} - -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - [self.connection cancel]; + self.mediatedAds = nil; + self.nativeAd = nil; [self clearMediationController]; } - (void)clearMediationController { - /* - Ad fetcher gets cleared, in the event the mediation controller lives beyond the ad fetcher. The controller maintains a weak reference to the - ad fetcher delegate so that messages to the delegate can proceed uninterrupted. Currently, the controller will only live on if it is still - displaying inside a banner ad view (in which case it will live on until the individual ad is destroyed). - */ self.mediationController = nil; } -#pragma mark Request Url Construction +#pragma mark - Ad Server Response -- (void)processFinalResponse:(ANAdResponse *)response { - [self sendDelegateFinishedResponse:response]; -} - -- (void)processAdResponse:(ANAdResponse *)response { - [self clearMediationController]; - - BOOL responseAdsExist = response && response.containsAds; - BOOL oldAdsExist = [self.mediatedAds count] > 0; - - if (!responseAdsExist && !oldAdsExist) { - ANLogWarn(ANErrorString(@"response_no_ads")); - NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: NSLocalizedString(@"Request got successful response from server, but no ads were available.", @"Error: Response was received, but it contained no ads")}; - [self finishRequestWithErrorAndRefresh:errorInfo code:ANAdResponseUnableToFill]; +- (void)processAdServerResponse:(ANAdServerResponse *)response { + if (!response.containsAds) { + [self finishRequestWithError:ANError(@"response_no_ads", ANAdResponseUnableToFill)]; return; } - // if mediatedAds is null as a result of this loop, - // then it must be a non-mediated ad - if (responseAdsExist) { - self.mediatedAds = response.mediatedAds; - } + self.mediatedAds = response.mediatedAds; - if ([self.mediatedAds count] > 0) { - // mediated - [self handleMediatedAds:self.mediatedAds]; - } - else { - ANLogError(ANErrorString(@"response_bad_format")); - NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: ANErrorString(@"response_bad_format")}; - [self finishRequestWithErrorAndRefresh:errorInfo code:ANAdResponseBadFormat]; + if (self.mediatedAds.count) { + self.nativeAd = response.nativeAd; + [self popAndLoadMediatedAd]; + } else if (response.nativeAd) { + [self processNativeResponse:response.nativeAd]; + } else { + [self finishRequestWithError:ANError(@"response_bad_format", ANAdResponseBadFormat)]; } } -- (void)handleMediatedAds:(NSMutableArray *)mediatedAds { - // pop the front ad - ANNativeMediatedAd *adToParse = mediatedAds.firstObject; - [mediatedAds removeObject:adToParse]; - - self.mediationController = [ANNativeMediatedAdController initMediatedAd:adToParse - withDelegate:self - adRequestDelegate:self.delegate]; +#pragma mark - Final Response + +- (void)finishRequestWithSuccessfulAdObject:(id)adObject { + self.loading = NO; + ANAdFetcherResponse *response = [[ANAdFetcherResponse alloc] initAdResponseSuccessWithAdObject:adObject]; + [self processFinalResponse:response]; } -- (void)finishRequestWithErrorAndRefresh:(NSDictionary *)errorInfo code:(NSInteger)code { +- (void)finishRequestWithError:(NSError *)error { self.loading = NO; - - NSError *error = [NSError errorWithDomain:AN_ERROR_DOMAIN code:code userInfo:errorInfo]; - ANLogInfo(@"No ad received. Error: %@", error.localizedDescription); - ANAdResponse *response = [ANAdResponse adResponseFailWithError:error]; + ANLogError(@"no_ad_received_error %@", error.localizedDescription); + ANAdFetcherResponse *response = [[ANAdFetcherResponse alloc] initAdResponseFailWithError:error]; [self processFinalResponse:response]; } -# pragma mark - -# pragma mark NSURLConnectionDataDelegate +- (void)processFinalResponse:(ANAdFetcherResponse *)response { + if ([self.delegate respondsToSelector:@selector(adFetcher:didFinishRequestWithResponse:)]) { + [self.delegate adFetcher:self didFinishRequestWithResponse:response]; + } +} + +# pragma mark - NSURLConnectionDataDelegate - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { if (connection == self.connection) { @@ -224,21 +174,15 @@ - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLRespon if (status >= 400) { [connection cancel]; - NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: [NSString stringWithFormat: - NSLocalizedString(@"Request failed with status code %d", @"Error Description: server request came back with error code."), - status]}; - NSError *statusError = [NSError errorWithDomain:AN_ERROR_DOMAIN - code:ANAdResponseNetworkError - userInfo:errorInfo]; - [self connection:connection didFailWithError:statusError]; + [self connection:connection didFailWithError:ANError(@"connection_failed %ld", ANAdResponseNetworkError, (long)status)]; return; } } self.data = [NSMutableData data]; - ANLogDebug(@"Received response: %@", response); + ANLogDebug(@"response_received %@", response); } else { - ANLogDebug(@"Received response from unknown"); + ANLogDebug(@"response_received_unknown"); } } @@ -250,111 +194,96 @@ - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)d { - (void)connectionDidFinishLoading:(NSURLConnection *)connection { if (connection == self.connection) { - ANAdResponse *adResponse = [[ANAdResponse alloc] init]; - adResponse = [adResponse processResponseData:self.data]; - [self processAdResponse:adResponse]; + ANAdServerResponse *adResponse = [[ANAdServerResponse alloc] initWithAdServerData:self.data]; + [self processAdServerResponse:adResponse]; } } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { if (connection == self.connection) { - NSString *errorMessage = [NSString stringWithFormat: - @"Ad request %@ failed with error %@", - connection, [error localizedDescription]]; - ANLogError(errorMessage); - - self.loading = NO; - - NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: errorMessage}; - NSError *ANError = [NSError errorWithDomain:AN_ERROR_DOMAIN - code:ANAdResponseNetworkError - userInfo:errorInfo]; - - ANAdResponse *failureResponse = [ANAdResponse adResponseFailWithError:ANError]; - [self processFinalResponse:failureResponse]; + NSError *anError = ANError(@"ad_request_failed %@%@", ANAdResponseNetworkError, connection, [error localizedDescription]); + [self finishRequestWithError:anError]; } } -#pragma mark handling resultCB +#pragma mark - Native + +- (void)processNativeResponse:(ANNativeStandardAdResponse *)nativeAd { + [self finishRequestWithSuccessfulAdObject:nativeAd]; +} + +#pragma mark - Mediation + +- (void)popAndLoadMediatedAd { + if (self.mediatedAds.count) { + [self clearMediationController]; + ANMediatedAd *adToParse = self.mediatedAds.firstObject; + [self.mediatedAds removeObjectAtIndex:0]; + self.mediationController = [ANNativeMediatedAdController initMediatedAd:adToParse + withDelegate:self + adRequestDelegate:self.delegate]; + } else { + ANLogError(@"No mediated ad to pop. Internal implementation error."); + } +} - (void)fireResultCB:(NSString *)resultCBString reason:(ANAdResponseCode)reason adObject:(id)adObject { self.loading = NO; + [self clearMediationController]; + + if (!self.delegate) { + return; + } NSURL *resultURL = [NSURL URLWithString:resultCBString]; if (reason == ANAdResponseSuccessful) { - // mediated ad succeeded. fire resultCB and ignore response - if ([resultCBString length] > 0) { + if (resultCBString.length) { [self fireAndIgnoreResultCB:resultURL]; } - - ANAdResponse *response = [ANAdResponse adResponseSuccessfulWithAdObject:adObject]; - [self processFinalResponse:response]; + [self finishRequestWithSuccessfulAdObject:adObject]; } else { - // mediated ad failed. clear mediation controller - [self clearMediationController]; - - // stop waterfall if delegate reference (adview) was lost - if (!self.delegate) { - return; - } - - // fire the resultCB if there is one - if ([resultCBString length] > 0) { - // treat the LAST (failed) resultCB responses as normal requests - if ([self.mediatedAds count] == 0) { - [self requestAdWithURL:resultURL]; - } else { - // otherwise, just fire resultCB asnychronously and ignore result + if (self.mediatedAds.count) { + if (resultURL) { [self fireAndIgnoreResultCB:resultURL]; - // not the last ad in waterfall, so continue to next ad - [self processAdResponse:nil]; } + [self popAndLoadMediatedAd]; } else { - // if no resultCB and no successful ads yet, - // simply continue waterfall - [self processAdResponse:nil]; + if (self.nativeAd) { + if (resultURL) { + [self fireAndIgnoreResultCB:resultURL]; + } + [self processNativeResponse:self.nativeAd]; + } else if (resultURL) { + [self requestAdWithURL:resultURL]; + } else { + [self finishRequestWithError:ANError(@"response_no_ads", ANAdResponseUnableToFill)]; + } } } } - (void)fireAndIgnoreResultCB:(NSURL *)url { - // just fire resultCB asnychronously and ignore result + ANLogDebug(@"Firing resultCB with url %@", url); NSMutableURLRequest *ignoredRequest = [[self class] initBasicRequest]; ignoredRequest.URL = url; [NSURLConnection sendAsynchronousRequest:ignoredRequest queue:[NSOperationQueue mainQueue] - completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { - if (error) { - ANLogInfo(@"Ignored resultCB received response with error: %@", [error localizedDescription]); - } else if ([response isKindOfClass:[NSHTTPURLResponse class]]) { - NSInteger status = [(NSHTTPURLResponse *)response statusCode]; - ANLogInfo(@"Ignored resultCB received response with code %ld", status); - } else { - ANLogInfo(@"Ignored resultCB received response."); - } - }]; + completionHandler:nil]; } -#pragma mark Total Latency Measurement +#pragma mark - Latency -/** - * Mark the beginning of an ad request for latency recording - */ - (void)markLatencyStart { self.totalLatencyStart = [NSDate timeIntervalSinceReferenceDate]; } -/** - * Returns the time difference since ad request start - */ - (NSTimeInterval)getTotalLatency:(NSTimeInterval)stopTime { if ((self.totalLatencyStart > 0) && (stopTime > 0)) { return (stopTime - self.totalLatencyStart); } - // return -1 if invalid parameters return -1; } diff --git a/sdk/native/internal/ANNativeAdRequest.m b/sdk/native/internal/ANNativeAdRequest.m index df80ad11c..3c076362c 100644 --- a/sdk/native/internal/ANNativeAdRequest.m +++ b/sdk/native/internal/ANNativeAdRequest.m @@ -56,8 +56,8 @@ - (void)adFetcher:(ANNativeAdFetcher *)fetcher didFinishRequestWithResponse:(ANA NSError *error; if (response.isSuccessful) { - if ([response.adObject isKindOfClass:[ANNativeMediatedAdResponse class]]) { - ANNativeMediatedAdResponse *finalResponse = (ANNativeMediatedAdResponse *)response.adObject; + if ([response.adObject isKindOfClass:[ANNativeAdResponse class]]) { + ANNativeAdResponse *finalResponse = (ANNativeAdResponse *)response.adObject; __weak ANNativeAdRequest *weakSelf = self; NSOperation *finish = [NSBlockOperation blockOperationWithBlock:^{ @@ -66,13 +66,13 @@ - (void)adFetcher:(ANNativeAdFetcher *)fetcher didFinishRequestWithResponse:(ANA [strongSelf.adFetchers removeObjectIdenticalTo:fetcher]; }]; - if (self.shouldLoadIconImage) { + if (self.shouldLoadIconImage && [finalResponse respondsToSelector:@selector(setIconImage:)]) { [self setImageForImageURL:finalResponse.iconImageURL onObject:finalResponse forKeyPath:@"iconImage" withCompletionOperation:finish]; } - if (self.shouldLoadMainImage) { + if (self.shouldLoadMainImage && [finalResponse respondsToSelector:@selector(setMainImage:)]) { [self setImageForImageURL:finalResponse.mainImageURL onObject:finalResponse forKeyPath:@"mainImage" diff --git a/sdk/native/internal/ANNativeAdRequestUrlBuilder.m b/sdk/native/internal/ANNativeAdRequestUrlBuilder.m index a6bd05ee3..6a6223b47 100644 --- a/sdk/native/internal/ANNativeAdRequestUrlBuilder.m +++ b/sdk/native/internal/ANNativeAdRequestUrlBuilder.m @@ -255,9 +255,9 @@ - (NSString *)ageParameter { - (NSString *)genderParameter { ANGender genderValue = [self.adRequestDelegate gender]; - if (genderValue == MALE) { + if (genderValue == ANGenderMale) { return @"gender=m"; - } else if (genderValue == FEMALE) { + } else if (genderValue == ANGenderFemale) { return @"gender=f"; } else { return @""; @@ -283,7 +283,7 @@ - (NSString *)customKeywordsParameter { [self URLEncodingFrom:value]]]; } }else{ - ANLogWarn(ANErrorString(@"request_parameter_override_attempt", key)); + ANLogWarn(@"request_parameter_override_attempt %@", key); } }]; diff --git a/sdk/native/internal/ANNativeAdResponse+PrivateMethods.h b/sdk/native/internal/ANNativeAdResponse+PrivateMethods.h new file mode 100644 index 000000000..3d6419e9e --- /dev/null +++ b/sdk/native/internal/ANNativeAdResponse+PrivateMethods.h @@ -0,0 +1,49 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANNativeAdResponse.h" + +@interface ANNativeAdResponse (PrivateMethods) + +@property (nonatomic, readonly, weak) UIViewController *rootViewController; +@property (nonatomic, readonly, strong) UIView *viewForTracking; + +#pragma mark - Registration + +- (BOOL)registerResponseInstanceWithNativeView:(UIView *)view + rootViewController:(UIViewController *)controller + clickableViews:(NSArray *)clickableViews + error:(NSError *__autoreleasing*)error; + +#pragma mark - Unregistration + +- (void)unregisterViewFromTracking; + +#pragma mark - Click handling + +- (void)attachGestureRecognizersToNativeView:(UIView *)nativeView + withClickableViews:(NSArray *)clickableViews; +- (void)handleClick; + +#pragma mark - ANNativeAdDelegate / ANNativeCustomAdapterAdDelegate + +- (void)adWasClicked; +- (void)willPresentAd; +- (void)didPresentAd; +- (void)willCloseAd; +- (void)didCloseAd; +- (void)willLeaveApplication; + +@end \ No newline at end of file diff --git a/sdk/native/internal/ANNativeAdResponse.m b/sdk/native/internal/ANNativeAdResponse.m index bd90de2d5..b0e2289c6 100644 --- a/sdk/native/internal/ANNativeAdResponse.m +++ b/sdk/native/internal/ANNativeAdResponse.m @@ -16,27 +16,190 @@ #import "ANNativeAdResponse.h" #import "ANLogging.h" #import "UIView+ANNativeAdCategory.h" +#import "ANGlobal.h" @interface ANNativeAdResponse () @property (nonatomic, readwrite, strong) UIView *viewForTracking; - -- (void)unregisterViewFromTracking; +@property (nonatomic, readwrite, strong) NSMutableDictionary *viewToGestureRecognizerMapping; +@property (nonatomic, readwrite, weak) UIViewController *rootViewController; +@property (nonatomic, readwrite, assign, getter=hasExpired) BOOL expired; +@property (nonatomic, readwrite, assign) ANNativeAdNetworkCode networkCode; @end @implementation ANNativeAdResponse +#pragma mark - Registration + - (BOOL)registerViewForTracking:(UIView *)view withRootViewController:(UIViewController *)controller clickableViews:(NSArray *)clickableViews error:(NSError **)error { - // Abstract + if (!view) { + ANLogError(@"native_invalid_view"); + if (error) { + *error = ANError(@"native_invalid_view", ANNativeAdRegisterErrorCodeInvalidView); + } + return NO; + } + if (!controller) { + ANLogError(@"native_invalid_rvc"); + if (error) { + *error = ANError(@"native_invalid_rvc", ANNativeAdRegisterErrorCodeInvalidRootViewController); + } + return NO; + } + if (self.hasExpired) { + ANLogError(@"native_expired_response"); + if (error) { + *error = ANError(@"native_expired_response", ANNativeAdRegisterErrorCodeExpiredResponse); + } + return NO; + } + + ANNativeAdResponse *response = [view anNativeAdResponse]; + if (response) { + ANLogDebug(@"Unregistering view from another response"); + [response unregisterViewFromTracking]; + } + + BOOL successfulResponseRegistration = [self registerResponseInstanceWithNativeView:view + rootViewController:controller + clickableViews:clickableViews + error:error]; + if (successfulResponseRegistration) { + self.viewForTracking = view; + [view setAnNativeAdResponse:self]; + self.rootViewController = controller; + self.expired = YES; + return YES; + } + + return NO; +} + +- (BOOL)registerResponseInstanceWithNativeView:(UIView *)view + rootViewController:(UIViewController *)controller + clickableViews:(NSArray *)clickableViews + error:(NSError *__autoreleasing*)error { + // Abstract method, to be implemented by subclass return NO; } +#pragma mark - Unregistration + - (void)unregisterViewFromTracking { - // Abstract + [self detachAllGestureRecognizers]; + [self.viewForTracking setAnNativeAdResponse:nil]; + self.viewForTracking = nil; +} + +#pragma mark - Click handling + +- (void)attachGestureRecognizersToNativeView:(UIView *)nativeView + withClickableViews:(NSArray *)clickableViews { + if (clickableViews.count) { + [clickableViews enumerateObjectsUsingBlock:^(id clickableView, NSUInteger idx, BOOL *stop) { + if ([clickableView isKindOfClass:[UIView class]]) { + [self attachGestureRecognizerToView:clickableView]; + } else { + ANLogWarn(@"native_invalid_clickable_views"); + } + }]; + } else { + [self attachGestureRecognizerToView:nativeView]; + } +} + +- (void)attachGestureRecognizerToView:(UIView *)view { + view.userInteractionEnabled = YES; + NSValue *key = [NSValue valueWithNonretainedObject:view]; + NSValue *value; + + if ([view isKindOfClass:[UIButton class]]) { + UIButton *button = (UIButton *)view; + [button addTarget:self + action:@selector(handleClick) + forControlEvents:UIControlEventTouchUpInside]; + value = [NSValue valueWithNonretainedObject:[NSNull null]]; + } else { + UITapGestureRecognizer *clickRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self + action:@selector(handleClick)]; + [view addGestureRecognizer:clickRecognizer]; + value = [NSValue valueWithNonretainedObject:clickRecognizer]; + } + self.viewToGestureRecognizerMapping[key] = value; +} + +- (void)detachAllGestureRecognizers { + [self.viewToGestureRecognizerMapping enumerateKeysAndObjectsUsingBlock:^(NSValue *viewValue, NSValue *gestureRecognizerValue, BOOL *stop) { + UIView *view = (UIView *)[viewValue nonretainedObjectValue]; + if (view) { + if ([view isKindOfClass:[UIButton class]]) { + [(UIButton *)view removeTarget:self + action:@selector(handleClick) + forControlEvents:UIControlEventTouchUpInside]; + } else { + UIGestureRecognizer *recognizer = (UIGestureRecognizer *)[gestureRecognizerValue nonretainedObjectValue]; + if (recognizer) { + [view removeGestureRecognizer:recognizer]; + } + } + } + }]; + [self.viewToGestureRecognizerMapping removeAllObjects]; +} + +- (NSMutableDictionary *)viewToGestureRecognizerMapping { + if (!_viewToGestureRecognizerMapping) _viewToGestureRecognizerMapping = [[NSMutableDictionary alloc] init]; + return _viewToGestureRecognizerMapping; +} + +- (void)handleClick { + // Abstract method, to be implemented by subclass +} + +- (void)dealloc { + [self unregisterViewFromTracking]; +} + +# pragma mark - ANNativeAdDelegate + +- (void)adWasClicked { + if ([self.delegate respondsToSelector:@selector(adWasClicked:)]) { + [self.delegate adWasClicked:self]; + } +} + +- (void)willPresentAd { + if ([self.delegate respondsToSelector:@selector(adWillPresent:)]) { + [self.delegate adWillPresent:self]; + } +} + +- (void)didPresentAd { + if ([self.delegate respondsToSelector:@selector(adDidPresent:)]) { + [self.delegate adDidPresent:self]; + } +} + +- (void)willCloseAd { + if ([self.delegate respondsToSelector:@selector(adWillClose:)]) { + [self.delegate adWillClose:self]; + } +} + +- (void)didCloseAd { + if ([self.delegate respondsToSelector:@selector(adDidClose:)]) { + [self.delegate adDidClose:self]; + } +} + +- (void)willLeaveApplication { + if ([self.delegate respondsToSelector:@selector(adWillLeaveApplication:)]) { + [self.delegate adWillLeaveApplication:self]; + } } @end \ No newline at end of file diff --git a/sdk/native/internal/ANNativeImpressionTrackerInfo.h b/sdk/native/internal/ANNativeImpressionTrackerInfo.h new file mode 100644 index 000000000..92664cb16 --- /dev/null +++ b/sdk/native/internal/ANNativeImpressionTrackerInfo.h @@ -0,0 +1,29 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +static NSTimeInterval const kANNativeImpressionTrackerExpirationInterval = 3600; + +@interface ANNativeImpressionTrackerInfo : NSObject + +- (instancetype)initWithURL:(NSURL *)URL; + +@property (nonatomic, readonly, strong) NSURL *URL; +@property (nonatomic, readonly, strong) NSDate *dateCreated; +@property (nonatomic, readonly, assign, getter=isExpired) BOOL expired; +@property (nonatomic, readwrite, assign) NSUInteger numberOfTimesFired; + +@end \ No newline at end of file diff --git a/sdk/native/internal/ANNativeImpressionTrackerInfo.m b/sdk/native/internal/ANNativeImpressionTrackerInfo.m new file mode 100644 index 000000000..cea6fd866 --- /dev/null +++ b/sdk/native/internal/ANNativeImpressionTrackerInfo.m @@ -0,0 +1,60 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANNativeImpressionTrackerInfo.h" +#import "NSTimer+ANCategory.h" + +@interface ANNativeImpressionTrackerInfo() + +@property (nonatomic, readwrite, strong) NSURL *URL; +@property (nonatomic, readwrite, strong) NSDate *dateCreated; +@property (nonatomic, readwrite, assign, getter=isExpired) BOOL expired; +@property (nonatomic, readwrite, strong) NSTimer *expirationTimer; + +@end + +@implementation ANNativeImpressionTrackerInfo + +- (instancetype)initWithURL:(NSURL *)URL { + if (!URL) { + return nil; + } + if (self = [super init]) { + _URL = URL; + _dateCreated = [NSDate date]; + [self createExpirationTimer]; + } + return self; +} + +- (void)createExpirationTimer { + __weak ANNativeImpressionTrackerInfo *weakSelf = self; + self.expirationTimer = [NSTimer scheduledTimerWithTimeInterval:kANNativeImpressionTrackerExpirationInterval + block:^{ + ANNativeImpressionTrackerInfo *strongSelf = weakSelf; + strongSelf.expired = YES; + } + repeats:NO]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%@ URL: %@", NSStringFromClass([self class]), self.URL]; +} + +- (void)dealloc { + [self.expirationTimer invalidate]; +} + +@end \ No newline at end of file diff --git a/sdk/native/internal/ANNativeImpressionTrackerManager.h b/sdk/native/internal/ANNativeImpressionTrackerManager.h new file mode 100644 index 000000000..3fb6387f7 --- /dev/null +++ b/sdk/native/internal/ANNativeImpressionTrackerManager.h @@ -0,0 +1,27 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +static const NSUInteger kANNativeImpressionTrackerManagerMaximumNumberOfRetries = 3; +static const NSTimeInterval kANNativeImpressionTrackerManagerRetryInterval = 300; + +@interface ANNativeImpressionTrackerManager : NSObject + ++ (instancetype)sharedManager; ++ (void)fireImpressionTrackerURLArray:(NSArray *)arrayWithURLs; ++ (void)fireImpressionTrackerURL:(NSURL *)URL; + +@end \ No newline at end of file diff --git a/sdk/native/internal/ANNativeImpressionTrackerManager.m b/sdk/native/internal/ANNativeImpressionTrackerManager.m new file mode 100644 index 000000000..42bc6d943 --- /dev/null +++ b/sdk/native/internal/ANNativeImpressionTrackerManager.m @@ -0,0 +1,162 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANNativeImpressionTrackerManager.h" +#import "ANReachability.h" +#import "ANNativeImpressionTrackerInfo.h" +#import "ANGlobal.h" +#import "ANLogging.h" + +#import "NSTimer+ANCategory.h" + +@interface ANNativeImpressionTrackerManager () + +@property (nonatomic, readwrite, strong) NSMutableArray *trackerArray; +@property (nonatomic, readwrite, strong) ANReachability *internetReachability; + +@property (nonatomic, readonly, assign) BOOL internetIsReachable; + +@property (nonatomic, readwrite, strong) NSTimer *impressionTrackerRetryTimer; + +@end + +@implementation ANNativeImpressionTrackerManager + ++ (instancetype)sharedManager { + static ANNativeImpressionTrackerManager *manager; + static dispatch_once_t managerToken; + dispatch_once(&managerToken, ^{ + manager = [[ANNativeImpressionTrackerManager alloc] init]; + }); + return manager; +} + ++ (void)fireImpressionTrackerURLArray:(NSArray *)arrayWithURLs { + ANNativeImpressionTrackerManager *manager = [[self class] sharedManager]; + [manager fireImpressionTrackerURLArray:arrayWithURLs]; +} + ++ (void)fireImpressionTrackerURL:(NSURL *)URL { + ANNativeImpressionTrackerManager *manager = [[self class] sharedManager]; + [manager fireImpressionTrackerURL:URL]; +} + +#pragma mark ANNativeImpressionTrackerHandlerManager implementation + +- (instancetype)init { + if (self = [super init]) { + _internetReachability = [ANReachability reachabilityForInternetConnection]; + } + return self; +} + +- (void)fireImpressionTrackerURLArray:(NSArray *)arrayWithURLs { + if (self.internetIsReachable) { + ANLogDebug(@"Internet is reachable - Firing impression trackers %@", arrayWithURLs); + [arrayWithURLs enumerateObjectsUsingBlock:^(NSURL *URL, NSUInteger idx, BOOL *stop) { + __weak ANNativeImpressionTrackerManager *weakSelf = self; + [NSURLConnection sendAsynchronousRequest:ANBasicRequestWithURL(URL) + queue:[NSOperationQueue mainQueue] + completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { + ANNativeImpressionTrackerManager *strongSelf = weakSelf; + if (connectionError) { + ANLogDebug(@"Connection error - queing impression tracker for firing later %@", URL); + [strongSelf queueImpressionTrackerURLForRetry:URL]; + } + }]; + }]; + } else { + ANLogDebug(@"Internet is unreachable - queing impression trackers for firing later %@", arrayWithURLs); + [arrayWithURLs enumerateObjectsUsingBlock:^(NSURL *URL, NSUInteger idx, BOOL *stop) { + [self queueImpressionTrackerURLForRetry:URL]; + }]; + } +} + +- (void)fireImpressionTrackerURL:(NSURL *)URL { + if (URL) { + [self fireImpressionTrackerURLArray:@[URL]]; + } +} + +- (BOOL)internetIsReachable { + ANNetworkStatus networkStatus = [self.internetReachability currentReachabilityStatus]; + BOOL connectionRequired = [self.internetReachability connectionRequired]; + if (networkStatus != ANNetworkStatusNotReachable && !connectionRequired) { + return YES; + } + return NO; +} + +- (void)retryImpressionTrackerFires { + NSArray *trackerArrayCopy; + @synchronized(self) { + if (self.trackerArray.count > 0 && self.internetIsReachable) { + ANLogDebug(@"Internet back online - Firing impression trackers %@", self.trackerArray); + trackerArrayCopy = [self.trackerArray copy]; + [self.trackerArray removeAllObjects]; + [self.impressionTrackerRetryTimer invalidate]; + } + } + __weak ANNativeImpressionTrackerManager *weakSelf = self; + [trackerArrayCopy enumerateObjectsUsingBlock:^(ANNativeImpressionTrackerInfo *info, NSUInteger idx, BOOL *stop) { + if (!info.isExpired) { + [NSURLConnection sendAsynchronousRequest:ANBasicRequestWithURL(info.URL) + queue:[NSOperationQueue mainQueue] + completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { + ANNativeImpressionTrackerManager *strongSelf = weakSelf; + if (connectionError) { + ANLogDebug(@"Connection error - queing impression tracker for firing later %@", info.URL); + info.numberOfTimesFired += 1; + if (info.numberOfTimesFired < kANNativeImpressionTrackerManagerMaximumNumberOfRetries && !info.isExpired) { + @synchronized(strongSelf) { + [strongSelf.trackerArray addObject:info]; + [strongSelf scheduleRetryTimerIfNecessary]; + } + } + } else { + ANLogDebug(@"Retry successful for %@", info); + } + }]; + } + }]; +} + +- (void)queueImpressionTrackerURLForRetry:(NSURL *)URL { + ANNativeImpressionTrackerInfo *trackerInfo = [[ANNativeImpressionTrackerInfo alloc] initWithURL:URL]; + @synchronized(self) { + [self.trackerArray addObject:trackerInfo]; + [self scheduleRetryTimerIfNecessary]; + } +} + +- (void)scheduleRetryTimerIfNecessary { + if (![self.impressionTrackerRetryTimer isScheduled]) { + __weak ANNativeImpressionTrackerManager *weakSelf = self; + self.impressionTrackerRetryTimer = [NSTimer scheduledTimerWithTimeInterval:kANNativeImpressionTrackerManagerRetryInterval + block:^{ + ANNativeImpressionTrackerManager *strongSelf = weakSelf; + [strongSelf retryImpressionTrackerFires]; + } + repeats:YES]; + } +} + +- (NSArray *)trackerArray { + if (!_trackerArray) _trackerArray = [[NSMutableArray alloc] init]; + return _trackerArray; +} + +@end \ No newline at end of file diff --git a/sdk/native/internal/ANNativeMediatedAdController.h b/sdk/native/internal/ANNativeMediatedAdController.h index f34e89693..be5b7fa42 100644 --- a/sdk/native/internal/ANNativeMediatedAdController.h +++ b/sdk/native/internal/ANNativeMediatedAdController.h @@ -14,7 +14,7 @@ */ #import "ANNativeAdFetcher.h" -#import "ANNativeMediatedAd.h" +#import "ANMediatedAd.h" #import "ANNativeAdTargetingProtocol.h" @protocol ANNativeMediationAdControllerDelegate; @@ -22,7 +22,7 @@ @interface ANNativeMediatedAdController : NSObject // Designated initializer -+ (instancetype)initMediatedAd:(ANNativeMediatedAd *)mediatedAd ++ (instancetype)initMediatedAd:(ANMediatedAd *)mediatedAd withDelegate:(id)delegate adRequestDelegate:(id)adRequestDelegate; diff --git a/sdk/native/internal/ANNativeMediatedAdController.m b/sdk/native/internal/ANNativeMediatedAdController.m index cecdb7d40..e79894fc9 100644 --- a/sdk/native/internal/ANNativeMediatedAdController.m +++ b/sdk/native/internal/ANNativeMediatedAdController.m @@ -20,7 +20,7 @@ @interface ANNativeMediatedAdController () -@property (nonatomic, readwrite, strong) ANNativeMediatedAd *mediatedAd; +@property (nonatomic, readwrite, strong) ANMediatedAd *mediatedAd; @property (nonatomic, readwrite, strong) id currentAdapter; @property (nonatomic, readwrite, assign) BOOL hasSucceeded; @@ -35,7 +35,7 @@ @interface ANNativeMediatedAdController () )delegate adRequestDelegate:(id)adRequestDelegate { ANNativeMediatedAdController *controller = [[ANNativeMediatedAdController alloc] initMediatedAd:mediatedAd @@ -49,7 +49,7 @@ + (instancetype)initMediatedAd:(ANNativeMediatedAd *)mediatedAd } -- (instancetype)initMediatedAd:(ANNativeMediatedAd *)mediatedAd +- (instancetype)initMediatedAd:(ANMediatedAd *)mediatedAd withDelegate:(id)delegate adRequestDelegate:(id)adRequestDelegate { self = [super init]; @@ -75,7 +75,7 @@ - (BOOL)initializeRequest { } className = self.mediatedAd.className; - ANLogDebug(ANErrorString(@"instantiating_class", className)); + ANLogDebug(@"instantiating_class %@", className); // check to see if an instance of this class exists Class adClass = NSClassFromString(className); @@ -135,10 +135,10 @@ - (void)handleInstantiationFailure:(NSString *)className errorCode:(ANAdResponseCode)errorCode errorInfo:(NSString *)errorInfo { if ([errorInfo length] > 0) { - ANLogError(ANErrorString(@"mediation_instantiation_failure", errorInfo)); + ANLogError(@"mediation_instantiation_failure %@", errorInfo); } if ([className length] > 0) { - ANLogWarn(ANErrorString(@"mediation_adding_invalid", className)); + ANLogWarn(@"mediation_adding_invalid %@", className); ANAddInvalidNetwork(className); } @@ -156,7 +156,7 @@ - (void)clearAdapter { self.hasSucceeded = NO; self.hasFailed = YES; [self cancelTimeout]; - ANLogInfo(ANErrorString(@"mediation_finish")); + ANLogInfo(@"mediation_finish"); } - (ANTargetingParameters *)targetingParameters { @@ -263,7 +263,7 @@ - (void)startTimeout { dispatch_get_main_queue(), ^{ ANNativeMediatedAdController *strongSelf = weakSelf; if (!strongSelf || strongSelf.timeoutCanceled) return; - ANLogWarn(ANErrorString(@"mediation_timeout")); + ANLogWarn(@"mediation_timeout"); [strongSelf didFailToReceiveAd:(ANAdResponseCode)ANAdResponseInternalError]; }); } diff --git a/sdk/native/internal/ANNativeMediatedAdResponse.m b/sdk/native/internal/ANNativeMediatedAdResponse.m index 20c34a02e..2919f9b96 100644 --- a/sdk/native/internal/ANNativeMediatedAdResponse.m +++ b/sdk/native/internal/ANNativeMediatedAdResponse.m @@ -18,21 +18,11 @@ #import "ANLogging.h" #import "ANGlobal.h" #import "UIView+ANNativeAdCategory.h" - -@interface ANNativeAdResponse (ANNativeMediatedAdResponse) - -@property (nonatomic, readwrite, strong) UIView *viewForTracking; - -- (void)unregisterViewFromTracking; - -@end +#import "ANNativeAdResponse+PrivateMethods.h" @interface ANNativeMediatedAdResponse () @property (nonatomic, readwrite, strong) id adapter; -@property (nonatomic, readwrite, weak) UIViewController *rootViewController; -@property (nonatomic, readwrite, strong) NSMutableDictionary *viewToGestureRecognizerMapping; -@property (nonatomic, readwrite, assign, getter=hasExpired) BOOL expired; @property (nonatomic, readwrite, assign) ANNativeAdNetworkCode networkCode; @end @@ -77,51 +67,14 @@ - (instancetype)initWithCustomAdapter:(id)adapter #pragma mark - Registration -- (BOOL)registerViewForTracking:(UIView *)view - withRootViewController:(UIViewController *)controller - clickableViews:(NSArray *)clickableViews - error:(NSError **)error { - if (!view) { - ANLogError(ANErrorString(@"native_invalid_view")); - if (error) { - *error = ANError(@"native_invalid_view", ANNativeAdRegisterErrorCodeInvalidView); - } - return NO; - } - if (!controller) { - ANLogError(ANErrorString(@"native_invalid_rvc")); - if (error) { - *error = ANError(@"native_invalid_rvc", ANNativeAdRegisterErrorCodeInvalidRootViewController); - } - return NO; - } - if (self.hasExpired) { - ANLogError(ANErrorString(@"native_expired_response")); - if (error) { - *error = ANError(@"native_expired_response", ANNativeAdRegisterErrorCodeExpiredResponse); - } - return NO; - } - - ANNativeAdResponse *response = [view anNativeAdResponse]; - if (response) { - ANLogDebug(@"Unregistering view from another response"); - [response unregisterViewFromTracking]; - } - - BOOL successfulAdapterRegistration = [self registerAdapterWithNativeView:view - rootViewController:controller - clickableViews:clickableViews - error:error]; - if (successfulAdapterRegistration) { - self.viewForTracking = view; - [view setAnNativeAdResponse:self]; - self.rootViewController = controller; - self.expired = YES; - return YES; - } - - return NO; +- (BOOL)registerResponseInstanceWithNativeView:(UIView *)view + rootViewController:(UIViewController *)controller + clickableViews:(NSArray *)clickableViews + error:(NSError *__autoreleasing *)error { + return [self registerAdapterWithNativeView:view + rootViewController:controller + clickableViews:clickableViews + error:error]; } - (BOOL)registerAdapterWithNativeView:(UIView *)view @@ -131,7 +84,7 @@ - (BOOL)registerAdapterWithNativeView:(UIView *)view if ([self.adapter respondsToSelector:@selector(nativeAdDelegate)]) { self.adapter.nativeAdDelegate = self; } else { - ANLogDebug(ANErrorString(@"native_adapter_native_ad_delegate_missing")); + ANLogDebug(@"native_adapter_native_ad_delegate_missing"); } if ([self.adapter respondsToSelector:@selector(registerViewForImpressionTrackingAndClickHandling:withRootViewController:clickableViews:)]) { [self.adapter registerViewForImpressionTrackingAndClickHandling:view @@ -144,7 +97,7 @@ - (BOOL)registerAdapterWithNativeView:(UIView *)view withClickableViews:clickableViews]; return YES; } else { - ANLogError(ANErrorString(@"native_adapter_error")); + ANLogError(@"native_adapter_error"); if (error) { *error = ANError(@"native_adapter_error", ANNativeAdRegisterErrorCodeBadAdapter); } @@ -155,109 +108,18 @@ - (BOOL)registerAdapterWithNativeView:(UIView *)view #pragma mark - Unregistration - (void)unregisterViewFromTracking { + [super unregisterViewFromTracking]; if ([self.adapter respondsToSelector:@selector(unregisterViewFromTracking)]) { [self.adapter unregisterViewFromTracking]; } - [self detachAllGestureRecognizers]; - [self.viewForTracking setAnNativeAdResponse:nil]; - self.viewForTracking = nil; -} - -- (void)dealloc { - [self unregisterViewFromTracking]; } #pragma mark - Click handling -- (void)attachGestureRecognizersToNativeView:(UIView *)nativeView - withClickableViews:(NSArray *)clickableViews { - if (clickableViews.count) { - [clickableViews enumerateObjectsUsingBlock:^(id clickableView, NSUInteger idx, BOOL *stop) { - if ([clickableView isKindOfClass:[UIView class]]) { - [self attachGestureRecognizerToView:clickableView]; - } else { - ANLogWarn(ANErrorString(@"native_invalid_clickable_views")); - } - }]; - } else { - [self attachGestureRecognizerToView:nativeView]; - } -} - -- (void)attachGestureRecognizerToView:(UIView *)view { - view.userInteractionEnabled = YES; - NSValue *key = [NSValue valueWithNonretainedObject:view]; - NSValue *value; - - if ([view isKindOfClass:[UIButton class]]) { - UIButton *button = (UIButton *)view; - [button addTarget:self - action:@selector(handleClick) - forControlEvents:UIControlEventTouchUpInside]; - value = [NSValue valueWithNonretainedObject:[NSNull null]]; - } else { - UITapGestureRecognizer *clickRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self - action:@selector(handleClick)]; - [view addGestureRecognizer:clickRecognizer]; - value = [NSValue valueWithNonretainedObject:clickRecognizer]; - } - self.viewToGestureRecognizerMapping[key] = value; -} - -- (void)detachAllGestureRecognizers { - [self.viewToGestureRecognizerMapping enumerateKeysAndObjectsUsingBlock:^(NSValue *viewValue, NSValue *gestureRecognizerValue, BOOL *stop) { - UIView *view = (UIView *)[viewValue nonretainedObjectValue]; - if (view) { - if ([view isKindOfClass:[UIButton class]]) { - [(UIButton *)view removeTarget:self - action:@selector(handleClick) - forControlEvents:UIControlEventTouchUpInside]; - } else { - UIGestureRecognizer *recognizer = (UIGestureRecognizer *)[gestureRecognizerValue nonretainedObjectValue]; - if (recognizer) { - [view removeGestureRecognizer:recognizer]; - } - } - } - }]; - [self.viewToGestureRecognizerMapping removeAllObjects]; -} - - (void)handleClick { if ([self.adapter respondsToSelector:@selector(handleClickFromRootViewController:)]) { [self.adapter handleClickFromRootViewController:self.rootViewController]; } } -- (NSMutableDictionary *)viewToGestureRecognizerMapping { - if (!_viewToGestureRecognizerMapping) _viewToGestureRecognizerMapping = [[NSMutableDictionary alloc] init]; - return _viewToGestureRecognizerMapping; -} - -#pragma mark - ANNativeCustomAdapterAdDelegate - -- (void)adWasClicked { - [self.delegate adWasClicked:self]; -} - -- (void)willPresentAd { - [self.delegate adWillPresent:self]; -} - -- (void)didPresentAd { - [self.delegate adDidPresent:self]; -} - -- (void)willCloseAd { - [self.delegate adWillClose:self]; -} - -- (void)didCloseAd { - [self.delegate adDidClose:self]; -} - -- (void)willLeaveApplication { - [self.delegate adWillLeaveApplication:self]; -} - @end \ No newline at end of file diff --git a/sdk/native/internal/ANNativeStandardAdResponse.h b/sdk/native/internal/ANNativeStandardAdResponse.h new file mode 100644 index 000000000..7fde4e1f8 --- /dev/null +++ b/sdk/native/internal/ANNativeStandardAdResponse.h @@ -0,0 +1,39 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANNativeAdResponse.h" + +@interface ANNativeStandardAdResponse : ANNativeAdResponse + +@property (nonatomic, readwrite, strong) NSString *title; +@property (nonatomic, readwrite, strong) NSString *body; +@property (nonatomic, readwrite, strong) NSString *callToAction; +@property (nonatomic, readwrite, strong) ANNativeAdStarRating *rating; +@property (nonatomic, readwrite, strong) UIImage *mainImage; +@property (nonatomic, readwrite, strong) NSURL *mainImageURL; +@property (nonatomic, readwrite, strong) UIImage *iconImage; +@property (nonatomic, readwrite, strong) NSURL *iconImageURL; +@property (nonatomic, readwrite, strong) NSString *socialContext; +@property (nonatomic, readwrite, strong) NSDictionary *customElements; + +@property (nonatomic, readwrite, strong) NSString *mediaType; +@property (nonatomic, readwrite, strong) NSString *fullText; + +@property (nonatomic, readwrite, strong) NSArray *clickTrackers; // Array of NSURL +@property (nonatomic, readwrite, strong) NSArray *impTrackers; // Array of NSURL +@property (nonatomic, readwrite, strong) NSURL *clickURL; +@property (nonatomic, readwrite, strong) NSURL *clickFallbackURL; + +@end \ No newline at end of file diff --git a/sdk/native/internal/ANNativeStandardAdResponse.m b/sdk/native/internal/ANNativeStandardAdResponse.m new file mode 100644 index 000000000..7502d3962 --- /dev/null +++ b/sdk/native/internal/ANNativeStandardAdResponse.m @@ -0,0 +1,197 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANNativeStandardAdResponse.h" +#import "ANGlobal.h" +#import "ANLogging.h" +#import "ANBrowserViewController.h" +#import "ANNativeAdResponse+PrivateMethods.h" +#import "NSTimer+ANCategory.h" +#import "UIView+ANCategory.h" +#import "ANNativeImpressionTrackerManager.h" + +@interface ANNativeStandardAdResponse() + +@property (nonatomic, readwrite, strong) NSDate *dateCreated; +@property (nonatomic, readwrite, assign) ANNativeAdNetworkCode networkCode; +@property (nonatomic, readwrite, assign, getter=hasExpired) BOOL expired; +@property (nonatomic, readwrite, strong) ANBrowserViewController *inAppBrowser; + +@property (nonatomic, readwrite, assign) NSUInteger viewabilityValue; +@property (nonatomic, readwrite, assign) NSUInteger targetViewabilityValue; +@property (nonatomic, readwrite, strong) NSTimer *viewabilityTimer; +@property (nonatomic, readwrite, assign) BOOL impressionHasBeenTracked; + +@end + +@implementation ANNativeStandardAdResponse + +@synthesize title = _title; +@synthesize body = _body; +@synthesize callToAction = _callToAction; +@synthesize rating = _rating; +@synthesize mainImage = _mainImage; +@synthesize mainImageURL = _mainImageURL; +@synthesize iconImage = _iconImage; +@synthesize iconImageURL = _iconImageURL; +@synthesize socialContext = _socialContext; +@synthesize customElements = _customElements; +@synthesize networkCode = _networkCode; +@synthesize expired = _expired; + +- (instancetype)init { + if (self = [super init]) { + _networkCode = ANNativeAdNetworkCodeAppNexus; + _dateCreated = [NSDate date]; + } + return self; +} + +#pragma mark - Registration + +- (BOOL)registerResponseInstanceWithNativeView:(UIView *)view + rootViewController:(UIViewController *)controller + clickableViews:(NSArray *)clickableViews + error:(NSError *__autoreleasing *)error { + [self setupViewabilityTracker]; + [self attachGestureRecognizersToNativeView:view + withClickableViews:clickableViews]; + return YES; +} + +#pragma mark - Unregistration + +- (void)unregisterViewFromTracking { + [super unregisterViewFromTracking]; + [self.viewabilityTimer invalidate]; +} + +#pragma mark - Impression Tracking + +- (void)setupViewabilityTracker { + __weak ANNativeStandardAdResponse *weakSelf = self; + NSInteger requiredAmountOfSimultaneousViewableEvents = lround(kAppNexusNativeAdIABShouldBeViewableForTrackingDuration + / kAppNexusNativeAdCheckViewabilityForTrackingFrequency) + 1; + self.targetViewabilityValue = lround(pow(2, requiredAmountOfSimultaneousViewableEvents) - 1); + self.viewabilityTimer = [NSTimer scheduledTimerWithTimeInterval:kAppNexusNativeAdCheckViewabilityForTrackingFrequency + block:^ { + ANNativeStandardAdResponse *strongSelf = weakSelf; + [strongSelf checkViewability]; + } + repeats:YES]; +} + +- (void)checkViewability { + self.viewabilityValue = (self.viewabilityValue << 1 | [self.viewForTracking an_isAtLeastHalfViewable]) & self.targetViewabilityValue; + BOOL isIABViewable = (self.viewabilityValue == self.targetViewabilityValue); + if (isIABViewable) { + [self trackImpression]; + } +} + +- (void)trackImpression { + if (!self.impressionHasBeenTracked) { + ANLogDebug(@"Firing impression trackers"); + [self fireImpTrackers]; + [self.viewabilityTimer invalidate]; + self.impressionHasBeenTracked = YES; + } +} + +- (void)fireImpTrackers { + if (self.impTrackers) { + [ANNativeImpressionTrackerManager fireImpressionTrackerURLArray:self.impTrackers]; + } +} + +#pragma mark - Click handling + +- (void)handleClick { + [self adWasClicked]; + [self fireClickTrackers]; + + BOOL successfullyOpenedBrowserWithClickURL = [self openIntendedBrowserWithURL:self.clickURL]; + if (!successfullyOpenedBrowserWithClickURL) { + ANLogDebug(@"Could not open click URL: %@", self.clickURL); + BOOL successfullyOpenedBrowserWithFallbackURL = [self openIntendedBrowserWithURL:self.clickFallbackURL]; + if (!successfullyOpenedBrowserWithFallbackURL) { + ANLogError(@"Could not open click fallback URL: %@", self.clickFallbackURL); + } + } +} + +- (BOOL)openIntendedBrowserWithURL:(NSURL *)URL { + if (!self.opensInNativeBrowser && (hasHttpPrefix(URL.absoluteString) || ANiTunesIDForURL(URL))) { + if (!self.inAppBrowser) { + self.inAppBrowser = [[ANBrowserViewController alloc] initWithURL:URL + delegate:self + delayPresentationForLoad:self.landingPageLoadsInBackground]; + } else { + self.inAppBrowser.url = self.clickURL; + } + return YES; + } else if ([[UIApplication sharedApplication] canOpenURL:URL]) { + [self willLeaveApplication]; + [[UIApplication sharedApplication] openURL:URL]; + return YES; + } else { + return NO; + } +} + +- (void)fireClickTrackers { + for (NSURL *URL in self.clickTrackers) { + ANLogDebug(@"Firing click tracker with URL %@", URL); + NSURLRequest *request = ANBasicRequestWithURL(URL); + [NSURLConnection sendAsynchronousRequest:request + queue:[NSOperationQueue mainQueue] + completionHandler:nil]; + } +} + +#pragma mark - Helper + +- (void)dealloc { + [self.viewabilityTimer invalidate]; +} + +#pragma mark - ANBrowserViewControllerDelegate + +- (UIViewController *)rootViewControllerForDisplayingBrowserViewController:(ANBrowserViewController *)controller { + return self.rootViewController; +} + +- (void)willPresentBrowserViewController:(ANBrowserViewController *)controller { + [self willPresentAd]; +} + +- (void)didPresentBrowserViewController:(ANBrowserViewController *)controller { + [self didPresentAd]; +} + +- (void)willDismissBrowserViewController:(ANBrowserViewController *)controller { + [self willCloseAd]; +} + +- (void)didDismissBrowserViewController:(ANBrowserViewController *)controller { + self.inAppBrowser = nil; + [self didCloseAd]; +} + +- (void)willLeaveApplicationFromBrowserViewController:(ANBrowserViewController *)controller { + [self willLeaveApplication]; +} + +@end \ No newline at end of file diff --git a/sdk/native/internal/ANNativeMediatedAd.h b/sdk/native/internal/ANStandardAd.h similarity index 64% rename from sdk/native/internal/ANNativeMediatedAd.h rename to sdk/native/internal/ANStandardAd.h index 31b1fedf6..79283ec46 100644 --- a/sdk/native/internal/ANNativeMediatedAd.h +++ b/sdk/native/internal/ANStandardAd.h @@ -15,11 +15,13 @@ #import -@interface ANNativeMediatedAd : NSObject +@interface ANStandardAd : NSObject -@property (nonatomic, readwrite, strong) NSString *className; -@property (nonatomic, readwrite, strong) NSString *param; -@property (nonatomic, readwrite, strong) NSString *adId; -@property (nonatomic, readwrite, strong) NSString *resultCB; +@property (nonatomic, readwrite, strong) NSString *content; +@property (nonatomic, readwrite, strong) NSString *height; +@property (nonatomic, readwrite, strong) NSString *width; +@property (nonatomic, readwrite, strong) NSString *type; + +@property (nonatomic, readwrite, assign, getter=isMraid) BOOL mraid; @end \ No newline at end of file diff --git a/sdk/native/internal/ANNativeMediatedAd.m b/sdk/native/internal/ANStandardAd.m similarity index 89% rename from sdk/native/internal/ANNativeMediatedAd.m rename to sdk/native/internal/ANStandardAd.m index c8e000abb..f8b999d45 100644 --- a/sdk/native/internal/ANNativeMediatedAd.m +++ b/sdk/native/internal/ANStandardAd.m @@ -13,8 +13,8 @@ limitations under the License. */ -#import "ANNativeMediatedAd.h" +#import "ANStandardAd.h" -@implementation ANNativeMediatedAd +@implementation ANStandardAd @end \ No newline at end of file diff --git a/tests/KIF/Additions/UIAccessibilityElement-KIFAdditions.m b/tests/KIF/Additions/UIAccessibilityElement-KIFAdditions.m index 79289cbe7..d0c877414 100755 --- a/tests/KIF/Additions/UIAccessibilityElement-KIFAdditions.m +++ b/tests/KIF/Additions/UIAccessibilityElement-KIFAdditions.m @@ -129,11 +129,17 @@ + (UIView *)viewContainingAccessibilityElement:(UIAccessibilityElement *)element if ([superview isKindOfClass:[UIScrollView class]]) { UIScrollView *scrollView = (UIScrollView *)superview; - if ((UIAccessibilityElement *)view == element) { + if (((UIAccessibilityElement *)view == element) && ![view isKindOfClass:[UITableViewCell class]]) { [scrollView scrollViewToVisible:view animated:YES]; } else { CGRect elementFrame = [view.window convertRect:element.accessibilityFrame toView:scrollView]; - [scrollView scrollRectToVisible:elementFrame animated:YES]; + CGRect visibleRect = CGRectMake(scrollView.contentOffset.x, scrollView.contentOffset.y, CGRectGetWidth(scrollView.bounds), CGRectGetHeight(scrollView.bounds)); + + // Only call scrollRectToVisible if the element isn't already visible + // iOS 8 will sometimes incorrectly scroll table views so the element scrolls out of view + if (!CGRectContainsRect(visibleRect, elementFrame)) { + [scrollView scrollRectToVisible:elementFrame animated:YES]; + } } // Give the scroll view a small amount of time to perform the scroll. diff --git a/tests/KIF/Additions/UIApplication-KIFAdditions.h b/tests/KIF/Additions/UIApplication-KIFAdditions.h index d92315d90..0ec04a3f7 100755 --- a/tests/KIF/Additions/UIApplication-KIFAdditions.h +++ b/tests/KIF/Additions/UIApplication-KIFAdditions.h @@ -35,7 +35,7 @@ UIKIT_EXTERN NSString *const UIApplicationOpenedURLKey; /*! @abstract Finds an accessibility element where @c matchBlock returns @c YES, across all windows in the application starting at the fronmost window. @discussion This method should be used if @c accessibilityElementWithLabel:accessibilityValue:traits: does not meet your requirements. For example, if you are searching for an element that begins with a pattern or if of a certain view type. - @param matchBlock. A block to be performed on each element to see if it passes. + @param matchBlock A block to be performed on each element to see if it passes. */ - (UIAccessibilityElement *)accessibilityElementMatchingBlock:(BOOL(^)(UIAccessibilityElement *))matchBlock; diff --git a/tests/KIF/Additions/UIApplication-KIFAdditions.m b/tests/KIF/Additions/UIApplication-KIFAdditions.m index 3156fe2f4..8028a1040 100755 --- a/tests/KIF/Additions/UIApplication-KIFAdditions.m +++ b/tests/KIF/Additions/UIApplication-KIFAdditions.m @@ -111,7 +111,7 @@ - (NSArray *)windowsWithKeyWindow return windows; } -#pragma mark - Screenshoting +#pragma mark - Screenshotting - (BOOL)writeScreenshotForLine:(NSUInteger)lineNumber inFile:(NSString *)filename description:(NSString *)description error:(NSError **)error; { @@ -131,22 +131,33 @@ - (BOOL)writeScreenshotForLine:(NSUInteger)lineNumber inFile:(NSString *)filenam return NO; } - UIGraphicsBeginImageContext([[windows objectAtIndex:0] bounds].size); + UIGraphicsBeginImageContextWithOptions([[windows objectAtIndex:0] bounds].size, YES, 0); for (UIWindow *window in windows) { - [window.layer renderInContext:UIGraphicsGetCurrentContext()]; + if ([window respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) { + [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES]; + } else { + [window.layer renderInContext:UIGraphicsGetCurrentContext()]; + } } UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); - - + + outputPath = [outputPath stringByExpandingTildeInPath]; + + NSError *directoryCreationError = nil; + if (![[NSFileManager defaultManager] createDirectoryAtPath:outputPath withIntermediateDirectories:YES attributes:nil error:&directoryCreationError]) { + *error = [NSError KIFErrorWithFormat:@"Couldn't create directory at path %@ (details: %@)", outputPath, directoryCreationError]; + return NO; + } + NSString *imageName = [NSString stringWithFormat:@"%@, line %lu", [filename lastPathComponent], (unsigned long)lineNumber]; if (description) { imageName = [imageName stringByAppendingFormat:@", %@", description]; } - - outputPath = [outputPath stringByExpandingTildeInPath]; + outputPath = [outputPath stringByAppendingPathComponent:imageName]; outputPath = [outputPath stringByAppendingPathExtension:@"png"]; + if (![UIImagePNGRepresentation(image) writeToFile:outputPath atomically:YES]) { if (error) { *error = [NSError KIFErrorWithFormat:@"Could not write file at path %@", outputPath]; diff --git a/tests/KIF/Additions/UIView-KIFAdditions.h b/tests/KIF/Additions/UIView-KIFAdditions.h index 441972c3a..a7dad07b5 100755 --- a/tests/KIF/Additions/UIView-KIFAdditions.h +++ b/tests/KIF/Additions/UIView-KIFAdditions.h @@ -86,6 +86,25 @@ typedef CGPoint KIFDisplacement; */ - (BOOL)isUserInteractionActuallyEnabled; +/*! + @abstract Evaluates if the view and all its superviews are visible. + */ +- (BOOL)isVisibleInViewHierarchy; + +/*! + @method performBlockOnDescendentViews: + @abstract Calls a block on the view itself and on all its descendent views. + @param block The block that will be called on the views. Stop the traversation of the views by assigning YES to the stop-parameter of the block. + */ +- (void)performBlockOnDescendentViews:(void (^)(UIView *view, BOOL *stop))block; + +/*! + @method performBlockOnAscendentViews: + @abstract Calls a block on the view itself and on all its superviews. + @param block The block that will be called on the views. Stop the traversation of the views by assigning YES to the stop-parameter of the block. + */ +- (void)performBlockOnAscendentViews:(void (^)(UIView *view, BOOL *stop))block; + /*! @abstract Returns either the current window or another window if a transform is applied. Returns `nil` if all windows in the application have transforms. */ diff --git a/tests/KIF/Additions/UIView-KIFAdditions.m b/tests/KIF/Additions/UIView-KIFAdditions.m index 6b3cfde1e..b7d0276a8 100755 --- a/tests/KIF/Additions/UIView-KIFAdditions.m +++ b/tests/KIF/Additions/UIView-KIFAdditions.m @@ -66,6 +66,39 @@ - (void)tapInteractionWithLocation:(CGPoint)point; @end +// On iOS 6 the accessibility label may contain line breaks, so when trying to find the +// element, these line breaks are necessary. But on iOS 7 the system replaces them with +// spaces. So the same test breaks on either iOS 6 or iOS 7. iOS8 befuddles this again by +//limiting replacement to spaces in between strings. To work around this replace +// the line breaks in both and try again. +NS_INLINE BOOL StringsMatchExceptLineBreaks(NSString *expected, NSString *actual) { + if (expected == actual) { + return YES; + } + + if (expected.length != actual.length) { + return NO; + } + + if ([expected isEqualToString:actual]) { + return YES; + } + + if ([expected rangeOfString:@"\n"].location == NSNotFound) { + return NO; + } + + for (NSUInteger i = 0; i < expected.length; i ++) { + unichar expectedChar = [expected characterAtIndex:i]; + unichar actualChar = [actual characterAtIndex:i]; + if (expectedChar != actualChar && !(expectedChar == '\n' && actualChar == ' ')) { + return NO; + } + } + + return YES; +} + @implementation UIView (KIFAdditions) @@ -109,17 +142,7 @@ - (UIAccessibilityElement *)accessibilityElementWithLabel:(NSString *)label acce accessibilityValue = [(NSAttributedString *)accessibilityValue string]; } - BOOL labelsMatch = element.accessibilityLabel == label || [element.accessibilityLabel isEqual:label]; - - // On iOS 6 the accessibility label may contain line breaks, so when trying to find the - // element, these line breaks are necessary. But on iOS 7 the system replaces them with - // spaces. So the same test breaks on either iOS 6 or iOS 7. To work around this replace - // the line breaks the same way and try again. - if (!labelsMatch) { - NSString *modifiedLabel = [label stringByReplacingOccurrencesOfString:@"\n" withString:@" "]; - labelsMatch = element.accessibilityLabel == modifiedLabel || [element.accessibilityLabel isEqual:modifiedLabel]; - } - + BOOL labelsMatch = StringsMatchExceptLineBreaks(label, element.accessibilityLabel); BOOL traitsMatch = ((element.accessibilityTraits) & traits) == traits; BOOL valuesMatch = !value || [value isEqual:accessibilityValue]; @@ -219,17 +242,19 @@ - (UIAccessibilityElement *)accessibilityElementMatchingBlock:(BOOL(^)(UIAccessi continue; } - // Get the cell directly from the dataSource because UICollectionView will only vend visible cells - UICollectionViewCell *cell = [collectionView.dataSource collectionView:collectionView cellForItemAtIndexPath:indexPath]; - - UIAccessibilityElement *element = [cell accessibilityElementMatchingBlock:matchBlock]; - - // Remove the cell from the collection view so that it doesn't stick around - [cell removeFromSuperview]; - - // Skip this cell if it isn't the one we're looking for - if (!element) { - continue; + @autoreleasepool { + // Get the cell directly from the dataSource because UICollectionView will only vend visible cells + UICollectionViewCell *cell = [collectionView.dataSource collectionView:collectionView cellForItemAtIndexPath:indexPath]; + + UIAccessibilityElement *element = [cell accessibilityElementMatchingBlock:matchBlock]; + + // Remove the cell from the collection view so that it doesn't stick around + [cell removeFromSuperview]; + + // Skip this cell if it isn't the one we're looking for + if (!element) { + continue; + } } // Scroll to the cell and wait for the animation to complete @@ -705,7 +730,8 @@ - (UIEvent *)eventWithTouches:(NSArray *)touches - (UIEvent *)eventWithTouch:(UITouch *)touch; { - return [self eventWithTouches:@[touch]]; + NSArray *touches = touch ? @[touch] : nil; + return [self eventWithTouches:touches]; } - (BOOL)isUserInteractionActuallyEnabled; @@ -759,4 +785,49 @@ - (UIWindow *)windowOrIdentityWindow return nil; } +- (BOOL)isVisibleInViewHierarchy +{ + __block BOOL result = YES; + [self performBlockOnAscendentViews:^(UIView *view, BOOL *stop) { + if (view.isHidden) { + result = NO; + if (stop != NULL) { + *stop = YES; + } + } + }]; + return result; +} + +- (void)performBlockOnDescendentViews:(void (^)(UIView *view, BOOL *stop))block +{ + BOOL stop = NO; + [self performBlockOnDescendentViews:block stop:&stop]; +} + +- (void)performBlockOnDescendentViews:(void (^)(UIView *view, BOOL *stop))block stop:(BOOL *)stop +{ + block(self, stop); + if (*stop) { + return; + } + + for (UIView *view in self.subviews) { + [view performBlockOnDescendentViews:block stop:stop]; + if (*stop) { + return; + } + } +} + +- (void)performBlockOnAscendentViews:(void (^)(UIView *view, BOOL *stop))block +{ + BOOL stop = NO; + UIView *checkedView = self; + while(checkedView && stop == NO) { + block(checkedView, &stop); + checkedView = checkedView.superview; + } +} + @end diff --git a/tests/KIF/Additions/XCTestCase-KIFAdditions.m b/tests/KIF/Additions/XCTestCase-KIFAdditions.m index 926b9f0fc..247dcbe61 100755 --- a/tests/KIF/Additions/XCTestCase-KIFAdditions.m +++ b/tests/KIF/Additions/XCTestCase-KIFAdditions.m @@ -8,9 +8,24 @@ #import "XCTestCase-KIFAdditions.h" #import "LoadableCategory.h" +#import MAKE_CATEGORIES_LOADABLE(TestCase_KIFAdditions) +static inline void Swizzle(Class c, SEL orig, SEL new) +{ + Method origMethod = class_getInstanceMethod(c, orig); + Method newMethod = class_getInstanceMethod(c, new); + if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) + class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); + else + method_exchangeImplementations(origMethod, newMethod); +} + +@interface XCTestCase () +- (void)_recordUnexpectedFailureWithDescription:(id)arg1 exception:(id)arg2; +@end + @implementation XCTestCase (KIFAdditions) - (void)failWithException:(NSException *)exception stopTest:(BOOL)stop @@ -20,6 +35,10 @@ - (void)failWithException:(NSException *)exception stopTest:(BOOL)stop [self recordFailureWithDescription:exception.description inFile:exception.userInfo[@"SenTestFilenameKey"] atLine:[exception.userInfo[@"SenTestLineNumberKey"] unsignedIntegerValue] expected:NO]; if (stop) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Swizzle([XCTestCase class], @selector(_recordUnexpectedFailureWithDescription:exception:), @selector(KIF_recordUnexpectedFailureWithDescription:exception:)); + }); [exception raise]; } } @@ -32,4 +51,37 @@ - (void)failWithExceptions:(NSArray *)exceptions stopTest:(BOOL)stop } } +- (void)KIF_recordUnexpectedFailureWithDescription:(id)arg1 exception:(NSException *)arg2 +{ + if (![[arg2 name] isEqualToString:@"KIFFailureException"]) { + [self KIF_recordUnexpectedFailureWithDescription:arg1 exception:arg2]; + } +} + +@end + +#ifdef __IPHONE_8_0 + +@interface XCTestSuite () +- (void)_recordUnexpectedFailureForTestRun:(id)arg1 description:(id)arg2 exception:(id)arg3; @end + +@implementation XCTestSuite (KIFAdditions) + ++ (void)load +{ + Swizzle([XCTestSuite class], @selector(_recordUnexpectedFailureForTestRun:description:exception:), @selector(KIF_recordUnexpectedFailureForTestRun:description:exception:)); +} + +- (void)KIF_recordUnexpectedFailureForTestRun:(XCTestSuiteRun *)arg1 description:(id)arg2 exception:(NSException *)arg3 +{ + if (![[arg3 name] isEqualToString:@"KIFFailureException"]) { + [self KIF_recordUnexpectedFailureForTestRun:arg1 description:arg2 exception:arg3]; + } else { + [arg1 recordFailureWithDescription:[NSString stringWithFormat:@"Test suite stopped on fatal error: %@", arg3.description] inFile:arg3.userInfo[@"SenTestFilenameKey"] atLine:[arg3.userInfo[@"SenTestLineNumberKey"] unsignedIntegerValue] expected:NO]; + } +} + +@end + +#endif diff --git a/tests/KIF/Classes/KIFTestActor.h b/tests/KIF/Classes/KIFTestActor.h index 8b4f2f885..854c310f2 100755 --- a/tests/KIF/Classes/KIFTestActor.h +++ b/tests/KIF/Classes/KIFTestActor.h @@ -89,6 +89,7 @@ typedef void (^KIFTestCompletionBlock)(KIFTestStepResult result, NSError *error) @property (nonatomic, readonly) NSInteger line; @property (weak, nonatomic, readonly) id delegate; @property (nonatomic) NSTimeInterval executionBlockTimeout; +@property (nonatomic) NSTimeInterval animationWaitingTimeout; - (instancetype)usingTimeout:(NSTimeInterval)executionBlockTimeout; @@ -144,6 +145,8 @@ typedef void (^KIFTestCompletionBlock)(KIFTestStepResult result, NSError *error) */ - (void)waitForTimeInterval:(NSTimeInterval)timeInterval; + + @end @protocol KIFTestActorDelegate diff --git a/tests/KIF/Classes/KIFTestActor.m b/tests/KIF/Classes/KIFTestActor.m index 133459696..6e539c404 100755 --- a/tests/KIF/Classes/KIFTestActor.m +++ b/tests/KIF/Classes/KIFTestActor.m @@ -19,6 +19,7 @@ #import #import #import "UIApplication-KIFAdditions.h" +#import "UIView-KIFAdditions.h" @implementation KIFTestActor @@ -63,6 +64,7 @@ - (instancetype)initWithFile:(NSString *)file line:(NSInteger)line delegate:(id< _line = line; _delegate = delegate; _executionBlockTimeout = [[self class] defaultTimeout]; + _animationWaitingTimeout = 0.5f; } return self; } diff --git a/tests/KIF/Classes/KIFTestCase.m b/tests/KIF/Classes/KIFTestCase.m index 367d533c8..8a940eea2 100755 --- a/tests/KIF/Classes/KIFTestCase.m +++ b/tests/KIF/Classes/KIFTestCase.m @@ -16,6 +16,9 @@ @implementation KIFTestCase +{ + NSException *_stoppingException; +} NSComparisonResult selectorSort(NSInvocation *invocOne, NSInvocation *invocTwo, void *reverse); @@ -65,45 +68,28 @@ + (NSArray *)testInvocations return newArray; } -- (void)setUp; -{ - [self beforeEach]; -} - -- (void)tearDown; -{ - [self afterEach]; -} - + (void)setUp { - [[self new] beforeAll]; + [self performSetupTearDownWithSelector:@selector(beforeAll)]; } + (void)tearDown { - [[self new] afterAll]; + [self performSetupTearDownWithSelector:@selector(afterAll)]; } -#else - -- (void)setUp; ++ (void)performSetupTearDownWithSelector:(SEL)selector { - [super setUp]; - - if ([self isNotBeforeOrAfter]) { - [self beforeEach]; + KIFTestCase *testCase = [self testCaseWithSelector:selector]; + XCTestCaseRun *run = [XCTestCaseRun testRunWithTest:testCase]; + [testCase performTest:run]; + + if (testCase->_stoppingException) { + [testCase->_stoppingException raise]; } } -- (void)tearDown; -{ - if ([self isNotBeforeOrAfter]) { - [self afterEach]; - } - - [super tearDown]; -} +#else + (NSArray *)testInvocations; { @@ -128,18 +114,37 @@ + (NSArray *)testInvocations; return testInvocations; } +#endif + +- (void)setUp; +{ + [super setUp]; + + if ([self isNotBeforeOrAfter]) { + [self beforeEach]; + } +} + +- (void)tearDown; +{ + if ([self isNotBeforeOrAfter]) { + [self afterEach]; + } + + [super tearDown]; +} + - (BOOL)isNotBeforeOrAfter; { SEL selector = self.invocation.selector; return selector != @selector(beforeAll) && selector != @selector(afterAll); } -#endif - - (void)failWithException:(NSException *)exception stopTest:(BOOL)stop { if (stop) { [self writeScreenshotForException:exception]; + _stoppingException = exception; } if (stop && self.stopTestsOnFirstBigFailure) { diff --git a/tests/KIF/Classes/KIFTypist.h b/tests/KIF/Classes/KIFTypist.h index e14b0cee7..b3a0866eb 100755 --- a/tests/KIF/Classes/KIFTypist.h +++ b/tests/KIF/Classes/KIFTypist.h @@ -14,5 +14,7 @@ + (BOOL)keyboardHidden; + (BOOL)enterCharacter:(NSString *)characterString; + (void)setKeystrokeDelay:(NSTimeInterval)delay; ++ (BOOL)hasHardwareKeyboard; ++ (BOOL)hasKeyInputResponder; @end diff --git a/tests/KIF/Classes/KIFTypist.m b/tests/KIF/Classes/KIFTypist.m index 03d44ab69..eb3765385 100755 --- a/tests/KIF/Classes/KIFTypist.m +++ b/tests/KIF/Classes/KIFTypist.m @@ -13,13 +13,18 @@ #import "CGGeometry-KIFAdditions.h" #import "UIAccessibilityElement-KIFAdditions.h" -static NSTimeInterval keystrokeDelay = 0.1f; +@interface UIKeyboardImpl : NSObject ++ (UIKeyboardImpl *)sharedInstance; +- (void)addInputString:(NSString *)string; +- (void)deleteFromInput; +@property(getter=isInHardwareKeyboardMode) BOOL inHardwareKeyboardMode; +@property(retain) UIResponder * delegate; +@end + +static NSTimeInterval keystrokeDelay = 0.01f; @interface KIFTypist() @property (nonatomic, assign) BOOL keyboardHidden; -+ (NSString *)_representedKeyboardStringForCharacter:(NSString *)characterString; -+ (BOOL)_enterCharacter:(NSString *)characterString history:(NSMutableDictionary *)history; -+ (BOOL)_enterCustomKeyboardCharacter:(NSString *)characterString; @end @implementation KIFTypist @@ -67,150 +72,32 @@ + (BOOL)keyboardHidden return [self sharedTypist].keyboardHidden; } -+ (NSString *)_representedKeyboardStringForCharacter:(NSString *)characterString; ++ (BOOL)enterCharacter:(NSString *)characterString; { - // Interpret control characters appropriately - if ([characterString isEqual:@"\b"]) { - characterString = @"Delete"; + if ([characterString isEqualToString:@"\b"]) { + [[UIKeyboardImpl sharedInstance] deleteFromInput]; + } else { + [[UIKeyboardImpl sharedInstance] addInputString:characterString]; } - return characterString; + CFRunLoopRunInMode(kCFRunLoopDefaultMode, keystrokeDelay, false); + return YES; } -+ (BOOL)enterCharacter:(NSString *)characterString; ++ (void)setKeystrokeDelay:(NSTimeInterval)delay { - return [self _enterCharacter:characterString history:[NSMutableDictionary dictionary]]; + keystrokeDelay = delay; } -+ (BOOL)_enterCharacter:(NSString *)characterString history:(NSMutableDictionary *)history; ++ (BOOL)hasHardwareKeyboard { - // Each key on the keyboard does not have its own view, so we have to ask for the list of keys, - // find the appropriate one, and tap inside the frame of that key on the main keyboard view. - if (!characterString.length) { - return YES; - } - - UIWindow *keyboardWindow = [[UIApplication sharedApplication] keyboardWindow]; - UIView *keyboardView = [[keyboardWindow subviewsWithClassNamePrefix:@"UIKBKeyplaneView"] lastObject]; - - // If we didn't find the standard keyboard view, then we may have a custom keyboard - if (!keyboardView) { - return [self _enterCustomKeyboardCharacter:characterString]; - } - id /*UIKBKeyplane*/ keyplane = [keyboardView valueForKey:@"keyplane"]; - BOOL isShiftKeyplane = [[keyplane valueForKey:@"isShiftKeyplane"] boolValue]; - - NSValue *keyplaneValue = [NSValue valueWithNonretainedObject:keyplane]; - - NSMutableArray *unvisitedForKeyplane = [history objectForKey:keyplaneValue]; - if (!unvisitedForKeyplane) { - unvisitedForKeyplane = [NSMutableArray arrayWithObjects:@"More", @"International", nil]; - if (!isShiftKeyplane) { - [unvisitedForKeyplane insertObject:@"Shift" atIndex:0]; - } - [history setObject:unvisitedForKeyplane forKey:keyplaneValue]; - } - - NSArray *keys = [keyplane valueForKey:@"keys"]; - - // Interpret control characters appropriately - characterString = [self _representedKeyboardStringForCharacter:characterString]; - - id keyToTap = nil; - id modifierKey = nil; - NSString *selectedModifierRepresentedString = nil; - - while (YES) { - for (id/*UIKBKey*/ key in keys) { - NSString *representedString = [key valueForKey:@"representedString"]; - - // Find the key based on the key's represented string - if ([representedString isEqual:characterString]) { - keyToTap = key; - } - - if (!modifierKey && unvisitedForKeyplane.count && [[unvisitedForKeyplane objectAtIndex:0] isEqual:representedString]) { - modifierKey = key; - selectedModifierRepresentedString = representedString; - [unvisitedForKeyplane removeObjectAtIndex:0]; - } - } - - if (keyToTap) { - break; - } - - if (modifierKey) { - break; - } - - if (!unvisitedForKeyplane.count) { - return NO; - } - - // If we didn't find the key or the modifier, then this modifier must not exist on this keyboard. Remove it. - [unvisitedForKeyplane removeObjectAtIndex:0]; - } - - if (keyToTap) { - [keyboardView tapAtPoint:CGPointCenteredInRect([keyToTap frame])]; - CFRunLoopRunInMode(kCFRunLoopDefaultMode, keystrokeDelay, false); - - return YES; - } - - // We didn't find anything, so try the symbols pane - if (modifierKey) { - [keyboardView tapAtPoint:CGPointCenteredInRect([modifierKey frame])]; - CFRunLoopRunInMode(kCFRunLoopDefaultMode, keystrokeDelay, false); - - // If we're back at a place we've been before, and we still have things to explore in the previous - id /*UIKBKeyplane*/ newKeyplane = [keyboardView valueForKey:@"keyplane"]; - id /*UIKBKeyplane*/ previousKeyplane = [history valueForKey:@"previousKeyplane"]; - - if (newKeyplane == previousKeyplane) { - // Come back to the keyplane that we just tested so that we can try the other modifiers - NSValue *keyplaneValue = [NSValue valueWithNonretainedObject:newKeyplane]; - NSMutableArray *previousKeyplaneHistory = [history objectForKey:keyplaneValue]; - [previousKeyplaneHistory insertObject:[history valueForKey:@"lastModifierRepresentedString"] atIndex:0]; - } else { - [history setValue:keyplane forKey:@"previousKeyplane"]; - [history setValue:selectedModifierRepresentedString forKey:@"lastModifierRepresentedString"]; - } - - return [self _enterCharacter:characterString history:history]; - } - - return NO; + return [UIKeyboardImpl sharedInstance].inHardwareKeyboardMode; } -+ (BOOL)_enterCustomKeyboardCharacter:(NSString *)characterString; ++ (BOOL)hasKeyInputResponder { - if (!characterString.length) { - return YES; - } - - characterString = [self _representedKeyboardStringForCharacter:characterString]; - - // For custom keyboards, use the classic methods of looking up views based on accessibility labels - UIWindow *keyboardWindow = [[UIApplication sharedApplication] keyboardWindow]; - - UIAccessibilityElement *element = [keyboardWindow accessibilityElementWithLabel:characterString]; - if (!element) { - return NO; - } - - UIView *view = [UIAccessibilityElement viewContainingAccessibilityElement:element]; - CGRect keyFrame = [view.windowOrIdentityWindow convertRect:[element accessibilityFrame] toView:view]; - [view tapAtPoint:CGPointCenteredInRect(keyFrame)]; - CFRunLoopRunInMode(kCFRunLoopDefaultMode, keystrokeDelay, false); - - return YES; + return [UIKeyboardImpl sharedInstance].delegate != nil; } -+ (void)setKeystrokeDelay:(NSTimeInterval)delay -{ - keystrokeDelay = delay; -} @end diff --git a/tests/KIF/Classes/KIFUITestActor-ConditionalTests.h b/tests/KIF/Classes/KIFUITestActor-ConditionalTests.h index 880b1e43a..10cdc3349 100755 --- a/tests/KIF/Classes/KIFUITestActor-ConditionalTests.h +++ b/tests/KIF/Classes/KIFUITestActor-ConditionalTests.h @@ -6,13 +6,13 @@ // // -#import +#import "KIF.h" @interface KIFUITestActor (ConditionalTests) /*! @abstract Checks if an accessibility element is visible on screen. - @discussion The view or accessibility elemetn with the given label is searched in the view hierarchy. If the element isn't found, then NO is returned. Note that the view does not necessarily have to be visible on the screen, and may be behind another view or offscreen. Views with their hidden property set to YES are ignored. + @discussion The view or accessibility element with the given label is searched in the view hierarchy. If the element isn't found, then NO is returned. Note that the view does not necessarily have to be visible on the screen, and may be behind another view or offscreen. Views with their hidden property set to YES are ignored. @param label The accessibility label of the element to wait for. If the view you want to check for is tappable, use the -tryFindingTappableViewWithAccessibilityLabel: methods instead as they provide a more strict test. @@ -22,7 +22,7 @@ /*! @abstract Checks if an accessibility element is visible on screen. - @discussion The view or accessibility elemetn with the given label is searched in the view hierarchy. If the element isn't found, then NO is returned. Note that the view does not necessarily have to be visible on the screen, and may be behind another view or offscreen. Views with their hidden property set to YES are ignored. + @discussion The view or accessibility element with the given label is searched in the view hierarchy. If the element isn't found, then NO is returned. Note that the view does not necessarily have to be visible on the screen, and may be behind another view or offscreen. Views with their hidden property set to YES are ignored. @param label The accessibility label of the element to wait for. @param traits The accessibility traits of the element to wait for. Elements that do not include at least these traits are ignored. */ @@ -30,7 +30,7 @@ /*! @abstract Checks if an accessibility element is visible on screen. - @discussion The view or accessibility elemetn with the given label is searched in the view hierarchy. If the element isn't found, then NO is returned. Note that the view does not necessarily have to be visible on the screen, and may be behind another view or offscreen. Views with their hidden property set to YES are ignored. + @discussion The view or accessibility element with the given label is searched in the view hierarchy. If the element isn't found, then NO is returned. Note that the view does not necessarily have to be visible on the screen, and may be behind another view or offscreen. Views with their hidden property set to YES are ignored. @param label The accessibility label of the element to wait for. @param value The accessibility value of the element to tap. @param traits The accessibility traits of the element to wait for. Elements that do not include at least these traits are ignored. @@ -39,14 +39,14 @@ /*! @abstract Checks if an accessibility element is visible on screen. - @discussion The view or accessibility elemetn with the given label is searched in the view hierarchy. If the element isn't found, then NO is returned. Note that the view does not necessarily have to be visible on the screen, and may be behind another view or offscreen. Views with their hidden property set to YES are ignored. + @discussion The view or accessibility element with the given label is searched in the view hierarchy. If the element isn't found, then NO is returned. Note that the view does not necessarily have to be visible on the screen, and may be behind another view or offscreen. Views with their hidden property set to YES are ignored. @param label The accessibility label of the element to wait for. */ - (BOOL)tryFindingTappableViewWithAccessibilityLabel:(NSString *)label error:(out NSError **)error; /*! @abstract Checks if an accessibility element is visible on screen. - @discussion The view or accessibility elemetn with the given label is searched in the view hierarchy. If the element isn't found, then NO is returned. Note that the view does not necessarily have to be visible on the screen, and may be behind another view or offscreen. Views with their hidden property set to YES are ignored. + @discussion The view or accessibility element with the given label is searched in the view hierarchy. If the element isn't found, then NO is returned. Note that the view does not necessarily have to be visible on the screen, and may be behind another view or offscreen. Views with their hidden property set to YES are ignored. @param label The accessibility label of the element to wait for. @param traits The accessibility traits of the element to wait for. Elements that do not include at least these traits are ignored. */ @@ -54,7 +54,7 @@ /*! @abstract Checks if an accessibility element is visible on screen. - @discussion The view or accessibility elemetn with the given label is searched in the view hierarchy. If the element isn't found, then NO is returned. Note that the view does not necessarily have to be visible on the screen, and may be behind another view or offscreen. Views with their hidden property set to YES are ignored. + @discussion The view or accessibility element with the given label is searched in the view hierarchy. If the element isn't found, then NO is returned. Note that the view does not necessarily have to be visible on the screen, and may be behind another view or offscreen. Views with their hidden property set to YES are ignored. @param label The accessibility label of the element to wait for. @param value The accessibility value of the element to tap. @param traits The accessibility traits of the element to wait for. Elements that do not include at least these traits are ignored. diff --git a/tests/KIF/Classes/KIFUITestActor.h b/tests/KIF/Classes/KIFUITestActor.h index d4f6e7860..710b3214a 100755 --- a/tests/KIF/Classes/KIFUITestActor.h +++ b/tests/KIF/Classes/KIFUITestActor.h @@ -143,7 +143,7 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec - (UIView *)waitForTappableViewWithAccessibilityLabel:(NSString *)label value:(NSString *)value traits:(UIAccessibilityTraits)traits; -/* +/*! @abstract Waits for an accessibility element and its containing view based on a variety of criteria. @discussion This method provides a more verbose API for achieving what is available in the waitForView/waitForTappableView family of methods, exposing both the found element and its containing view. The results can be used in other methods such as @c tapAccessibilityElement:inView: @param element To be populated with the matching accessibility element when found. Can be NULL. @@ -155,7 +155,7 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec */ - (void)waitForAccessibilityElement:(UIAccessibilityElement **)element view:(out UIView **)view withLabel:(NSString *)label value:(NSString *)value traits:(UIAccessibilityTraits)traits tappable:(BOOL)mustBeTappable; -/* +/*! @abstract Waits for an accessibility element and its containing view based the accessibility identifier. @discussion This method provides a more verbose API for achieving what is available in the waitForView/waitForTappableView family of methods, exposing both the found element and its containing view. The results can be used in other methods such as @c tapAccessibilityElement:inView: @param element To be populated with the matching accessibility element when found. Can be NULL. @@ -165,7 +165,7 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec */ - (void)waitForAccessibilityElement:(UIAccessibilityElement **)element view:(out UIView **)view withIdentifier:(NSString *)identifier tappable:(BOOL)mustBeTappable; -/* +/*! @abstract Waits for an accessibility element and its containing view based on a predicate. @discussion This method provides a more verbose API for achieving what is available in the waitForView/waitForTappableView family of methods, exposing both the found element and its containing view. The results can be used in other methods such as @c tapAccessibilityElement:inView: @@ -177,6 +177,17 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec */ - (void)waitForAccessibilityElement:(UIAccessibilityElement **)element view:(out UIView **)view withElementMatchingPredicate:(NSPredicate *)predicate tappable:(BOOL)mustBeTappable; +/*! + @abstract Tries to guess if there are any unfinished animations and waits for a certain amount of time to let them finish. + */ +- (void)waitForAnimationsToFinish; + +/*! + @abstract Tries to guess if there are any unfinished animations and waits for a certain amount of time to let them finish. + @param timeout The maximum duration the method waits to let the animations finish. + */ +- (void)waitForAnimationsToFinishWithTimeout:(NSTimeInterval)timeout; + /*! @abstract Taps a particular view in the view hierarchy. @discussion The view or accessibility element with the given label is searched for in the view hierarchy. If the element isn't found or isn't currently tappable, then the step will attempt to wait until it is. Once the view is present and tappable, a tap event is simulated in the center of the view or element. @@ -238,6 +249,8 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec */ - (void)longPressViewWithAccessibilityLabel:(NSString *)label value:(NSString *)value duration:(NSTimeInterval)duration; +- (void)longPressAccessibilityElement:(UIAccessibilityElement *)element inView:(UIView *)view duration:(NSTimeInterval)duration; + /*! @abstract Performs a long press on a particular view in the view hierarchy. @discussion The view or accessibility element with the given label is searched for in the view hierarchy. If the element isn't found or isn't currently tappable, then the step will attempt to wait until it is. Once the view is present and tappable, touch events are simulated in the center of the view or element. @@ -250,9 +263,24 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec */ - (void)longPressViewWithAccessibilityLabel:(NSString *)label value:(NSString *)value traits:(UIAccessibilityTraits)traits duration:(NSTimeInterval)duration; -- (void)waitForKeyboard; -- (void)waitForAbsenceOfKeyboard; +/*! + @abstract Waits for the software keyboard to be visible. + @discussion If input is also possible from a hardare keyboard @c waitForKeyInputReady may be more appropriate. + */ +- (void)waitForSoftwareKeyboard; +- (void)waitForKeyboard KIF_DEPRECATED("Use waitForSoftwareKeyboard or waitForKeyInputReady."); + +/*! + @abstract If present, waits for the software keyboard to dismiss. + */ +- (void)waitForAbsenceOfSoftwareKeyboard; +- (void)waitForAbsenceOfKeyboard KIF_DEPRECATED("Use waitForAbscenseOfSoftwareKeyboard."); + +/*! + @abstract Waits for the keyboard to be ready for input. This tests whether or not a hardware or software keyboard is available and if the keyboard has a responder to send events to. + */ +- (void)waitForKeyInputReady; /*! @abstract Enters text into a the current first responder. @@ -260,6 +288,7 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec @param text The text to enter. */ - (void)enterTextIntoCurrentFirstResponder:(NSString *)text; +- (void)enterTextIntoCurrentFirstResponder:(NSString *)text fallbackView:(UIView *)fallbackView; /*! @abstract Enters text into a particular view in the view hierarchy. @@ -279,12 +308,17 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec */ - (void)enterText:(NSString *)text intoViewWithAccessibilityLabel:(NSString *)label traits:(UIAccessibilityTraits)traits expectedResult:(NSString *)expectedResult; +- (void)clearTextFromFirstResponder; - (void)clearTextFromViewWithAccessibilityLabel:(NSString *)label; - (void)clearTextFromViewWithAccessibilityLabel:(NSString *)label traits:(UIAccessibilityTraits)traits; +- (void)clearTextFromElement:(UIAccessibilityElement*)element inView:(UIView*)view; +- (void)clearTextFromAndThenEnterTextIntoCurrentFirstResponder:(NSString *)text; - (void)clearTextFromAndThenEnterText:(NSString *)text intoViewWithAccessibilityLabel:(NSString *)label; - (void)clearTextFromAndThenEnterText:(NSString *)text intoViewWithAccessibilityLabel:(NSString *)label traits:(UIAccessibilityTraits)traits expectedResult:(NSString *)expectedResult; +- (void)expectView:(UIView *)view toContainText:(NSString *)expectedResult; + /*! @abstract Selects an item from a currently visible picker view. @discussion With a picker view already visible, this step will find an item with the given title, select that item, and tap the Done button. @@ -292,6 +326,14 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec */ - (void)selectPickerViewRowWithTitle:(NSString *)title; +/*! + @abstract Selects an item from a currently visible picker view in specified component. + @discussion With a picker view already visible, this step will find an item with the given title in given component, select that item, and tap the Done button. + @param title The title of the row to select. + @param component The component tester inteds to select the title in. + */ +- (void)selectPickerViewRowWithTitle:(NSString *)title inComponent:(NSInteger)component; + /*! @abstract Selects a value from a currently visible date picker view. @discussion With a date picker view already visible, this step will select the different rotating weel values in order of how the array parameter is passed in. After it is done it will hide the date picker. It works with all 4 UIDatePickerMode* modes. The input parameter of type NSArray has to match in what order the date picker is displaying the values/columns. So if the locale is changing the input parameter has to be adjusted. Example: Mode: UIDatePickerModeDate, Locale: en_US, Input param: NSArray *date = @[@"June", @"17", @"1965"];. Example: Mode: UIDatePickerModeDate, Locale: de_DE, Input param: NSArray *date = @[@"17.", @"Juni", @"1965". @@ -314,6 +356,7 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec @param label The accessibility label of the element to drag. */ - (void)setValue:(float)value forSliderWithAccessibilityLabel:(NSString *)label; +- (void)setValue:(float)value forSlider:(UISlider *)slider; /*! @abstract Dismisses a popover on screen. @@ -324,8 +367,8 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec /*! @abstract Select a certain photo from the built in photo picker. @discussion This set of steps expects that the photo picker has been initiated and that the sheet is up. From there it will tap the "Choose Photo" button and select the desired photo. - @param albumName The name of the album to select the photo from. - @param row The row number in the album for the desired photo. + @param albumName The name of the album to select the photo from. (1-indexed) + @param row The row number in the album for the desired photo. (1-indexed) @param column The column number in the album for the desired photo. */ - (void)choosePhotoInAlbum:(NSString *)albumName atRow:(NSInteger)row column:(NSInteger)column; @@ -363,6 +406,14 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec */ - (void)tapItemAtIndexPath:(NSIndexPath *)indexPath inCollectionViewWithAccessibilityIdentifier:(NSString *)identifier; +#if TARGET_IPHONE_SIMULATOR +/*! + @abstract If present, dismisses a system alert with the last button, usually 'Allow'. + @discussion Use this to dissmiss a location services authorization dialog or a photos access dialog by tapping the 'Allow' button. No action is taken if no alert is present. + */ +- (void)acknowledgeSystemAlert; +#endif + /*! @abstract Swipes a particular view in the view hierarchy in the given direction. @discussion The view will get the view with the specified accessibility label and swipe the screen in the given direction from the view's center. diff --git a/tests/KIF/Classes/KIFUITestActor.m b/tests/KIF/Classes/KIFUITestActor.m index ee1319fed..6789afde6 100755 --- a/tests/KIF/Classes/KIFUITestActor.m +++ b/tests/KIF/Classes/KIFUITestActor.m @@ -16,6 +16,7 @@ #import "CGGeometry-KIFAdditions.h" #import "NSError-KIFAdditions.h" #import "KIFTypist.h" +#import "UIAutomationHelper.h" @implementation KIFUITestActor @@ -123,6 +124,48 @@ - (void)waitForAbsenceOfViewWithAccessibilityLabel:(NSString *)label value:(NSSt }]; } +- (void)waitForAnimationsToFinish { + [self waitForAnimationsToFinishWithTimeout:self.animationWaitingTimeout]; +} + +- (void)waitForAnimationsToFinishWithTimeout:(NSTimeInterval)timeout { + static const CGFloat kStabilizationWait = 0.5f; + + NSTimeInterval maximumWaitingTimeInterval = timeout; + if (maximumWaitingTimeInterval <= kStabilizationWait) { + if(maximumWaitingTimeInterval >= 0) { + [self waitForTimeInterval:maximumWaitingTimeInterval]; + } + + return; + } + + // Wait for the view to stabilize and give them a chance to start animations before we wait for them. + [self waitForTimeInterval:kStabilizationWait]; + maximumWaitingTimeInterval -= kStabilizationWait; + + NSTimeInterval startTime = [NSDate timeIntervalSinceReferenceDate]; + [self runBlock:^KIFTestStepResult(NSError **error) { + __block BOOL runningAnimationFound = false; + for (UIWindow *window in [UIApplication sharedApplication].windowsWithKeyWindow) { + [window performBlockOnDescendentViews:^(UIView *view, BOOL *stop) { + BOOL isViewVisible = [view isVisibleInViewHierarchy]; // do not wait for animatinos of views that aren't visible + BOOL hasAnimation = view.layer.animationKeys.count != 0 && ![view.layer.animationKeys isEqualToArray:@[@"_UIParallaxMotionEffect"]]; // explicitly exclude _UIParallaxMotionEffect as it is used in alertviews, and we don't want every alertview to be paused + BOOL hasUnfinishedSystemAnimation = [NSStringFromClass(view.class) isEqualToString:@"_UIParallaxDimmingView"]; // indicates that the view-hierarchy is in an in-between-state of an animation + if (isViewVisible && (hasAnimation || hasUnfinishedSystemAnimation)) { + runningAnimationFound = YES; + if (stop != NULL) { + *stop = YES; + } + return; + } + }]; + } + + return runningAnimationFound && ([NSDate timeIntervalSinceReferenceDate] - startTime) < maximumWaitingTimeInterval ? KIFTestStepResultWait : KIFTestStepResultSuccess; + } timeout:maximumWaitingTimeInterval + 1]; +} + - (void)tapViewWithAccessibilityLabel:(NSString *)label { [self tapViewWithAccessibilityLabel:label value:nil traits:UIAccessibilityTraitNone]; @@ -167,9 +210,8 @@ - (void)tapAccessibilityElement:(UIAccessibilityElement *)element inView:(UIView return KIFTestStepResultSuccess; }]; - - // Wait for the view to stabilize. - [self waitForTimeInterval:0.5]; + + [self waitForAnimationsToFinish]; } - (void)tapScreenAtPoint:(CGPoint)screenPoint @@ -241,6 +283,11 @@ - (void)longPressAccessibilityElement:(UIAccessibilityElement *)element inView:( } - (void)waitForKeyboard +{ + [self waitForSoftwareKeyboard]; +} + +- (void)waitForSoftwareKeyboard { [self runBlock:^KIFTestStepResult(NSError **error) { KIFTestWaitCondition(![KIFTypist keyboardHidden], error, @"Keyboard is not visible"); @@ -250,6 +297,11 @@ - (void)waitForKeyboard } - (void)waitForAbsenceOfKeyboard +{ + [self waitForAbsenceOfSoftwareKeyboard]; +} + +- (void)waitForAbsenceOfSoftwareKeyboard { [self runBlock:^KIFTestStepResult(NSError **error) { KIFTestWaitCondition([KIFTypist keyboardHidden], error, @"Keyboard is visible"); @@ -258,9 +310,19 @@ - (void)waitForAbsenceOfKeyboard }]; } +- (void)waitForKeyInputReady +{ + [self runBlock:^KIFTestStepResult(NSError **error) { + KIFTestWaitCondition(![KIFTypist keyboardHidden] || [KIFTypist hasHardwareKeyboard], error, @"No software or hardware keyboard."); + KIFTestWaitCondition([KIFTypist hasKeyInputResponder], error, @"No responder for key inputs."); + + return KIFTestStepResultSuccess; + }]; +} + - (void)enterTextIntoCurrentFirstResponder:(NSString *)text; { - [self waitForKeyboard]; + [self waitForKeyInputReady]; [self enterTextIntoCurrentFirstResponder:text fallbackView:nil]; } @@ -301,7 +363,7 @@ - (void)enterText:(NSString *)text intoViewWithAccessibilityLabel:(NSString *)la [self waitForAccessibilityElement:&element view:&view withLabel:label value:nil traits:traits tappable:YES]; [self tapAccessibilityElement:element inView:view]; - [self waitForKeyboard]; + [self waitForTimeInterval:0.25]; [self enterTextIntoCurrentFirstResponder:text fallbackView:view]; [self expectView:view toContainText:expectedResult ?: text]; } @@ -317,9 +379,12 @@ - (void)expectView:(UIView *)view toContainText:(NSString *)expectedResult // Some slower machines take longer for typing to catch up, so wait for a bit before failing [self runBlock:^KIFTestStepResult(NSError **error) { - // We trim \n and \r because they trigger the return key, so they won't show up in the final product on single-line inputs - NSString *expected = [expectedResult stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; - NSString *actual = [textView.text stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + // We trim \n and \r because they trigger the return key, so they won't show up in the final product on single-line inputs. + // Also trim \b (backspace) characters to allow for deletion. + NSMutableCharacterSet *charExclusionSet = [NSMutableCharacterSet characterSetWithCharactersInString:@"\b"]; + [charExclusionSet formUnionWithCharacterSet:[NSCharacterSet newlineCharacterSet]]; + NSString *expected = [expectedResult stringByTrimmingCharactersInSet:charExclusionSet]; + NSString *actual = [textView.text stringByTrimmingCharactersInSet:charExclusionSet]; KIFTestWaitCondition([actual isEqualToString:expected], error, @"Failed to get text \"%@\" in field; instead, it was \"%@\"", expected, actual); @@ -327,7 +392,13 @@ - (void)expectView:(UIView *)view toContainText:(NSString *)expectedResult } timeout:1.0]; } - +- (void)clearTextFromFirstResponder +{ + UIView *firstResponder = (id)[[[UIApplication sharedApplication] keyWindow] firstResponder]; + if ([firstResponder isKindOfClass:[UIView class]]) { + [self clearTextFromElement:(UIAccessibilityElement *)firstResponder inView:firstResponder]; + } +} - (void)clearTextFromViewWithAccessibilityLabel:(NSString *)label { @@ -340,11 +411,13 @@ - (void)clearTextFromViewWithAccessibilityLabel:(NSString *)label traits:(UIAcce UIAccessibilityElement *element = nil; [self waitForAccessibilityElement:&element view:&view withLabel:label value:nil traits:traits tappable:YES]; - - NSUInteger numberOfCharacters = [view respondsToSelector:@selector(text)] ? [(UITextField *)view text].length : element.accessibilityValue.length; - + [self clearTextFromElement:element inView:view]; +} + +- (void)clearTextFromElement:(UIAccessibilityElement*)element inView:(UIView*)view +{ [self tapAccessibilityElement:element inView:view]; - + // Per issue #294, the tap occurs in the center of the text view. If the text is too long, this means not all text gets cleared. To address this for most cases, we can check if the selected view conforms to UITextInput and select the whole text range. if ([view conformsToProtocol:@protocol(UITextInput)]) { id textInput = (id )view; @@ -353,7 +426,7 @@ - (void)clearTextFromViewWithAccessibilityLabel:(NSString *)label traits:(UIAcce [self waitForTimeInterval:0.1]; [self enterTextIntoCurrentFirstResponder:@"\b" fallbackView:view]; } else { - + NSUInteger numberOfCharacters = [view respondsToSelector:@selector(text)] ? [(UITextField *)view text].length : element.accessibilityValue.length; NSMutableString *text = [NSMutableString string]; for (NSInteger i = 0; i < numberOfCharacters; i ++) { [text appendString:@"\b"]; @@ -376,6 +449,12 @@ - (void)clearTextFromAndThenEnterText:(NSString *)text intoViewWithAccessibility [self enterText:text intoViewWithAccessibilityLabel:label traits:traits expectedResult:expectedResult]; } +- (void)clearTextFromAndThenEnterTextIntoCurrentFirstResponder:(NSString *)text +{ + [self clearTextFromFirstResponder]; + [self enterTextIntoCurrentFirstResponder:text]; +} + - (void) selectDatePickerValue:(NSArray*)datePickerColumnValues { [self selectPickerValue:datePickerColumnValues pickerType:KIFUIDatePicker]; } @@ -386,8 +465,51 @@ - (void)selectPickerViewRowWithTitle:(NSString *)title [self selectPickerValue:dataToSelect pickerType:KIFUIPickerView]; } -- (void) selectPickerValue:(NSArray*)pickerColumnValues pickerType:(KIFPickerType)pickerType { +- (void)selectPickerViewRowWithTitle:(NSString *)title inComponent:(NSInteger)component +{ + NSMutableArray *dataToSelect = [[NSMutableArray alloc] init]; + + // Assume it is datePicker and then test our hypothesis later! + UIPickerView *pickerView = [[[[UIApplication sharedApplication] datePickerWindow] subviewsWithClassNameOrSuperClassNamePrefix:@"UIPickerView"] lastObject]; + + // Check which type of UIPickerVIew is visible on current window. + KIFPickerType pickerType = 0; + if ([pickerView respondsToSelector:@selector(setDate:animated:)]) { + pickerType = KIFUIDatePicker; + } + else { + pickerType = KIFUIPickerView; + pickerView = [[[[UIApplication sharedApplication] pickerViewWindow] subviewsWithClassNameOrSuperClassNamePrefix:@"UIPickerView"] lastObject]; + } + + // Add title at component index and add empty strings for other. + // This support legacy function re-use. + for (int i = 0; i < pickerView.numberOfComponents; i++) { + if (component == i) { + [dataToSelect addObject:title]; + } + else { + NSInteger currentIndex = [pickerView selectedRowInComponent:i]; + NSString *rowTitle = nil; + if ([pickerView.delegate respondsToSelector:@selector(pickerView:titleForRow:forComponent:)]) { + rowTitle = [pickerView.delegate pickerView:pickerView titleForRow:currentIndex forComponent: i]; + } else if ([pickerView.delegate respondsToSelector:@selector(pickerView:viewForRow:forComponent:reusingView:)]) { + // This delegate inserts views directly, so try to figure out what the title is by looking for a label + UIView *rowView = [pickerView.delegate pickerView:pickerView viewForRow:currentIndex forComponent: i reusingView:nil]; + NSArray *labels = [rowView subviewsWithClassNameOrSuperClassNamePrefix:@"UILabel"]; + UILabel *label = (labels.count > 0 ? labels[0] : nil); + rowTitle = label.text; + } + NSAssert(rowTitle != nil, @"Unknown picker type. Delegate responds neither to pickerView:titleForRow:forComponent: nor to pickerView:viewForRow:forComponent:reusingView:"); + [dataToSelect addObject: rowTitle]; + } + } + + [self selectPickerValue:dataToSelect pickerType:pickerType]; +} +- (void) selectPickerValue:(NSArray*)pickerColumnValues pickerType:(KIFPickerType)pickerType { + [self runBlock:^KIFTestStepResult(NSError **error) { NSInteger columnCount = [pickerColumnValues count]; NSMutableArray* found_values = [NSMutableArray arrayWithCapacity:columnCount]; @@ -403,12 +525,12 @@ - (void) selectPickerValue:(NSArray*)pickerColumnValues pickerType:(KIFPickerTyp KIFTestCondition(pickerView, error, @"No picker view is present"); break; case KIFUIPickerView: - pickerView = [[[[UIApplication sharedApplication] pickerViewWindow] subviewsWithClassNameOrSuperClassNamePrefix:@"UIPickerView"] lastObject]; + pickerView = [[[[UIApplication sharedApplication] pickerViewWindow] subviewsWithClassNameOrSuperClassNamePrefix:@"UIPickerView"] lastObject]; } - + NSInteger componentCount = [pickerView.dataSource numberOfComponentsInPickerView:pickerView]; KIFTestCondition(componentCount == columnCount, error, @"The UIDatePicker does not have the expected column count."); - + for (NSInteger componentIndex = 0; componentIndex < componentCount; componentIndex++) { NSInteger rowCount = [pickerView.dataSource pickerView:pickerView numberOfRowsInComponent:componentIndex]; for (NSInteger rowIndex = 0; rowIndex < rowCount; rowIndex++) { @@ -416,27 +538,37 @@ - (void) selectPickerValue:(NSArray*)pickerColumnValues pickerType:(KIFPickerTyp if ([pickerView.delegate respondsToSelector:@selector(pickerView:titleForRow:forComponent:)]) { rowTitle = [pickerView.delegate pickerView:pickerView titleForRow:rowIndex forComponent:componentIndex]; } else if ([pickerView.delegate respondsToSelector:@selector(pickerView:viewForRow:forComponent:reusingView:)]) { - // This delegate inserts views directly, so try to figure out what the title is by looking for a label + UIView *rowView = [pickerView.delegate pickerView:pickerView viewForRow:rowIndex forComponent:componentIndex reusingView:nil]; - NSArray *labels = [rowView subviewsWithClassNameOrSuperClassNamePrefix:@"UILabel"]; - UILabel *label = (labels.count > 0 ? labels[0] : nil); + UILabel *label; + if ([rowView isKindOfClass:[UILabel class]] ) { + label = (id)rowView; + } else { + // This delegate inserts views directly, so try to figure out what the title is by looking for a label + NSArray *labels = [rowView subviewsWithClassNameOrSuperClassNamePrefix:@"UILabel"]; + label = (labels.count > 0 ? labels[0] : nil); + } rowTitle = label.text; } - - if ([rowTitle isEqual:pickerColumnValues[componentIndex]]) { + + if (rowIndex==[pickerView selectedRowInComponent:componentIndex] && [rowTitle isEqual:pickerColumnValues[componentIndex]]){ + [found_values replaceObjectAtIndex:componentIndex withObject:@(YES)]; + break; + } + else if ([rowTitle isEqual:pickerColumnValues[componentIndex]]) { [pickerView selectRow:rowIndex inComponent:componentIndex animated:false]; CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, false); - + // Tap in the middle of the picker view to select the item [pickerView tap]; [self waitForTimeInterval:0.5]; - + // The combination of selectRow:inComponent:animated: and tap does not consistently result in // pickerView:didSelectRow:inComponent: being called on the delegate. We need to do it explicitly. if ([pickerView.delegate respondsToSelector:@selector(pickerView:didSelectRow:inComponent:)]) { [pickerView.delegate pickerView:pickerView didSelectRow:rowIndex inComponent:componentIndex]; } - + [found_values replaceObjectAtIndex:componentIndex withObject:@(YES)]; break; } @@ -444,19 +576,25 @@ - (void) selectPickerValue:(NSArray*)pickerColumnValues pickerType:(KIFPickerTyp if (found_values[componentIndex] == [NSNumber numberWithBool:YES]) { continue; } - } - + + // Support multiple column by adding flag to check if the value found in + // at-least one column + BOOL _foundInOneColumn = NO; for (NSInteger componentIndex = 0; componentIndex < columnCount; componentIndex++) { - if (found_values[componentIndex] == [NSNumber numberWithBool:NO]) { - KIFTestCondition(NO, error, @"Failed to select from Picker."); - return KIFTestStepResultFailure; + if (found_values[componentIndex] != [NSNumber numberWithBool:NO]) { + _foundInOneColumn = YES; } } - + + if (!_foundInOneColumn) { + KIFTestCondition(NO, error, @"Failed to select from Picker."); + return KIFTestStepResultFailure; + } + return KIFTestStepResultSuccess; }]; - + } - (void)setOn:(BOOL)switchIsOn forSwitchWithAccessibilityLabel:(NSString *)label @@ -495,6 +633,8 @@ - (void)setOn:(BOOL)switchIsOn forSwitchWithAccessibilityLabel:(NSString *)label } } + + - (void)setValue:(float)value forSliderWithAccessibilityLabel:(NSString *)label { UISlider *slider = nil; @@ -504,20 +644,30 @@ - (void)setValue:(float)value forSliderWithAccessibilityLabel:(NSString *)label if (![slider isKindOfClass:[UISlider class]]) { [self failWithError:[NSError KIFErrorWithFormat:@"View with accessibility label \"%@\" is a %@, not a UISlider", label, NSStringFromClass([slider class])] stopTest:YES]; } - - if (value < slider.minimumValue) { - [self failWithError:[NSError KIFErrorWithFormat:@"Cannot slide past minimum value of %f", slider.minimumValue] stopTest:YES]; - } - - if (value > slider.maximumValue) { - [self failWithError:[NSError KIFErrorWithFormat:@"Cannot slide past maximum value of %f", slider.maximumValue] stopTest:YES]; + [self setValue:value forSlider:slider]; +} + +- (void)setValue:(float)value forSlider:(UISlider *)slider +{ + if (value < slider.minimumValue) { + [self failWithError:[NSError KIFErrorWithFormat:@"Cannot slide past minimum value of %f", slider.minimumValue] stopTest:YES]; + } + + if (value > slider.maximumValue) { + [self failWithError:[NSError KIFErrorWithFormat:@"Cannot slide past maximum value of %f", slider.maximumValue] stopTest:YES]; + } + + CGRect trackRect = [slider trackRectForBounds:slider.bounds]; + CGPoint currentPosition = CGPointCenteredInRect([slider thumbRectForBounds:slider.bounds trackRect:trackRect value:slider.value]); + CGPoint finalPosition = CGPointCenteredInRect([slider thumbRectForBounds:slider.bounds trackRect:trackRect value:value]); + + if (value == slider.minimumValue) { + finalPosition.x = 0; + } else if (value == slider.maximumValue) { + finalPosition.x = slider.bounds.size.width; } - - CGRect trackRect = [slider trackRectForBounds:slider.bounds]; - CGPoint currentPosition = CGPointCenteredInRect([slider thumbRectForBounds:slider.bounds trackRect:trackRect value:slider.value]); - CGPoint finalPosition = CGPointCenteredInRect([slider thumbRectForBounds:slider.bounds trackRect:trackRect value:value]); - - [slider dragFromPoint:currentPosition toPoint:finalPosition steps:10]; + + [slider dragFromPoint:currentPosition toPoint:finalPosition steps:10]; } - (void)dismissPopover @@ -534,12 +684,10 @@ - (void)dismissPopover - (void)choosePhotoInAlbum:(NSString *)albumName atRow:(NSInteger)row column:(NSInteger)column { - [self tapViewWithAccessibilityLabel:@"Choose Photo"]; - // This is basically the same as the step to tap with an accessibility label except that the accessibility labels for the albums have the number of photos appended to the end, such as "My Photos (3)." This means that we have to do a prefix match rather than an exact match. [self runBlock:^KIFTestStepResult(NSError **error) { - NSString *labelPrefix = [NSString stringWithFormat:@"%@, (", albumName]; + NSString *labelPrefix = [NSString stringWithFormat:@"%@", albumName]; UIAccessibilityElement *element = [[UIApplication sharedApplication] accessibilityElementMatchingBlock:^(UIAccessibilityElement *element) { return [element.accessibilityLabel hasPrefix:labelPrefix]; }]; @@ -565,7 +713,7 @@ - (void)choosePhotoInAlbum:(NSString *)albumName atRow:(NSInteger)row column:(NS }]; // Wait for media picker view controller to be pushed. - [self waitForTimeInterval:0.5]; + [self waitForTimeInterval:1]; // Tap the desired photo in the grid // TODO: This currently only works for the first page of photos. It should scroll appropriately at some point. @@ -576,9 +724,6 @@ - (void)choosePhotoInAlbum:(NSString *)albumName atRow:(NSInteger)row column:(NS thumbnailCenter.x = thumbnailMargin + (MAX(0, column - 1) * (thumbnailSize.width + thumbnailMargin)) + thumbnailSize.width / 2.0; thumbnailCenter.y = headerHeight + thumbnailMargin + (MAX(0, row - 1) * (thumbnailSize.height + thumbnailMargin)) + thumbnailSize.height / 2.0; [self tapScreenAtPoint:thumbnailCenter]; - - // Dismiss the resize UI - [self tapViewWithAccessibilityLabel:@"Choose"]; } - (void)tapRowAtIndexPath:(NSIndexPath *)indexPath inTableViewWithAccessibilityIdentifier:(NSString *)identifier @@ -600,8 +745,7 @@ - (void)tapRowAtIndexPath:(NSIndexPath *)indexPath inTableView:(UITableView *)ta CGRect cellFrame = [cell.contentView convertRect:cell.contentView.frame toView:tableView]; [tableView tapAtPoint:CGPointCenteredInRect(cellFrame)]; - // Wait for the view to stabilize. - [tester waitForTimeInterval:0.5]; + [self waitForAnimationsToFinish]; } - (void)tapItemAtIndexPath:(NSIndexPath *)indexPath inCollectionViewWithAccessibilityIdentifier:(NSString *)identifier @@ -611,6 +755,10 @@ - (void)tapItemAtIndexPath:(NSIndexPath *)indexPath inCollectionViewWithAccessib [self tapItemAtIndexPath:indexPath inCollectionView:collectionView]; } +- (void)acknowledgeSystemAlert { + [UIAutomationHelper acknowledgeSystemAlert]; +} + - (void)tapItemAtIndexPath:(NSIndexPath *)indexPath inCollectionView:(UICollectionView *)collectionView { UICollectionViewCell *cell; @@ -619,8 +767,7 @@ - (void)tapItemAtIndexPath:(NSIndexPath *)indexPath inCollectionView:(UICollecti CGRect cellFrame = [cell.contentView convertRect:cell.contentView.frame toView:collectionView]; [collectionView tapAtPoint:CGPointCenteredInRect(cellFrame)]; - // Wait for the view to stabilize. - [tester waitForTimeInterval:0.5]; + [self waitForAnimationsToFinish]; } - (void)swipeViewWithAccessibilityLabel:(NSString *)label inDirection:(KIFSwipeDirection)direction @@ -748,13 +895,23 @@ - (UITableViewCell *)waitForCellAtIndexPath:(NSIndexPath *)indexPath inTableView return KIFTestStepResultSuccess; }]; - [tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; - [self waitForTimeInterval:0.5]; - UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; - - if (!cell) { - [self failWithError:[NSError KIFErrorWithFormat: @"Table view cell at index path %@ not found", indexPath] stopTest:YES]; - } + __block UITableViewCell *cell = nil; + __block CGFloat lastYOffset = CGFLOAT_MAX; + [self runBlock:^KIFTestStepResult(NSError **error) { + [tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; + cell = [tableView cellForRowAtIndexPath:indexPath]; + KIFTestWaitCondition(!!cell, error, @"Table view cell at index path %@ not found", indexPath); + + if (lastYOffset != tableView.contentOffset.y) { + lastYOffset = tableView.contentOffset.y; + KIFTestWaitCondition(NO, error, @"Didn't finish scrolling to cell."); + } + + return KIFTestStepResultSuccess; + }]; + + [self waitForTimeInterval:0.1]; // Let things settle. + return cell; } diff --git a/tests/KIF/Classes/UIAutomationHelper.h b/tests/KIF/Classes/UIAutomationHelper.h new file mode 100755 index 000000000..78fe4de63 --- /dev/null +++ b/tests/KIF/Classes/UIAutomationHelper.h @@ -0,0 +1,17 @@ +// +// UIAutomationHelper.h +// KIF +// +// Created by Joe Masilotti on 12/1/14. +// +// + +#import + +@class KIFTestActor; + +@interface UIAutomationHelper : NSObject + ++ (void)acknowledgeSystemAlert; + +@end diff --git a/tests/KIF/Classes/UIAutomationHelper.m b/tests/KIF/Classes/UIAutomationHelper.m new file mode 100755 index 000000000..e40071263 --- /dev/null +++ b/tests/KIF/Classes/UIAutomationHelper.m @@ -0,0 +1,84 @@ +// +// UIAutomationHelper.m +// KIF +// +// Created by Joe Masilotti on 12/1/14. +// +// + +#import "UIAutomationHelper.h" +#include + +@interface UIAElement : NSObject +- (void)tap; +@end + +@interface UIAAlert : UIAElement +- (NSArray *)buttons; +@end + +@interface UIAApplication : UIAElement +- (UIAAlert *)alert; +@end + +@interface UIATarget : UIAElement ++ (UIATarget *)localTarget; +- (UIAApplication *)frontMostApp; +@end + +@interface UIAElementNil : UIAElement + +@end + +@implementation UIAutomationHelper + ++ (UIAutomationHelper *)sharedHelper +{ + static dispatch_once_t once; + static UIAutomationHelper *sharedHelper = nil; + dispatch_once(&once, ^{ + sharedHelper = [[self alloc] init]; + [sharedHelper linkAutomationFramework]; + }); + return sharedHelper; +} + ++ (void)acknowledgeSystemAlert { + [[self sharedHelper] acknowledgeSystemAlert]; +} + +- (void)acknowledgeSystemAlert { + UIAApplication *application = [[self target] frontMostApp]; + UIAAlert *alert = application.alert; + + if (![alert isKindOfClass:[self nilElementClass]]) { + [[alert.buttons lastObject] tap]; + while (![application.alert isKindOfClass:[self nilElementClass]]) { } + } +} + +#pragma mark - Private + +- (void)linkAutomationFramework { + dlopen([@"/Developer/Library/PrivateFrameworks/UIAutomation.framework/UIAutomation" fileSystemRepresentation], RTLD_LOCAL); + + // Keep trying until the accessibility server starts up (it takes a little while on iOS 7) + UIATarget *target = nil; + while (!target) { + @try { + target = [self target]; + } + @catch (NSException *exception) { } + @finally { } + } +} + +- (UIATarget *)target { + return [NSClassFromString(@"UIATarget") localTarget]; +} + +- (Class)nilElementClass { + return NSClassFromString(@"UIAElementNil"); +} + +@end diff --git a/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift.xcodeproj/project.pbxproj b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift.xcodeproj/project.pbxproj new file mode 100755 index 000000000..e08b71a66 --- /dev/null +++ b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift.xcodeproj/project.pbxproj @@ -0,0 +1,556 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + A88CD9831A019AFF0064F706 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88CD9821A019AFF0064F706 /* AppDelegate.swift */; }; + A88CD9851A019AFF0064F706 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88CD9841A019AFF0064F706 /* MasterViewController.swift */; }; + A88CD98A1A019AFF0064F706 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A88CD9881A019AFF0064F706 /* Main.storyboard */; }; + A88CD98C1A019AFF0064F706 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A88CD98B1A019AFF0064F706 /* Images.xcassets */; }; + A88CD98F1A019AFF0064F706 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = A88CD98D1A019AFF0064F706 /* LaunchScreen.xib */; }; + A88CD99B1A019AFF0064F706 /* Testable_SwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88CD99A1A019AFF0064F706 /* Testable_SwiftTests.swift */; }; + A88CD9B91A019E430064F706 /* libKIF.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A88CD9AE1A019D520064F706 /* libKIF.a */; }; + A88CD9BC1A019F0B0064F706 /* SimpleObjCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A88CD9BB1A019F0B0064F706 /* SimpleObjCTest.m */; }; + A88CD9BE1A019F300064F706 /* SimpleSwiftTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88CD9BD1A019F300064F706 /* SimpleSwiftTest.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + A88CD9951A019AFF0064F706 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A88CD9751A019AFF0064F706 /* Project object */; + proxyType = 1; + remoteGlobalIDString = A88CD97C1A019AFF0064F706; + remoteInfo = "Testable Swift"; + }; + A88CD9AD1A019D520064F706 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A88CD9A41A019D510064F706 /* KIF.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = EABD46AA1857A0C700A5F081; + remoteInfo = KIF; + }; + A88CD9AF1A019D520064F706 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A88CD9A41A019D510064F706 /* KIF.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = EB72047C1680DDAD00278DA2; + remoteInfo = "KIF-OCUnit"; + }; + A88CD9B11A019D520064F706 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A88CD9A41A019D510064F706 /* KIF.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = EB60ECC1177F8C83005A041A; + remoteInfo = "Test Host"; + }; + A88CD9B31A019D520064F706 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A88CD9A41A019D510064F706 /* KIF.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = EABD46CD1857A0F300A5F081; + remoteInfo = "KIF Tests"; + }; + A88CD9B51A019D520064F706 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A88CD9A41A019D510064F706 /* KIF.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = EB60ECEB177F8DB3005A041A; + remoteInfo = "KIF Tests-OCUnit"; + }; + A88CD9B71A019E2B0064F706 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A88CD9A41A019D510064F706 /* KIF.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = EABD46791857A0C700A5F081; + remoteInfo = KIF; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + A88CD97D1A019AFF0064F706 /* Testable Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Testable Swift.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + A88CD9811A019AFF0064F706 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + A88CD9821A019AFF0064F706 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + A88CD9841A019AFF0064F706 /* MasterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = ""; }; + A88CD9891A019AFF0064F706 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + A88CD98B1A019AFF0064F706 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + A88CD98E1A019AFF0064F706 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + A88CD9941A019AFF0064F706 /* Testable SwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Testable SwiftTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + A88CD9991A019AFF0064F706 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + A88CD99A1A019AFF0064F706 /* Testable_SwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Testable_SwiftTests.swift; sourceTree = ""; }; + A88CD9A41A019D510064F706 /* KIF.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = KIF.xcodeproj; path = ../../../../KIF.xcodeproj; sourceTree = ""; }; + A88CD9BA1A019F0B0064F706 /* Testable SwiftTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Testable SwiftTests-Bridging-Header.h"; sourceTree = ""; }; + A88CD9BB1A019F0B0064F706 /* SimpleObjCTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimpleObjCTest.m; sourceTree = ""; }; + A88CD9BD1A019F300064F706 /* SimpleSwiftTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleSwiftTest.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + A88CD97A1A019AFF0064F706 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A88CD9911A019AFF0064F706 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A88CD9B91A019E430064F706 /* libKIF.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + A88CD9741A019AFF0064F706 = { + isa = PBXGroup; + children = ( + A88CD97F1A019AFF0064F706 /* Testable Swift */, + A88CD9971A019AFF0064F706 /* Testable SwiftTests */, + A88CD97E1A019AFF0064F706 /* Products */, + ); + sourceTree = ""; + }; + A88CD97E1A019AFF0064F706 /* Products */ = { + isa = PBXGroup; + children = ( + A88CD97D1A019AFF0064F706 /* Testable Swift.app */, + A88CD9941A019AFF0064F706 /* Testable SwiftTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + A88CD97F1A019AFF0064F706 /* Testable Swift */ = { + isa = PBXGroup; + children = ( + A88CD9821A019AFF0064F706 /* AppDelegate.swift */, + A88CD9841A019AFF0064F706 /* MasterViewController.swift */, + A88CD9881A019AFF0064F706 /* Main.storyboard */, + A88CD98B1A019AFF0064F706 /* Images.xcassets */, + A88CD98D1A019AFF0064F706 /* LaunchScreen.xib */, + A88CD9801A019AFF0064F706 /* Supporting Files */, + ); + path = "Testable Swift"; + sourceTree = ""; + }; + A88CD9801A019AFF0064F706 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + A88CD9811A019AFF0064F706 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + A88CD9971A019AFF0064F706 /* Testable SwiftTests */ = { + isa = PBXGroup; + children = ( + A88CD9A41A019D510064F706 /* KIF.xcodeproj */, + A88CD99A1A019AFF0064F706 /* Testable_SwiftTests.swift */, + A88CD9981A019AFF0064F706 /* Supporting Files */, + A88CD9BB1A019F0B0064F706 /* SimpleObjCTest.m */, + A88CD9BD1A019F300064F706 /* SimpleSwiftTest.swift */, + A88CD9BA1A019F0B0064F706 /* Testable SwiftTests-Bridging-Header.h */, + ); + path = "Testable SwiftTests"; + sourceTree = ""; + }; + A88CD9981A019AFF0064F706 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + A88CD9991A019AFF0064F706 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + A88CD9A51A019D510064F706 /* Products */ = { + isa = PBXGroup; + children = ( + A88CD9AE1A019D520064F706 /* libKIF.a */, + A88CD9B01A019D520064F706 /* libKIF-OCUnit.a */, + A88CD9B21A019D520064F706 /* Test Host.app */, + A88CD9B41A019D520064F706 /* KIF Tests - XCTest.xctest */, + A88CD9B61A019D520064F706 /* KIF Tests-OCUnit.octest */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + A88CD97C1A019AFF0064F706 /* Testable Swift */ = { + isa = PBXNativeTarget; + buildConfigurationList = A88CD99E1A019AFF0064F706 /* Build configuration list for PBXNativeTarget "Testable Swift" */; + buildPhases = ( + A88CD9791A019AFF0064F706 /* Sources */, + A88CD97A1A019AFF0064F706 /* Frameworks */, + A88CD97B1A019AFF0064F706 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Testable Swift"; + productName = "Testable Swift"; + productReference = A88CD97D1A019AFF0064F706 /* Testable Swift.app */; + productType = "com.apple.product-type.application"; + }; + A88CD9931A019AFF0064F706 /* Testable SwiftTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = A88CD9A11A019AFF0064F706 /* Build configuration list for PBXNativeTarget "Testable SwiftTests" */; + buildPhases = ( + A88CD9901A019AFF0064F706 /* Sources */, + A88CD9911A019AFF0064F706 /* Frameworks */, + A88CD9921A019AFF0064F706 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + A88CD9B81A019E2B0064F706 /* PBXTargetDependency */, + A88CD9961A019AFF0064F706 /* PBXTargetDependency */, + ); + name = "Testable SwiftTests"; + productName = "Testable SwiftTests"; + productReference = A88CD9941A019AFF0064F706 /* Testable SwiftTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + A88CD9751A019AFF0064F706 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0610; + TargetAttributes = { + A88CD97C1A019AFF0064F706 = { + CreatedOnToolsVersion = 6.1; + }; + A88CD9931A019AFF0064F706 = { + CreatedOnToolsVersion = 6.1; + TestTargetID = A88CD97C1A019AFF0064F706; + }; + }; + }; + buildConfigurationList = A88CD9781A019AFF0064F706 /* Build configuration list for PBXProject "Testable Swift" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = A88CD9741A019AFF0064F706; + productRefGroup = A88CD97E1A019AFF0064F706 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = A88CD9A51A019D510064F706 /* Products */; + ProjectRef = A88CD9A41A019D510064F706 /* KIF.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + A88CD97C1A019AFF0064F706 /* Testable Swift */, + A88CD9931A019AFF0064F706 /* Testable SwiftTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + A88CD9AE1A019D520064F706 /* libKIF.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libKIF.a; + remoteRef = A88CD9AD1A019D520064F706 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + A88CD9B01A019D520064F706 /* libKIF-OCUnit.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libKIF-OCUnit.a"; + remoteRef = A88CD9AF1A019D520064F706 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + A88CD9B21A019D520064F706 /* Test Host.app */ = { + isa = PBXReferenceProxy; + fileType = wrapper.application; + path = "Test Host.app"; + remoteRef = A88CD9B11A019D520064F706 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + A88CD9B41A019D520064F706 /* KIF Tests - XCTest.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = "KIF Tests - XCTest.xctest"; + remoteRef = A88CD9B31A019D520064F706 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + A88CD9B61A019D520064F706 /* KIF Tests-OCUnit.octest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = "KIF Tests-OCUnit.octest"; + remoteRef = A88CD9B51A019D520064F706 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + A88CD97B1A019AFF0064F706 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A88CD98A1A019AFF0064F706 /* Main.storyboard in Resources */, + A88CD98F1A019AFF0064F706 /* LaunchScreen.xib in Resources */, + A88CD98C1A019AFF0064F706 /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A88CD9921A019AFF0064F706 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + A88CD9791A019AFF0064F706 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A88CD9851A019AFF0064F706 /* MasterViewController.swift in Sources */, + A88CD9831A019AFF0064F706 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A88CD9901A019AFF0064F706 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A88CD99B1A019AFF0064F706 /* Testable_SwiftTests.swift in Sources */, + A88CD9BE1A019F300064F706 /* SimpleSwiftTest.swift in Sources */, + A88CD9BC1A019F0B0064F706 /* SimpleObjCTest.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + A88CD9961A019AFF0064F706 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = A88CD97C1A019AFF0064F706 /* Testable Swift */; + targetProxy = A88CD9951A019AFF0064F706 /* PBXContainerItemProxy */; + }; + A88CD9B81A019E2B0064F706 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = KIF; + targetProxy = A88CD9B71A019E2B0064F706 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + A88CD9881A019AFF0064F706 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + A88CD9891A019AFF0064F706 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + A88CD98D1A019AFF0064F706 /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + A88CD98E1A019AFF0064F706 /* Base */, + ); + name = LaunchScreen.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + A88CD99C1A019AFF0064F706 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.1; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + A88CD99D1A019AFF0064F706 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.1; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + A88CD99F1A019AFF0064F706 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = "Testable Swift/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + A88CD9A01A019AFF0064F706 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = "Testable Swift/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + A88CD9A21A019AFF0064F706 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ENABLE_MODULES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = "Testable SwiftTests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + XCTest, + "-ObjC", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Testable SwiftTests/Testable SwiftTests-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Testable Swift.app/Testable Swift"; + }; + name = Debug; + }; + A88CD9A31A019AFF0064F706 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ENABLE_MODULES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = "Testable SwiftTests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + XCTest, + "-ObjC", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Testable SwiftTests/Testable SwiftTests-Bridging-Header.h"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Testable Swift.app/Testable Swift"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + A88CD9781A019AFF0064F706 /* Build configuration list for PBXProject "Testable Swift" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A88CD99C1A019AFF0064F706 /* Debug */, + A88CD99D1A019AFF0064F706 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + A88CD99E1A019AFF0064F706 /* Build configuration list for PBXNativeTarget "Testable Swift" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A88CD99F1A019AFF0064F706 /* Debug */, + A88CD9A01A019AFF0064F706 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + A88CD9A11A019AFF0064F706 /* Build configuration list for PBXNativeTarget "Testable SwiftTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A88CD9A21A019AFF0064F706 /* Debug */, + A88CD9A31A019AFF0064F706 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = A88CD9751A019AFF0064F706 /* Project object */; +} diff --git a/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift.xcodeproj/xcshareddata/xcschemes/Testable Swift.xcscheme b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift.xcodeproj/xcshareddata/xcschemes/Testable Swift.xcscheme new file mode 100755 index 000000000..bee04e6e2 --- /dev/null +++ b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift.xcodeproj/xcshareddata/xcschemes/Testable Swift.xcscheme @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/AppDelegate.swift b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/AppDelegate.swift new file mode 100755 index 000000000..23992badf --- /dev/null +++ b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/AppDelegate.swift @@ -0,0 +1,15 @@ +// +// AppDelegate.swift +// Testable Swift +// +// Created by Jim Puls on 10/29/14. +// Licensed to Square, Inc. under one or more contributor license agreements. +// See the LICENSE file distributed with this work for the terms under +// which Square, Inc. licenses this file to you. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/Base.lproj/LaunchScreen.xib b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/Base.lproj/LaunchScreen.xib new file mode 100755 index 000000000..5271f5e02 --- /dev/null +++ b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/Base.lproj/LaunchScreen.xib @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/Base.lproj/Main.storyboard b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/Base.lproj/Main.storyboard new file mode 100755 index 000000000..b0dd79bcd --- /dev/null +++ b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/Base.lproj/Main.storyboard @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/MediationAdapterApp/Images.xcassets/AppIcon.appiconset/Contents.json b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/Images.xcassets/AppIcon.appiconset/Contents.json old mode 100644 new mode 100755 similarity index 100% rename from tests/MediationAdapterApp/Images.xcassets/AppIcon.appiconset/Contents.json rename to tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/Images.xcassets/AppIcon.appiconset/Contents.json diff --git a/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/Info.plist b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/Info.plist new file mode 100755 index 000000000..3eb326eef --- /dev/null +++ b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/Info.plist @@ -0,0 +1,50 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + com.squareup.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/MasterViewController.swift b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/MasterViewController.swift new file mode 100755 index 000000000..888a97706 --- /dev/null +++ b/tests/KIF/Documentation/Examples/Testable Swift/Testable Swift/MasterViewController.swift @@ -0,0 +1,19 @@ +// +// MasterViewController.swift +// Testable Swift +// +// Created by Jim Puls on 10/29/14. +// Licensed to Square, Inc. under one or more contributor license agreements. +// See the LICENSE file distributed with this work for the terms under +// which Square, Inc. licenses this file to you. + +import UIKit + +class MasterViewController: UITableViewController { + override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { + let cell = tableView.cellForRowAtIndexPath(indexPath) + if let text = cell?.textLabel?.text? { + navigationItem.title = "Selected: " + text + } + } +} diff --git a/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/Info.plist b/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/Info.plist new file mode 100755 index 000000000..c08e01bc9 --- /dev/null +++ b/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + com.squareup.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/SimpleObjCTest.m b/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/SimpleObjCTest.m new file mode 100755 index 000000000..560e3f6d9 --- /dev/null +++ b/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/SimpleObjCTest.m @@ -0,0 +1,24 @@ +// +// SimpleObjCTest.m +// Testable Swift +// +// Created by Jim Puls on 10/29/14. +// Licensed to Square, Inc. under one or more contributor license agreements. +// See the LICENSE file distributed with this work for the terms under +// which Square, Inc. licenses this file to you. + +#import +#import + + +@interface SimpleObjCTest : KIFTestCase +@end + +@implementation SimpleObjCTest + +- (void)testRed { + [tester tapViewWithAccessibilityLabel:@"Red"]; + [tester waitForViewWithAccessibilityLabel:@"Selected: Red"]; +} + +@end diff --git a/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/SimpleSwiftTest.swift b/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/SimpleSwiftTest.swift new file mode 100755 index 000000000..f0b1402ba --- /dev/null +++ b/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/SimpleSwiftTest.swift @@ -0,0 +1,29 @@ +// +// SimpleSwiftTest.swift +// Testable Swift +// +// Created by Jim Puls on 10/29/14. +// Licensed to Square, Inc. under one or more contributor license agreements. +// See the LICENSE file distributed with this work for the terms under +// which Square, Inc. licenses this file to you. + +import UIKit +import XCTest + + +extension XCTestCase { + func tester(_ file : String = __FILE__, _ line : Int = __LINE__) -> KIFUITestActor { + return KIFUITestActor(inFile: file, atLine: line, delegate: self) + } + + func system(_ file : String = __FILE__, _ line : Int = __LINE__) -> KIFSystemTestActor { + return KIFSystemTestActor(inFile: file, atLine: line, delegate: self) + } +} + +class SimpleSwiftTest: KIFTestCase { + func testGreen() { + tester().tapViewWithAccessibilityLabel("Green") + tester().waitForViewWithAccessibilityLabel("Selected: Green") + } +} diff --git a/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/Testable SwiftTests-Bridging-Header.h b/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/Testable SwiftTests-Bridging-Header.h new file mode 100755 index 000000000..12c223598 --- /dev/null +++ b/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/Testable SwiftTests-Bridging-Header.h @@ -0,0 +1,5 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import diff --git a/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/Testable_SwiftTests.swift b/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/Testable_SwiftTests.swift new file mode 100755 index 000000000..5ac78e4f8 --- /dev/null +++ b/tests/KIF/Documentation/Examples/Testable Swift/Testable SwiftTests/Testable_SwiftTests.swift @@ -0,0 +1,37 @@ +// +// Testable_SwiftTests.swift +// Testable SwiftTests +// +// Created by Jim Puls on 10/29/14. +// Licensed to Square, Inc. under one or more contributor license agreements. +// See the LICENSE file distributed with this work for the terms under +// which Square, Inc. licenses this file to you. + +import UIKit +import XCTest + +class Testable_SwiftTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + XCTAssert(true, "Pass") + } + + func testPerformanceExample() { + // This is an example of a performance test case. + self.measureBlock() { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/tests/KIF/Documentation/Images/Add Category Linker Flags.png b/tests/KIF/Documentation/Images/Add Category Linker Flags.png index 44871d37d..3bdc581d7 100755 Binary files a/tests/KIF/Documentation/Images/Add Category Linker Flags.png and b/tests/KIF/Documentation/Images/Add Category Linker Flags.png differ diff --git a/tests/KIF/Documentation/Images/Add Library Sheet.png b/tests/KIF/Documentation/Images/Add Library Sheet.png index ae72efe21..76bb08120 100755 Binary files a/tests/KIF/Documentation/Images/Add Library Sheet.png and b/tests/KIF/Documentation/Images/Add Library Sheet.png differ diff --git a/tests/KIF/Documentation/Images/Add Library.png b/tests/KIF/Documentation/Images/Add Library.png index 075ad8d3a..ad34d718a 100755 Binary files a/tests/KIF/Documentation/Images/Add Library.png and b/tests/KIF/Documentation/Images/Add Library.png differ diff --git a/tests/KIF/Documentation/Images/Added KIF to Project.png b/tests/KIF/Documentation/Images/Added KIF to Project.png new file mode 100755 index 000000000..5eb221e22 Binary files /dev/null and b/tests/KIF/Documentation/Images/Added KIF to Project.png differ diff --git a/tests/KIF/Documentation/Images/Simple App.png b/tests/KIF/Documentation/Images/Simple App.png new file mode 100755 index 000000000..debab50a1 Binary files /dev/null and b/tests/KIF/Documentation/Images/Simple App.png differ diff --git a/tests/KIF/IdentifierTests/KIFUITestActor-IdentifierTests.h b/tests/KIF/IdentifierTests/KIFUITestActor-IdentifierTests.h new file mode 100755 index 000000000..09ebdc1b5 --- /dev/null +++ b/tests/KIF/IdentifierTests/KIFUITestActor-IdentifierTests.h @@ -0,0 +1,73 @@ +// +// KIFUITestActor+IdentifierTests.h +// KIF +// +// Created by Brian Nickel on 11/6/14. +// +// + +#import "KIF.h" + +@interface KIFUITestActor (IdentifierTests) + +- (UIView *)waitForViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier; +- (UIView *)waitForTappableViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier; +- (void)tapViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier; +- (void)waitForAbsenceOfViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier; + +/*! + @abstract Performs a long press on a particular view in the view hierarchy. + @discussion The view or accessibility element with the given label is searched for in the view hierarchy. If the element isn't found or isn't currently tappable, then the step will attempt to wait until it is. Once the view is present and tappable, touch events are simulated in the center of the view or element. + @param accessibilityIdentifier The accessibility identifier of the element to tap. + @param duration The length of time to long press the element. + */ +- (void)longPressViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier duration:(NSTimeInterval)duration; + +/*! + @abstract Enters text into a particular view in the view hierarchy. + @discussion The view or accessibility element with the given label is searched for in the view hierarchy. If the element isn't found or isn't currently tappable, then the step will attempt to wait until it is. Once the view is present and tappable, a tap event is simulated in the center of the view or element, then text is entered into the view by simulating taps on the appropriate keyboard keys. + @param text The text to enter. + @param accessibilityIdentifier The accessibility identifier of the element to type into. + */ +- (void)enterText:(NSString *)text intoViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier; + +/*! + @abstract Enters text into a particular view in the view hierarchy. + @discussion The view or accessibility element with the given label is searched for in the view hierarchy. If the element isn't found or isn't currently tappable, then the step will attempt to wait until it is. Once the view is present and tappable, a tap event is simulated in the center of the view or element, then text is entered into the view by simulating taps on the appropriate keyboard keys. + @param text The text to enter. + @param accessibilityIdentifier The accessibility identifier of the element to type into. + @param expectedResult What the text value should be after entry, including any formatting done by the field. If this is nil, the "text" parameter will be used. + */ +- (void)enterText:(NSString *)text intoViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier expectedResult:(NSString *)expectedResult; + +- (void)clearTextFromViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier; + +- (void)clearTextFromAndThenEnterText:(NSString *)text intoViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier; +- (void)clearTextFromAndThenEnterText:(NSString *)text intoViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier expectedResult:(NSString *)expectedResult; + +/*! + @abstract Toggles a UISwitch into a specified position. + @discussion The UISwitch with the given label is searched for in the view hierarchy. If the element isn't found or isn't currently tappable, then the step will attempt to wait until it is. Once the view is present, the step will return if it's already in the desired position. If the switch is tappable but not in the desired position, a tap event is simulated in the center of the view or element, toggling the switch into the desired position. + @param switchIsOn The desired position of the UISwitch. + @param accessibilityIdentifier The accessibility identifier of the element to switch. + */ +- (void)setOn:(BOOL)switchIsOn forSwitchWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier; + +/*! + @abstract Slides a UISlider to a specified value. + @discussion The UISlider with the given label is searched for in the view hierarchy. If the element isn't found or isn't currently tappable, then the step will attempt to wait until it is. Once the view is present, the step will attempt to drag the slider to the new value. The step will fail if it finds a view with the given accessibility label that is not a UISlider or if value is outside of the possible values. Because this step simulates drag events, the value reached may not be the exact value requested and the app may ignore the touch events if the movement is less than the drag gesture recognizer's minimum distance. + @param value The desired value of the UISlider. + @param accessibilityIdentifier The accessibility identifier of the element to drag. + */ +- (void)setValue:(float)value forSliderWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier; + +/*! + @abstract Waits until a view or accessibility element is the first responder. + @discussion The first responder is found by searching the view hierarchy of the application's + main window and its accessibility identifier is compared to the given value. If they match, the + step returns success else it will attempt to wait until they do. + @param accessibilityIdentifier The accessibility identifier of the element to wait for. + */ +- (void)waitForFirstResponderWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier; + +@end diff --git a/tests/KIF/IdentifierTests/KIFUITestActor-IdentifierTests.m b/tests/KIF/IdentifierTests/KIFUITestActor-IdentifierTests.m new file mode 100755 index 000000000..649f7f678 --- /dev/null +++ b/tests/KIF/IdentifierTests/KIFUITestActor-IdentifierTests.m @@ -0,0 +1,202 @@ +// +// KIFUITestActor+IdentifierTests.m +// KIF +// +// Created by Brian Nickel on 11/6/14. +// +// + +#import +#import "KIFUITestActor-IdentifierTests.h" +#import "UIAccessibilityElement-KIFAdditions.h" +#import "NSError-KIFAdditions.h" +#import "UIWindow-KIFAdditions.h" + +@implementation KIFUITestActor (IdentifierTests) + +- (UIView *)waitForViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier +{ + return [self waitForViewWithAccessibilityIdentifier:accessibilityIdentifier tappable:NO]; +} + +- (UIView *)waitForTappableViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier +{ + return [self waitForViewWithAccessibilityIdentifier:accessibilityIdentifier tappable:YES]; +} + +- (void)tapViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier +{ + @autoreleasepool { + UIView *view = nil; + UIAccessibilityElement *element = nil; + [self waitForAccessibilityElement:&element view:&view withIdentifier:accessibilityIdentifier tappable:YES]; + [self tapAccessibilityElement:element inView:view]; + } +} + +- (void)waitForAbsenceOfViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier +{ + [self runBlock:^KIFTestStepResult(NSError **error) { + // If the app is ignoring interaction events, then wait before doing our analysis + KIFTestWaitCondition(![[UIApplication sharedApplication] isIgnoringInteractionEvents], error, @"Application is ignoring interaction events."); + + // If the element can't be found, then we're done + + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"accessibilityIdentifier = %@", accessibilityIdentifier]; + UIAccessibilityElement *element = nil; + + if (![UIAccessibilityElement accessibilityElement:&element view:NULL withElementMatchingPredicate:predicate tappable:NO error:NULL]) { + return KIFTestStepResultSuccess; + } + + UIView *view = [UIAccessibilityElement viewContainingAccessibilityElement:element]; + + // If we found an element, but it's not associated with a view, then something's wrong. Wait it out and try again. + KIFTestWaitCondition(view, error, @"Cannot find view containing accessibility element with the identifier \"%@\"", accessibilityIdentifier); + + // Hidden views count as absent + KIFTestWaitCondition([view isHidden] || [view superview] == nil, error, @"Accessibility element with identifier \"%@\" is visible and not hidden.", accessibilityIdentifier); + + return KIFTestStepResultSuccess; + }]; +} + +- (UIView *)waitForViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier tappable:(BOOL)mustBeTappable +{ + UIView *view = nil; + @autoreleasepool { + [self waitForAccessibilityElement:NULL view:&view withIdentifier:accessibilityIdentifier tappable:mustBeTappable]; + } + + return view; +} + +- (void)longPressViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier duration:(NSTimeInterval)duration +{ + @autoreleasepool { + UIView *view = nil; + UIAccessibilityElement *element = nil; + [self waitForAccessibilityElement:&element view:&view withIdentifier:accessibilityIdentifier tappable:YES]; + [self longPressAccessibilityElement:element inView:view duration:duration]; + } +} + +- (void)enterText:(NSString *)text intoViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier +{ + return [self enterText:text intoViewWithAccessibilityIdentifier:accessibilityIdentifier expectedResult:nil]; + +} + +- (void)enterText:(NSString *)text intoViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier expectedResult:(NSString *)expectedResult +{ + UIView *view = nil; + UIAccessibilityElement *element = nil; + + [self waitForAccessibilityElement:&element view:&view withIdentifier:accessibilityIdentifier tappable:YES]; + [self tapAccessibilityElement:element inView:view]; + [self waitForTimeInterval:0.25]; + [self enterTextIntoCurrentFirstResponder:text fallbackView:view]; + [self expectView:view toContainText:expectedResult ?: text]; +} + +- (void)clearTextFromViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier +{ + UIView *view = nil; + UIAccessibilityElement *element = nil; + + [self waitForAccessibilityElement:&element view:&view withIdentifier:accessibilityIdentifier tappable:YES]; + [self clearTextFromElement:element inView:view]; +} + +- (void)clearTextFromAndThenEnterText:(NSString *)text intoViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier +{ + [self clearTextFromViewWithAccessibilityIdentifier:accessibilityIdentifier]; + [self enterText:text intoViewWithAccessibilityIdentifier:accessibilityIdentifier]; +} + +- (void)clearTextFromAndThenEnterText:(NSString *)text intoViewWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier expectedResult:(NSString *)expectedResult +{ + [self clearTextFromViewWithAccessibilityIdentifier:accessibilityIdentifier]; + [self enterText:text intoViewWithAccessibilityIdentifier:accessibilityIdentifier expectedResult:expectedResult]; +} + +- (void)setOn:(BOOL)switchIsOn forSwitchWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier +{ + UIView *view = nil; + UIAccessibilityElement *element = nil; + + [self waitForAccessibilityElement:&element view:&view withIdentifier:accessibilityIdentifier tappable:YES]; + + if (![view isKindOfClass:[UISwitch class]]) { + [self failWithError:[NSError KIFErrorWithFormat:@"View with accessibility identifier \"%@\" is a %@, not a UISwitch", accessibilityIdentifier, NSStringFromClass([view class])] stopTest:YES]; + } + + UISwitch *switchView = (UISwitch *)view; + + // No need to switch it if it's already in the correct position + if (switchView.isOn == switchIsOn) { + return; + } + + [self tapAccessibilityElement:element inView:view]; + + // If we succeeded, stop the test. + if (switchView.isOn == switchIsOn) { + return; + } + + NSLog(@"Faking turning switch %@ with accessibility identifier %@", switchIsOn ? @"ON" : @"OFF", accessibilityIdentifier); + [switchView setOn:switchIsOn animated:YES]; + [switchView sendActionsForControlEvents:UIControlEventValueChanged]; + [self waitForTimeInterval:0.5]; + + // We gave it our best shot. Fail the test. + if (switchView.isOn != switchIsOn) { + [self failWithError:[NSError KIFErrorWithFormat:@"Failed to toggle switch to \"%@\"; instead, it was \"%@\"", switchIsOn ? @"ON" : @"OFF", switchView.on ? @"ON" : @"OFF"] stopTest:YES]; + } + +} + +- (void)setValue:(float)value forSliderWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier +{ + UISlider *slider = nil; + UIAccessibilityElement *element = nil; + [self waitForAccessibilityElement:&element view:&slider withIdentifier:accessibilityIdentifier tappable:YES]; + + if (![slider isKindOfClass:[UISlider class]]) { + [self failWithError:[NSError KIFErrorWithFormat:@"View with accessibility identifier \"%@\" is a %@, not a UISlider", accessibilityIdentifier, NSStringFromClass([slider class])] stopTest:YES]; + } + [self setValue:value forSlider:slider]; +} + +- (void)waitForFirstResponderWithAccessibilityIdentifier:(NSString *)accessibilityIdentifier +{ + [self runBlock:^KIFTestStepResult(NSError **error) { + UIResponder *firstResponder = [[[UIApplication sharedApplication] keyWindow] firstResponder]; + if ([firstResponder isKindOfClass:NSClassFromString(@"UISearchBarTextField")]) { + do { + firstResponder = [(UIView *)firstResponder superview]; + } while (firstResponder && ![firstResponder isKindOfClass:[UISearchBar class]]); + } + UIResponder* firstResponderIdentification = nil; + if ([firstResponder conformsToProtocol:@protocol(UIAccessibilityIdentification)]) + { + firstResponderIdentification = (UIResponder*)firstResponder; + } + else + { + [self failWithError:[NSError KIFErrorWithFormat:@"First responder does not conform to UIAccessibilityIdentification %@", NSStringFromClass([firstResponder class])] stopTest:YES]; + + } + KIFTestWaitCondition([[firstResponderIdentification accessibilityIdentifier] isEqualToString:accessibilityIdentifier], + error, @"Expected accessibility identifier for first responder to be '%@', got '%@'", + accessibilityIdentifier, [firstResponderIdentification accessibilityIdentifier]); + + return KIFTestStepResultSuccess; + }]; +} + + + + +@end diff --git a/tests/KIF/KIF Tests/AccessibilityIdentifierTests.m b/tests/KIF/KIF Tests/AccessibilityIdentifierTests.m new file mode 100755 index 000000000..47f0de7c8 --- /dev/null +++ b/tests/KIF/KIF Tests/AccessibilityIdentifierTests.m @@ -0,0 +1,79 @@ +// +// AccessibilityIdentifierTests.m +// KIF +// +// Created by Brian Nickel on 11/6/14. +// +// + +#import +#import +#import + +@interface AccessibilityIdentifierTests : KIFTestCase +@end + +@implementation AccessibilityIdentifierTests + +- (void)beforeEach +{ + [tester tapViewWithAccessibilityLabel:@"Tapping"]; +} + +- (void)testWaitingForViewWithAccessibilityIdentifier +{ + // Since the tap has occurred in setup, we just need to wait for the result. + [tester waitForViewWithAccessibilityIdentifier:@"X_BUTTON"]; + KIFExpectFailure([[tester usingTimeout:0.5] waitForViewWithAccessibilityIdentifier:@"NOT_X_BUTTON"]); +} + +- (void)testTappingViewWithAccessibilityIdentifier +{ + [tester tapViewWithAccessibilityIdentifier:@"X_BUTTON"]; + [tester waitForViewWithAccessibilityLabel:@"X" traits:UIAccessibilityTraitButton | UIAccessibilityTraitSelected]; + KIFExpectFailure([[tester usingTimeout:0.5] tapViewWithAccessibilityIdentifier:@"NOT_X_BUTTON"]); +} + +- (void)testWaitingForAbscenceOfViewWithAccessibilityIdentifier +{ + // Since the tap has occurred in setup, we just need to wait for the result. + [tester waitForViewWithAccessibilityIdentifier:@"X_BUTTON"]; + [tester waitForAbsenceOfViewWithAccessibilityIdentifier:@"NOT_X_BUTTON"]; + KIFExpectFailure([[tester usingTimeout:0.5] waitForAbsenceOfViewWithAccessibilityIdentifier:@"X_BUTTON"]); + [tester tapViewWithAccessibilityLabel:@"Test Suite" traits:UIAccessibilityTraitButton]; + [tester waitForAbsenceOfViewWithAccessibilityIdentifier:@"X_BUTTON"]; + [tester tapViewWithAccessibilityLabel:@"Tapping"]; +} + +- (void)testLongPressingViewWithAccessibilityIdentifier +{ + [tester longPressViewWithAccessibilityIdentifier:@"idGreeting" duration:2]; + [tester tapViewWithAccessibilityLabel:@"Select All"]; +} + +- (void)testEnteringTextIntoViewWithAccessibilityIdentifier +{ + [tester longPressViewWithAccessibilityIdentifier:@"idGreeting" duration:2]; + [tester tapViewWithAccessibilityLabel:@"Select All"]; + [tester tapViewWithAccessibilityLabel:@"Cut"]; + [tester enterText:@"Yo" intoViewWithAccessibilityIdentifier:@"idGreeting"]; +} + +- (void)testEnteringTextIntoViewWithAccessibilityIdentifierExpectingResults +{ + [tester enterText:@", world" intoViewWithAccessibilityIdentifier:@"idGreeting" expectedResult:@"Hello, world"]; + [tester waitForViewWithAccessibilityLabel:@"Greeting" value:@"Hello, world" traits:UIAccessibilityTraitNone]; +} + +- (void)testClearingAndEnteringTextIntoViewWithAccessibilityLabel +{ + [tester clearTextFromAndThenEnterText:@"Yo" intoViewWithAccessibilityIdentifier:@"idGreeting"]; +} + + +- (void)afterEach +{ + [tester tapViewWithAccessibilityLabel:@"Test Suite" traits:UIAccessibilityTraitButton]; +} + +@end diff --git a/tests/KIF/KIF Tests/CollectionViewTests.m b/tests/KIF/KIF Tests/CollectionViewTests.m index 8778d33ea..3b2f8b8cb 100755 --- a/tests/KIF/KIF Tests/CollectionViewTests.m +++ b/tests/KIF/KIF Tests/CollectionViewTests.m @@ -40,7 +40,7 @@ - (void)testTappingLastItemAndSection - (void)testOutOfBounds { - KIFExpectFailure([tester tapItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:99] inCollectionViewWithAccessibilityIdentifier:@"CollectionView Tests CollectionView"]); + KIFExpectFailure([[tester usingTimeout:1] tapItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:99] inCollectionViewWithAccessibilityIdentifier:@"CollectionView Tests CollectionView"]); } - (void)testUnknownCollectionView diff --git a/tests/KIF/KIF Tests/LandscapeTests.m b/tests/KIF/KIF Tests/LandscapeTests.m index e44888e8d..c4e778ddf 100755 --- a/tests/KIF/KIF Tests/LandscapeTests.m +++ b/tests/KIF/KIF Tests/LandscapeTests.m @@ -22,7 +22,7 @@ - (void)beforeAll - (void)afterAll { [system simulateDeviceRotationToOrientation:UIDeviceOrientationPortrait]; - [tester waitForTimeInterval:0.25]; + [tester waitForTimeInterval:0.5]; } - (void)beforeEach diff --git a/tests/KIF/KIF Tests/PickerTests.m b/tests/KIF/KIF Tests/PickerTests.m index a6025fd0c..b90ac7878 100755 --- a/tests/KIF/KIF Tests/PickerTests.m +++ b/tests/KIF/KIF Tests/PickerTests.m @@ -61,7 +61,22 @@ - (void)testSelectingCountdown - (void)testSelectingAPickerRow { [tester selectPickerViewRowWithTitle:@"Charlie"]; - [tester waitForViewWithAccessibilityLabel:@"Call Sign" value:@"Charlie. 3 of 3" traits:UIAccessibilityTraitNone]; + + NSOperatingSystemVersion iOS8 = {8, 0, 0}; + if ([NSProcessInfo instancesRespondToSelector:@selector(isOperatingSystemAtLeastVersion:)] && [[NSProcessInfo new] isOperatingSystemAtLeastVersion:iOS8]) { + [tester waitForViewWithAccessibilityLabel:@"Call Sign" value:@"Charlie" traits:UIAccessibilityTraitNone]; + } else { + [tester waitForViewWithAccessibilityLabel:@"Call Sign" value:@"Charlie. 3 of 3" traits:UIAccessibilityTraitNone]; + } +} + +- (void)testSelectingRowInComponent +{ + [tester tapViewWithAccessibilityLabel:@"Date Selection"]; + NSArray *date = @[@"December", @"31", @"2030"]; + [tester selectDatePickerValue:date]; + [tester selectPickerViewRowWithTitle:@"17" inComponent:1]; + [tester waitForViewWithAccessibilityLabel:@"Date Selection" value:@"Dec 17, 2030" traits:UIAccessibilityTraitNone]; } @end diff --git a/tests/KIF/KIF Tests/SpecificControlTests.m b/tests/KIF/KIF Tests/SpecificControlTests.m index ab0b7afa3..285d83a49 100755 --- a/tests/KIF/KIF Tests/SpecificControlTests.m +++ b/tests/KIF/KIF Tests/SpecificControlTests.m @@ -37,19 +37,24 @@ - (void)testMovingASlider [tester waitForTimeInterval:1]; [tester setValue:3 forSliderWithAccessibilityLabel:@"Slider"]; [tester waitForViewWithAccessibilityLabel:@"Slider" value:@"3" traits:UIAccessibilityTraitNone]; + [tester setValue:0 forSliderWithAccessibilityLabel:@"Slider"]; + [tester waitForViewWithAccessibilityLabel:@"Slider" value:@"0" traits:UIAccessibilityTraitNone]; + [tester setValue:5 forSliderWithAccessibilityLabel:@"Slider"]; + [tester waitForViewWithAccessibilityLabel:@"Slider" value:@"5" traits:UIAccessibilityTraitNone]; } -- (void)testReturningFromATextField -{ - [tester tapViewWithAccessibilityLabel:@"Greeting"]; - [tester waitForTimeInterval:1]; - [tester tapViewWithAccessibilityLabel:@"return"]; - [tester waitForAbsenceOfViewWithAccessibilityLabel:@"return"]; +- (void)testPickingAPhoto { + [tester tapViewWithAccessibilityLabel:@"Photos"]; + [tester acknowledgeSystemAlert]; + [tester waitForTimeInterval:0.5f]; // Wait for view to stabilize + + NSOperatingSystemVersion iOS8 = {8, 0, 0}; + if ([NSProcessInfo instancesRespondToSelector:@selector(isOperatingSystemAtLeastVersion:)] && [[NSProcessInfo new] isOperatingSystemAtLeastVersion:iOS8]) { + [tester choosePhotoInAlbum:@"Camera Roll" atRow:1 column:2]; + } else { + [tester choosePhotoInAlbum:@"Saved Photos" atRow:1 column:2]; + } + [tester waitForViewWithAccessibilityLabel:@"{834, 1250}"]; } -/* - TODO: Should we implement this test? It is really domain specific. It depends on a UI element named "Choose Photo" which is wired to create an image picker, an album with a matching name, and photos to be on the device. - + (NSArray *)stepsToChoosePhotoInAlbum:(NSString *)albumName atRow:(NSInteger)row column:(NSInteger)column; - */ - @end diff --git a/tests/KIF/KIF Tests/SystemAlertTests.m b/tests/KIF/KIF Tests/SystemAlertTests.m new file mode 100755 index 000000000..cda8f8b03 --- /dev/null +++ b/tests/KIF/KIF Tests/SystemAlertTests.m @@ -0,0 +1,43 @@ +// +// SystemAlertTests.m +// KIF +// +// Created by Joe Masilotti on 12/1/14. +// +// + +#import + +@interface SystemAlertTests : KIFTestCase + +@end + +@implementation SystemAlertTests + +- (void)beforeEach +{ + [tester tapViewWithAccessibilityLabel:@"System Alerts"]; +} + +- (void)afterEach +{ + [tester tapViewWithAccessibilityLabel:@"Test Suite" traits:UIAccessibilityTraitButton]; +} + +- (void)testAuthorizingLocationServices { + [tester tapViewWithAccessibilityLabel:@"Location Services"]; + [tester acknowledgeSystemAlert]; +} + +- (void)testAuthorizingPhotosAccess { + [tester tapViewWithAccessibilityLabel:@"Photos"]; + [tester acknowledgeSystemAlert]; + [tester tapViewWithAccessibilityLabel:@"Cancel"]; +} + +- (void)testNotificationScheduling { + [tester tapViewWithAccessibilityLabel:@"Notifications"]; + [tester acknowledgeSystemAlert]; +} + +@end diff --git a/tests/KIF/KIF Tests/TableViewTests.m b/tests/KIF/KIF Tests/TableViewTests.m index b38e471aa..ceb5c39d1 100755 --- a/tests/KIF/KIF Tests/TableViewTests.m +++ b/tests/KIF/KIF Tests/TableViewTests.m @@ -41,7 +41,7 @@ - (void)testTappingLastRowAndSection - (void)testOutOfBounds { - KIFExpectFailure([tester tapRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:99] inTableViewWithAccessibilityIdentifier:@"TableView Tests Table"]); + KIFExpectFailure([[tester usingTimeout:1] tapRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:99] inTableViewWithAccessibilityIdentifier:@"TableView Tests Table"]); } - (void)testUnknownTable @@ -146,4 +146,9 @@ - (void)testButtonAbsentAfterSetHidden [tester waitForViewWithAccessibilityLabel:@"Button"]; } +- (void)testEnteringTextIntoATextFieldInATableCell +{ + [tester enterText:@"Test-Driven Development" intoViewWithAccessibilityLabel:@"TextField"]; +} + @end diff --git a/tests/KIF/KIF Tests/TypingTests.m b/tests/KIF/KIF Tests/TypingTests.m index 7339a875d..f4a1363f4 100755 --- a/tests/KIF/KIF Tests/TypingTests.m +++ b/tests/KIF/KIF Tests/TypingTests.m @@ -7,6 +7,7 @@ // #import +#import "KIFTestStepValidation.h" @interface TypingTests : KIFTestCase @end @@ -23,13 +24,17 @@ - (void)afterEach [tester tapViewWithAccessibilityLabel:@"Test Suite" traits:UIAccessibilityTraitButton]; } - - (void)testWaitingForFirstResponder { [tester tapViewWithAccessibilityLabel:@"Greeting" value:@"Hello" traits:UIAccessibilityTraitNone]; [tester waitForFirstResponderWithAccessibilityLabel:@"Greeting"]; } +- (void)testMissingFirstResponder +{ + KIFExpectFailure([[tester usingTimeout:1] waitForFirstResponderWithAccessibilityLabel:@"Greeting"]); +} + - (void)testEnteringTextIntoFirstResponder { [tester longPressViewWithAccessibilityLabel:@"Greeting" value:@"Hello" duration:2]; @@ -38,11 +43,16 @@ - (void)testEnteringTextIntoFirstResponder [tester waitForViewWithAccessibilityLabel:@"Greeting" value:@"Yo" traits:UIAccessibilityTraitNone]; } +- (void)testFailingToEnterTextIntoFirstResponder +{ + KIFExpectFailure([[tester usingTimeout:1] enterTextIntoCurrentFirstResponder:@"Yo"]); +} + - (void)testEnteringTextIntoViewWithAccessibilityLabel { [tester longPressViewWithAccessibilityLabel:@"Greeting" value:@"Hello" duration:2]; [tester tapViewWithAccessibilityLabel:@"Select All"]; - [tester tapViewWithAccessibilityLabel:@"Delete"]; + [tester tapViewWithAccessibilityLabel:@"Cut"]; [tester enterText:@"Yo" intoViewWithAccessibilityLabel:@"Greeting"]; [tester waitForViewWithAccessibilityLabel:@"Greeting" value:@"Yo" traits:UIAccessibilityTraitNone]; } @@ -71,4 +81,17 @@ - (void)testClearingALongTextField [tester clearTextFromViewWithAccessibilityLabel:@"Greeting"]; } +- (void)testThatClearingTextHitsTheDelegate +{ + [tester enterText:@"hello" intoViewWithAccessibilityLabel:@"Other Text"]; + [tester clearTextFromViewWithAccessibilityLabel:@"Other Text"]; + [tester waitForViewWithAccessibilityLabel:@"Greeting" value:@"Deleted something." traits:UIAccessibilityTraitNone]; +} + +- (void)testThatBackspaceDeletesOneCharacter +{ + [tester enterText:@"hi\bello" intoViewWithAccessibilityLabel:@"Other Text" traits:UIAccessibilityTraitNone expectedResult:@"hello"]; + [tester waitForViewWithAccessibilityLabel:@"Greeting" value:@"Deleted something." traits:UIAccessibilityTraitNone]; +} + @end diff --git a/tests/KIF/KIF Tests/WaitForAnimationTests.m b/tests/KIF/KIF Tests/WaitForAnimationTests.m new file mode 100755 index 000000000..df9192154 --- /dev/null +++ b/tests/KIF/KIF Tests/WaitForAnimationTests.m @@ -0,0 +1,31 @@ +// +// WaitForAnimationTests.m +// KIF +// +// Created by Hendrik von Prince on 11.11.14. +// +// + +#import + +@interface WaitForAnimationTests : KIFTestCase + +@end + +@implementation WaitForAnimationTests + +- (void)beforeEach { + [tester tapViewWithAccessibilityLabel:@"Tapping"]; + [tester tapViewWithAccessibilityLabel:@"Animations"]; +} + +- (void)afterEach { + [tester tapViewWithAccessibilityLabel:@"Back"]; + [tester tapViewWithAccessibilityLabel:@"Test Suite" traits:UIAccessibilityTraitButton]; +} + +- (void)testWaitForFinishingAnimation { + [tester waitForViewWithAccessibilityLabel:@"Label"]; +} + +@end diff --git a/tests/KIF/KIF Tests/WebViewTests.m b/tests/KIF/KIF Tests/WebViewTests.m new file mode 100755 index 000000000..e2b4a7598 --- /dev/null +++ b/tests/KIF/KIF Tests/WebViewTests.m @@ -0,0 +1,43 @@ +// +// WebViewTests.m +// KIF +// +// Created by Joe Masilotti on 11/19/14. +// +// + +#import +#import +#import + +@interface WebViewTests : KIFTestCase +@end + +@implementation WebViewTests + +- (void)beforeEach +{ + [tester tapViewWithAccessibilityLabel:@"WebViews"]; +} + +- (void)afterEach +{ + [tester tapViewWithAccessibilityLabel:@"Test Suite" traits:UIAccessibilityTraitButton]; +} + +- (void)testTappingLinks { + [tester tapViewWithAccessibilityLabel:@"A link"]; + [tester waitForViewWithAccessibilityLabel:@"Page 2"]; +} + +- (void)testScrolling { + // Off screen, the web view will need to be scrolled down + [tester waitForViewWithAccessibilityLabel:@"Footer"]; +} + +- (void)testEnteringText { + [tester tapViewWithAccessibilityLabel:@"Input Label"]; + [tester enterTextIntoCurrentFirstResponder:@"Keyboard text"]; +} + +@end diff --git a/tests/KIF/KIF.podspec b/tests/KIF/KIF.podspec index d99e1d469..65984ea59 100755 --- a/tests/KIF/KIF.podspec +++ b/tests/KIF/KIF.podspec @@ -1,11 +1,11 @@ Pod::Spec.new do |s| s.name = "KIF" - s.version = "3.0.8" + s.version = "3.1.2" s.summary = "Keep It Functional - iOS UI acceptance testing in an XCUnit harness." s.homepage = "https://github.com/kif-framework/KIF/" s.license = 'Apache 2.0' s.authors = 'Eric Firestone', 'Jim Puls', 'Brian Nickel' - s.source = { :git => "https://github.com/kif-framework/KIF.git", :tag => "v3.0.8" } + s.source = { :git => "https://github.com/kif-framework/KIF.git", :tag => "v3.1.2" } s.platform = :ios, '5.1' s.frameworks = 'CoreGraphics' s.default_subspec = 'XCTest' @@ -33,4 +33,11 @@ Pod::Spec.new do |s| sentest.xcconfig = { 'OTHER_CFLAGS' => '-DKIF_SENTEST' } sentest.requires_arc = true end + + s.subspec 'IdentifierTests' do |kiaf| + kiaf.dependency 'KIF/XCTest' + kiaf.source_files = 'IdentifierTests' + kiaf.public_header_files = 'IdentifierTests/**/*.h' + kiaf.requires_arc = true + end end diff --git a/tests/KIF/KIF.xcodeproj/project.pbxproj b/tests/KIF/KIF.xcodeproj/project.pbxproj index a902b6ade..fab3aadc8 100755 --- a/tests/KIF/KIF.xcodeproj/project.pbxproj +++ b/tests/KIF/KIF.xcodeproj/project.pbxproj @@ -8,19 +8,25 @@ /* Begin PBXBuildFile section */ 2CDEE1CB181DBED200DF6E63 /* PickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CDEE1CA181DBED200DF6E63 /* PickerController.m */; }; - 2CED883E181F5EE1005ABD20 /* PickerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CED883D181F5EE1005ABD20 /* PickerTests.m */; }; 2EE12710198991920031D347 /* MultiFingerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EE1270F198991920031D347 /* MultiFingerTests.m */; }; - 2EE12711198991920031D347 /* MultiFingerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EE1270F198991920031D347 /* MultiFingerTests.m */; }; + 3812FB611A1212A700335733 /* AnimationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3812FB601A1212A700335733 /* AnimationViewController.m */; }; + 3812FB631A12188700335733 /* WaitForAnimationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3812FB621A12188700335733 /* WaitForAnimationTests.m */; }; 4A48107B19708CAB0003A32E /* ExistTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A48107A19708CAB0003A32E /* ExistTests.m */; }; - A88930121685098E00FC7C63 /* KIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A88930111685098E00FC7C63 /* KIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 84D293AD1A2C84F700C10944 /* SystemAlertViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D293AC1A2C84F700C10944 /* SystemAlertViewController.m */; }; + 84D293AF1A2C867300C10944 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D293AE1A2C867300C10944 /* CoreLocation.framework */; }; + 84D293B11A2C891700C10944 /* SystemAlertTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D293B01A2C891700C10944 /* SystemAlertTests.m */; }; + 84D293B81A2C8DF700C10944 /* AddressBookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D293B71A2C8DF700C10944 /* AddressBookUI.framework */; }; + 84D293BB1A2CC30B00C10944 /* UIAutomationHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D293B91A2CC30B00C10944 /* UIAutomationHelper.h */; }; + 84D293BD1A2CC30B00C10944 /* UIAutomationHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D293BA1A2CC30B00C10944 /* UIAutomationHelper.m */; }; + AE62FCD01A1D20E5002B10DA /* WebViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = AE62FCCF1A1D20E5002B10DA /* WebViewTests.m */; }; + AE62FCD61A1D2447002B10DA /* WebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AE62FCD51A1D2447002B10DA /* WebViewController.m */; }; + AE62FCD81A1D2667002B10DA /* index.html in Resources */ = {isa = PBXBuildFile; fileRef = AE62FCD71A1D2667002B10DA /* index.html */; }; + AE62FCDA1A1D26BB002B10DA /* page2.html in Resources */ = {isa = PBXBuildFile; fileRef = AE62FCD91A1D26BB002B10DA /* page2.html */; }; D927B9DC18F9DF2D00DAD036 /* TableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D927B9DB18F9DF2D00DAD036 /* TableViewController.m */; }; D927B9DF18F9E46400DAD036 /* UITableView-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D927B9DD18F9E46400DAD036 /* UITableView-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D927B9E018F9E46400DAD036 /* UITableView-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D927B9DE18F9E46400DAD036 /* UITableView-KIFAdditions.m */; }; - D927B9E118F9E47000DAD036 /* UITableView-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D927B9DD18F9E46400DAD036 /* UITableView-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D927B9E218F9E47600DAD036 /* UITableView-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D927B9DE18F9E46400DAD036 /* UITableView-KIFAdditions.m */; }; D9EA274118F05A6000D87E57 /* ScrollViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EA274018F05A6000D87E57 /* ScrollViewTests.m */; }; D9EA274318F05A6700D87E57 /* ScrollViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EA274218F05A6700D87E57 /* ScrollViewController.m */; }; - EA0F2547182979BE006FF825 /* CollectionViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EA0F2546182979BE006FF825 /* CollectionViewTests.m */; }; EA0F254A1829839E006FF825 /* CollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EA0F25491829839E006FF825 /* CollectionViewController.m */; }; EA4655881905B92500B2C60E /* PickerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CED883D181F5EE1005ABD20 /* PickerTests.m */; }; EA47DA2818EDFD6F0034D2F5 /* CollectionViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EA0F2546182979BE006FF825 /* CollectionViewTests.m */; }; @@ -85,17 +91,13 @@ EABD46D21857A24E00A5F081 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EABD46AB1857A0EB00A5F081 /* XCTest.framework */; }; EABD46D51857C54500A5F081 /* KIF-XCTestPrefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = EABD46D31857BE8600A5F081 /* KIF-XCTestPrefix.pch */; }; EABD46D61858C8ED00A5F081 /* libKIF.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EABD46AA1857A0C700A5F081 /* libKIF.a */; }; - EABD474B185F509E00A5F081 /* SenTestCase-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = EABD4749185F509E00A5F081 /* SenTestCase-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EABD474C185F509E00A5F081 /* SenTestCase-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = EABD474A185F509E00A5F081 /* SenTestCase-KIFAdditions.m */; }; EAC8096A1864F19C000E819F /* NSException-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = EAC809681864F19C000E819F /* NSException-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; EAC8096B1864F19C000E819F /* NSException-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = EAC809691864F19C000E819F /* NSException-KIFAdditions.m */; }; - EB02523E17AA109400A7D13A /* CompositionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB02523D17AA109400A7D13A /* CompositionTests.m */; }; - EB09001017E3696A00AA15B1 /* SearchFieldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB09000F17E3696A00AA15B1 /* SearchFieldTests.m */; }; - EB22B5B017AF52640090B848 /* CascadingFailureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB22B5AF17AF52640090B848 /* CascadingFailureTests.m */; }; + EB1A44D51A0C3268004A3F61 /* KIFUITestActor-IdentifierTests.h in Headers */ = {isa = PBXBuildFile; fileRef = EB1A44D31A0C3268004A3F61 /* KIFUITestActor-IdentifierTests.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EB1A44D61A0C3268004A3F61 /* KIFUITestActor-IdentifierTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB1A44D41A0C3268004A3F61 /* KIFUITestActor-IdentifierTests.m */; }; + EB1A44DA1A0C33AD004A3F61 /* AccessibilityIdentifierTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB1A44D91A0C33AD004A3F61 /* AccessibilityIdentifierTests.m */; }; EB2526481981BF7A00DBC747 /* KIFUITestActor-ConditionalTests.h in Headers */ = {isa = PBXBuildFile; fileRef = EB2526461981BF7A00DBC747 /* KIFUITestActor-ConditionalTests.h */; settings = {ATTRIBUTES = (Public, ); }; }; EB2526491981BF7A00DBC747 /* KIFUITestActor-ConditionalTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB2526471981BF7A00DBC747 /* KIFUITestActor-ConditionalTests.m */; }; - EB25264A1981BF8400DBC747 /* KIFUITestActor-ConditionalTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB2526471981BF7A00DBC747 /* KIFUITestActor-ConditionalTests.m */; }; - EB3F654517AA0B8400469D18 /* TableViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB3F654417AA0B8400469D18 /* TableViewTests.m */; }; EB60ECC2177F8C83005A041A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAB072B413971AEA008AF393 /* UIKit.framework */; }; EB60ECC3177F8C83005A041A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAB0726B139719AC008AF393 /* Foundation.framework */; }; EB60ECC5177F8C83005A041A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB60ECC4177F8C83005A041A /* CoreGraphics.framework */; }; @@ -104,66 +106,12 @@ EB60ECD3177F8C84005A041A /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = EB60ECD2177F8C84005A041A /* Default.png */; }; EB60ECD5177F8C84005A041A /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = EB60ECD4177F8C84005A041A /* Default@2x.png */; }; EB60ECD7177F8C84005A041A /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = EB60ECD6177F8C84005A041A /* Default-568h@2x.png */; }; - EB60ECEC177F8DB3005A041A /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB4C3138167BA3D200E31109 /* SenTestingKit.framework */; }; - EB60ECED177F8DB3005A041A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAB072B413971AEA008AF393 /* UIKit.framework */; }; - EB60ECEE177F8DB3005A041A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAB0726B139719AC008AF393 /* Foundation.framework */; }; - EB60ECF4177F8DB3005A041A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = EB60ECF2177F8DB3005A041A /* InfoPlist.strings */; }; EB60ED00177F9032005A041A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ECFC177F9031005A041A /* AppDelegate.m */; }; EB60ED01177F9032005A041A /* ShowHideViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ECFD177F9031005A041A /* ShowHideViewController.m */; }; EB60ED02177F9032005A041A /* TapViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ECFE177F9032005A041A /* TapViewController.m */; }; EB60ED03177F9032005A041A /* TestSuiteViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ECFF177F9032005A041A /* TestSuiteViewController.m */; }; EB60ED06177F9041005A041A /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EB60ED04177F9041005A041A /* MainStoryboard.storyboard */; }; - EB60ED10177F90BA005A041A /* LongPressTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ED07177F90BA005A041A /* LongPressTests.m */; }; - EB60ED11177F90BA005A041A /* ModalViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ED08177F90BA005A041A /* ModalViewTests.m */; }; - EB60ED12177F90BA005A041A /* SpecificControlTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ED09177F90BA005A041A /* SpecificControlTests.m */; }; - EB60ED13177F90BA005A041A /* SystemTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ED0A177F90BA005A041A /* SystemTests.m */; }; - EB60ED14177F90BA005A041A /* TappingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ED0B177F90BA005A041A /* TappingTests.m */; }; - EB60ED15177F90BA005A041A /* TypingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ED0C177F90BA005A041A /* TypingTests.m */; }; - EB60ED16177F90BA005A041A /* WaitForAbscenceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ED0D177F90BA005A041A /* WaitForAbscenceTests.m */; }; - EB60ED17177F90BA005A041A /* WaitForTappableViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ED0E177F90BA005A041A /* WaitForTappableViewTests.m */; }; - EB60ED18177F90BA005A041A /* WaitForViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ED0F177F90BA005A041A /* WaitForViewTests.m */; }; - EB60ED1A177F90C2005A041A /* GestureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ED19177F90C2005A041A /* GestureTests.m */; }; - EB60ED1B177F90EA005A041A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB60ECC4177F8C83005A041A /* CoreGraphics.framework */; }; - EB60ED1C177F90F0005A041A /* libKIF-OCUnit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EB72047C1680DDAD00278DA2 /* libKIF-OCUnit.a */; }; - EB7204431680DDAD00278DA2 /* CGGeometry-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB0729513971AB2008AF393 /* CGGeometry-KIFAdditions.m */; }; - EB7204441680DDAD00278DA2 /* UIAccessibilityElement-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB0729713971AB2008AF393 /* UIAccessibilityElement-KIFAdditions.m */; }; - EB7204451680DDAD00278DA2 /* UIApplication-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB0729913971AB2008AF393 /* UIApplication-KIFAdditions.m */; }; - EB7204461680DDAD00278DA2 /* UIScrollView-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB0729B13971AB2008AF393 /* UIScrollView-KIFAdditions.m */; }; - EB7204471680DDAD00278DA2 /* UITouch-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB0729D13971AB2008AF393 /* UITouch-KIFAdditions.m */; }; - EB7204481680DDAD00278DA2 /* UIView-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB072A113971AB2008AF393 /* UIView-KIFAdditions.m */; }; - EB7204491680DDAD00278DA2 /* UIWindow-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB072A313971AB2008AF393 /* UIWindow-KIFAdditions.m */; }; - EB72044A1680DDAD00278DA2 /* NSFileManager-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CDFD8E85139728B4008D299F /* NSFileManager-KIFAdditions.m */; }; - EB72044B1680DDAD00278DA2 /* KIFTypist.m in Sources */ = {isa = PBXBuildFile; fileRef = C194255715D83DE9004FC314 /* KIFTypist.m */; }; - EB72044C1680DDAD00278DA2 /* KIFTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = EB4C3124167BA37B00E31109 /* KIFTestActor.m */; }; - EB72044D1680DDAD00278DA2 /* KIFTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = EB4C3128167BA37B00E31109 /* KIFTestCase.m */; }; - EB72044E1680DDAD00278DA2 /* KIFSystemTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = EB4C3131167BA3AC00E31109 /* KIFSystemTestActor.m */; }; - EB72044F1680DDAD00278DA2 /* KIFUITestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = EB4C3133167BA3AC00E31109 /* KIFUITestActor.m */; }; - EB7204511680DDAD00278DA2 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB4C3138167BA3D200E31109 /* SenTestingKit.framework */; }; - EB7204521680DDAD00278DA2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAB0726B139719AC008AF393 /* Foundation.framework */; }; - EB7204531680DDAD00278DA2 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAB072B413971AEA008AF393 /* UIKit.framework */; }; - EB7204551680DDAD00278DA2 /* KIF-Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = AAB0728113971A63008AF393 /* KIF-Prefix.pch */; }; - EB7204591680DDAD00278DA2 /* CGGeometry-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = AAB0729413971AB2008AF393 /* CGGeometry-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EB72045A1680DDAD00278DA2 /* UIAccessibilityElement-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = AAB0729613971AB2008AF393 /* UIAccessibilityElement-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EB72045B1680DDAD00278DA2 /* UIApplication-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = AAB0729813971AB2008AF393 /* UIApplication-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EB72045C1680DDAD00278DA2 /* UIScrollView-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = AAB0729A13971AB2008AF393 /* UIScrollView-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EB72045D1680DDAD00278DA2 /* UITouch-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = AAB0729C13971AB2008AF393 /* UITouch-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EB72045E1680DDAD00278DA2 /* UIView-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = AAB072A013971AB2008AF393 /* UIView-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EB72045F1680DDAD00278DA2 /* UIWindow-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = AAB072A213971AB2008AF393 /* UIWindow-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EB7204601680DDAD00278DA2 /* NSFileManager-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = CDFD8E84139728B4008D299F /* NSFileManager-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EB7204611680DDAD00278DA2 /* LoadableCategory.h in Headers */ = {isa = PBXBuildFile; fileRef = 39160B1013D1E6BB00311E38 /* LoadableCategory.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EB7204621680DDAD00278DA2 /* KIFTypist.h in Headers */ = {isa = PBXBuildFile; fileRef = C194255615D83DE9004FC314 /* KIFTypist.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EB7204631680DDAD00278DA2 /* KIFTestActor.h in Headers */ = {isa = PBXBuildFile; fileRef = EB4C3123167BA37B00E31109 /* KIFTestActor.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EB7204641680DDAD00278DA2 /* KIFTestCase.h in Headers */ = {isa = PBXBuildFile; fileRef = EB4C3127167BA37B00E31109 /* KIFTestCase.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EB7204651680DDAD00278DA2 /* KIFSystemTestActor.h in Headers */ = {isa = PBXBuildFile; fileRef = EB4C3130167BA3AC00E31109 /* KIFSystemTestActor.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EB7204661680DDAD00278DA2 /* KIFUITestActor.h in Headers */ = {isa = PBXBuildFile; fileRef = EB4C3132167BA3AC00E31109 /* KIFUITestActor.h */; settings = {ATTRIBUTES = (Public, ); }; }; EB9FB42717A5BACB00DDF160 /* GestureViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9FB42617A5BACB00DDF160 /* GestureViewController.m */; }; - EB9FC00517E144B700138266 /* LandscapeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9FC00417E144B700138266 /* LandscapeTests.m */; }; - EBAE487C17A45A8E0005EE19 /* NSBundle-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = EBAE487A17A45A8E0005EE19 /* NSBundle-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EBAE487D17A45A8E0005EE19 /* NSBundle-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = EBAE487B17A45A8E0005EE19 /* NSBundle-KIFAdditions.m */; }; - EBAE488117A460E50005EE19 /* NSError-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = EBAE487F17A460E50005EE19 /* NSError-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EBAE488217A460E50005EE19 /* NSError-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = EBAE488017A460E50005EE19 /* NSError-KIFAdditions.m */; }; - EBAE488717A4E5C30005EE19 /* KIFTestStepValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = EBAE488517A4E5C30005EE19 /* KIFTestStepValidation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EBAE488817A4E5C30005EE19 /* KIFTestStepValidation.m in Sources */ = {isa = PBXBuildFile; fileRef = EBAE488617A4E5C30005EE19 /* KIFTestStepValidation.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -174,21 +122,22 @@ remoteGlobalIDString = EB60ECC0177F8C83005A041A; remoteInfo = "Test Host"; }; - EB8C0CEC1780CBF5000DBC0B /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = AAB0725F139719AC008AF393 /* Project object */; - proxyType = 1; - remoteGlobalIDString = EB60ECC0177F8C83005A041A; - remoteInfo = "Test Host"; - }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 2CDEE1CA181DBED200DF6E63 /* PickerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PickerController.m; sourceTree = ""; }; 2CED883D181F5EE1005ABD20 /* PickerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PickerTests.m; sourceTree = ""; }; 2EE1270F198991920031D347 /* MultiFingerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MultiFingerTests.m; sourceTree = ""; }; + 3812FB601A1212A700335733 /* AnimationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AnimationViewController.m; sourceTree = ""; }; + 3812FB621A12188700335733 /* WaitForAnimationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WaitForAnimationTests.m; sourceTree = ""; }; 39160B1013D1E6BB00311E38 /* LoadableCategory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadableCategory.h; sourceTree = ""; }; 4A48107A19708CAB0003A32E /* ExistTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExistTests.m; sourceTree = ""; }; + 84D293AC1A2C84F700C10944 /* SystemAlertViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SystemAlertViewController.m; sourceTree = ""; }; + 84D293AE1A2C867300C10944 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; + 84D293B01A2C891700C10944 /* SystemAlertTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SystemAlertTests.m; sourceTree = ""; }; + 84D293B71A2C8DF700C10944 /* AddressBookUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBookUI.framework; path = System/Library/Frameworks/AddressBookUI.framework; sourceTree = SDKROOT; }; + 84D293B91A2CC30B00C10944 /* UIAutomationHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIAutomationHelper.h; sourceTree = ""; }; + 84D293BA1A2CC30B00C10944 /* UIAutomationHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIAutomationHelper.m; sourceTree = ""; }; A88930111685098E00FC7C63 /* KIF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KIF.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; AAB0726B139719AC008AF393 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; AAB0728113971A63008AF393 /* KIF-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "KIF-Prefix.pch"; path = "Classes/KIF-Prefix.pch"; sourceTree = SOURCE_ROOT; }; @@ -208,6 +157,10 @@ AAB072A213971AB2008AF393 /* UIWindow-KIFAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIWindow-KIFAdditions.h"; sourceTree = ""; }; AAB072A313971AB2008AF393 /* UIWindow-KIFAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIWindow-KIFAdditions.m"; sourceTree = ""; }; AAB072B413971AEA008AF393 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + AE62FCCF1A1D20E5002B10DA /* WebViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewTests.m; sourceTree = ""; }; + AE62FCD51A1D2447002B10DA /* WebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewController.m; sourceTree = ""; }; + AE62FCD71A1D2667002B10DA /* index.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = index.html; sourceTree = ""; }; + AE62FCD91A1D26BB002B10DA /* page2.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = page2.html; sourceTree = ""; }; C194255615D83DE9004FC314 /* KIFTypist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KIFTypist.h; sourceTree = ""; }; C194255715D83DE9004FC314 /* KIFTypist.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KIFTypist.m; sourceTree = ""; }; CDFD8E84139728B4008D299F /* NSFileManager-KIFAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSFileManager-KIFAdditions.h"; sourceTree = ""; }; @@ -232,6 +185,9 @@ EAC809691864F19C000E819F /* NSException-KIFAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSException-KIFAdditions.m"; sourceTree = ""; }; EB02523D17AA109400A7D13A /* CompositionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CompositionTests.m; sourceTree = ""; }; EB09000F17E3696A00AA15B1 /* SearchFieldTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchFieldTests.m; sourceTree = ""; }; + EB1A44D31A0C3268004A3F61 /* KIFUITestActor-IdentifierTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "KIFUITestActor-IdentifierTests.h"; path = "IdentifierTests/KIFUITestActor-IdentifierTests.h"; sourceTree = ""; }; + EB1A44D41A0C3268004A3F61 /* KIFUITestActor-IdentifierTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "KIFUITestActor-IdentifierTests.m"; path = "IdentifierTests/KIFUITestActor-IdentifierTests.m"; sourceTree = ""; }; + EB1A44D91A0C33AD004A3F61 /* AccessibilityIdentifierTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AccessibilityIdentifierTests.m; sourceTree = ""; }; EB22B5AF17AF52640090B848 /* CascadingFailureTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CascadingFailureTests.m; sourceTree = ""; }; EB2526461981BF7A00DBC747 /* KIFUITestActor-ConditionalTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "KIFUITestActor-ConditionalTests.h"; sourceTree = ""; }; EB2526471981BF7A00DBC747 /* KIFUITestActor-ConditionalTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "KIFUITestActor-ConditionalTests.m"; sourceTree = ""; }; @@ -254,7 +210,6 @@ EB60ECD2177F8C84005A041A /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; EB60ECD4177F8C84005A041A /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; EB60ECD6177F8C84005A041A /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; - EB60ECEB177F8DB3005A041A /* KIF Tests-OCUnit.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "KIF Tests-OCUnit.octest"; sourceTree = BUILT_PRODUCTS_DIR; }; EB60ECF1177F8DB3005A041A /* KIF Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "KIF Tests-Info.plist"; sourceTree = ""; }; EB60ECF3177F8DB3005A041A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; EB60ECF8177F8DB3005A041A /* KIF Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "KIF Tests-Prefix.pch"; sourceTree = ""; }; @@ -273,7 +228,6 @@ EB60ED0E177F90BA005A041A /* WaitForTappableViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WaitForTappableViewTests.m; sourceTree = ""; }; EB60ED0F177F90BA005A041A /* WaitForViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WaitForViewTests.m; sourceTree = ""; }; EB60ED19177F90C2005A041A /* GestureTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GestureTests.m; sourceTree = ""; }; - EB72047C1680DDAD00278DA2 /* libKIF-OCUnit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libKIF-OCUnit.a"; sourceTree = BUILT_PRODUCTS_DIR; }; EB9FB42617A5BACB00DDF160 /* GestureViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GestureViewController.m; sourceTree = ""; }; EB9FC00417E144B700138266 /* LandscapeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LandscapeTests.m; sourceTree = ""; }; EBAE487A17A45A8E0005EE19 /* NSBundle-KIFAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle-KIFAdditions.h"; sourceTree = ""; }; @@ -314,28 +268,8 @@ EB60ECC2177F8C83005A041A /* UIKit.framework in Frameworks */, EB60ECC3177F8C83005A041A /* Foundation.framework in Frameworks */, EB60ECC5177F8C83005A041A /* CoreGraphics.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EB60ECE7177F8DB3005A041A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - EB60ED1C177F90F0005A041A /* libKIF-OCUnit.a in Frameworks */, - EB60ECEC177F8DB3005A041A /* SenTestingKit.framework in Frameworks */, - EB60ECED177F8DB3005A041A /* UIKit.framework in Frameworks */, - EB60ECEE177F8DB3005A041A /* Foundation.framework in Frameworks */, - EB60ED1B177F90EA005A041A /* CoreGraphics.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EB7204501680DDAD00278DA2 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - EB7204511680DDAD00278DA2 /* SenTestingKit.framework in Frameworks */, - EB7204521680DDAD00278DA2 /* Foundation.framework in Frameworks */, - EB7204531680DDAD00278DA2 /* UIKit.framework in Frameworks */, + 84D293AF1A2C867300C10944 /* CoreLocation.framework in Frameworks */, + 84D293B81A2C8DF700C10944 /* AddressBookUI.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -356,9 +290,7 @@ AAB07269139719AC008AF393 /* Products */ = { isa = PBXGroup; children = ( - EB72047C1680DDAD00278DA2 /* libKIF-OCUnit.a */, EB60ECC1177F8C83005A041A /* Test Host.app */, - EB60ECEB177F8DB3005A041A /* KIF Tests-OCUnit.octest */, EABD46AA1857A0C700A5F081 /* libKIF.a */, EABD46CD1857A0F300A5F081 /* KIF Tests - XCTest.xctest */, ); @@ -368,6 +300,8 @@ AAB0726A139719AC008AF393 /* Frameworks */ = { isa = PBXGroup; children = ( + 84D293B71A2C8DF700C10944 /* AddressBookUI.framework */, + 84D293AE1A2C867300C10944 /* CoreLocation.framework */, EABD46AB1857A0EB00A5F081 /* XCTest.framework */, EB4C3138167BA3D200E31109 /* SenTestingKit.framework */, AAB072B413971AEA008AF393 /* UIKit.framework */, @@ -401,6 +335,8 @@ EBAE488517A4E5C30005EE19 /* KIFTestStepValidation.h */, EBAE488617A4E5C30005EE19 /* KIFTestStepValidation.m */, EABD46D31857BE8600A5F081 /* KIF-XCTestPrefix.pch */, + 84D293B91A2CC30B00C10944 /* UIAutomationHelper.h */, + 84D293BA1A2CC30B00C10944 /* UIAutomationHelper.m */, ); path = Classes; sourceTree = ""; @@ -441,6 +377,15 @@ path = Additions; sourceTree = ""; }; + EB1A44D21A0C3222004A3F61 /* Identifier Tests */ = { + isa = PBXGroup; + children = ( + EB1A44D31A0C3268004A3F61 /* KIFUITestActor-IdentifierTests.h */, + EB1A44D41A0C3268004A3F61 /* KIFUITestActor-IdentifierTests.m */, + ); + name = "Identifier Tests"; + sourceTree = ""; + }; EB4C312F167BA39200E31109 /* Actors */ = { isa = PBXGroup; children = ( @@ -459,6 +404,7 @@ children = ( AAB0729313971AB2008AF393 /* Additions */, AAB0728413971A98008AF393 /* Classes */, + EB1A44D21A0C3222004A3F61 /* Identifier Tests */, AAB0726E139719AC008AF393 /* Supporting Files */, ); name = KIF; @@ -467,6 +413,7 @@ EB60ECC6177F8C83005A041A /* Test Host */ = { isa = PBXGroup; children = ( + 3812FB601A1212A700335733 /* AnimationViewController.m */, 2CDEE1CA181DBED200DF6E63 /* PickerController.m */, EB60ED04177F9041005A041A /* MainStoryboard.storyboard */, EB60ECFC177F9031005A041A /* AppDelegate.m */, @@ -477,6 +424,8 @@ EA0F25491829839E006FF825 /* CollectionViewController.m */, D9EA274218F05A6700D87E57 /* ScrollViewController.m */, D927B9DB18F9DF2D00DAD036 /* TableViewController.m */, + AE62FCD51A1D2447002B10DA /* WebViewController.m */, + 84D293AC1A2C84F700C10944 /* SystemAlertViewController.m */, EB60ECC7177F8C83005A041A /* Supporting Files */, ); path = "Test Host"; @@ -492,6 +441,8 @@ EB60ECD2177F8C84005A041A /* Default.png */, EB60ECD4177F8C84005A041A /* Default@2x.png */, EB60ECD6177F8C84005A041A /* Default-568h@2x.png */, + AE62FCD71A1D2667002B10DA /* index.html */, + AE62FCD91A1D26BB002B10DA /* page2.html */, ); name = "Supporting Files"; sourceTree = ""; @@ -501,6 +452,7 @@ children = ( 2CED883D181F5EE1005ABD20 /* PickerTests.m */, EB60ED19177F90C2005A041A /* GestureTests.m */, + 3812FB621A12188700335733 /* WaitForAnimationTests.m */, EB60ED07177F90BA005A041A /* LongPressTests.m */, EB60ED08177F90BA005A041A /* ModalViewTests.m */, EB60ED09177F90BA005A041A /* SpecificControlTests.m */, @@ -519,6 +471,9 @@ EB9FC00417E144B700138266 /* LandscapeTests.m */, EB09000F17E3696A00AA15B1 /* SearchFieldTests.m */, 2EE1270F198991920031D347 /* MultiFingerTests.m */, + EB1A44D91A0C33AD004A3F61 /* AccessibilityIdentifierTests.m */, + AE62FCCF1A1D20E5002B10DA /* WebViewTests.m */, + 84D293B01A2C891700C10944 /* SystemAlertTests.m */, EB60ECF0177F8DB3005A041A /* Supporting Files */, ); path = "KIF Tests"; @@ -542,11 +497,13 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + EB1A44D51A0C3268004A3F61 /* KIFUITestActor-IdentifierTests.h in Headers */, EABD46911857A0C700A5F081 /* KIF.h in Headers */, D927B9DF18F9E46400DAD036 /* UITableView-KIFAdditions.h in Headers */, EABD46921857A0C700A5F081 /* CGGeometry-KIFAdditions.h in Headers */, EABD46931857A0C700A5F081 /* UIAccessibilityElement-KIFAdditions.h in Headers */, EABD46941857A0C700A5F081 /* UIApplication-KIFAdditions.h in Headers */, + 84D293BB1A2CC30B00C10944 /* UIAutomationHelper.h in Headers */, EABD46951857A0C700A5F081 /* UIScrollView-KIFAdditions.h in Headers */, EABD46971857A0C700A5F081 /* UITouch-KIFAdditions.h in Headers */, EABD46981857A0C700A5F081 /* UIView-KIFAdditions.h in Headers */, @@ -568,34 +525,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - EB7204541680DDAD00278DA2 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - A88930121685098E00FC7C63 /* KIF.h in Headers */, - EB7204591680DDAD00278DA2 /* CGGeometry-KIFAdditions.h in Headers */, - EB72045A1680DDAD00278DA2 /* UIAccessibilityElement-KIFAdditions.h in Headers */, - EB72045B1680DDAD00278DA2 /* UIApplication-KIFAdditions.h in Headers */, - EB72045C1680DDAD00278DA2 /* UIScrollView-KIFAdditions.h in Headers */, - EB72045D1680DDAD00278DA2 /* UITouch-KIFAdditions.h in Headers */, - EB72045E1680DDAD00278DA2 /* UIView-KIFAdditions.h in Headers */, - EB72045F1680DDAD00278DA2 /* UIWindow-KIFAdditions.h in Headers */, - EB7204601680DDAD00278DA2 /* NSFileManager-KIFAdditions.h in Headers */, - EB7204611680DDAD00278DA2 /* LoadableCategory.h in Headers */, - EB7204621680DDAD00278DA2 /* KIFTypist.h in Headers */, - EB7204631680DDAD00278DA2 /* KIFTestActor.h in Headers */, - EB7204641680DDAD00278DA2 /* KIFTestCase.h in Headers */, - EB7204651680DDAD00278DA2 /* KIFSystemTestActor.h in Headers */, - EB7204661680DDAD00278DA2 /* KIFUITestActor.h in Headers */, - EBAE487C17A45A8E0005EE19 /* NSBundle-KIFAdditions.h in Headers */, - EBAE488117A460E50005EE19 /* NSError-KIFAdditions.h in Headers */, - D927B9E118F9E47000DAD036 /* UITableView-KIFAdditions.h in Headers */, - EABD474B185F509E00A5F081 /* SenTestCase-KIFAdditions.h in Headers */, - EBAE488717A4E5C30005EE19 /* KIFTestStepValidation.h in Headers */, - EB7204551680DDAD00278DA2 /* KIF-Prefix.pch in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXHeadersBuildPhase section */ /* Begin PBXLegacyTarget section */ @@ -669,49 +598,13 @@ productReference = EB60ECC1177F8C83005A041A /* Test Host.app */; productType = "com.apple.product-type.application"; }; - EB60ECEA177F8DB3005A041A /* KIF Tests-OCUnit */ = { - isa = PBXNativeTarget; - buildConfigurationList = EB60ECF9177F8DB3005A041A /* Build configuration list for PBXNativeTarget "KIF Tests-OCUnit" */; - buildPhases = ( - EB60ECE6177F8DB3005A041A /* Sources */, - EB60ECE7177F8DB3005A041A /* Frameworks */, - EB60ECE8177F8DB3005A041A /* Resources */, - EB60ECE9177F8DB3005A041A /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - EB8C0CED1780CBF5000DBC0B /* PBXTargetDependency */, - ); - name = "KIF Tests-OCUnit"; - productName = "KIF Tests"; - productReference = EB60ECEB177F8DB3005A041A /* KIF Tests-OCUnit.octest */; - productType = "com.apple.product-type.bundle.ocunit-test"; - }; - EB72043E1680DDAD00278DA2 /* KIF-OCUnit */ = { - isa = PBXNativeTarget; - buildConfigurationList = EB7204791680DDAD00278DA2 /* Build configuration list for PBXNativeTarget "KIF-OCUnit" */; - buildPhases = ( - EB72043F1680DDAD00278DA2 /* Sources */, - EB7204501680DDAD00278DA2 /* Frameworks */, - EB7204541680DDAD00278DA2 /* Headers */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "KIF-OCUnit"; - productName = KIFTestCase; - productReference = EB72047C1680DDAD00278DA2 /* libKIF-OCUnit.a */; - productType = "com.apple.product-type.library.static"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ AAB0725F139719AC008AF393 /* Project object */ = { isa = PBXProject; attributes = { - LastTestingUpgradeCheck = 0600; + LastTestingUpgradeCheck = 0610; LastUpgradeCheck = 0510; }; buildConfigurationList = AAB07262139719AC008AF393 /* Build configuration list for PBXProject "KIF" */; @@ -727,11 +620,9 @@ projectRoot = ""; targets = ( EABD46791857A0C700A5F081 /* KIF */, - EB72043E1680DDAD00278DA2 /* KIF-OCUnit */, A88930091685088F00FC7C63 /* KIF Documentation */, EB60ECC0177F8C83005A041A /* Test Host */, EABD46AD1857A0F300A5F081 /* KIF Tests */, - EB60ECEA177F8DB3005A041A /* KIF Tests-OCUnit */, ); }; /* End PBXProject section */ @@ -752,16 +643,10 @@ EB60ECCB177F8C84005A041A /* InfoPlist.strings in Resources */, EB60ECD3177F8C84005A041A /* Default.png in Resources */, EB60ECD5177F8C84005A041A /* Default@2x.png in Resources */, + AE62FCD81A1D2667002B10DA /* index.html in Resources */, EB60ECD7177F8C84005A041A /* Default-568h@2x.png in Resources */, EB60ED06177F9041005A041A /* MainStoryboard.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EB60ECE8177F8DB3005A041A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - EB60ECF4177F8DB3005A041A /* InfoPlist.strings in Resources */, + AE62FCDA1A1D26BB002B10DA /* page2.html in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -781,19 +666,6 @@ shellPath = /bin/sh; shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; }; - EB60ECE9177F8DB3005A041A /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -803,6 +675,7 @@ files = ( EABD467B1857A0C700A5F081 /* CGGeometry-KIFAdditions.m in Sources */, EABD467C1857A0C700A5F081 /* UIAccessibilityElement-KIFAdditions.m in Sources */, + 84D293BD1A2CC30B00C10944 /* UIAutomationHelper.m in Sources */, EABD467D1857A0C700A5F081 /* UIApplication-KIFAdditions.m in Sources */, EABD467E1857A0C700A5F081 /* UIScrollView-KIFAdditions.m in Sources */, EABD467F1857A0C700A5F081 /* UITouch-KIFAdditions.m in Sources */, @@ -814,6 +687,7 @@ EABD46841857A0C700A5F081 /* KIFTestActor.m in Sources */, EABD46851857A0C700A5F081 /* KIFTestCase.m in Sources */, EABD46861857A0C700A5F081 /* XCTestCase-KIFAdditions.m in Sources */, + EB1A44D61A0C3268004A3F61 /* KIFUITestActor-IdentifierTests.m in Sources */, EB2526491981BF7A00DBC747 /* KIFUITestActor-ConditionalTests.m in Sources */, EABD46871857A0C700A5F081 /* KIFSystemTestActor.m in Sources */, EAC8096B1864F19C000E819F /* NSException-KIFAdditions.m in Sources */, @@ -833,6 +707,8 @@ EABD46B31857A0F300A5F081 /* CompositionTests.m in Sources */, 4A48107B19708CAB0003A32E /* ExistTests.m in Sources */, EA4655881905B92500B2C60E /* PickerTests.m in Sources */, + 3812FB631A12188700335733 /* WaitForAnimationTests.m in Sources */, + EB1A44DA1A0C33AD004A3F61 /* AccessibilityIdentifierTests.m in Sources */, EABD46B41857A0F300A5F081 /* LongPressTests.m in Sources */, EABD46B51857A0F300A5F081 /* ModalViewTests.m in Sources */, EABD46B61857A0F300A5F081 /* SpecificControlTests.m in Sources */, @@ -848,6 +724,8 @@ EABD46BF1857A0F300A5F081 /* GestureTests.m in Sources */, 2EE12710198991920031D347 /* MultiFingerTests.m in Sources */, D9EA274118F05A6000D87E57 /* ScrollViewTests.m in Sources */, + AE62FCD01A1D20E5002B10DA /* WebViewTests.m in Sources */, + 84D293B11A2C891700C10944 /* SystemAlertTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -857,6 +735,8 @@ files = ( EB9FB42717A5BACB00DDF160 /* GestureViewController.m in Sources */, EA0F254A1829839E006FF825 /* CollectionViewController.m in Sources */, + 84D293AD1A2C84F700C10944 /* SystemAlertViewController.m in Sources */, + AE62FCD61A1D2447002B10DA /* WebViewController.m in Sources */, EB60ECCD177F8C84005A041A /* main.m in Sources */, EB60ED00177F9032005A041A /* AppDelegate.m in Sources */, D927B9DC18F9DF2D00DAD036 /* TableViewController.m in Sources */, @@ -865,57 +745,7 @@ 2CDEE1CB181DBED200DF6E63 /* PickerController.m in Sources */, EB60ED03177F9032005A041A /* TestSuiteViewController.m in Sources */, D9EA274318F05A6700D87E57 /* ScrollViewController.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EB60ECE6177F8DB3005A041A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2EE12711198991920031D347 /* MultiFingerTests.m in Sources */, - EB09001017E3696A00AA15B1 /* SearchFieldTests.m in Sources */, - EB22B5B017AF52640090B848 /* CascadingFailureTests.m in Sources */, - EB02523E17AA109400A7D13A /* CompositionTests.m in Sources */, - EB60ED10177F90BA005A041A /* LongPressTests.m in Sources */, - EB60ED11177F90BA005A041A /* ModalViewTests.m in Sources */, - EB60ED12177F90BA005A041A /* SpecificControlTests.m in Sources */, - EB60ED13177F90BA005A041A /* SystemTests.m in Sources */, - EB60ED14177F90BA005A041A /* TappingTests.m in Sources */, - 2CED883E181F5EE1005ABD20 /* PickerTests.m in Sources */, - EB60ED15177F90BA005A041A /* TypingTests.m in Sources */, - EB60ED16177F90BA005A041A /* WaitForAbscenceTests.m in Sources */, - EA0F2547182979BE006FF825 /* CollectionViewTests.m in Sources */, - EB60ED17177F90BA005A041A /* WaitForTappableViewTests.m in Sources */, - EB60ED18177F90BA005A041A /* WaitForViewTests.m in Sources */, - EB9FC00517E144B700138266 /* LandscapeTests.m in Sources */, - EB3F654517AA0B8400469D18 /* TableViewTests.m in Sources */, - EB60ED1A177F90C2005A041A /* GestureTests.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EB72043F1680DDAD00278DA2 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - EB7204431680DDAD00278DA2 /* CGGeometry-KIFAdditions.m in Sources */, - EB7204441680DDAD00278DA2 /* UIAccessibilityElement-KIFAdditions.m in Sources */, - EB7204451680DDAD00278DA2 /* UIApplication-KIFAdditions.m in Sources */, - EB7204461680DDAD00278DA2 /* UIScrollView-KIFAdditions.m in Sources */, - EB7204471680DDAD00278DA2 /* UITouch-KIFAdditions.m in Sources */, - EB7204481680DDAD00278DA2 /* UIView-KIFAdditions.m in Sources */, - D927B9E218F9E47600DAD036 /* UITableView-KIFAdditions.m in Sources */, - EB7204491680DDAD00278DA2 /* UIWindow-KIFAdditions.m in Sources */, - EB72044A1680DDAD00278DA2 /* NSFileManager-KIFAdditions.m in Sources */, - EB72044B1680DDAD00278DA2 /* KIFTypist.m in Sources */, - EB25264A1981BF8400DBC747 /* KIFUITestActor-ConditionalTests.m in Sources */, - EB72044C1680DDAD00278DA2 /* KIFTestActor.m in Sources */, - EB72044D1680DDAD00278DA2 /* KIFTestCase.m in Sources */, - EB72044E1680DDAD00278DA2 /* KIFSystemTestActor.m in Sources */, - EB72044F1680DDAD00278DA2 /* KIFUITestActor.m in Sources */, - EBAE487D17A45A8E0005EE19 /* NSBundle-KIFAdditions.m in Sources */, - EBAE488217A460E50005EE19 /* NSError-KIFAdditions.m in Sources */, - EBAE488817A4E5C30005EE19 /* KIFTestStepValidation.m in Sources */, - EABD474C185F509E00A5F081 /* SenTestCase-KIFAdditions.m in Sources */, + 3812FB611A1212A700335733 /* AnimationViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -927,11 +757,6 @@ target = EB60ECC0177F8C83005A041A /* Test Host */; targetProxy = EABD46AF1857A0F300A5F081 /* PBXContainerItemProxy */; }; - EB8C0CED1780CBF5000DBC0B /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = EB60ECC0177F8C83005A041A /* Test Host */; - targetProxy = EB8C0CEC1780CBF5000DBC0B /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -1272,97 +1097,6 @@ }; name = Release; }; - EB60ECFA177F8DB3005A041A /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Test Host.app/Test Host"; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - FRAMEWORK_SEARCH_PATHS = "\"$(SDKROOT)/Developer/Library/Frameworks\""; - GCC_DYNAMIC_NO_PIC = NO; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "KIF Tests/KIF Tests-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_UNINITIALIZED_AUTOS = YES; - INFOPLIST_FILE = "KIF Tests/KIF Tests-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.1; - ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUNDLE_LOADER)"; - WRAPPER_EXTENSION = octest; - }; - name = Debug; - }; - EB60ECFB177F8DB3005A041A /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Test Host.app/Test Host"; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = YES; - FRAMEWORK_SEARCH_PATHS = "\"$(SDKROOT)/Developer/Library/Frameworks\""; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "KIF Tests/KIF Tests-Prefix.pch"; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - INFOPLIST_FILE = "KIF Tests/KIF Tests-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.1; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUNDLE_LOADER)"; - VALIDATE_PRODUCT = YES; - WRAPPER_EXTENSION = octest; - }; - name = Release; - }; - EB72047A1680DDAD00278DA2 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ENABLE_OBJC_ARC = YES; - DSTROOT = /tmp/KIF.dst; - FRAMEWORK_SEARCH_PATHS = "\"$(SDKROOT)/Developer/Library/Frameworks\""; - GCC_PREFIX_HEADER = "Classes/KIF-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - DEBUG, - "KIF_SENTEST=1", - ); - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "KIF-OCUnit"; - }; - name = Debug; - }; - EB72047B1680DDAD00278DA2 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ENABLE_OBJC_ARC = YES; - DSTROOT = /tmp/KIF.dst; - FRAMEWORK_SEARCH_PATHS = "\"$(SDKROOT)/Developer/Library/Frameworks\""; - GCC_PREFIX_HEADER = "Classes/KIF-Prefix.pch"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "KIF-OCUnit"; - }; - name = Release; - }; EBAE48FF17A5B1380005EE19 /* Coverage */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1386,23 +1120,6 @@ }; name = Coverage; }; - EBAE490017A5B1380005EE19 /* Coverage */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ENABLE_OBJC_ARC = YES; - DSTROOT = /tmp/KIF.dst; - FRAMEWORK_SEARCH_PATHS = "\"$(SDKROOT)/Developer/Library/Frameworks\""; - GCC_PREFIX_HEADER = "Classes/KIF-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - DEBUG, - "KIF_SENTEST=1", - ); - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "KIF-OCUnit"; - }; - name = Coverage; - }; EBAE490117A5B1380005EE19 /* Coverage */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1464,40 +1181,6 @@ }; name = Coverage; }; - EBAE490317A5B1380005EE19 /* Coverage */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Test Host.app/Test Host"; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - FRAMEWORK_SEARCH_PATHS = "\"$(SDKROOT)/Developer/Library/Frameworks\""; - GCC_DYNAMIC_NO_PIC = NO; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "KIF Tests/KIF Tests-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - "KIF_SENTEST=1", - ); - GCC_WARN_UNINITIALIZED_AUTOS = YES; - INFOPLIST_FILE = "KIF Tests/KIF Tests-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.1; - ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUNDLE_LOADER)"; - WRAPPER_EXTENSION = octest; - }; - name = Coverage; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1551,26 +1234,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - EB60ECF9177F8DB3005A041A /* Build configuration list for PBXNativeTarget "KIF Tests-OCUnit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - EB60ECFA177F8DB3005A041A /* Debug */, - EBAE490317A5B1380005EE19 /* Coverage */, - EB60ECFB177F8DB3005A041A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - EB7204791680DDAD00278DA2 /* Build configuration list for PBXNativeTarget "KIF-OCUnit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - EB72047A1680DDAD00278DA2 /* Debug */, - EBAE490017A5B1380005EE19 /* Coverage */, - EB72047B1680DDAD00278DA2 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ }; rootObject = AAB0725F139719AC008AF393 /* Project object */; diff --git a/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/KIF Documentation.xcscheme b/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/KIF Documentation.xcscheme old mode 100644 new mode 100755 index 0561205a6..bcf70aa62 --- a/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/KIF Documentation.xcscheme +++ b/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/KIF Documentation.xcscheme @@ -1,6 +1,6 @@ - - - - @@ -57,15 +48,6 @@ useCustomWorkingDirectory = "NO" buildConfiguration = "Release" debugDocumentVersioning = "YES"> - - - - diff --git a/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/KIF-OCUnit.xcscheme b/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/KIF-OCUnit.xcscheme old mode 100644 new mode 100755 index c362db5fc..a530f4368 --- a/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/KIF-OCUnit.xcscheme +++ b/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/KIF-OCUnit.xcscheme @@ -1,6 +1,6 @@ + buildConfiguration = "Coverage"> + + + + - - - - @@ -57,15 +58,6 @@ useCustomWorkingDirectory = "NO" buildConfiguration = "Release" debugDocumentVersioning = "YES"> - - - - diff --git a/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/KIF.xcscheme b/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/KIF.xcscheme old mode 100644 new mode 100755 index 6b646b1ea..088aafe7a --- a/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/KIF.xcscheme +++ b/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/KIF.xcscheme @@ -1,6 +1,6 @@ + buildConfiguration = "Coverage"> + + + + - - - - @@ -57,15 +58,6 @@ useCustomWorkingDirectory = "NO" buildConfiguration = "Release" debugDocumentVersioning = "YES"> - - - - diff --git a/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/Test Host.xcscheme b/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/Test Host.xcscheme deleted file mode 100644 index fe000b8b6..000000000 --- a/tests/KIF/KIF.xcodeproj/xcshareddata/xcschemes/Test Host.xcscheme +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/KIF/README.md b/tests/KIF/README.md index 13467b246..4b1fb3236 100755 --- a/tests/KIF/README.md +++ b/tests/KIF/README.md @@ -21,7 +21,7 @@ All of the tests for KIF are written in Objective C. This allows for maximum int KIF integrates directly into your Xcode project, so there's no need to run an additional web server or install any additional packages. #### Wide OS coverage -KIF's test suite has been run against iOS 5.1 and above (including iOS 7), though lower versions will likely work. +KIF's test suite has been run against iOS 5.1 and above (including iOS 8), though lower versions will likely work. #### Test Like a User KIF attempts to imitate actual user input. Automation is done using tap events wherever possible. @@ -49,7 +49,7 @@ Once your test target set up, add the following to your Podfile file. Use your t ```Ruby target 'Acceptance Tests', :exclusive => true do - pod 'KIF', '~> 3.0' + pod 'KIF', '~> 3.0', :configurations => ['Debug'] end ``` @@ -68,9 +68,12 @@ end Installation (from GitHub) -------------------------- -To install KIF, you'll need to link the libKIF static library directly into your application. Download the source from the [kif-framework/KIF](https://github.com/kif-framework/KIF/) and follow the instructions below. +To install KIF, you'll need to link the libKIF static library directly into your application. Download the source from the [kif-framework/KIF](https://github.com/kif-framework/KIF/) and follow the instructions below. The screenshots are from Xcode 6 on Yosemite, but the instructions should be the same for Xcode 5 or later on any OS version. + +We'll be using a simple project as an example, and you can find it in `Documentation/Examples/Testable Swift` in this repository. + +![Simple App](https://github.com/kif-framework/KIF/raw/master/Documentation/Images/Simple App.png) -*NOTE* These instruction assume you are using Xcode 4 or later. For Xcode 3 you won't be able to take advantage of Workspaces, so the instructions will differ slightly. ### Add KIF to your project files The first step is to add the KIF project into the ./Frameworks/KIF subdirectory of your existing app. If your project uses Git for version control, you can use submodules to make updating in the future easier: @@ -81,17 +84,18 @@ mkdir Frameworks git submodule add https://github.com/kif-framework/KIF.git Frameworks/KIF ``` -If you're not using Git, simply download the source and copy it into the ./Frameworks/KIF directory. +If you're not using Git, simply download the source and copy it into the `./Frameworks/KIF` directory. ### Add KIF to Your Workspace -Let your project know about KIF by adding the KIF project into a workspace along with your main project. Find the KIF.xcodeproj file in Finder and drag it into the Project Navigator (⌘1). If you don't already have a workspace, Xcode will ask if you want to create a new one. Click "Save" when it does. +Let your project know about KIF by adding the KIF project into a workspace along with your main project. Find the `KIF.xcodeproj` file in Finder and drag it into the Project Navigator (⌘1). + +![Added KIF to the project](https://github.com/kif-framework/KIF/raw/master/Documentation/Images/Added KIF to Project.png) -![Create workspace screen shot](https://github.com/kif-framework/KIF/raw/master/Documentation/Images/Create Workspace.png) ### Create a Testing Target -You'll need to create a test target for your app. You may already have one named *MyApplication*_Tests if you selected to automatically create unit tests. If you did, you can keep using it if you aren't using it for unit tests. Otherwise, follow these directions to create a new one. +You'll need to create a test target for your app. You may already have one named *MyApplication*Tests if you selected to automatically create unit tests when you created the project. If you did, you can keep using it if you aren't using it for unit tests. Otherwise, follow these directions to create a new one. -Select your project in Xcode and click on "Add Target" in the bottom left corner of the editor. Select iOS -> Other -> Cocoa Touch Unit Testing Bundle. Give it a product name like "Acceptance Tests", "UI Tests", or something that indicates the intent of your testing process. You can select "Use Automatic Reference Counting" even if the remainder of your app doesn't, just to make your life easier. +Select your project in Xcode and click on "Add Target" in the bottom left corner of the editor. Select iOS -> Other -> Cocoa Touch Testing Bundle. Give it a product name like "Acceptance Tests", "UI Tests", or something that indicates the intent of your testing process. The testing target will add a header and implementation file, likely "Acceptance_Tests.m/h" to match your target name. Delete those. @@ -102,9 +106,7 @@ Now that you have a target for your tests, add the tests to that target. With th ![Add libKIF library screen shot](https://github.com/kif-framework/KIF/raw/master/Documentation/Images/Add Library Sheet.png) -In the target's Build Settings, add KIF_XCTEST=1 to the Preprocessor Macros section. If you are using OCUnit, then instead add KIF_SENTEST=1. - -KIF takes advantage of Objective C's ability to add categories on an object, but this isn't enabled for static libraries by default. To enable this, add the `-ObjC` flag to the "Other Linker Flags" build setting as shown below. +KIF takes advantage of Objective C's ability to add categories on an object, but this isn't enabled for static libraries by default. To enable this, add the `-ObjC` flag to the "Other Linker Flags" build setting on your test bundle target as shown below. ![Add category linker flags screen shot](https://github.com/kif-framework/KIF/raw/master/Documentation/Images/Add Category Linker Flags.png) @@ -113,14 +115,15 @@ Read **Final Test Target Configurations** below for the final details on getting Final Test Target Configurations -------------------------------- -You need your tests to run hosted in your application. To do this, first add your application by first selecting "Build Phases", expanding the "Target Dependencies" section, clicking on the "+" button, and in the new sheet that appears selecting your application target and clicking "Add". +You need your tests to run hosted in your application. **Xcode does this for you by default** when creating a new testing bundle target, but if you're migrating an older bundle, follow the steps below. + +First add your application by selecting "Build Phases", expanding the "Target Dependencies" section, clicking on the "+" button, and in the new sheet that appears selecting your application target and clicking "Add". -Next, configure your bundle loader. In "Build Settings", expand "Linking" and edit "Bundle Loader" to be `$(BUILT_PRODUCTS_DIR)/My App.app/My App` where *My App* is the name of your app. Expand the "Unit Testing" section and edit "Test Host" to be `$(BUNDLE_LOADER)`. Also make sure that "Wrapper Extension" is set to "xctest". +Next, configure your bundle loader. In "Build Settings", expand "Linking" and edit "Bundle Loader" to be `$(BUILT_PRODUCTS_DIR)/MyApplication.app/MyApplication` where *MyApplication* is the name of your app. Expand the "Unit Testing" section and edit "Test Host" to be `$(BUNDLE_LOADER)`. Also make sure that "Wrapper Extension" is set to "xctest". The last step is to configure your unit tests to run when you trigger a test (⌘U). Click on your scheme name and select "Edit Scheme…". Click on "Test" in the sidebar followed by the "+" in the bottom left corner. Select your testing target and click "OK". -Example -------- +## Example test cases With your project configured to use KIF, it's time to start writing tests. There are two main classes used in KIF testing: the test case (`KIFTestCase`, subclass of `XCTestCase`) and the UI test actor (`KIFUITestActor`). The XCTest test runner loads the test case classes and executes their test. Inside these tests, the tester performs the UI operations which generally imitate a user interaction. Three of the most common tester actions are "tap this view," "enter text into this view," and "wait for this view." These steps are included as factory methods on `KIFUITestActor` in the base KIF implementation. KIF relies on the built-in accessibility of iOS to perform its test steps. As such, it's important that your app is fully accessible. This is also a great way to ensure that your app is usable by the sight impaired. Making your application accessible is usually as easy as giving your views reasonable labels. More details are available in [Apple's Documentation](http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/iPhoneAccessibility/Making_Application_Accessible/Making_Application_Accessible.html#//apple_ref/doc/uid/TP40008785-CH102-SW5). @@ -130,7 +133,7 @@ The first step is to create a test class to test some functionality. In our cas *LoginTestCase.h* #import - + @interface LoginTests : KIFTestCase @end @@ -145,12 +148,12 @@ The first step is to create a test class to test some functionality. In our cas { [tester navigateToLoginPage]; } - + - (void)afterEach { [tester returnToLoggedOutHomeScreen]; } - + - (void)testSuccessfulLogin { [tester enterText:@"user@example.com" intoViewWithAccessibilityLabel:@"Login User Name"]; @@ -160,7 +163,7 @@ The first step is to create a test class to test some functionality. In our cas // Verify that the login succeeded [tester waitForTappableViewWithAccessibilityLabel:@"Welcome"]; } - + @end Most of the tester actions in the test are already defined by the KIF framework, but `-navigateToLoginPage` and `-returnToLoggedOutHomeScreen` are not. These are examples of custom actions which are specific to your application. Adding such steps is easy, and is done using a factory method in a category of `KIFUITestActor`, similar to how we added the scenario. @@ -170,7 +173,7 @@ Most of the tester actions in the test are already defined by the KIF framework, #import @interface KIFUITestActor (EXAdditions) - + - (void)navigateToLoginPage; - (void)returnToLoggedOutHomeScreen; @@ -211,12 +214,12 @@ For example, the following [Specta](https://github.com/specta/specta) test works SpecBegin(App) describe(@"Tab controller", ^{ - + it(@"should show second view when I tap on the second tab", ^{ [tester tapViewWithAccessibilityLabel:@"Second" traits:UIAccessibilityTraitButton]; [tester waitForViewWithAccessibilityLabel:@"Second View"]; }); - + }); SpecEnd @@ -228,6 +231,38 @@ If you want to use KIF with a test runner that does not subclass `XCTestCase`, y In the first case, the test runner should log the exception and halt the test execution if `stop` is `YES`. In the second, the runner should log all the exceptions and halt the test execution if `stop` is `YES`. The exceptions take advantage of KIF's extensions to `NSException` that include the `lineNumber` and `filename` in the exception's `userData` to record the error's origin. +## Use with Swift + +Since it's easy to combine Swift and Objective-C code in a single project, KIF is fully capable of testing apps written in both Objective-C and Swift. + +If you want to write your test cases in Swift, you'll need to keep two things in mind. + +1. Your test bundle's bridging header will need to `#import `, since KIF is a static library and not a header. +2. The `tester` and `system` keywords are C preprocessor macros which aren't available in Swift. You can easily write a small extension to `XCTestCase` or any other class to access them: + +```swift +extension XCTestCase { + func tester(_ file : String = __FILE__, _ line : Int = __LINE__) -> KIFUITestActor { + return KIFUITestActor(inFile: file, atLine: line, delegate: self) + } + + func system(_ file : String = __FILE__, _ line : Int = __LINE__) -> KIFSystemTestActor { + return KIFSystemTestActor(inFile: file, atLine: line, delegate: self) + } +} + +extension KIFTestActor { + func tester(_ file : String = __FILE__, _ line : Int = __LINE__) -> KIFUITestActor { + return KIFUITestActor(inFile: file, atLine: line, delegate: self) + } + + func system(_ file : String = __FILE__, _ line : Int = __LINE__) -> KIFSystemTestActor { + return KIFSystemTestActor(inFile: file, atLine: line, delegate: self) + } +} +``` + + Troubleshooting --------------- diff --git a/tests/KIF/Test Host/AnimationViewController.m b/tests/KIF/Test Host/AnimationViewController.m new file mode 100755 index 000000000..d8f6caeaa --- /dev/null +++ b/tests/KIF/Test Host/AnimationViewController.m @@ -0,0 +1,25 @@ +// +// AnimationViewController.m +// KIF +// +// Created by Hendrik von Prince on 11.11.14. +// +// + +#import + +@interface AnimationViewController : UIViewController +@property (strong, nonatomic) IBOutlet UILabel *testLabel; +@end + +@implementation AnimationViewController + +-(void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + // simulate a time-consuming calculation + sleep(2); + self.testLabel.hidden = NO; +} + +@end diff --git a/tests/KIF/Test Host/SystemAlertViewController.m b/tests/KIF/Test Host/SystemAlertViewController.m new file mode 100755 index 000000000..1aa700e81 --- /dev/null +++ b/tests/KIF/Test Host/SystemAlertViewController.m @@ -0,0 +1,42 @@ +// +// SystemAlertViewController.m +// KIF +// +// Created by Joe Masilotti on 12/1/14. +// +// + +#import +#import + +@interface SystemAlertViewController : UIViewController +@property (nonatomic, strong) CLLocationManager *locationManager; +@end + +@implementation SystemAlertViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.locationManager = [[CLLocationManager alloc] init]; +} + +- (IBAction)requestLocationServicesAccess { + if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) { + [self.locationManager requestWhenInUseAuthorization]; + } + [self.locationManager startUpdatingLocation]; +} + +- (IBAction)requestPhotosAccess { + UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init]; + [self presentViewController:imagePickerController animated:YES completion:nil]; +} + +- (IBAction)requestNotificationScheduling { + if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) { + UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert categories:nil]; + [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; + } +} + +@end diff --git a/tests/KIF/Test Host/TapViewController.m b/tests/KIF/Test Host/TapViewController.m index c15efe6c5..fe83d1e6f 100755 --- a/tests/KIF/Test Host/TapViewController.m +++ b/tests/KIF/Test Host/TapViewController.m @@ -8,10 +8,11 @@ #import -@interface TapViewController : UIViewController +@interface TapViewController : UIViewController @property (weak, nonatomic) IBOutlet UISlider *slider; @property (weak, nonatomic) IBOutlet UILabel *lineBreakLabel; @property (weak, nonatomic) IBOutlet UILabel *memoryWarningLabel; +@property (weak, nonatomic) IBOutlet UILabel *selectedPhotoSizeLabel; @property (weak, nonatomic) IBOutlet UITextField *otherTextField; @property (weak, nonatomic) IBOutlet UITextField *greetingTextField; @end @@ -55,6 +56,7 @@ - (IBAction)pickPhoto:(id)sender { UIImagePickerController *controller = [[UIImagePickerController alloc] init]; controller.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + controller.delegate = self; [self presentViewController:controller animated:YES completion:nil]; } @@ -73,4 +75,20 @@ - (BOOL)textFieldShouldReturn:(UITextField *)textField return NO; } +- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string +{ + if (textField == self.otherTextField && range.length != 0) { + self.greetingTextField.text = @"Deleted something."; + } + + return YES; +} + +#pragma mark - + +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { + self.selectedPhotoSizeLabel.text = NSStringFromCGSize([info[UIImagePickerControllerOriginalImage] size]); + [self dismissViewControllerAnimated:YES completion:nil]; +} + @end diff --git a/tests/KIF/Test Host/Test Host-Info.plist b/tests/KIF/Test Host/Test Host-Info.plist index 30d6736aa..faf98f217 100755 --- a/tests/KIF/Test Host/Test Host-Info.plist +++ b/tests/KIF/Test Host/Test Host-Info.plist @@ -24,6 +24,8 @@ 1.0 LSRequiresIPhoneOS + NSLocationWhenInUseUsageDescription + To test system alert views. UIMainStoryboardFile MainStoryboard UIRequiredDeviceCapabilities diff --git a/tests/KIF/Test Host/TestSuiteViewController.m b/tests/KIF/Test Host/TestSuiteViewController.m index f150caf65..a6c05682a 100755 --- a/tests/KIF/Test Host/TestSuiteViewController.m +++ b/tests/KIF/Test Host/TestSuiteViewController.m @@ -18,21 +18,26 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath if (indexPath.section != 1) { return; } - + switch (indexPath.row) { case 0: { [[[UIAlertView alloc] initWithTitle:@"Alert View" message:@"Message" delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:@"Continue", nil] show]; break; } - + case 1: { - [[[UIActionSheet alloc] initWithTitle:@"Action Sheet" delegate:nil cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Destroy" otherButtonTitles:@"A", @"B", nil] showInView:tableView]; break; } - + case 2: + { + [[[UIActionSheet alloc] initWithTitle:@"Action Sheet" delegate:nil cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Destroy" otherButtonTitles:@"A", @"B", nil] showInView:tableView]; + break; + } + + case 3: { Class AVCClass = NSClassFromString(@"UIActivityViewController"); if (AVCClass) { diff --git a/tests/KIF/Test Host/WebViewController.m b/tests/KIF/Test Host/WebViewController.m new file mode 100755 index 000000000..0eadcf4d5 --- /dev/null +++ b/tests/KIF/Test Host/WebViewController.m @@ -0,0 +1,23 @@ +// +// WebViewController.m +// KIF +// +// Created by Joe Masilotti on 11/19/14. +// +// + +@interface WebViewController : UIViewController +@property (weak, nonatomic) IBOutlet UIWebView *webView; +@end + +@implementation WebViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + NSURL *url = [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"html"]; + [self.webView loadRequest:[NSURLRequest requestWithURL:url]]; +} + +@end diff --git a/tests/KIF/Test Host/en.lproj/MainStoryboard.storyboard b/tests/KIF/Test Host/en.lproj/MainStoryboard.storyboard index 88865c9c5..7aaee3bd1 100755 --- a/tests/KIF/Test Host/en.lproj/MainStoryboard.storyboard +++ b/tests/KIF/Test Host/en.lproj/MainStoryboard.storyboard @@ -1,16 +1,16 @@ - + - + - + - + @@ -21,7 +21,7 @@ - + @@ -164,7 +164,7 @@ - + @@ -185,6 +185,27 @@ + + + + + + + + + + + + + + + @@ -208,6 +229,27 @@ + + + + + + + + + + + + + + + @@ -271,7 +313,7 @@ - + @@ -321,6 +363,24 @@ + + + + + + + + + + + + + + + + + + @@ -1122,7 +1182,7 @@ - + @@ -1328,7 +1388,7 @@ - + @@ -1348,6 +1408,9 @@ + + + @@ -1359,6 +1422,9 @@ + + + @@ -1388,6 +1454,9 @@ + + + @@ -1478,6 +1572,7 @@ Line Break + @@ -1486,7 +1581,7 @@ Line Break - + @@ -1510,6 +1605,31 @@ Line Break + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1530,6 +1650,7 @@ Line Break + @@ -1563,6 +1684,7 @@ Line Break + @@ -1577,6 +1699,98 @@ Line Break + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/KIF/Test Host/index.html b/tests/KIF/Test Host/index.html new file mode 100755 index 000000000..7e8ffb232 --- /dev/null +++ b/tests/KIF/Test Host/index.html @@ -0,0 +1,14 @@ + + +

Testing with KIF

+

Page 1

+
A link + +
+ + + +
















+ Footer + + diff --git a/tests/KIF/Test Host/page2.html b/tests/KIF/Test Host/page2.html new file mode 100755 index 000000000..37ba0a45a --- /dev/null +++ b/tests/KIF/Test Host/page2.html @@ -0,0 +1,6 @@ + + +

Testing with KIF

+

Page 2

+ + diff --git a/tests/MediationAdapterApp/ANMediationAdapterViewController.m b/tests/MediationAdapterApp/ANMediationAdapterViewController.m index 89b89a888..f2a559bbd 100644 --- a/tests/MediationAdapterApp/ANMediationAdapterViewController.m +++ b/tests/MediationAdapterApp/ANMediationAdapterViewController.m @@ -42,7 +42,9 @@ + (NSArray *)networks { @"AdMobBanner", @"AdMobInterstitial", @"DFPBanner", - @"DFPInterstitial"]; + @"DFPInterstitial", + @"DoesNotExistBanner", + @"DoesNotExistInterstitial"]; } #pragma mark - Picker View @@ -283,6 +285,34 @@ - (void)stubDFPInterstitial { [self stubMediatedAd:mediatedAd]; } +#pragma mark - Does Not Exist + +- (ANBannerAdView *)loadDoesNotExistBannerWithDelegate:(id)delegate { + [self stubNonExistentBanner]; + return [self bannerWithDelegate:delegate]; +} + +- (ANInterstitialAd *)loadDoesNotExistInterstitialWithDelegate:(id)delegate { + [self stubNonExistentInterstitial]; + return [self interstitialWithDelegate:delegate]; +} + +- (void)stubNonExistentBanner { + ANMediatedAd *mediatedAd = [[ANMediatedAd alloc] init]; + mediatedAd.className = @"ANAdAdapterBannerDoesNotExist"; + mediatedAd.adId = @"/6925/Shazam_iPhoneAPP/Standard_Banners/AutoShazam_TagsTab"; + mediatedAd.width = @"320"; + mediatedAd.height = @"50"; + [self stubMediatedAd:mediatedAd]; +} + +- (void)stubNonExistentInterstitial { + ANMediatedAd *mediatedAd = [[ANMediatedAd alloc] init]; + mediatedAd.className = @"ANAdAdapterInterstitialDoesNotExist"; + mediatedAd.adId = @"/6925/Shazam_iPhoneAPP/Standard_Banners/AutoShazam_TagsTab"; + [self stubMediatedAd:mediatedAd]; +} + #pragma mark - ANAdProtocol - (void)ad:(id)ad requestFailedWithError:(NSError *)error { diff --git a/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/AppIcon.appiconset/Contents.json b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..118c98f74 --- /dev/null +++ b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-2.launchimage/Contents.json b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-2.launchimage/Contents.json new file mode 100644 index 000000000..ce5e4a3ad --- /dev/null +++ b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-2.launchimage/Contents.json @@ -0,0 +1,42 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "Default@2x.png", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "Default-568h@2x.png", + "minimum-system-version" : "7.0", + "subtype" : "retina4", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "Default.png", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "Default@2x.png", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "Default-568h@2x.png", + "subtype" : "retina4", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-2.launchimage/Default-568h@2x.png b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-2.launchimage/Default-568h@2x.png new file mode 100755 index 000000000..0891b7aab Binary files /dev/null and b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-2.launchimage/Default-568h@2x.png differ diff --git a/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-2.launchimage/Default.png b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-2.launchimage/Default.png new file mode 100755 index 000000000..4c8ca6f69 Binary files /dev/null and b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-2.launchimage/Default.png differ diff --git a/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-2.launchimage/Default@2x.png b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-2.launchimage/Default@2x.png new file mode 100755 index 000000000..35b84cffe Binary files /dev/null and b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-2.launchimage/Default@2x.png differ diff --git a/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-3.launchimage/Contents.json b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-3.launchimage/Contents.json new file mode 100644 index 000000000..ce5e4a3ad --- /dev/null +++ b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-3.launchimage/Contents.json @@ -0,0 +1,42 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "Default@2x.png", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "Default-568h@2x.png", + "minimum-system-version" : "7.0", + "subtype" : "retina4", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "Default.png", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "Default@2x.png", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "Default-568h@2x.png", + "subtype" : "retina4", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-3.launchimage/Default-568h@2x.png b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-3.launchimage/Default-568h@2x.png new file mode 100755 index 000000000..0891b7aab Binary files /dev/null and b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-3.launchimage/Default-568h@2x.png differ diff --git a/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-3.launchimage/Default.png b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-3.launchimage/Default.png new file mode 100755 index 000000000..4c8ca6f69 Binary files /dev/null and b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-3.launchimage/Default.png differ diff --git a/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-3.launchimage/Default@2x.png b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-3.launchimage/Default@2x.png new file mode 100755 index 000000000..35b84cffe Binary files /dev/null and b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage-3.launchimage/Default@2x.png differ diff --git a/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage.launchimage/Contents.json b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 000000000..80ea696bf --- /dev/null +++ b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,143 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "8.0", + "subtype" : "736h", + "scale" : "3x" + }, + { + "orientation" : "landscape", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "8.0", + "subtype" : "736h", + "scale" : "3x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "8.0", + "subtype" : "667h", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "retina4", + "filename" : "Default-568h@2x.png", + "minimum-system-version" : "7.0", + "orientation" : "portrait", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "subtype" : "retina4", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "to-status-bar", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "to-status-bar", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "to-status-bar", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "to-status-bar", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage.launchimage/Default-568h@2x.png b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage.launchimage/Default-568h@2x.png new file mode 100644 index 000000000..0891b7aab Binary files /dev/null and b/tests/MediationAdapterApp/MediationAdapterAppImages.xcassets/LaunchImage.launchimage/Default-568h@2x.png differ diff --git a/tests/MediationAdapterAppTests/MediationAdaptersTestCase.m b/tests/MediationAdapterAppTests/MediationAdaptersTestCase.m index ae93e0ee2..2267921cb 100644 --- a/tests/MediationAdapterAppTests/MediationAdaptersTestCase.m +++ b/tests/MediationAdapterAppTests/MediationAdaptersTestCase.m @@ -132,8 +132,7 @@ - (void)testFacebookSuccessfulBanner { #if kANMediationAdaptersUITesting bannerAdView.accessibilityLabel = @"banner"; - [tester tapViewWithAccessibilityLabel:@"banner"]; - [tester tapScreenAtPoint:CGPointMake(300, 25)]; + [tester tapScreenAtPoint:CGPointMake(310, 25)]; [tester waitForTimeInterval:3.0]; XCTAssertTrue(self.adWasClicked, @"expected adWasClicked callback"); XCTAssertTrue(self.adWillPresent, @"expected adWillPresent callback"); diff --git a/tests/NativeUnitTests/ANAdServerResponseTestCase.m b/tests/NativeUnitTests/ANAdServerResponseTestCase.m new file mode 100644 index 000000000..59d4d80c5 --- /dev/null +++ b/tests/NativeUnitTests/ANAdServerResponseTestCase.m @@ -0,0 +1,83 @@ +/* Copyright 2014 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import +#import +#import "ANAdServerResponse.h" +#import "XCTestCase+ANCategory.h" +#import "ANMediatedAd.h" + +@interface ANAdServerResponseTestCase : XCTestCase + +@end + +@implementation ANAdServerResponseTestCase + +- (void)testMediationResponse { + ANAdServerResponse *response = [[ANAdServerResponse alloc] initWithAdServerData:[self dataWithJSONResource:@"SuccessfulMediationResponse"]]; + XCTAssertTrue(response.containsAds); + XCTAssertEqual(response.mediatedAds.count, 4); + for (ANMediatedAd *mediatedAd in response.mediatedAds) { + XCTAssertNotNil(mediatedAd.resultCB); + XCTAssertNotNil(mediatedAd.className); + } + XCTAssertNil(response.nativeAd); +} + +- (void)testNativeResponse1 { + ANAdServerResponse *response = [[ANAdServerResponse alloc] initWithAdServerData:[self dataWithJSONResource:@"nativeResponse1"]]; + XCTAssertTrue(response.containsAds); + XCTAssertNotNil(response.nativeAd); + XCTAssertNotNil(response.nativeAd.rating); + XCTAssertEqual(response.nativeAd.rating.scale, 5); + XCTAssertEqual(response.nativeAd.rating.value, 5.0); + XCTAssertNotNil(response.nativeAd.title); + XCTAssertNotNil(response.nativeAd.body); + XCTAssertNotNil(response.nativeAd.iconImageURL); + XCTAssertNotNil(response.nativeAd.mainImageURL); +} + +# pragma mark - Invalid JSON + +- (void)testNativeResponse2 { + ANAdServerResponse *response = [[ANAdServerResponse alloc] initWithAdServerData:[self dataWithJSONResource:@"nativeResponse2"]]; + XCTAssertFalse(response.containsAds); +} + +- (void)testNativeResponse3 { + ANAdServerResponse *response = [[ANAdServerResponse alloc] initWithAdServerData:[self dataWithJSONResource:@"nativeResponse3"]]; + XCTAssertFalse(response.containsAds); +} + +# pragma mark - Rating a string, not a object (dict) + +- (void)testNativeResponse4 { + ANAdServerResponse *response = [[ANAdServerResponse alloc] initWithAdServerData:[self dataWithJSONResource:@"nativeResponse4"]]; + XCTAssertTrue(response.containsAds); + XCTAssertTrue(response.nativeAd.title); + XCTAssertTrue(response.nativeAd.body); + XCTAssertNil(response.nativeAd.rating); +} + +#pragma mark - Invalid impression tracker array + +- (void)testNativeResponse5 { + ANAdServerResponse *response = [[ANAdServerResponse alloc] initWithAdServerData:[self dataWithJSONResource:@"nativeResponse5"]]; + XCTAssertTrue(response.containsAds); + XCTAssertNotNil(response.nativeAd.clickTrackers); + XCTAssertNil(response.nativeAd.impTrackers); +} + +@end diff --git a/tests/NativeUnitTests/ANNativeAdRequestTestCase.m b/tests/NativeUnitTests/ANNativeAdRequestTestCase.m new file mode 100644 index 000000000..8e9aa3529 --- /dev/null +++ b/tests/NativeUnitTests/ANNativeAdRequestTestCase.m @@ -0,0 +1,300 @@ +/* Copyright 2015 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import +#import +#import "ANNativeAdRequest+ANBaseUrlOverride.h" +#import "ANGlobal.h" +#import "ANURLConnectionStub.h" +#import "ANHTTPStubbingManager.h" + +@interface ANNativeAdRequestTestCase : XCTestCase + +@property (nonatomic, readwrite, strong) ANNativeAdRequest *adRequest; +@property (nonatomic, readwrite, strong) XCTestExpectation *delegateCallbackExpectation; +@property (nonatomic, readwrite, assign) BOOL successfulAdCall; +@property (nonatomic, readwrite, strong) ANNativeAdResponse *adResponse; +@property (nonatomic, readwrite, strong) NSError *adRequestError; + +@end + +@implementation ANNativeAdRequestTestCase + +- (void)setUp { + [super setUp]; + self.adRequest = [[ANNativeAdRequest alloc] init]; + self.adRequest.delegate = self; + [ANHTTPStubbingManager sharedStubbingManager].ignoreUnstubbedRequests = YES; + [self stubResultCBResponse]; +} + +- (void)tearDown { + [super tearDown]; + self.adRequest = nil; + self.delegateCallbackExpectation = nil; + self.successfulAdCall = NO; + self.adResponse = nil; + self.adRequestError = nil; + [[ANHTTPStubbingManager sharedStubbingManager] removeAllStubs]; +} + +- (void)testAppNexusWithMainImageLoad { + [self stubRequestWithResponse:@"appnexus_standard_response"]; + [self.adRequest loadAd]; + self.adRequest.shouldLoadMainImage = YES; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + [self validateGenericAdResponse]; + XCTAssertEqual(self.adResponse.networkCode, ANNativeAdNetworkCodeAppNexus); + XCTAssertNil(self.adResponse.iconImage); + self.adResponse.mainImageURL ? XCTAssertNotNil(self.adResponse.mainImage) : XCTAssertNil(self.adResponse.mainImage); + self.adResponse.mainImageURL ? XCTAssertTrue([self.adResponse.mainImage isKindOfClass:[UIImage class]]) : nil; +} + +- (void)testFacebook { + [self stubRequestWithResponse:@"facebook_mediated_response"]; + [self.adRequest loadAd]; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + if (self.successfulAdCall) { + [self validateGenericAdResponse]; + XCTAssertEqual(self.adResponse.networkCode, ANNativeAdNetworkCodeFacebook); + XCTAssertNil(self.adResponse.iconImage); + XCTAssertNil(self.adResponse.mainImage); + } else { + XCTAssertNotNil(self.adRequestError); + } +} + +- (void)testFacebookWithIconImageLoad { + [self stubRequestWithResponse:@"facebook_mediated_response"]; + [self.adRequest loadAd]; + self.adRequest.shouldLoadIconImage = YES; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + if (self.successfulAdCall) { + [self validateGenericAdResponse]; + XCTAssertEqual(self.adResponse.networkCode, ANNativeAdNetworkCodeFacebook); + self.adResponse.iconImageURL ? XCTAssertNotNil(self.adResponse.iconImage) : XCTAssertNil(self.adResponse.iconImage); + self.adResponse.iconImageURL ? XCTAssertTrue([self.adResponse.iconImage isKindOfClass:[UIImage class]]) : nil; + XCTAssertNil(self.adResponse.mainImage); + } else { + XCTAssertNotNil(self.adRequestError); + } +} + +- (void)testMoPub { + [self stubRequestWithResponse:@"mopub_mediated_response"]; + [self.adRequest loadAd]; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + if (self.successfulAdCall) { + [self validateGenericAdResponse]; + XCTAssertEqual(self.adResponse.networkCode, ANNativeAdNetworkCodeMoPub); + XCTAssertNil(self.adResponse.iconImage); + XCTAssertNil(self.adResponse.mainImage); + } else { + XCTAssertNotNil(self.adRequestError); + } +} + +- (void)testInvalidMediationAdapter { + [self stubRequestWithResponse:@"custom_adapter_mediated_response"]; + [self.adRequest loadAd]; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertFalse(self.successfulAdCall); + XCTAssertNotNil(self.adRequestError); +} + +- (void)testWaterfallMediationAdapterEndingInFacebook { + [self stubRequestWithResponse:@"custom_adapter_fb_mediated_response"]; + [self.adRequest loadAd]; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + if (self.successfulAdCall) { + [self validateGenericAdResponse]; + XCTAssertEqual(self.adResponse.networkCode, ANNativeAdNetworkCodeFacebook); + XCTAssertNil(self.adResponse.iconImage); + XCTAssertNil(self.adResponse.mainImage); + } else { + XCTAssertNotNil(self.adRequestError); + } +} + +- (void)testNoResponse { + [self stubRequestWithResponse:@"empty_response"]; + [self.adRequest loadAd]; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertFalse(self.successfulAdCall); + XCTAssertNotNil(self.adRequestError); +} + +- (void)testCustomAdapterFailToStandardResponse { + [self stubRequestWithResponse:@"custom_adapter_to_standard_response"]; + [self.adRequest loadAd]; + self.adRequest.shouldLoadMainImage = YES; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + [self validateGenericAdResponse]; + XCTAssertEqual(self.adResponse.networkCode, ANNativeAdNetworkCodeAppNexus); + XCTAssertNil(self.adResponse.iconImage); + self.adResponse.mainImageURL ? XCTAssertNotNil(self.adResponse.mainImage) : XCTAssertNil(self.adResponse.mainImage); + self.adResponse.mainImageURL ? XCTAssertTrue([self.adResponse.mainImage isKindOfClass:[UIImage class]]) : nil; +} + +- (void)testCustomAdapterFailToNativeAd { + [self stubRequestWithResponse:@"custom_adapter_to_native_ad"]; + [self.adRequest loadAd]; + self.adRequest.shouldLoadMainImage = YES; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + [self validateGenericAdResponse]; + XCTAssertEqual(self.adResponse.networkCode, ANNativeAdNetworkCodeAppNexus); + XCTAssertNil(self.adResponse.iconImage); + self.adResponse.mainImageURL ? XCTAssertNotNil(self.adResponse.mainImage) : XCTAssertNil(self.adResponse.mainImage); + self.adResponse.mainImageURL ? XCTAssertTrue([self.adResponse.mainImage isKindOfClass:[UIImage class]]) : nil; +} + +- (void)testMediatedResponseInvalidType { + [self stubRequestWithResponse:@"custom_adapter_invalid_type"]; + [self.adRequest loadAd]; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertFalse(self.successfulAdCall); + XCTAssertNotNil(self.adRequestError); +} + +- (void)testSuccessfulResponseWithNoAds { + [self stubRequestWithResponse:@"no_ads_ok_response"]; + [self.adRequest loadAd]; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertFalse(self.successfulAdCall); + XCTAssertNotNil(self.adRequestError); +} + +- (void)testMediatedResponseEmptyMediatedAd { + [self stubRequestWithResponse:@"empty_mediated_ad_response"]; + [self.adRequest loadAd]; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertFalse(self.successfulAdCall); + XCTAssertNotNil(self.adRequestError); +} + +- (void)validateGenericAdResponse { + XCTAssertNotNil(self.adResponse); + if (self.adResponse.title) { + XCTAssert([self.adResponse.title isKindOfClass:[NSString class]]); + } + if (self.adResponse.body) { + XCTAssert([self.adResponse.body isKindOfClass:[NSString class]]); + } + if (self.adResponse.callToAction) { + XCTAssert([self.adResponse.body isKindOfClass:[NSString class]]); + } + if (self.adResponse.rating) { + XCTAssert([self.adResponse.rating isKindOfClass:[ANNativeAdStarRating class]]); + } + if (self.adResponse.socialContext) { + XCTAssert([self.adResponse.socialContext isKindOfClass:[NSString class]]); + } + if (self.adResponse.mainImageURL) { + XCTAssert([self.adResponse.mainImageURL isKindOfClass:[NSURL class]]); + } + if (self.adResponse.iconImageURL) { + XCTAssert([self.adResponse.iconImageURL isKindOfClass:[NSURL class]]); + } + if (self.adResponse.customElements) { + XCTAssert([self.adResponse.customElements isKindOfClass:[NSDictionary class]]); + } +} + +#pragma mark - ANNativeAdRequestDelegate + +- (void)adRequest:(ANNativeAdRequest *)request didReceiveResponse:(ANNativeAdResponse *)response { + self.adResponse = response; + self.successfulAdCall = YES; + [self.delegateCallbackExpectation fulfill]; +} + +- (void)adRequest:(ANNativeAdRequest *)request didFailToLoadWithError:(NSError *)error { + self.adRequestError = error; + self.successfulAdCall = NO; + [self.delegateCallbackExpectation fulfill]; +} + +# pragma mark - Ad Server Response Stubbing + +- (void)stubRequestWithResponse:(NSString *)responseName { + NSBundle *currentBundle = [NSBundle bundleForClass:[self class]]; + NSString *baseResponse = [NSString stringWithContentsOfFile:[currentBundle pathForResource:responseName + ofType:@"json"] + encoding:NSUTF8StringEncoding + error:nil]; + ANURLConnectionStub *requestStub = [[ANURLConnectionStub alloc] init]; + requestStub.requestURLRegexPatternString = @"http://mediation.adnxs.com/mob\\?.*"; + requestStub.responseCode = 200; + requestStub.responseBody = baseResponse; + [[ANHTTPStubbingManager sharedStubbingManager] addStub:requestStub]; +} + +- (void)stubResultCBResponse { + ANURLConnectionStub *resultCBStub = [[ANURLConnectionStub alloc] init]; + resultCBStub.requestURLRegexPatternString = @"http://nym1.mobile.adnxs.com/mediation.*"; + resultCBStub.responseCode = 200; + resultCBStub.responseBody = @""; + [[ANHTTPStubbingManager sharedStubbingManager] addStub:resultCBStub]; +} + +@end \ No newline at end of file diff --git a/tests/NativeUnitTests/ANNativeAdResponseTestCase.m b/tests/NativeUnitTests/ANNativeAdResponseTestCase.m new file mode 100644 index 000000000..1e58c3169 --- /dev/null +++ b/tests/NativeUnitTests/ANNativeAdResponseTestCase.m @@ -0,0 +1,680 @@ +/* Copyright 2015 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import +#import +#import + +#import "ANNativeAdRequest.h" +#import "ANGlobal.h" +#import "ANNativeAdView.h" +#import "ANLogManager.h" + +#import "ANURLConnectionStub.h" +#import "ANHTTPStubbingManager.h" + +#import "XCTestCase+ANCategory.h" + +#import "ANNativeStandardAdResponse.h" + +@interface ANNativeAdResponseTestCase : KIFTestCase + +@property (nonatomic, readwrite, strong) ANNativeAdRequest *adRequest; +@property (nonatomic, readwrite, strong) XCTestExpectation *delegateCallbackExpectation; +@property (nonatomic, readwrite, assign) BOOL successfulAdCall; +@property (nonatomic, readwrite, strong) ANNativeAdResponse *adResponse; +@property (nonatomic, readwrite, strong) NSError *adRequestError; +@property (nonatomic, readwrite, strong) ANNativeAdView *nativeAdView; + +@property (nonatomic, readwrite, strong) NSMutableArray *impressionTrackers; +@property (nonatomic, readwrite, strong) NSMutableArray *clickTrackers; + +@property (nonatomic, readwrite, strong) UIViewController *rootViewController; + +@property (nonatomic, readwrite, assign) BOOL receivedCallbackAdWasClicked; +@property (nonatomic, readwrite, assign) BOOL receivedCallbackAdWillPresent; +@property (nonatomic, readwrite, assign) BOOL receivedCallbackAdDidPresent; +@property (nonatomic, readwrite, assign) BOOL receivedCallbackAdWillClose; +@property (nonatomic, readwrite, assign) BOOL receivedCallbackAdDidClose; +@property (nonatomic, readwrite, assign) BOOL receivedCallbackAdWillLeaveApplication; + +@end + +@implementation ANNativeAdResponseTestCase + +- (void)setUp { + [super setUp]; + [ANLogManager setANLogLevel:ANLogLevelAll]; + self.adRequest = [[ANNativeAdRequest alloc] init]; + self.adRequest.delegate = self; + [ANHTTPStubbingManager sharedStubbingManager].ignoreUnstubbedRequests = YES; + [self stubResultCBResponse]; +} + +- (void)tearDown { + [super tearDown]; + self.adRequest = nil; + self.delegateCallbackExpectation = nil; + self.successfulAdCall = NO; + self.adResponse = nil; + self.adRequestError = nil; + [self.nativeAdView removeFromSuperview]; + self.nativeAdView = nil; + [[ANHTTPStubbingManager sharedStubbingManager] removeAllStubs]; + [ANHTTPStubbingManager sharedStubbingManager].broadcastRequests = NO; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:kANHTTPStubURLProtocolRequestDidLoadNotification + object:nil]; + self.impressionTrackers = nil; + self.clickTrackers = nil; + + self.rootViewController = nil; + + self.receivedCallbackAdWasClicked = NO; + self.receivedCallbackAdWillPresent = NO; + self.receivedCallbackAdDidPresent = NO; + self.receivedCallbackAdWillClose = NO; + self.receivedCallbackAdDidClose = NO; + self.receivedCallbackAdWillLeaveApplication = NO; +} + +#pragma mark - Tests + +- (void)testAppNexusWithIconImageLoad { + [self stubRequestWithResponse:@"appnexus_standard_response"]; + [self.adRequest loadAd]; + self.adRequest.shouldLoadIconImage = YES; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertTrue(self.successfulAdCall); + XCTAssertNil(self.adRequestError); + + [self iconImageShouldBePresentInResponse:YES]; + [self mainImageShouldBePresentInResponse:NO]; + + [self createBasicNativeView]; + [self populateNativeViewWithResponse]; + [self registerNativeView]; + [self addNativeViewToViewHierarchy]; + + [self pullImpressionAndClickTrackersFromResponse]; + [self setupURLDidLoadTracker]; + [self assertPendingImpressionTrackerCount:1]; + [self assertPendingClickTrackerCount:1]; + + [tester waitForTimeInterval:2.0]; + + [self assertPendingImpressionTrackerCount:0]; + [self assertPendingClickTrackerCount:1]; + + [self clickOnAd]; + [tester waitForTimeInterval:2.0]; + [self assertPresentCallbacksReceived]; + [self assertPendingClickTrackerCount:0]; + + [self closeInAppBrowser]; + [tester waitForTimeInterval:3.0]; + [self assertCloseCallbacksReceived]; +} + +- (void)testAppNexusWithIconAndMainImageLoad { + [self stubRequestWithResponse:@"appnexus_standard_response_store_url"]; + [self.adRequest loadAd]; + self.adRequest.shouldLoadIconImage = YES; + self.adRequest.shouldLoadMainImage = YES; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertTrue(self.successfulAdCall); + XCTAssertNil(self.adRequestError); + + [self iconImageShouldBePresentInResponse:YES]; + [self mainImageShouldBePresentInResponse:YES]; + + [self createMainImageNativeView]; + [self populateNativeViewWithResponse]; + [self registerNativeView]; + [self addNativeViewToViewHierarchy]; + + [tester waitForTimeInterval:2.0]; + + [self clickOnAd]; + [tester waitForTimeInterval:2.0]; + [self assertPresentCallbacksReceived]; + + [self forceDismissPresentedController]; + [tester waitForTimeInterval:3.0]; +} + +- (void)testAppNexusWithIconImageLoadToStoreUrl { + [self stubRequestWithResponse:@"appnexus_standard_response_store_url"]; + [self.adRequest loadAd]; + self.adRequest.shouldLoadIconImage = YES; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertTrue(self.successfulAdCall); + XCTAssertNil(self.adRequestError); + + [self iconImageShouldBePresentInResponse:YES]; + [self mainImageShouldBePresentInResponse:NO]; + + [self createBasicNativeView]; + [self populateNativeViewWithResponse]; + [self registerNativeView]; + [self addNativeViewToViewHierarchy]; + + [tester waitForTimeInterval:2.0]; + + [self clickOnAd]; + [tester waitForTimeInterval:2.0]; + [self assertPresentCallbacksReceived]; + + [self forceDismissPresentedController]; + [tester waitForTimeInterval:3.0]; +} + +- (void)testAppNexusWithMultipleMainMedia { + [self stubRequestWithResponse:@"appnexus_multiple_main_media"]; + [self.adRequest loadAd]; + self.adRequest.shouldLoadIconImage = YES; + self.adRequest.shouldLoadMainImage = YES; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertTrue(self.successfulAdCall); + XCTAssertNil(self.adRequestError); + + [self iconImageShouldBePresentInResponse:YES]; + [self mainImageShouldBePresentInResponse:YES]; + + XCTAssertTrue([self.adResponse.mainImageURL.absoluteString containsString:@"rlissack.adnxs.net"]); + + [self createMainImageNativeView]; + [self populateNativeViewWithResponse]; + [self registerNativeView]; + [self addNativeViewToViewHierarchy]; + + [tester waitForTimeInterval:2.0]; + + [self clickOnAd]; + [tester waitForTimeInterval:2.0]; + [self assertPresentCallbacksReceived]; + + [self closeInAppBrowser]; + [tester waitForTimeInterval:3.0]; + [self assertCloseCallbacksReceived]; +} + +- (void)testAppNexusWithMultipleMainMediaDefault { + [self stubRequestWithResponse:@"appnexus_multiple_main_media_default"]; + [self.adRequest loadAd]; + self.adRequest.shouldLoadIconImage = YES; + self.adRequest.shouldLoadMainImage = YES; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertTrue(self.successfulAdCall); + XCTAssertNil(self.adRequestError); + + [self iconImageShouldBePresentInResponse:YES]; + [self mainImageShouldBePresentInResponse:YES]; + + XCTAssertTrue([self.adResponse.mainImageURL.absoluteString containsString:@"rlissack.adnxs.net"]); + + [self createMainImageNativeView]; + [self populateNativeViewWithResponse]; + [self registerNativeView]; + [self addNativeViewToViewHierarchy]; + + [tester waitForTimeInterval:2.0]; + + [self clickOnAd]; + [tester waitForTimeInterval:2.0]; + [self assertPresentCallbacksReceived]; + + [self closeInAppBrowser]; + [tester waitForTimeInterval:3.0]; + [self assertCloseCallbacksReceived]; +} + +- (void)testAppNexusWithMultipleTrackers { + [self stubRequestWithResponse:@"appnexus_multiple_trackers"]; + [self.adRequest loadAd]; + self.adRequest.shouldLoadIconImage = YES; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertTrue(self.successfulAdCall); + XCTAssertNil(self.adRequestError); + + [self iconImageShouldBePresentInResponse:YES]; + [self mainImageShouldBePresentInResponse:NO]; + + [self createBasicNativeView]; + [self populateNativeViewWithResponse]; + [self registerNativeView]; + [self addNativeViewToViewHierarchy]; + + [self pullImpressionAndClickTrackersFromResponse]; + [self setupURLDidLoadTracker]; + [self assertPendingImpressionTrackerCount:3]; + [self assertPendingClickTrackerCount:4]; + + [tester waitForTimeInterval:2.0]; + + [self assertPendingImpressionTrackerCount:0]; + [self assertPendingClickTrackerCount:4]; + + [self clickOnAd]; + [tester waitForTimeInterval:2.0]; + [self assertPresentCallbacksReceived]; + [self assertPendingClickTrackerCount:0]; + + [self closeInAppBrowser]; + [tester waitForTimeInterval:3.0]; + [self assertCloseCallbacksReceived]; +} + +- (void)testAppNexusRecycledView { + [self stubRequestWithResponse:@"appnexus_standard_response"]; + [self.adRequest loadAd]; + self.adRequest.shouldLoadIconImage = YES; + self.adRequest.shouldLoadMainImage = YES; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertTrue(self.successfulAdCall); + XCTAssertNil(self.adRequestError); + + [self createMainImageNativeView]; + [self populateNativeViewWithResponse]; + [self addNativeViewToViewHierarchy]; + [self registerNativeView]; + + [tester waitForTimeInterval:3.0]; + + [self clickOnAd]; + [tester waitForTimeInterval:2.0]; + [self assertPresentCallbacksReceived]; + + [self closeInAppBrowser]; + [tester waitForTimeInterval:3.0]; + [self assertCloseCallbacksReceived]; + + self.adResponse = nil; + + //-----// + + [[ANHTTPStubbingManager sharedStubbingManager] removeAllStubs]; + [self stubRequestWithResponse:@"facebook_mediated_response"]; + [self stubResultCBResponse]; + [self.adRequest loadAd]; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertTrue(self.successfulAdCall); + XCTAssertNil(self.adRequestError); + + [self populateNativeViewWithResponse]; + [self registerNativeView]; + + [tester waitForTimeInterval:3.0]; + + if ([[UIScreen mainScreen] respondsToSelector:@selector(coordinateSpace)]) { + [self clickOnAd]; + [tester waitForTimeInterval:2.0]; + [self assertPresentCallbacksReceived]; + + [self forceDismissPresentedController]; + [tester waitForTimeInterval:3.0]; + } + + //-----// + + [[ANHTTPStubbingManager sharedStubbingManager] removeAllStubs]; + [self stubRequestWithResponse:@"appnexus_standard_response"]; + [self stubResultCBResponse]; + [self.adRequest loadAd]; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertTrue(self.successfulAdCall); + XCTAssertNil(self.adRequestError); + + [self populateNativeViewWithResponse]; + [self registerNativeView]; + + [tester waitForTimeInterval:3.0]; +} + +- (void)testAppNexusClickFallbackBehavior { + [self stubRequestWithResponse:@"appnexus_click_fallback_example"]; + [self.adRequest loadAd]; + self.adRequest.shouldLoadIconImage = YES; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertTrue(self.successfulAdCall); + XCTAssertNil(self.adRequestError); + + [self iconImageShouldBePresentInResponse:YES]; + [self mainImageShouldBePresentInResponse:NO]; + + [self createBasicNativeView]; + [self populateNativeViewWithResponse]; + [self registerNativeView]; + [self addNativeViewToViewHierarchy]; + + [self pullImpressionAndClickTrackersFromResponse]; + [self setupURLDidLoadTracker]; + [self assertPendingImpressionTrackerCount:1]; + [self assertPendingClickTrackerCount:1]; + + [tester waitForTimeInterval:2.0]; + + [self assertPendingImpressionTrackerCount:0]; + [self assertPendingClickTrackerCount:1]; + + [self clickOnAd]; + // click_url_fallback will be triggered after click_url fails + [tester waitForTimeInterval:2.0]; + [self assertPresentCallbacksReceived]; + [self assertPendingClickTrackerCount:0]; + + [self closeInAppBrowser]; + [tester waitForTimeInterval:3.0]; + [self assertCloseCallbacksReceived]; +} + +#pragma mark - Mediation Tests + +- (void)testMoPubWithIconImageLoad { + [self stubRequestWithResponse:@"mopub_mediated_response"]; + [self.adRequest loadAd]; + self.adRequest.shouldLoadIconImage = YES; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertTrue(self.successfulAdCall); + XCTAssertNil(self.adRequestError); + + [self iconImageShouldBePresentInResponse:YES]; + [self mainImageShouldBePresentInResponse:NO]; + + [self createBasicNativeView]; + [self populateNativeViewWithResponse]; + [self registerNativeView]; + [self addNativeViewToViewHierarchy]; + + [tester waitForTimeInterval:2.0]; + + [self clickOnAd]; + [tester waitForTimeInterval:2.0]; + [self assertPresentCallbacksReceived]; + + [self forceDismissPresentedController]; + [tester waitForTimeInterval:3.0]; +} + +- (void)testFacebookWithIconImageLoad { + [self stubRequestWithResponse:@"facebook_mediated_response"]; + [self.adRequest loadAd]; + self.adRequest.shouldLoadIconImage = YES; + self.delegateCallbackExpectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self waitForExpectationsWithTimeout:2 * kAppNexusRequestTimeoutInterval + handler:^(NSError *error) { + + }]; + XCTAssertTrue(self.successfulAdCall); + XCTAssertNil(self.adRequestError); + + [self iconImageShouldBePresentInResponse:YES]; + [self mainImageShouldBePresentInResponse:NO]; + + [self createBasicNativeView]; + [self populateNativeViewWithResponse]; + [self registerNativeView]; + [self addNativeViewToViewHierarchy]; + + [tester waitForTimeInterval:2.0]; + + if ([[UIScreen mainScreen] respondsToSelector:@selector(coordinateSpace)]) { + [self clickOnAd]; + [tester waitForTimeInterval:2.0]; + [self assertPresentCallbacksReceived]; + + [self forceDismissPresentedController]; + [tester waitForTimeInterval:3.0]; + } +} + +#pragma mark - ANNativeAdRequestDelegate + +- (void)adRequest:(ANNativeAdRequest *)request didReceiveResponse:(ANNativeAdResponse *)response { + self.adResponse = response; + self.successfulAdCall = YES; + [self.delegateCallbackExpectation fulfill]; +} + +- (void)adRequest:(ANNativeAdRequest *)request didFailToLoadWithError:(NSError *)error { + self.adRequestError = error; + self.successfulAdCall = NO; + [self.delegateCallbackExpectation fulfill]; +} + +# pragma mark - Ad Server Response Stubbing + +- (void)stubRequestWithResponse:(NSString *)responseName { + NSBundle *currentBundle = [NSBundle bundleForClass:[self class]]; + NSString *baseResponse = [NSString stringWithContentsOfFile:[currentBundle pathForResource:responseName + ofType:@"json"] + encoding:NSUTF8StringEncoding + error:nil]; + ANURLConnectionStub *requestStub = [[ANURLConnectionStub alloc] init]; + requestStub.requestURLRegexPatternString = @"http://mediation.adnxs.com/mob\\?.*"; + requestStub.responseCode = 200; + requestStub.responseBody = baseResponse; + [[ANHTTPStubbingManager sharedStubbingManager] addStub:requestStub]; +} + +- (void)stubResultCBResponse { + ANURLConnectionStub *resultCBStub = [[ANURLConnectionStub alloc] init]; + resultCBStub.requestURLRegexPatternString = @"http://nym1.mobile.adnxs.com/mediation.*"; + resultCBStub.responseCode = 200; + resultCBStub.responseBody = @""; + [[ANHTTPStubbingManager sharedStubbingManager] addStub:resultCBStub]; +} + +#pragma mark - ANAdDelegate + +- (void)adWasClicked:(ANNativeAdResponse *)response { + self.receivedCallbackAdWasClicked = YES; +} + +- (void)adWillPresent:(ANNativeAdResponse *)response { + self.receivedCallbackAdWillPresent = YES; +} + +- (void)adDidPresent:(ANNativeAdResponse *)response { + self.receivedCallbackAdDidPresent = YES; +} + +- (void)adWillClose:(ANNativeAdResponse *)response { + self.receivedCallbackAdWillClose = YES; +} + +- (void)adDidClose:(ANNativeAdResponse *)response { + self.receivedCallbackAdDidClose = YES; +} + +- (void)adWillLeaveApplication:(ANNativeAdResponse *)response { + self.receivedCallbackAdWillLeaveApplication = YES; +} + +#pragma mark - Helper + +- (void)requestLoaded:(NSNotification *)notification { + NSURLRequest *request = notification.userInfo[kANHTTPStubURLProtocolRequest]; + __block NSInteger indexToRemove = -1; + [self.impressionTrackers enumerateObjectsUsingBlock:^(NSURL *URL, NSUInteger idx, BOOL *stop) { + if ([request.URL isEqual:URL]) { + indexToRemove = (NSInteger)idx; + *stop = YES; + } + }]; + if (indexToRemove >= 0) { + [self.impressionTrackers removeObjectAtIndex:indexToRemove]; + return; + } + [self.clickTrackers enumerateObjectsUsingBlock:^(NSURL *URL, NSUInteger idx, BOOL *stop) { + if ([request.URL isEqual:URL]) { + indexToRemove = (NSInteger)idx; + *stop = YES; + } + }]; + if (indexToRemove >= 0) { + [self.clickTrackers removeObjectAtIndex:indexToRemove]; + } +} + +- (void)setupURLDidLoadTracker { + [ANHTTPStubbingManager sharedStubbingManager].broadcastRequests = YES; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(requestLoaded:) + name:kANHTTPStubURLProtocolRequestDidLoadNotification + object:nil]; +} + +- (void)iconImageShouldBePresentInResponse:(BOOL)iconPresent { + if (iconPresent) { + XCTAssertNotNil(self.adResponse.iconImage); + XCTAssertTrue([self.adResponse.iconImage isKindOfClass:[UIImage class]]); + } else { + XCTAssertNil(self.adResponse.iconImage); + } +} + +- (void)mainImageShouldBePresentInResponse:(BOOL)mainImagePresent { + if (mainImagePresent) { + XCTAssertNotNil(self.adResponse.mainImage); + XCTAssertTrue([self.adResponse.mainImage isKindOfClass:[UIImage class]]); + } else { + XCTAssertNil(self.adResponse.mainImage); + } +} + +- (void)createBasicNativeView { + UINib *adNib = [UINib nibWithNibName:@"ANNativeAdView" bundle:[NSBundle bundleForClass:[self class]]]; + NSArray *array = [adNib instantiateWithOwner:self options:nil]; + self.nativeAdView = [array firstObject]; +} + +- (void)createMainImageNativeView { + UINib *adNib = [UINib nibWithNibName:@"ANNativeAdViewMainImage" bundle:[NSBundle bundleForClass:[self class]]]; + NSArray *array = [adNib instantiateWithOwner:self options:nil]; + self.nativeAdView = [array firstObject]; +} + +- (void)populateNativeViewWithResponse { + ANNativeAdView *nativeAdView = self.nativeAdView; + nativeAdView.titleLabel.text = self.adResponse.title; + nativeAdView.bodyLabel.text = self.adResponse.body; + nativeAdView.iconImageView.image = self.adResponse.iconImage; + nativeAdView.mainImageView.image = self.adResponse.mainImage; + [nativeAdView.callToActionButton setTitle:self.adResponse.callToAction forState:UIControlStateNormal]; +} + +- (void)registerNativeView { + NSError *registerError; + UIViewController *rvc = [UIApplication sharedApplication].keyWindow.rootViewController; + self.adResponse.delegate = self; + [self.adResponse registerViewForTracking:self.nativeAdView + withRootViewController:rvc + clickableViews:@[self.nativeAdView.callToActionButton] + error:®isterError]; + XCTAssertNil(registerError); +} + +- (void)assertPendingImpressionTrackerCount:(NSInteger)numImpTrackers { + XCTAssertEqual(self.impressionTrackers.count, numImpTrackers); +} + +- (void)assertPendingClickTrackerCount:(NSInteger)numClickTrackers { + XCTAssertEqual(self.clickTrackers.count, numClickTrackers); +} + +- (void)pullImpressionAndClickTrackersFromResponse { + XCTAssertTrue([self.adResponse isKindOfClass:[ANNativeStandardAdResponse class]]); + ANNativeStandardAdResponse *standardResponse = (ANNativeStandardAdResponse *)self.adResponse; + self.impressionTrackers = [standardResponse.impTrackers mutableCopy]; + self.clickTrackers = [standardResponse.clickTrackers mutableCopy]; +} + +- (void)addNativeViewToViewHierarchy { + UIViewController *rvc = [UIApplication sharedApplication].keyWindow.rootViewController; + self.rootViewController = rvc; + [rvc.view addSubview:self.nativeAdView]; +} + +- (void)clickOnAd { + self.adResponse.landingPageLoadsInBackground = NO; + [tester tapViewWithAccessibilityLabel:@"ANNativeAdViewCallToAction"]; +} + +- (void)assertPresentCallbacksReceived { + XCTAssertTrue(self.receivedCallbackAdWasClicked); + XCTAssertTrue(self.receivedCallbackAdWillPresent); + XCTAssertTrue(self.receivedCallbackAdDidPresent); +} + +- (void)closeInAppBrowser { + [tester tapViewWithAccessibilityLabel:@"Done"]; +} + +- (void)forceDismissPresentedController { + XCTAssertNotNil(self.rootViewController.presentedViewController); + [self.rootViewController dismissViewControllerAnimated:YES completion:nil]; +} + +- (void)assertCloseCallbacksReceived { + XCTAssertTrue(self.receivedCallbackAdWillClose); + XCTAssertTrue(self.receivedCallbackAdDidClose); +} + +@end diff --git a/tests/NativeUnitTests/ANNativeAdView.h b/tests/NativeUnitTests/ANNativeAdView.h new file mode 100644 index 000000000..3fbdfd3af --- /dev/null +++ b/tests/NativeUnitTests/ANNativeAdView.h @@ -0,0 +1,26 @@ +/* Copyright 2015 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +@interface ANNativeAdView : UIView + +@property (weak, nonatomic) IBOutlet UIImageView *iconImageView; +@property (weak, nonatomic) IBOutlet UIImageView *mainImageView; +@property (weak, nonatomic) IBOutlet UILabel *titleLabel; +@property (weak, nonatomic) IBOutlet UILabel *bodyLabel; +@property (weak, nonatomic) IBOutlet UIButton *callToActionButton; + +@end diff --git a/tests/NativeUnitTests/ANNativeAdView.m b/tests/NativeUnitTests/ANNativeAdView.m new file mode 100644 index 000000000..808e317e5 --- /dev/null +++ b/tests/NativeUnitTests/ANNativeAdView.m @@ -0,0 +1,20 @@ +/* Copyright 2015 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANNativeAdView.h" + +@implementation ANNativeAdView + +@end diff --git a/tests/NativeUnitTests/ANNativeAdView.xib b/tests/NativeUnitTests/ANNativeAdView.xib new file mode 100644 index 000000000..a7c19896e --- /dev/null +++ b/tests/NativeUnitTests/ANNativeAdView.xib @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/NativeUnitTests/ANNativeAdViewMainImage.xib b/tests/NativeUnitTests/ANNativeAdViewMainImage.xib new file mode 100644 index 000000000..d13b2cdaf --- /dev/null +++ b/tests/NativeUnitTests/ANNativeAdViewMainImage.xib @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/NativeUnitTests/ANNativeImpressionTrackerManagerTestCase.m b/tests/NativeUnitTests/ANNativeImpressionTrackerManagerTestCase.m new file mode 100644 index 000000000..858e0745b --- /dev/null +++ b/tests/NativeUnitTests/ANNativeImpressionTrackerManagerTestCase.m @@ -0,0 +1,73 @@ +/* Copyright 2015 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import +#import "ANNativeImpressionTrackerManager.h" +#import "ANReachability+ANTest.h" +#import "XCTestCase+ANCategory.h" + +#import "ANHTTPStubbingManager.h" +#import "ANNativeImpressionTrackerManager+ANTest.h" +#import "NSTimer+ANCategory.h" + +@interface ANNativeImpressionTrackerManagerTestCase : XCTestCase + +@property (nonatomic, readwrite, strong) NSURL *URL; +@property (nonatomic, readwrite, assign) BOOL urlWasFired; + +@end + +@implementation ANNativeImpressionTrackerManagerTestCase + +- (void)setUp { + [ANHTTPStubbingManager sharedStubbingManager].ignoreUnstubbedRequests = YES; +} + +- (void)tearDown { + [super tearDown]; + [ANReachability toggleNonReachableNetworkStatusSimulationEnabled:NO]; + [ANHTTPStubbingManager sharedStubbingManager].broadcastRequests = NO; +} + +- (void)testSimulateOffline { + [ANHTTPStubbingManager sharedStubbingManager].broadcastRequests = YES; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(requestLoaded:) + name:kANHTTPStubURLProtocolRequestDidLoadNotification + object:nil]; + [ANReachability toggleNonReachableNetworkStatusSimulationEnabled:YES]; + self.URL = [NSURL URLWithString:@"http://rlissack.adnxs.net:8080/jtest/native/empty_response.json"]; + [ANNativeImpressionTrackerManager fireImpressionTrackerURL:self.URL]; + [XCTestCase delayForTimeInterval:3.0]; + XCTAssertFalse(self.urlWasFired); + + NSTimer *fireTimer = [ANNativeImpressionTrackerManager sharedManager].impressionTrackerRetryTimer; + XCTAssertTrue(fireTimer.isScheduled); + + [ANReachability toggleNonReachableNetworkStatusSimulationEnabled:NO]; + fireTimer.fireDate = [NSDate dateWithTimeIntervalSinceNow:1.0]; + + [XCTestCase delayForTimeInterval:1.5]; + XCTAssertTrue(self.urlWasFired); +} + +- (void)requestLoaded:(NSNotification *)notification { + NSURLRequest *request = notification.userInfo[kANHTTPStubURLProtocolRequest]; + if (self.URL && [request.URL isEqual:self.URL]) { + self.urlWasFired = YES; + } +} + +@end \ No newline at end of file diff --git a/tests/NativeUnitTests/Info.plist b/tests/NativeUnitTests/Info.plist new file mode 100644 index 000000000..2984231fe --- /dev/null +++ b/tests/NativeUnitTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + corp.appnexus.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/tests/NativeUnitTests/Native Responses/appnexus_click_fallback_example.json b/tests/NativeUnitTests/Native Responses/appnexus_click_fallback_example.json new file mode 100644 index 000000000..71c5871b2 --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/appnexus_click_fallback_example.json @@ -0,0 +1,37 @@ +{ + "status":"ok", + "ads":[ + + ], + "mediated":[ + + ], + "native":[ + { + "title":"AppNexusSDKApp", + "description":"Showcases the AppNexus mobile SDK and all its features. Works with placements generated under a publisher in the AppNexus Console.", + "cta":"Install Now!", + "icon_img_url":"http://rlissack.adnxs.net:8080/jtest/appnexus_logo_icon@2x.png", + "main_media":[ + { + "url":"http://rlissack.adnxs.net:8080/jtest/MainImageAppNexusSDKApp@2x.png", + "width":300, + "height":250, + "label":"default" + } + ], + "rating":{ + "value":5.0, + "scale":5 + }, + "impression_trackers":[ + "http://rlissack.adnxs.net:8080/jtest/trackImpression" + ], + "click_trackers":[ + "http://nym1.ib.adnxs.com/click?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA_AAAAAAAAAAAAAAAAAAAAAJkJvjGlBMFaZyDVla9jmxLH_n1UAAAAAJ-nIAC-AwAAvgMAAAIAAACL37AAtZgCAAAAAQBVU0QAVVNEACwB-gARIAAA5uUAAgMCAQIAAAAAJBbkOAAAAAA./cnd=%21-gXbOAi9vKkBEIu_wwUYtbEKIAQ./referrer=http%3A%2F%2Fapps.mobile.adnxs.com/clickenc=" + ], + "click_url":"unknown://openapp", + "click_url_fallback":"http://appnexus.com" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/appnexus_multiple_main_media.json b/tests/NativeUnitTests/Native Responses/appnexus_multiple_main_media.json new file mode 100644 index 000000000..74e17b365 --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/appnexus_multiple_main_media.json @@ -0,0 +1,48 @@ +{ + "status":"ok", + "ads":[ + + ], + "mediated":[ + + ], + "native":[ + { + "title":"AppNexusSDKApp", + "description":"Showcases the AppNexus mobile SDK and all its features. Works with placements generated under a publisher in the AppNexus Console.", + "cta":"Install Now!", + "icon_img_url":"http://rlissack.adnxs.net:8080/jtest/appnexus_logo_icon@2x.png", + "main_media":[ + { + "url":"http://upload.wikimedia.org/wikipedia/commons/0/0a/Eastern_Grey_Squirrel.jpg", + "width":300, + "height":250, + "label":"banner" + }, + { + "url":"http://rlissack.adnxs.net:8080/jtest/MainImageAppNexusSDKApp@2x.png", + "width":300, + "height":250, + "label":"default" + }, + { + "url":"http://animalstime.com/wp-content/uploads/2012/05/kangaroo-facts-for-kids.jpg", + "width":300, + "height":250, + "label":"kangaroo" + } + ], + "rating":{ + "value":5.0, + "scale":5 + }, + "impression_trackers":[ + "http://rlissack.adnxs.net:8080/jtest/trackImpression" + ], + "click_trackers":[ + "http://nym1.ib.adnxs.com/click?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA_AAAAAAAAAAAAAAAAAAAAAJkJvjGlBMFaZyDVla9jmxLH_n1UAAAAAJ-nIAC-AwAAvgMAAAIAAACL37AAtZgCAAAAAQBVU0QAVVNEACwB-gARIAAA5uUAAgMCAQIAAAAAJBbkOAAAAAA./cnd=%21-gXbOAi9vKkBEIu_wwUYtbEKIAQ./referrer=http%3A%2F%2Fapps.mobile.adnxs.com/clickenc=" + ], + "click_url":"http://appnexus.com" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/appnexus_multiple_main_media_default.json b/tests/NativeUnitTests/Native Responses/appnexus_multiple_main_media_default.json new file mode 100644 index 000000000..a61338685 --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/appnexus_multiple_main_media_default.json @@ -0,0 +1,48 @@ +{ + "status":"ok", + "ads":[ + + ], + "mediated":[ + + ], + "native":[ + { + "title":"AppNexusSDKApp", + "description":"Showcases the AppNexus mobile SDK and all its features. Works with placements generated under a publisher in the AppNexus Console.", + "cta":"Install Now!", + "icon_img_url":"http://rlissack.adnxs.net:8080/jtest/appnexus_logo_icon@2x.png", + "main_media":[ + { + "url":"http://upload.wikimedia.org/wikipedia/commons/0/0a/Eastern_Grey_Squirrel.jpg", + "width":300, + "height":250, + "label":"banner" + }, + { + "url":"http://rlissack.adnxs.net:8080/jtest/MainImageAppNexusSDKApp@2x.png", + "width":300, + "height":250, + "label":"default" + }, + { + "url":"http://animalstime.com/wp-content/uploads/2012/05/kangaroo-facts-for-kids.jpg", + "width":300, + "height":250, + "label":"default" + } + ], + "rating":{ + "value":5.0, + "scale":5 + }, + "impression_trackers":[ + "http://rlissack.adnxs.net:8080/jtest/trackImpression" + ], + "click_trackers":[ + "http://nym1.ib.adnxs.com/click?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA_AAAAAAAAAAAAAAAAAAAAAJkJvjGlBMFaZyDVla9jmxLH_n1UAAAAAJ-nIAC-AwAAvgMAAAIAAACL37AAtZgCAAAAAQBVU0QAVVNEACwB-gARIAAA5uUAAgMCAQIAAAAAJBbkOAAAAAA./cnd=%21-gXbOAi9vKkBEIu_wwUYtbEKIAQ./referrer=http%3A%2F%2Fapps.mobile.adnxs.com/clickenc=" + ], + "click_url":"http://appnexus.com" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/appnexus_multiple_trackers.json b/tests/NativeUnitTests/Native Responses/appnexus_multiple_trackers.json new file mode 100644 index 000000000..9166791ea --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/appnexus_multiple_trackers.json @@ -0,0 +1,41 @@ +{ + "status":"ok", + "ads":[ + + ], + "mediated":[ + + ], + "native":[ + { + "title":"AppNexusSDKApp", + "description":"Showcases the AppNexus mobile SDK and all its features. Works with placements generated under a publisher in the AppNexus Console.", + "cta":"Install Now!", + "icon_img_url":"http://rlissack.adnxs.net:8080/jtest/appnexus_logo_icon@2x.png", + "main_media":[ + { + "url":"http://rlissack.adnxs.net:8080/jtest/MainImageAppNexusSDKApp@2x.png", + "width":300, + "height":250, + "label":"default" + } + ], + "rating":{ + "value":5.0, + "scale":5 + }, + "impression_trackers":[ + "http://rlissack.adnxs.net:8080/jtest/trackImpression", + "http://rlissack.adnxs.net:8080/jtest/trackImpression2", + "http://rlissack.adnxs.net:8080/jtest/trackImpression3", + ], + "click_trackers":[ + "http://nym1.ib.adnxs.com/click?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA_AAAAAAAAAAAAAAAAAAAAAJkJvjGlBMFaZyDVla9jmxLH_n1UAAAAAJ-nIAC-AwAAvgMAAAIAAACL37AAtZgCAAAAAQBVU0QAVVNEACwB-gARIAAA5uUAAgMCAQIAAAAAJBbkOAAAAAA./cnd=%21-gXbOAi9vKkBEIu_wwUYtbEKIAQ./referrer=http%3A%2F%2Fapps.mobile.adnxs.com/clickenc=", + "http://rlissack.adnxs.net:8080/jtest/trackClick", + "http://rlissack.adnxs.net:8080/jtest/trackClick2", + "http://rlissack.adnxs.net:8080/jtest/trackClick3" + ], + "click_url":"http://appnexus.com" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/appnexus_standard_response.json b/tests/NativeUnitTests/Native Responses/appnexus_standard_response.json new file mode 100644 index 000000000..4d8327e71 --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/appnexus_standard_response.json @@ -0,0 +1,36 @@ +{ + "status":"ok", + "ads":[ + + ], + "mediated":[ + + ], + "native":[ + { + "title":"AppNexusSDKApp", + "description":"Showcases the AppNexus mobile SDK and all its features. Works with placements generated under a publisher in the AppNexus Console.", + "cta":"Install Now!", + "icon_img_url":"http://rlissack.adnxs.net:8080/jtest/appnexus_logo_icon@2x.png", + "main_media":[ + { + "url":"http://rlissack.adnxs.net:8080/jtest/MainImageAppNexusSDKApp@2x.png", + "width":300, + "height":250, + "label":"default" + } + ], + "rating":{ + "value":5.0, + "scale":5 + }, + "impression_trackers":[ + "http://rlissack.adnxs.net:8080/jtest/trackImpression" + ], + "click_trackers":[ + "http://nym1.ib.adnxs.com/click?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA_AAAAAAAAAAAAAAAAAAAAAJkJvjGlBMFaZyDVla9jmxLH_n1UAAAAAJ-nIAC-AwAAvgMAAAIAAACL37AAtZgCAAAAAQBVU0QAVVNEACwB-gARIAAA5uUAAgMCAQIAAAAAJBbkOAAAAAA./cnd=%21-gXbOAi9vKkBEIu_wwUYtbEKIAQ./referrer=http%3A%2F%2Fapps.mobile.adnxs.com/clickenc=" + ], + "click_url":"http://appnexus.com" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/appnexus_standard_response_store_url.json b/tests/NativeUnitTests/Native Responses/appnexus_standard_response_store_url.json new file mode 100644 index 000000000..ef403f735 --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/appnexus_standard_response_store_url.json @@ -0,0 +1,36 @@ +{ + "status":"ok", + "ads":[ + + ], + "mediated":[ + + ], + "native":[ + { + "title":"AppNexusSDKApp", + "description":"Showcases the AppNexus mobile SDK and all its features. Works with placements generated under a publisher in the AppNexus Console.", + "cta":"Install Now!", + "icon_img_url":"http://rlissack.adnxs.net:8080/jtest/appnexus_logo_icon@2x.png", + "main_media":[ + { + "url":"http://rlissack.adnxs.net:8080/jtest/MainImageAppNexusSDKApp@2x.png", + "width":300, + "height":250, + "label":"default" + } + ], + "rating":{ + "value":5.0, + "scale":5 + }, + "impression_trackers":[ + "http://rlissack.adnxs.net:8080/jtest/trackImpression" + ], + "click_trackers":[ + "http://nym1.ib.adnxs.com/click?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA_AAAAAAAAAAAAAAAAAAAAAJkJvjGlBMFaZyDVla9jmxLH_n1UAAAAAJ-nIAC-AwAAvgMAAAIAAACL37AAtZgCAAAAAQBVU0QAVVNEACwB-gARIAAA5uUAAgMCAQIAAAAAJBbkOAAAAAA./cnd=%21-gXbOAi9vKkBEIu_wwUYtbEKIAQ./referrer=http%3A%2F%2Fapps.mobile.adnxs.com/clickenc=" + ], + "click_url":"https://itunes.apple.com/us/app/appnexus-sdk-app/id736869833?mt=8" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/custom_adapter_fb_mediated_response.json b/tests/NativeUnitTests/Native Responses/custom_adapter_fb_mediated_response.json new file mode 100644 index 000000000..d4a8a2fdc --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/custom_adapter_fb_mediated_response.json @@ -0,0 +1,48 @@ +{ + "status":"ok", + "ads":[ + + ], + "mediated":[ + { + "handler":[ + { + "width":"", + "height":"", + "type":"ios", + "class":"MyDummyNativeCustomAdapter", + "id":"210827375150_10154672420735151" + }, + { + "width":"320", + "height":"50", + "type":"android", + "class":"com.appnexus.opensdk.mediatedviews.MyDummyNativeCustomAdapter", + "id":"210827375150_10154672419150151" + } + ], + "init_cb":"", + "result_cb":"" + }, + { + "handler":[ + { + "width":"", + "height":"", + "type":"ios", + "class":"ANAdAdapterNativeFacebook", + "id":"210827375150_10154672420735151" + }, + { + "width":"320", + "height":"50", + "type":"android", + "class":"com.appnexus.opensdk.mediatedviews.FacebookNative", + "id":"210827375150_10154672419150151" + } + ], + "init_cb":"", + "result_cb":"" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/custom_adapter_invalid_type.json b/tests/NativeUnitTests/Native Responses/custom_adapter_invalid_type.json new file mode 100644 index 000000000..d925d8cd3 --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/custom_adapter_invalid_type.json @@ -0,0 +1,28 @@ +{ + "status":"ok", + "ads":[ + + ], + "mediated":[ + { + "handler":[ + { + "width":"", + "height":"", + "type":"windows_phone", + "class":"MyDummyNativeCustomAdapter", + "id":"210827375150_10154672420735151" + }, + { + "width":"320", + "height":"50", + "type":"android", + "class":"com.appnexus.opensdk.mediatedviews.MyDummyNativeCustomAdapter", + "id":"210827375150_10154672419150151" + } + ], + "init_cb":"", + "result_cb":"" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/custom_adapter_mediated_response.json b/tests/NativeUnitTests/Native Responses/custom_adapter_mediated_response.json new file mode 100644 index 000000000..a3ca29d4c --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/custom_adapter_mediated_response.json @@ -0,0 +1,28 @@ +{ + "status":"ok", + "ads":[ + + ], + "mediated":[ + { + "handler":[ + { + "width":"", + "height":"", + "type":"ios", + "class":"MyDummyNativeCustomAdapter", + "id":"210827375150_10154672420735151" + }, + { + "width":"320", + "height":"50", + "type":"android", + "class":"com.appnexus.opensdk.mediatedviews.MyDummyNativeCustomAdapter", + "id":"210827375150_10154672419150151" + } + ], + "init_cb":"", + "result_cb":"" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/custom_adapter_to_native_ad.json b/tests/NativeUnitTests/Native Responses/custom_adapter_to_native_ad.json new file mode 100644 index 000000000..21138a344 --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/custom_adapter_to_native_ad.json @@ -0,0 +1,55 @@ +{ + "status":"ok", + "ads":[ + + ], + "native":[ + { + "title":"AppNexusSDKApp", + "description":"Showcases the AppNexus mobile SDK and all its features. Works with placements generated under a publisher in the AppNexus Console.", + "cta":"Install Now!", + "icon_img_url":"http://rlissack.adnxs.net:8080/jtest/appnexus_logo_icon@2x.png", + "main_media":[ + { + "url":"http://rlissack.adnxs.net:8080/jtest/MainImageAppNexusSDKApp@2x.png", + "width":300, + "height":250, + "label":"default" + } + ], + "rating":{ + "value":5.0, + "scale":5 + }, + "impression_trackers":[ + "http://rlissack.adnxs.net:8080/jtest/trackImpression" + ], + "click_trackers":[ + "http://nym1.ib.adnxs.com/click?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA_AAAAAAAAAAAAAAAAAAAAAJkJvjGlBMFaZyDVla9jmxLH_n1UAAAAAJ-nIAC-AwAAvgMAAAIAAACL37AAtZgCAAAAAQBVU0QAVVNEACwB-gARIAAA5uUAAgMCAQIAAAAAJBbkOAAAAAA./cnd=%21-gXbOAi9vKkBEIu_wwUYtbEKIAQ./referrer=http%3A%2F%2Fapps.mobile.adnxs.com/clickenc=" + ], + "click_url":"http://appnexus.com" + } + ], + "mediated":[ + { + "handler":[ + { + "width":"", + "height":"", + "type":"ios", + "class":"MyDummyNativeCustomAdapter", + "id":"210827375150_10154672420735151" + }, + { + "width":"320", + "height":"50", + "type":"android", + "class":"com.appnexus.opensdk.mediatedviews.MyDummyNativeCustomAdapter", + "id":"210827375150_10154672419150151" + } + ], + "init_cb":"", + "result_cb":"http://rlissack.adnxs.net:8080/jtest/native/empty_mediated_ad_response.json" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/custom_adapter_to_standard_response.json b/tests/NativeUnitTests/Native Responses/custom_adapter_to_standard_response.json new file mode 100644 index 000000000..5db87818c --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/custom_adapter_to_standard_response.json @@ -0,0 +1,28 @@ +{ + "status":"ok", + "ads":[ + + ], + "mediated":[ + { + "handler":[ + { + "width":"", + "height":"", + "type":"ios", + "class":"MyDummyNativeCustomAdapter", + "id":"210827375150_10154672420735151" + }, + { + "width":"320", + "height":"50", + "type":"android", + "class":"com.appnexus.opensdk.mediatedviews.MyDummyNativeCustomAdapter", + "id":"210827375150_10154672419150151" + } + ], + "init_cb":"", + "result_cb":"http://rlissack.adnxs.net:8080/jtest/native/appnexus_standard_response.json" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/empty_mediated_ad_response.json b/tests/NativeUnitTests/Native Responses/empty_mediated_ad_response.json new file mode 100644 index 000000000..a196bc7a0 --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/empty_mediated_ad_response.json @@ -0,0 +1,14 @@ +{ + "status":"ok", + "ads":[ + + ], + "mediated":[ + { + + } + ], + "native":[ + + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/empty_response.json b/tests/NativeUnitTests/Native Responses/empty_response.json new file mode 100644 index 000000000..e69de29bb diff --git a/tests/NativeUnitTests/Native Responses/facebook_mediated_response.json b/tests/NativeUnitTests/Native Responses/facebook_mediated_response.json new file mode 100644 index 000000000..9f0f4afc0 --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/facebook_mediated_response.json @@ -0,0 +1,28 @@ +{ + "status":"ok", + "ads":[ + + ], + "mediated":[ + { + "handler":[ + { + "width":"", + "height":"", + "type":"ios", + "class":"ANAdAdapterNativeFacebook", + "id":"210827375150_10154672420735151" + }, + { + "width":"320", + "height":"50", + "type":"android", + "class":"com.appnexus.opensdk.mediatedviews.FacebookNative", + "id":"210827375150_10154672419150151" + } + ], + "init_cb":"", + "result_cb":"" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/mopub_mediated_response.json b/tests/NativeUnitTests/Native Responses/mopub_mediated_response.json new file mode 100644 index 000000000..a5a0db361 --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/mopub_mediated_response.json @@ -0,0 +1,28 @@ +{ + "status":"ok", + "ads":[ + + ], + "mediated":[ + { + "handler":[ + { + "width":"", + "height":"", + "type":"ios", + "class":"ANAdAdapterNativeMoPub", + "id":"2e1dc30d43c34a888d91b5203560bbf6" + }, + { + "width":"320", + "height":"50", + "type":"android", + "class":"com.appnexus.opensdk.mediatedviews.MoPubNative", + "id":"2e1dc30d43c34a888d91b5203560bbf6" + } + ], + "init_cb":"", + "result_cb":"" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/nativeResponse1.json b/tests/NativeUnitTests/Native Responses/nativeResponse1.json new file mode 100644 index 000000000..6ec80f451 --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/nativeResponse1.json @@ -0,0 +1,30 @@ +{ + "status":"OK", + "ads":[ + + ], + "mediated":[ + + ], + "native":[ + { + "title":"AppNexusSDKApp", + "description":"Showcases the AppNexus mobile SDK and all its features. Works with placements generated under a publisher in the AppNexus Console.", + "cta":"Install Now!", + "icon_img_url":"http://rlissack.adnxs.net:8080/jtest/appnexus_logo_icon@2x.png", + "main_media":[ + { + "url":"http://rlissack.adnxs.net:8080/jtest/MainImageAppNexusSDKApp@2x.png", + "width":300, + "height":250, + "label":"default" + } + ], + "rating":{ + "value":5.0, + "scale":5 + }, + "click_url":"https://itunes.apple.com/us/app/appnexussdkapp/id736869833?mt=8" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/nativeResponse2.json b/tests/NativeUnitTests/Native Responses/nativeResponse2.json new file mode 100644 index 000000000..03caccc7a --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/nativeResponse2.json @@ -0,0 +1,30 @@ +{ + "status":"OK", + "ads":[ + + ], + "mediated":[ + + ], + "native":[ + { + "title":"AppNexusSDKApp", + "description":"Showcases the AppNexus mobile SDK and all its features. Works with placements generated under a publisher in the AppNexus Console.", + "cta":"Install Now!", + "icon_img_url":"http://rlissack.adnxs.net:8080/jtest/appnexus_logo_icon@2x.png", + "main_media":[ + { + "url":"http://rlissack.adnxs.net:8080/jtest/MainImageAppNexusSDKApp@2x.png", + "width":300, + "height":250, + "label":"default" + } + ], + "rating":{ + "value":5.0, + "scale":5 + } + "click_url":"https://itunes.apple.com/us/app/appnexussdkapp/id736869833?mt=8" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/nativeResponse3.json b/tests/NativeUnitTests/Native Responses/nativeResponse3.json new file mode 100644 index 000000000..a76d6097b --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/nativeResponse3.json @@ -0,0 +1,30 @@ +{ + "status":"OK", + "ads":[ + + ], + "mediated":[ + + ], + "native":[ + { + "title":"AppNexusSDKApp", + "description":"Showcases the AppNexus mobile SDK and all its features. Works with placements generated under a publisher in the AppNexus Console.", + "cta":"Install Now!", + "icon_img_url":http://rlissack.adnxs.net:8080/jtest/appnexus_logo_icon@2x.png", + "main_media":[ + { + "url":"http://rlissack.adnxs.net:8080/jtest/MainImageAppNexusSDKApp@2x.png", + "width":300, + "height":250, + "label":"default" + } + ], + "rating":{ + "value":5.0, + "scale":5 + }, + "click_url":"https://itunes.apple.com/us/app/appnexussdkapp/id736869833?mt=8" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/nativeResponse4.json b/tests/NativeUnitTests/Native Responses/nativeResponse4.json new file mode 100644 index 000000000..883a6df57 --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/nativeResponse4.json @@ -0,0 +1,27 @@ +{ + "status":"OK", + "ads":[ + + ], + "mediated":[ + + ], + "native":[ + { + "title":"AppNexusSDKApp", + "description":"Showcases the AppNexus mobile SDK and all its features. Works with placements generated under a publisher in the AppNexus Console.", + "cta":"Install Now!", + "icon_img_url":"http://rlissack.adnxs.net:8080/jtest/appnexus_logo_icon@2x.png", + "main_media":[ + { + "url":"http://rlissack.adnxs.net:8080/jtest/MainImageAppNexusSDKApp@2x.png", + "width":300, + "height":250, + "label":"default" + } + ], + "rating":"5.0", + "click_url":"https://itunes.apple.com/us/app/appnexussdkapp/id736869833?mt=8" + } + ] +} diff --git a/tests/NativeUnitTests/Native Responses/nativeResponse5.json b/tests/NativeUnitTests/Native Responses/nativeResponse5.json new file mode 100644 index 000000000..b50f1025f --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/nativeResponse5.json @@ -0,0 +1,34 @@ +{ + "status":"OK", + "ads":[ + + ], + "mediated":[ + + ], + "native":[ + { + "title":"AppNexusSDKApp", + "description":"Showcases the AppNexus mobile SDK and all its features. Works with placements generated under a publisher in the AppNexus Console.", + "cta":"Install Now!", + "icon_img_url":"http://rlissack.adnxs.net:8080/jtest/appnexus_logo_icon@2x.png", + "main_media":[ + { + "url":"http://rlissack.adnxs.net:8080/jtest/MainImageAppNexusSDKApp@2x.png", + "width":300, + "height":250, + "label":"default" + } + ], + "rating":{ + "value":5.0, + "scale":5 + }, + "click_url":"https://itunes.apple.com/us/app/appnexussdkapp/id736869833?mt=8", + "click_trackers":[ + + ], + "impression_trackers":"" + } + ] +} \ No newline at end of file diff --git a/tests/NativeUnitTests/Native Responses/no_ads_ok_response.json b/tests/NativeUnitTests/Native Responses/no_ads_ok_response.json new file mode 100644 index 000000000..766ab916e --- /dev/null +++ b/tests/NativeUnitTests/Native Responses/no_ads_ok_response.json @@ -0,0 +1,12 @@ +{ + "status":"ok", + "ads":[ + + ], + "mediated":[ + + ], + "native":[ + + ] +} \ No newline at end of file diff --git a/tests/NewTestApp.xcodeproj/project.pbxproj b/tests/NewTestApp.xcodeproj/project.pbxproj index 3aa82d436..848c86c55 100644 --- a/tests/NewTestApp.xcodeproj/project.pbxproj +++ b/tests/NewTestApp.xcodeproj/project.pbxproj @@ -18,7 +18,6 @@ 8A0AA46C19DB30A2005EC52C /* ANBannerAdViewTransitionsTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A0AA46519DB30A2005EC52C /* ANBannerAdViewTransitionsTestCase.m */; }; 8A0AA46D19DB30A2005EC52C /* ANLocationTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A0AA46619DB30A2005EC52C /* ANLocationTestCase.m */; }; 8A0AA46E19DB30A2005EC52C /* ANMediationAdViewControllerTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A0AA46719DB30A2005EC52C /* ANMediationAdViewControllerTestCase.m */; }; - 8A0AA46F19DB30A2005EC52C /* ANMRAIDViewControllerTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A0AA46819DB30A2005EC52C /* ANMRAIDViewControllerTestCase.m */; }; 8A0AA47019DB30A2005EC52C /* UIViewConstraintsTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A0AA46919DB30A2005EC52C /* UIViewConstraintsTestCase.m */; }; 8A0AA47719DB314C005EC52C /* ANAdAdapterBannerUnableToFillWithSubsequentCallbacks.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A0AA47219DB314C005EC52C /* ANAdAdapterBannerUnableToFillWithSubsequentCallbacks.m */; }; 8A0AA47819DB314C005EC52C /* ANFailedMultiple.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A0AA47419DB314C005EC52C /* ANFailedMultiple.m */; }; @@ -33,14 +32,41 @@ 8A0AA49519DB3453005EC52C /* ANAdAdapterBannerTimeoutThenSuccessful.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A0AA48919DB3453005EC52C /* ANAdAdapterBannerTimeoutThenSuccessful.m */; }; 8A0AA49619DB3453005EC52C /* ANAdAdapterBannerUnableToFill.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A0AA48B19DB3453005EC52C /* ANAdAdapterBannerUnableToFill.m */; }; 8A0AA49719DB3453005EC52C /* ANAdAdapterBannerUnableToFillThenSuccessful.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A0AA48D19DB3453005EC52C /* ANAdAdapterBannerUnableToFillThenSuccessful.m */; }; + 8A33A5101A7C250500F8ED5E /* ANNativeImpressionTrackerManagerTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A33A50F1A7C250500F8ED5E /* ANNativeImpressionTrackerManagerTestCase.m */; }; + 8A33A5131A7C264D00F8ED5E /* ANNativeImpressionTrackerManager+ANTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A33A5121A7C264D00F8ED5E /* ANNativeImpressionTrackerManager+ANTest.m */; }; 8A3B37AF19D62A4E00CE24A5 /* iAd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8A5D27CA199AB26B00F2A516 /* iAd.framework */; }; 8A3C13CB19EF2F1700CB1502 /* MediationAdaptersTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A3C13B119EF2CB000CB1502 /* MediationAdaptersTestCase.m */; }; + 8A4017F81A95006B00D56208 /* MPCloseButtonX@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A4017F71A95006B00D56208 /* MPCloseButtonX@3x.png */; }; + 8A4017F91A95006B00D56208 /* MPCloseButtonX@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A4017F71A95006B00D56208 /* MPCloseButtonX@3x.png */; }; + 8A4018001A95008A00D56208 /* MPAdBrowserController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8A7F4CC119DB3976003ECC5C /* MPAdBrowserController.xib */; }; + 8A4018011A95008A00D56208 /* MPCloseButtonX.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A7F4CC219DB3976003ECC5C /* MPCloseButtonX.png */; }; + 8A4018021A95008A00D56208 /* MPCloseButtonX@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A7F4CC319DB3976003ECC5C /* MPCloseButtonX@2x.png */; }; + 8A4018031A95008E00D56208 /* MRAID.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 8A7F4CC419DB3976003ECC5C /* MRAID.bundle */; }; + 8A4018051A9500A300D56208 /* GoogleMobileAds.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8A4018041A9500A300D56208 /* GoogleMobileAds.framework */; }; + 8A549EAE1A706BC7009F797A /* ANNativeAdRequestTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A549EAD1A706BC7009F797A /* ANNativeAdRequestTestCase.m */; }; + 8A549EB01A706BFE009F797A /* ANAdServerResponseTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A549EAF1A706BFE009F797A /* ANAdServerResponseTestCase.m */; }; + 8A549EB21A706C65009F797A /* XCTestCase+ANCategory.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AA00A0F19DB1E150090EBED /* XCTestCase+ANCategory.m */; }; + 8A549EB31A706C71009F797A /* ANNativeAdRequest+ANBaseUrlOverride.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A8458711A6998F40014F291 /* ANNativeAdRequest+ANBaseUrlOverride.m */; }; + 8A549EB41A706C7D009F797A /* ANAdAdapterBannerMoPub+ANTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB5326A19F0503E00CA4427 /* ANAdAdapterBannerMoPub+ANTest.m */; }; + 8A549EBB1A706D6F009F797A /* nativeResponse1.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A549EB61A706D6F009F797A /* nativeResponse1.json */; }; + 8A549EBC1A706D6F009F797A /* nativeResponse2.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A549EB71A706D6F009F797A /* nativeResponse2.json */; }; + 8A549EBD1A706D6F009F797A /* nativeResponse3.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A549EB81A706D6F009F797A /* nativeResponse3.json */; }; + 8A549EBE1A706D6F009F797A /* nativeResponse4.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A549EB91A706D6F009F797A /* nativeResponse4.json */; }; + 8A549EBF1A706D6F009F797A /* nativeResponse5.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A549EBA1A706D6F009F797A /* nativeResponse5.json */; }; + 8A549EC01A706DA5009F797A /* SuccessfulMediationResponse.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AA00A2019DB1E150090EBED /* SuccessfulMediationResponse.json */; }; + 8A661ED01A85597E00117553 /* appnexus_click_fallback_example.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A661ECF1A85597E00117553 /* appnexus_click_fallback_example.json */; }; 8A742A8E19CB2E4700D2AE6F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8AD0183A199932F9007874BA /* Main.storyboard */; }; + 8A764F041A7078F500C02A97 /* ANReachability+ANTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A764F031A7078F500C02A97 /* ANReachability+ANTest.m */; }; + 8A764F0E1A70798A00C02A97 /* NSObject+Swizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AA00A0919DB1E150090EBED /* NSObject+Swizzling.m */; }; 8A7AE41019DF2A610037DDC8 /* BaseMediationSingleNetworkResponse.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A7AE40F19DF2A610037DDC8 /* BaseMediationSingleNetworkResponse.json */; }; 8A7F4CC519DB3976003ECC5C /* MPAdBrowserController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8A7F4CC119DB3976003ECC5C /* MPAdBrowserController.xib */; }; 8A7F4CC619DB3976003ECC5C /* MPCloseButtonX.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A7F4CC219DB3976003ECC5C /* MPCloseButtonX.png */; }; 8A7F4CC719DB3976003ECC5C /* MPCloseButtonX@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8A7F4CC319DB3976003ECC5C /* MPCloseButtonX@2x.png */; }; 8A7F4CC819DB3976003ECC5C /* MRAID.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 8A7F4CC419DB3976003ECC5C /* MRAID.bundle */; }; + 8A8458721A6998F40014F291 /* ANNativeAdRequest+ANBaseUrlOverride.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A8458711A6998F40014F291 /* ANNativeAdRequest+ANBaseUrlOverride.m */; }; + 8A8458741A699CF90014F291 /* ANNativeAdRequest+ANBaseUrlOverride.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A8458711A6998F40014F291 /* ANNativeAdRequest+ANBaseUrlOverride.m */; }; + 8A8458881A69A34C0014F291 /* ANSDKResources.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 8AA0094219DB169B0090EBED /* ANSDKResources.bundle */; }; + 8A9BF1441A7FE3B800C0D227 /* ANNativeAdViewMainImage.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8A9BF1431A7FE3B800C0D227 /* ANNativeAdViewMainImage.xib */; }; 8AA0095A19DB16C50090EBED /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AA0095519DB16C50090EBED /* AppDelegate.m */; }; 8AA0095B19DB16C50090EBED /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AA0095619DB16C50090EBED /* main.m */; }; 8AA0095C19DB16C50090EBED /* TestsStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8AA0095719DB16C50090EBED /* TestsStoryboard.storyboard */; }; @@ -78,10 +104,9 @@ 8AA009CA19DB1B200090EBED /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AA009C219DB1B200090EBED /* main.m */; }; 8AA009E419DB1D270090EBED /* AmazonAd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AA009E319DB1D270090EBED /* AmazonAd.framework */; }; 8AA009E619DB1D320090EBED /* FBAudienceNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AA009E519DB1D320090EBED /* FBAudienceNetwork.framework */; }; - 8AA009E819DB1D3C0090EBED /* libGoogleAdMobAds.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AA009E719DB1D3C0090EBED /* libGoogleAdMobAds.a */; }; 8AA009EA19DB1D480090EBED /* MillennialMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AA009E919DB1D480090EBED /* MillennialMedia.framework */; }; 8AA009EC19DB1D530090EBED /* libMoPubSDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AA009EB19DB1D530090EBED /* libMoPubSDK.a */; }; - 8AA009ED19DB1D670090EBED /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8AA009C019DB1B200090EBED /* Images.xcassets */; }; + 8AA009ED19DB1D670090EBED /* MediationAdapterAppImages.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8AA009C019DB1B200090EBED /* MediationAdapterAppImages.xcassets */; }; 8AA009EE19DB1D790090EBED /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8AA009BC19DB1B200090EBED /* LaunchScreen.xib */; }; 8AA009EF19DB1D790090EBED /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8AA009BE19DB1B200090EBED /* Main.storyboard */; }; 8AA009F019DB1DA50090EBED /* libANSDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AA0094019DB169B0090EBED /* libANSDK.a */; }; @@ -120,11 +145,45 @@ 8AD01833199932F9007874BA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD01832199932F9007874BA /* main.m */; }; 8AD01836199932F9007874BA /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD01835199932F9007874BA /* AppDelegate.m */; }; 8AD01839199932F9007874BA /* ANNewTestAppViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD01838199932F9007874BA /* ANNewTestAppViewController.m */; }; + 8AD052E31A802FCD00EE0182 /* appnexus_multiple_main_media.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AD052E21A802FCD00EE0182 /* appnexus_multiple_main_media.json */; }; + 8AD052ED1A80333800EE0182 /* appnexus_multiple_main_media_default.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AD052EC1A80333800EE0182 /* appnexus_multiple_main_media_default.json */; }; + 8AD052EF1A80461200EE0182 /* appnexus_multiple_trackers.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AD052EE1A80461200EE0182 /* appnexus_multiple_trackers.json */; }; 8AD0DBFD19CA40AE00170BCB /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8AD0DBFC19CA40AE00170BCB /* Default-568h@2x.png */; }; + 8AE3999F1A42105B00C0D7B1 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AE3999E1A42105B00C0D7B1 /* WebKit.framework */; }; + 8AE7AD6D1A7AA4CD009E2F2F /* appnexus_standard_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AE7AD6C1A7AA4CD009E2F2F /* appnexus_standard_response.json */; }; + 8AE7AD7A1A7AA526009E2F2F /* custom_adapter_to_native_ad.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AE7AD791A7AA526009E2F2F /* custom_adapter_to_native_ad.json */; }; + 8AE7AD7C1A7AA53B009E2F2F /* custom_adapter_mediated_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AE7AD7B1A7AA53B009E2F2F /* custom_adapter_mediated_response.json */; }; + 8AE7AD7E1A7AA556009E2F2F /* empty_mediated_ad_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AE7AD7D1A7AA556009E2F2F /* empty_mediated_ad_response.json */; }; + 8AE7AD801A7AA56C009E2F2F /* mopub_mediated_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AE7AD7F1A7AA56C009E2F2F /* mopub_mediated_response.json */; }; + 8AE7AD821A7AA589009E2F2F /* custom_adapter_fb_mediated_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AE7AD811A7AA589009E2F2F /* custom_adapter_fb_mediated_response.json */; }; + 8AE7AD841A7AA5A7009E2F2F /* empty_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AE7AD831A7AA5A7009E2F2F /* empty_response.json */; }; + 8AE7AD861A7AA5C9009E2F2F /* no_ads_ok_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AE7AD851A7AA5C9009E2F2F /* no_ads_ok_response.json */; }; + 8AE7AD881A7AA5F5009E2F2F /* custom_adapter_invalid_type.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AE7AD871A7AA5F5009E2F2F /* custom_adapter_invalid_type.json */; }; + 8AE7AD8A1A7AA606009E2F2F /* custom_adapter_to_standard_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AE7AD891A7AA606009E2F2F /* custom_adapter_to_standard_response.json */; }; + 8AE7AD8C1A7AA61D009E2F2F /* facebook_mediated_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AE7AD8B1A7AA61D009E2F2F /* facebook_mediated_response.json */; }; + 8AE7AD8E1A7AABB4009E2F2F /* ANNativeAdResponseTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AE7AD8D1A7AABB4009E2F2F /* ANNativeAdResponseTestCase.m */; }; + 8AE7AD921A7AAE33009E2F2F /* ANNativeAdView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8AE7AD911A7AAE33009E2F2F /* ANNativeAdView.xib */; }; + 8AE7AD951A7AAE81009E2F2F /* ANNativeAdView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AE7AD941A7AAE81009E2F2F /* ANNativeAdView.m */; }; + 8AE7AD981A7AB348009E2F2F /* libKIF.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AB5325719F0464B00CA4427 /* libKIF.a */; }; + 8AE7AD9C1A7AC372009E2F2F /* appnexus_standard_response_store_url.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AE7AD9B1A7AC372009E2F2F /* appnexus_standard_response_store_url.json */; }; 8AF3659419D479130097019F /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AF3659319D479130097019F /* AdSupport.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 8A549E9F1A706BA6009F797A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8AD01825199932F9007874BA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8A9F94BF19D1C37700AB739F; + remoteInfo = MediationAdapterApp; + }; + 8A84E4111A2516E000C60EAB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8AF3654C19D472A60097019F /* ANSDK.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 8A9AED8C1A1BE84F00C58BDA; + remoteInfo = AppNexusSDK; + }; 8A9F94D919D1C37700AB739F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 8AD01825199932F9007874BA /* Project object */; @@ -300,13 +359,6 @@ remoteGlobalIDString = EABD46AA1857A0C700A5F081; remoteInfo = KIF; }; - 8AB5325819F0464B00CA4427 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 8AB5324A19F0464B00CA4427 /* KIF.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = EB72047C1680DDAD00278DA2; - remoteInfo = "KIF-OCUnit"; - }; 8AB5325A19F0464B00CA4427 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 8AB5324A19F0464B00CA4427 /* KIF.xcodeproj */; @@ -321,13 +373,6 @@ remoteGlobalIDString = EABD46CD1857A0F300A5F081; remoteInfo = "KIF Tests"; }; - 8AB5325E19F0464B00CA4427 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 8AB5324A19F0464B00CA4427 /* KIF.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = EB60ECEB177F8DB3005A041A; - remoteInfo = "KIF Tests-OCUnit"; - }; 8AB5326119F046A500CA4427 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 8AB5324A19F0464B00CA4427 /* KIF.xcodeproj */; @@ -342,6 +387,13 @@ remoteGlobalIDString = 8AD0182C199932F9007874BA; remoteInfo = NewTestApp; }; + 8AE7AD961A7AB343009E2F2F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8AB5324A19F0464B00CA4427 /* KIF.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = EABD46791857A0C700A5F081; + remoteInfo = KIF; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -350,7 +402,6 @@ 8A0AA46519DB30A2005EC52C /* ANBannerAdViewTransitionsTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANBannerAdViewTransitionsTestCase.m; sourceTree = ""; }; 8A0AA46619DB30A2005EC52C /* ANLocationTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANLocationTestCase.m; sourceTree = ""; }; 8A0AA46719DB30A2005EC52C /* ANMediationAdViewControllerTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMediationAdViewControllerTestCase.m; sourceTree = ""; }; - 8A0AA46819DB30A2005EC52C /* ANMRAIDViewControllerTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMRAIDViewControllerTestCase.m; sourceTree = ""; }; 8A0AA46919DB30A2005EC52C /* UIViewConstraintsTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIViewConstraintsTestCase.m; sourceTree = ""; }; 8A0AA47119DB314C005EC52C /* ANAdAdapterBannerUnableToFillWithSubsequentCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ANAdAdapterBannerUnableToFillWithSubsequentCallbacks.h; path = "Banner Adapters/ANAdAdapterBannerUnableToFillWithSubsequentCallbacks.h"; sourceTree = ""; }; 8A0AA47219DB314C005EC52C /* ANAdAdapterBannerUnableToFillWithSubsequentCallbacks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ANAdAdapterBannerUnableToFillWithSubsequentCallbacks.m; path = "Banner Adapters/ANAdAdapterBannerUnableToFillWithSubsequentCallbacks.m"; sourceTree = ""; }; @@ -378,15 +429,37 @@ 8A0AA48B19DB3453005EC52C /* ANAdAdapterBannerUnableToFill.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ANAdAdapterBannerUnableToFill.m; path = "Banner Adapters/ANAdAdapterBannerUnableToFill.m"; sourceTree = ""; }; 8A0AA48C19DB3453005EC52C /* ANAdAdapterBannerUnableToFillThenSuccessful.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ANAdAdapterBannerUnableToFillThenSuccessful.h; path = "Banner Adapters/ANAdAdapterBannerUnableToFillThenSuccessful.h"; sourceTree = ""; }; 8A0AA48D19DB3453005EC52C /* ANAdAdapterBannerUnableToFillThenSuccessful.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ANAdAdapterBannerUnableToFillThenSuccessful.m; path = "Banner Adapters/ANAdAdapterBannerUnableToFillThenSuccessful.m"; sourceTree = ""; }; + 8A33A50F1A7C250500F8ED5E /* ANNativeImpressionTrackerManagerTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANNativeImpressionTrackerManagerTestCase.m; sourceTree = ""; }; + 8A33A5111A7C264D00F8ED5E /* ANNativeImpressionTrackerManager+ANTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ANNativeImpressionTrackerManager+ANTest.h"; sourceTree = ""; }; + 8A33A5121A7C264D00F8ED5E /* ANNativeImpressionTrackerManager+ANTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ANNativeImpressionTrackerManager+ANTest.m"; sourceTree = ""; }; 8A3C13B119EF2CB000CB1502 /* MediationAdaptersTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MediationAdaptersTestCase.m; path = MediationAdapterAppTests/MediationAdaptersTestCase.m; sourceTree = SOURCE_ROOT; }; + 8A4017F71A95006B00D56208 /* MPCloseButtonX@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "MPCloseButtonX@3x.png"; path = "../mediation/mediatedviews/MoPub/MoPubSDK/MPCloseButtonX@3x.png"; sourceTree = ""; }; + 8A4018041A9500A300D56208 /* GoogleMobileAds.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GoogleMobileAds.framework; path = ../mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/GoogleMobileAds.framework; sourceTree = ""; }; + 8A4018071A95025C00D56208 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; + 8A40180A1A95028700D56208 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; + 8A549E991A706BA6009F797A /* NativeUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NativeUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 8A549E9C1A706BA6009F797A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 8A549EAD1A706BC7009F797A /* ANNativeAdRequestTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANNativeAdRequestTestCase.m; sourceTree = ""; }; + 8A549EAF1A706BFE009F797A /* ANAdServerResponseTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANAdServerResponseTestCase.m; sourceTree = ""; }; + 8A549EB61A706D6F009F797A /* nativeResponse1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = nativeResponse1.json; sourceTree = ""; }; + 8A549EB71A706D6F009F797A /* nativeResponse2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = nativeResponse2.json; sourceTree = ""; }; + 8A549EB81A706D6F009F797A /* nativeResponse3.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = nativeResponse3.json; sourceTree = ""; }; + 8A549EB91A706D6F009F797A /* nativeResponse4.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = nativeResponse4.json; sourceTree = ""; }; + 8A549EBA1A706D6F009F797A /* nativeResponse5.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = nativeResponse5.json; sourceTree = ""; }; 8A5D27BC199A9DAB00F2A516 /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = System/Library/Frameworks/CoreMotion.framework; sourceTree = SDKROOT; }; 8A5D27CA199AB26B00F2A516 /* iAd.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = iAd.framework; path = System/Library/Frameworks/iAd.framework; sourceTree = SDKROOT; }; 8A64C0B519D1CBE000B92D30 /* NewTestAppPrefixHeader.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NewTestAppPrefixHeader.pch; sourceTree = ""; }; + 8A661ECF1A85597E00117553 /* appnexus_click_fallback_example.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = appnexus_click_fallback_example.json; sourceTree = ""; }; + 8A764F021A7078F500C02A97 /* ANReachability+ANTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ANReachability+ANTest.h"; sourceTree = ""; }; + 8A764F031A7078F500C02A97 /* ANReachability+ANTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ANReachability+ANTest.m"; sourceTree = ""; }; 8A7AE40F19DF2A610037DDC8 /* BaseMediationSingleNetworkResponse.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = BaseMediationSingleNetworkResponse.json; sourceTree = ""; }; 8A7F4CC119DB3976003ECC5C /* MPAdBrowserController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = MPAdBrowserController.xib; path = ../mediation/mediatedviews/MoPub/MoPubSDK/MPAdBrowserController.xib; sourceTree = ""; }; 8A7F4CC219DB3976003ECC5C /* MPCloseButtonX.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = MPCloseButtonX.png; path = ../mediation/mediatedviews/MoPub/MoPubSDK/MPCloseButtonX.png; sourceTree = ""; }; 8A7F4CC319DB3976003ECC5C /* MPCloseButtonX@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "MPCloseButtonX@2x.png"; path = "../mediation/mediatedviews/MoPub/MoPubSDK/MPCloseButtonX@2x.png"; sourceTree = ""; }; 8A7F4CC419DB3976003ECC5C /* MRAID.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = MRAID.bundle; path = ../mediation/mediatedviews/MoPub/MoPubSDK/MRAID.bundle; sourceTree = ""; }; + 8A8458701A6998F40014F291 /* ANNativeAdRequest+ANBaseUrlOverride.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ANNativeAdRequest+ANBaseUrlOverride.h"; sourceTree = ""; }; + 8A8458711A6998F40014F291 /* ANNativeAdRequest+ANBaseUrlOverride.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ANNativeAdRequest+ANBaseUrlOverride.m"; sourceTree = ""; }; + 8A9BF1431A7FE3B800C0D227 /* ANNativeAdViewMainImage.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ANNativeAdViewMainImage.xib; sourceTree = ""; }; 8A9F94C019D1C37700AB739F /* MediationAdapterApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MediationAdapterApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 8A9F94D819D1C37700AB739F /* MediationAdapterAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MediationAdapterAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 8AA0095419DB16C50090EBED /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; @@ -448,14 +521,13 @@ 8AA009BB19DB1B200090EBED /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 8AA009BD19DB1B200090EBED /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 8AA009BF19DB1B200090EBED /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 8AA009C019DB1B200090EBED /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 8AA009C019DB1B200090EBED /* MediationAdapterAppImages.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = MediationAdapterAppImages.xcassets; sourceTree = ""; }; 8AA009C119DB1B200090EBED /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8AA009C219DB1B200090EBED /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 8AA009C319DB1B200090EBED /* MediationAdapterPrefixHeader.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediationAdapterPrefixHeader.pch; sourceTree = ""; }; 8AA009E019DB1CEC0090EBED /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8AA009E319DB1D270090EBED /* AmazonAd.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AmazonAd.framework; path = ../mediation/mediatedviews/Amazon/AmazonSDK/AmazonAd.framework; sourceTree = ""; }; 8AA009E519DB1D320090EBED /* FBAudienceNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FBAudienceNetwork.framework; path = ../mediation/mediatedviews/Facebook/FacebookSDK/FBAudienceNetwork.framework; sourceTree = ""; }; - 8AA009E719DB1D3C0090EBED /* libGoogleAdMobAds.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libGoogleAdMobAds.a; path = ../mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK/libGoogleAdMobAds.a; sourceTree = ""; }; 8AA009E919DB1D480090EBED /* MillennialMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MillennialMedia.framework; path = ../mediation/mediatedviews/MillennialMedia/MillennialMediaSDK/MillennialMedia.framework; sourceTree = ""; }; 8AA009EB19DB1D530090EBED /* libMoPubSDK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libMoPubSDK.a; path = ../mediation/mediatedviews/MoPub/MoPubSDK/libMoPubSDK.a; sourceTree = ""; }; 8AA009FC19DB1E150090EBED /* ANAdFetcher+ANTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ANAdFetcher+ANTest.h"; sourceTree = ""; }; @@ -508,7 +580,27 @@ 8AD0183D199932F9007874BA /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 8AD01843199932F9007874BA /* NewTestAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NewTestAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 8AD01848199932F9007874BA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 8AD052E21A802FCD00EE0182 /* appnexus_multiple_main_media.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = appnexus_multiple_main_media.json; sourceTree = ""; }; + 8AD052EC1A80333800EE0182 /* appnexus_multiple_main_media_default.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = appnexus_multiple_main_media_default.json; sourceTree = ""; }; + 8AD052EE1A80461200EE0182 /* appnexus_multiple_trackers.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = appnexus_multiple_trackers.json; sourceTree = ""; }; 8AD0DBFC19CA40AE00170BCB /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; + 8AE3999E1A42105B00C0D7B1 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + 8AE7AD6C1A7AA4CD009E2F2F /* appnexus_standard_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = appnexus_standard_response.json; sourceTree = ""; }; + 8AE7AD791A7AA526009E2F2F /* custom_adapter_to_native_ad.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = custom_adapter_to_native_ad.json; sourceTree = ""; }; + 8AE7AD7B1A7AA53B009E2F2F /* custom_adapter_mediated_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = custom_adapter_mediated_response.json; sourceTree = ""; }; + 8AE7AD7D1A7AA556009E2F2F /* empty_mediated_ad_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = empty_mediated_ad_response.json; sourceTree = ""; }; + 8AE7AD7F1A7AA56C009E2F2F /* mopub_mediated_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = mopub_mediated_response.json; sourceTree = ""; }; + 8AE7AD811A7AA589009E2F2F /* custom_adapter_fb_mediated_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = custom_adapter_fb_mediated_response.json; sourceTree = ""; }; + 8AE7AD831A7AA5A7009E2F2F /* empty_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = empty_response.json; sourceTree = ""; }; + 8AE7AD851A7AA5C9009E2F2F /* no_ads_ok_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = no_ads_ok_response.json; sourceTree = ""; }; + 8AE7AD871A7AA5F5009E2F2F /* custom_adapter_invalid_type.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = custom_adapter_invalid_type.json; sourceTree = ""; }; + 8AE7AD891A7AA606009E2F2F /* custom_adapter_to_standard_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = custom_adapter_to_standard_response.json; sourceTree = ""; }; + 8AE7AD8B1A7AA61D009E2F2F /* facebook_mediated_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = facebook_mediated_response.json; sourceTree = ""; }; + 8AE7AD8D1A7AABB4009E2F2F /* ANNativeAdResponseTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANNativeAdResponseTestCase.m; sourceTree = ""; }; + 8AE7AD911A7AAE33009E2F2F /* ANNativeAdView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ANNativeAdView.xib; sourceTree = ""; }; + 8AE7AD931A7AAE81009E2F2F /* ANNativeAdView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANNativeAdView.h; sourceTree = ""; }; + 8AE7AD941A7AAE81009E2F2F /* ANNativeAdView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANNativeAdView.m; sourceTree = ""; }; + 8AE7AD9B1A7AC372009E2F2F /* appnexus_standard_response_store_url.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = appnexus_standard_response_store_url.json; sourceTree = ""; }; 8AF3654C19D472A60097019F /* ANSDK.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ANSDK.xcodeproj; path = ../BinaryProjects/ANSDK.xcodeproj; sourceTree = ""; }; 8AF3657F19D473B00097019F /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 8AF3658319D474650097019F /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; }; @@ -517,19 +609,27 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 8A549E961A706BA6009F797A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8AE7AD981A7AB348009E2F2F /* libKIF.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8A9F94BD19D1C37700AB739F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 8AA009F019DB1DA50090EBED /* libANSDK.a in Frameworks */, 8AA009F219DB1DA50090EBED /* libANSDKGoogleAdMobAdapter.a in Frameworks */, + 8A4018051A9500A300D56208 /* GoogleMobileAds.framework in Frameworks */, 8AA009F319DB1DA50090EBED /* libANSDKiAdAdapter.a in Frameworks */, 8AA009F419DB1DA50090EBED /* libANSDKMillennialMediaAdapter.a in Frameworks */, 8AA009F519DB1DA50090EBED /* libANSDKMoPubAdapter.a in Frameworks */, 8AA009F619DB1DA50090EBED /* libANSDKFacebookAdapter.a in Frameworks */, 8AA009F719DB1DA50090EBED /* libANSDKAmazonAdapter.a in Frameworks */, 8AA009E619DB1D320090EBED /* FBAudienceNetwork.framework in Frameworks */, - 8AA009E819DB1D3C0090EBED /* libGoogleAdMobAds.a in Frameworks */, 8A3B37AF19D62A4E00CE24A5 /* iAd.framework in Frameworks */, 8AA009EA19DB1D480090EBED /* MillennialMedia.framework in Frameworks */, 8AA009EC19DB1D530090EBED /* libMoPubSDK.a in Frameworks */, @@ -549,6 +649,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 8AE3999F1A42105B00C0D7B1 /* WebKit.framework in Frameworks */, 8AA009A319DB16F30090EBED /* libANSDK.a in Frameworks */, 8AB387F919DB1297006F9E15 /* AdSupport.framework in Frameworks */, 8AB387F819DB1245006F9E15 /* UIKit.framework in Frameworks */, @@ -589,7 +690,6 @@ 8A0AA46519DB30A2005EC52C /* ANBannerAdViewTransitionsTestCase.m */, 8A0AA46619DB30A2005EC52C /* ANLocationTestCase.m */, 8A0AA46719DB30A2005EC52C /* ANMediationAdViewControllerTestCase.m */, - 8A0AA46819DB30A2005EC52C /* ANMRAIDViewControllerTestCase.m */, 8A0AA46919DB30A2005EC52C /* UIViewConstraintsTestCase.m */, ); path = Tests; @@ -652,12 +752,68 @@ name = "Banner Adapters"; sourceTree = ""; }; + 8A549E9A1A706BA6009F797A /* NativeUnitTests */ = { + isa = PBXGroup; + children = ( + 8A33A50F1A7C250500F8ED5E /* ANNativeImpressionTrackerManagerTestCase.m */, + 8AE7AD8D1A7AABB4009E2F2F /* ANNativeAdResponseTestCase.m */, + 8A549EAF1A706BFE009F797A /* ANAdServerResponseTestCase.m */, + 8A549EAD1A706BC7009F797A /* ANNativeAdRequestTestCase.m */, + 8A549E9B1A706BA6009F797A /* Supporting Files */, + ); + path = NativeUnitTests; + sourceTree = ""; + }; + 8A549E9B1A706BA6009F797A /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 8AE7AD931A7AAE81009E2F2F /* ANNativeAdView.h */, + 8AE7AD941A7AAE81009E2F2F /* ANNativeAdView.m */, + 8AE7AD911A7AAE33009E2F2F /* ANNativeAdView.xib */, + 8A9BF1431A7FE3B800C0D227 /* ANNativeAdViewMainImage.xib */, + 8A549E9C1A706BA6009F797A /* Info.plist */, + 8A549EB51A706D6F009F797A /* Native Responses */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 8A549EB51A706D6F009F797A /* Native Responses */ = { + isa = PBXGroup; + children = ( + 8AE7AD6C1A7AA4CD009E2F2F /* appnexus_standard_response.json */, + 8A661ECF1A85597E00117553 /* appnexus_click_fallback_example.json */, + 8AD052EE1A80461200EE0182 /* appnexus_multiple_trackers.json */, + 8AD052E21A802FCD00EE0182 /* appnexus_multiple_main_media.json */, + 8AD052EC1A80333800EE0182 /* appnexus_multiple_main_media_default.json */, + 8AE7AD9B1A7AC372009E2F2F /* appnexus_standard_response_store_url.json */, + 8AE7AD811A7AA589009E2F2F /* custom_adapter_fb_mediated_response.json */, + 8AE7AD871A7AA5F5009E2F2F /* custom_adapter_invalid_type.json */, + 8AE7AD7B1A7AA53B009E2F2F /* custom_adapter_mediated_response.json */, + 8AE7AD791A7AA526009E2F2F /* custom_adapter_to_native_ad.json */, + 8AE7AD891A7AA606009E2F2F /* custom_adapter_to_standard_response.json */, + 8AE7AD7D1A7AA556009E2F2F /* empty_mediated_ad_response.json */, + 8AE7AD831A7AA5A7009E2F2F /* empty_response.json */, + 8AE7AD8B1A7AA61D009E2F2F /* facebook_mediated_response.json */, + 8AE7AD7F1A7AA56C009E2F2F /* mopub_mediated_response.json */, + 8A549EB61A706D6F009F797A /* nativeResponse1.json */, + 8A549EB71A706D6F009F797A /* nativeResponse2.json */, + 8A549EB81A706D6F009F797A /* nativeResponse3.json */, + 8A549EB91A706D6F009F797A /* nativeResponse4.json */, + 8A549EBA1A706D6F009F797A /* nativeResponse5.json */, + 8AE7AD851A7AA5C9009E2F2F /* no_ads_ok_response.json */, + ); + path = "Native Responses"; + sourceTree = ""; + }; 8A65BE8A19A4FCDF00A72571 /* Frameworks */ = { isa = PBXGroup; children = ( + 8A40180A1A95028700D56208 /* StoreKit.framework */, + 8A4018071A95025C00D56208 /* CoreTelephony.framework */, + 8A4018041A9500A300D56208 /* GoogleMobileAds.framework */, + 8AE3999E1A42105B00C0D7B1 /* WebKit.framework */, 8AA009EB19DB1D530090EBED /* libMoPubSDK.a */, 8AA009E919DB1D480090EBED /* MillennialMedia.framework */, - 8AA009E719DB1D3C0090EBED /* libGoogleAdMobAds.a */, 8AA009E519DB1D320090EBED /* FBAudienceNetwork.framework */, 8AA009E319DB1D270090EBED /* AmazonAd.framework */, 8AB387F719DB1245006F9E15 /* UIKit.framework */, @@ -677,6 +833,7 @@ 8A7F4CC119DB3976003ECC5C /* MPAdBrowserController.xib */, 8A7F4CC219DB3976003ECC5C /* MPCloseButtonX.png */, 8A7F4CC319DB3976003ECC5C /* MPCloseButtonX@2x.png */, + 8A4017F71A95006B00D56208 /* MPCloseButtonX@3x.png */, 8A7F4CC419DB3976003ECC5C /* MRAID.bundle */, ); name = MPResources; @@ -695,6 +852,7 @@ 8AA0094E19DB169B0090EBED /* libANAdapterForGoogleAdMobSDK.a */, 8AA0095019DB169B0090EBED /* libANAdapterForMoPubSDK.a */, 8AA0095219DB169B0090EBED /* libANSDKAmazonAdapter.a */, + 8A84E4121A2516E000C60EAB /* AppNexusSDK.framework */, ); name = Products; sourceTree = ""; @@ -809,7 +967,7 @@ 8AA009BB19DB1B200090EBED /* AppDelegate.m */, 8AA009BC19DB1B200090EBED /* LaunchScreen.xib */, 8AA009BE19DB1B200090EBED /* Main.storyboard */, - 8AA009C019DB1B200090EBED /* Images.xcassets */, + 8AA009C019DB1B200090EBED /* MediationAdapterAppImages.xcassets */, 8AA009C119DB1B200090EBED /* Info.plist */, 8AA009C219DB1B200090EBED /* main.m */, 8AA009C319DB1B200090EBED /* MediationAdapterPrefixHeader.pch */, @@ -829,6 +987,8 @@ 8AA009FB19DB1E150090EBED /* Categories */ = { isa = PBXGroup; children = ( + 8A8458701A6998F40014F291 /* ANNativeAdRequest+ANBaseUrlOverride.h */, + 8A8458711A6998F40014F291 /* ANNativeAdRequest+ANBaseUrlOverride.m */, 8AA00A2B19DB1FC20090EBED /* ANAdAdapterBaseAmazon+ANTest.h */, 8AA00A2C19DB1FC20090EBED /* ANAdAdapterBaseAmazon+ANTest.m */, 8AA009FC19DB1E150090EBED /* ANAdFetcher+ANTest.h */, @@ -857,6 +1017,10 @@ 8AB5324719F01FD700CA4427 /* ANAdAdapterBannerAdMob+ANTest.m */, 8AB5326919F0503E00CA4427 /* ANAdAdapterBannerMoPub+ANTest.h */, 8AB5326A19F0503E00CA4427 /* ANAdAdapterBannerMoPub+ANTest.m */, + 8A764F021A7078F500C02A97 /* ANReachability+ANTest.h */, + 8A764F031A7078F500C02A97 /* ANReachability+ANTest.m */, + 8A33A5111A7C264D00F8ED5E /* ANNativeImpressionTrackerManager+ANTest.h */, + 8A33A5121A7C264D00F8ED5E /* ANNativeImpressionTrackerManager+ANTest.m */, ); path = Categories; sourceTree = ""; @@ -887,10 +1051,8 @@ isa = PBXGroup; children = ( 8AB5325719F0464B00CA4427 /* libKIF.a */, - 8AB5325919F0464B00CA4427 /* libKIF-OCUnit.a */, 8AB5325B19F0464B00CA4427 /* Test Host.app */, 8AB5325D19F0464B00CA4427 /* KIF Tests - XCTest.xctest */, - 8AB5325F19F0464B00CA4427 /* KIF Tests-OCUnit.octest */, ); name = Products; sourceTree = ""; @@ -900,6 +1062,7 @@ children = ( 8AB5324A19F0464B00CA4427 /* KIF.xcodeproj */, 8AF3654C19D472A60097019F /* ANSDK.xcodeproj */, + 8A549E9A1A706BA6009F797A /* NativeUnitTests */, 8A65BE8A19A4FCDF00A72571 /* Frameworks */, 8AA009B719DB1B1F0090EBED /* MediationAdapterApp */, 8AA009DE19DB1CEC0090EBED /* MediationAdapterAppTests */, @@ -922,6 +1085,7 @@ 8A9F94D819D1C37700AB739F /* MediationAdapterAppTests.xctest */, 8AB387A519DB0CA8006F9E15 /* OriginalUnitTestApp.app */, 8AB387BD19DB0CA8006F9E15 /* OriginalUnitTestAppTests.xctest */, + 8A549E991A706BA6009F797A /* NativeUnitTests.xctest */, ); name = Products; sourceTree = ""; @@ -972,6 +1136,25 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 8A549E981A706BA6009F797A /* NativeUnitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8A549EAC1A706BA6009F797A /* Build configuration list for PBXNativeTarget "NativeUnitTests" */; + buildPhases = ( + 8A549E951A706BA6009F797A /* Sources */, + 8A549E961A706BA6009F797A /* Frameworks */, + 8A549E971A706BA6009F797A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 8AE7AD971A7AB343009E2F2F /* PBXTargetDependency */, + 8A549EA01A706BA6009F797A /* PBXTargetDependency */, + ); + name = NativeUnitTests; + productName = NativeUnitTests; + productReference = 8A549E991A706BA6009F797A /* NativeUnitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 8A9F94BF19D1C37700AB739F /* MediationAdapterApp */ = { isa = PBXNativeTarget; buildConfigurationList = 8A9F94E019D1C37800AB739F /* Build configuration list for PBXNativeTarget "MediationAdapterApp" */; @@ -1099,9 +1282,13 @@ LastUpgradeCheck = 0600; ORGANIZATIONNAME = AppNexus; TargetAttributes = { + 8A549E981A706BA6009F797A = { + CreatedOnToolsVersion = 6.2; + TestTargetID = 8A9F94BF19D1C37700AB739F; + }; 8A9F94BF19D1C37700AB739F = { CreatedOnToolsVersion = 6.0.1; - DevelopmentTeam = DC4W7ZY24G; + DevelopmentTeam = 8V5AA2KNR5; }; 8A9F94D719D1C37700AB739F = { CreatedOnToolsVersion = 6.0.1; @@ -1109,6 +1296,7 @@ }; 8AB387A419DB0CA8006F9E15 = { CreatedOnToolsVersion = 6.0.1; + DevelopmentTeam = 8V5AA2KNR5; }; 8AB387BC19DB0CA8006F9E15 = { CreatedOnToolsVersion = 6.0.1; @@ -1116,7 +1304,7 @@ }; 8AD0182C199932F9007874BA = { CreatedOnToolsVersion = 6.0; - DevelopmentTeam = DC4W7ZY24G; + DevelopmentTeam = 8V5AA2KNR5; }; 8AD01842199932F9007874BA = { CreatedOnToolsVersion = 6.0; @@ -1151,6 +1339,7 @@ 8AD01842199932F9007874BA /* NewTestAppTests */, 8A9F94BF19D1C37700AB739F /* MediationAdapterApp */, 8A9F94D719D1C37700AB739F /* MediationAdapterAppTests */, + 8A549E981A706BA6009F797A /* NativeUnitTests */, 8AB387A419DB0CA8006F9E15 /* OriginalUnitTestApp */, 8AB387BC19DB0CA8006F9E15 /* OriginalUnitTestAppTests */, ); @@ -1158,6 +1347,13 @@ /* End PBXProject section */ /* Begin PBXReferenceProxy section */ + 8A84E4121A2516E000C60EAB /* AppNexusSDK.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = AppNexusSDK.framework; + remoteRef = 8A84E4111A2516E000C60EAB /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 8AA0094019DB169B0090EBED /* libANSDK.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -1235,13 +1431,6 @@ remoteRef = 8AB5325619F0464B00CA4427 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 8AB5325919F0464B00CA4427 /* libKIF-OCUnit.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libKIF-OCUnit.a"; - remoteRef = 8AB5325819F0464B00CA4427 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; 8AB5325B19F0464B00CA4427 /* Test Host.app */ = { isa = PBXReferenceProxy; fileType = wrapper.application; @@ -1256,28 +1445,59 @@ remoteRef = 8AB5325C19F0464B00CA4427 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 8AB5325F19F0464B00CA4427 /* KIF Tests-OCUnit.octest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = "KIF Tests-OCUnit.octest"; - remoteRef = 8AB5325E19F0464B00CA4427 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ + 8A549E971A706BA6009F797A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8AE7AD861A7AA5C9009E2F2F /* no_ads_ok_response.json in Resources */, + 8A549EBF1A706D6F009F797A /* nativeResponse5.json in Resources */, + 8AE7AD9C1A7AC372009E2F2F /* appnexus_standard_response_store_url.json in Resources */, + 8A549EBD1A706D6F009F797A /* nativeResponse3.json in Resources */, + 8A4018001A95008A00D56208 /* MPAdBrowserController.xib in Resources */, + 8AE7AD8C1A7AA61D009E2F2F /* facebook_mediated_response.json in Resources */, + 8AE7AD7E1A7AA556009E2F2F /* empty_mediated_ad_response.json in Resources */, + 8AE7AD7C1A7AA53B009E2F2F /* custom_adapter_mediated_response.json in Resources */, + 8AE7AD821A7AA589009E2F2F /* custom_adapter_fb_mediated_response.json in Resources */, + 8A4018021A95008A00D56208 /* MPCloseButtonX@2x.png in Resources */, + 8AE7AD881A7AA5F5009E2F2F /* custom_adapter_invalid_type.json in Resources */, + 8A4018011A95008A00D56208 /* MPCloseButtonX.png in Resources */, + 8AD052E31A802FCD00EE0182 /* appnexus_multiple_main_media.json in Resources */, + 8A661ED01A85597E00117553 /* appnexus_click_fallback_example.json in Resources */, + 8AE7AD6D1A7AA4CD009E2F2F /* appnexus_standard_response.json in Resources */, + 8AD052ED1A80333800EE0182 /* appnexus_multiple_main_media_default.json in Resources */, + 8A549EBC1A706D6F009F797A /* nativeResponse2.json in Resources */, + 8A549EBE1A706D6F009F797A /* nativeResponse4.json in Resources */, + 8A549EBB1A706D6F009F797A /* nativeResponse1.json in Resources */, + 8A4018031A95008E00D56208 /* MRAID.bundle in Resources */, + 8AE7AD921A7AAE33009E2F2F /* ANNativeAdView.xib in Resources */, + 8AE7AD8A1A7AA606009E2F2F /* custom_adapter_to_standard_response.json in Resources */, + 8AE7AD841A7AA5A7009E2F2F /* empty_response.json in Resources */, + 8AE7AD7A1A7AA526009E2F2F /* custom_adapter_to_native_ad.json in Resources */, + 8AE7AD801A7AA56C009E2F2F /* mopub_mediated_response.json in Resources */, + 8A4017F91A95006B00D56208 /* MPCloseButtonX@3x.png in Resources */, + 8A9BF1441A7FE3B800C0D227 /* ANNativeAdViewMainImage.xib in Resources */, + 8AD052EF1A80461200EE0182 /* appnexus_multiple_trackers.json in Resources */, + 8A549EC01A706DA5009F797A /* SuccessfulMediationResponse.json in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8A9F94BE19D1C37700AB739F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 8A7F4CC619DB3976003ECC5C /* MPCloseButtonX.png in Resources */, - 8AA009ED19DB1D670090EBED /* Images.xcassets in Resources */, + 8AA009ED19DB1D670090EBED /* MediationAdapterAppImages.xcassets in Resources */, 8AA009EE19DB1D790090EBED /* LaunchScreen.xib in Resources */, 8AA009EF19DB1D790090EBED /* Main.storyboard in Resources */, 8A7F4CC519DB3976003ECC5C /* MPAdBrowserController.xib in Resources */, 8A7F4CC719DB3976003ECC5C /* MPCloseButtonX@2x.png in Resources */, + 8A4017F81A95006B00D56208 /* MPCloseButtonX@3x.png in Resources */, 8A7F4CC819DB3976003ECC5C /* MRAID.bundle in Resources */, 8A7AE41019DF2A610037DDC8 /* BaseMediationSingleNetworkResponse.json in Resources */, + 8A8458881A69A34C0014F291 /* ANSDKResources.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1334,6 +1554,24 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 8A549E951A706BA6009F797A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8A549EB41A706C7D009F797A /* ANAdAdapterBannerMoPub+ANTest.m in Sources */, + 8A549EB31A706C71009F797A /* ANNativeAdRequest+ANBaseUrlOverride.m in Sources */, + 8A33A5131A7C264D00F8ED5E /* ANNativeImpressionTrackerManager+ANTest.m in Sources */, + 8A549EB21A706C65009F797A /* XCTestCase+ANCategory.m in Sources */, + 8A764F0E1A70798A00C02A97 /* NSObject+Swizzling.m in Sources */, + 8AE7AD951A7AAE81009E2F2F /* ANNativeAdView.m in Sources */, + 8A549EAE1A706BC7009F797A /* ANNativeAdRequestTestCase.m in Sources */, + 8AE7AD8E1A7AABB4009E2F2F /* ANNativeAdResponseTestCase.m in Sources */, + 8A764F041A7078F500C02A97 /* ANReachability+ANTest.m in Sources */, + 8A549EB01A706BFE009F797A /* ANAdServerResponseTestCase.m in Sources */, + 8A33A5101A7C250500F8ED5E /* ANNativeImpressionTrackerManagerTestCase.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8A9F94BC19D1C37700AB739F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1357,6 +1595,7 @@ files = ( 8A3C13CB19EF2F1700CB1502 /* MediationAdaptersTestCase.m in Sources */, 8AA00A3719DB21FA0090EBED /* XCTestCase+ANCategory.m in Sources */, + 8A8458741A699CF90014F291 /* ANNativeAdRequest+ANBaseUrlOverride.m in Sources */, 8AB5326B19F0503E00CA4427 /* ANAdAdapterBannerMoPub+ANTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1418,6 +1657,7 @@ 8A0AA45919DB2CB4005EC52C /* ANInterstitialAd+ANTest.m in Sources */, 8A0AA48F19DB3453005EC52C /* ANAdAdapterBannerMultipleSuccessCallbacks.m in Sources */, 8AA00A5119DB2B160090EBED /* XCTestCase+ANCategory.m in Sources */, + 8A8458721A6998F40014F291 /* ANNativeAdRequest+ANBaseUrlOverride.m in Sources */, 8A0AA46E19DB30A2005EC52C /* ANMediationAdViewControllerTestCase.m in Sources */, 8AA00A5019DB2B160090EBED /* XCTestCase+ANBannerAdView.m in Sources */, 8A0AA48E19DB3453005EC52C /* ANAdAdapterBannerMultipleFailureCallbacks.m in Sources */, @@ -1442,7 +1682,6 @@ 8A0AA49719DB3453005EC52C /* ANAdAdapterBannerUnableToFillThenSuccessful.m in Sources */, 8A0AA47819DB314C005EC52C /* ANFailedMultiple.m in Sources */, 8A0AA45519DB2CB4005EC52C /* ANAdFetcher+ANTest.m in Sources */, - 8A0AA46F19DB30A2005EC52C /* ANMRAIDViewControllerTestCase.m in Sources */, 8AA00A5519DB2BF40090EBED /* ANMediationAdViewController+ANTest.m in Sources */, 8A0AA49619DB3453005EC52C /* ANAdAdapterBannerUnableToFill.m in Sources */, 8A0AA49319DB3453005EC52C /* ANAdAdapterBannerSuccessful.m in Sources */, @@ -1452,6 +1691,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 8A549EA01A706BA6009F797A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8A9F94BF19D1C37700AB739F /* MediationAdapterApp */; + targetProxy = 8A549E9F1A706BA6009F797A /* PBXContainerItemProxy */; + }; 8A9F94DA19D1C37700AB739F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8A9F94BF19D1C37700AB739F /* MediationAdapterApp */; @@ -1532,6 +1776,11 @@ target = 8AD0182C199932F9007874BA /* NewTestApp */; targetProxy = 8AD01844199932F9007874BA /* PBXContainerItemProxy */; }; + 8AE7AD971A7AB343009E2F2F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = KIF; + targetProxy = 8AE7AD961A7AB343009E2F2F /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -1570,10 +1819,48 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 8A549EA11A706BA6009F797A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = NativeUnitTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MediationAdapterApp.app/MediationAdapterApp"; + }; + name = Debug; + }; + 8A549EA21A706BA6009F797A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = NativeUnitTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MediationAdapterApp.app/MediationAdapterApp"; + }; + name = Release; + }; 8A9F94E119D1C37800AB739F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "LaunchImage-3"; CODE_SIGN_IDENTITY = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_PREFIX_HEADER = MediationAdapterApp/MediationAdapterPrefixHeader.pch; @@ -1594,6 +1881,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "LaunchImage-3"; CODE_SIGN_IDENTITY = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_PREFIX_HEADER = MediationAdapterApp/MediationAdapterPrefixHeader.pch; @@ -1653,6 +1941,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CODE_SIGN_IDENTITY = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_PREFIX_HEADER = "$(SRCROOT)/OriginalUnitTestApp/Tests_Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -1674,6 +1963,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CODE_SIGN_IDENTITY = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_PREFIX_HEADER = "$(SRCROOT)/OriginalUnitTestApp/Tests_Prefix.pch"; HEADER_SEARCH_PATHS = "$(inherited)"; @@ -1750,6 +2040,7 @@ "$(PROJECT_DIR)/../mediation/mediatedviews/MillennialMedia/MillennialMediaSDK", "$(PROJECT_DIR)/../mediation/mediatedviews/Amazon/AmazonSDK", "$(PROJECT_DIR)/../mediation/mediatedviews/Facebook/FacebookSDK", + "$(PROJECT_DIR)/../mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK", ); GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; @@ -1771,10 +2062,7 @@ "$(PROJECT_DIR)/../mediation/**", ); IPHONEOS_DEPLOYMENT_TARGET = 7.0; - LIBRARY_SEARCH_PATHS = ( - "$(PROJECT_DIR)/../mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK", - "$(PROJECT_DIR)/../mediation/mediatedviews/MoPub/MoPubSDK", - ); + LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/../mediation/mediatedviews/MoPub/MoPubSDK"; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "-ObjC"; @@ -1807,6 +2095,7 @@ "$(PROJECT_DIR)/../mediation/mediatedviews/MillennialMedia/MillennialMediaSDK", "$(PROJECT_DIR)/../mediation/mediatedviews/Amazon/AmazonSDK", "$(PROJECT_DIR)/../mediation/mediatedviews/Facebook/FacebookSDK", + "$(PROJECT_DIR)/../mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK", ); GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -1821,10 +2110,7 @@ "$(PROJECT_DIR)/../mediation/**", ); IPHONEOS_DEPLOYMENT_TARGET = 7.0; - LIBRARY_SEARCH_PATHS = ( - "$(PROJECT_DIR)/../mediation/mediatedviews/GoogleAdMob/GoogleAdMobSDK", - "$(PROJECT_DIR)/../mediation/mediatedviews/MoPub/MoPubSDK", - ); + LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/../mediation/mediatedviews/MoPub/MoPubSDK"; MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = "-ObjC"; SDKROOT = iphoneos; @@ -1919,6 +2205,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 8A549EAC1A706BA6009F797A /* Build configuration list for PBXNativeTarget "NativeUnitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8A549EA11A706BA6009F797A /* Debug */, + 8A549EA21A706BA6009F797A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 8A9F94E019D1C37800AB739F /* Build configuration list for PBXNativeTarget "MediationAdapterApp" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/tests/NewTestApp.xcodeproj/xcshareddata/xcschemes/MediationAdapterApp.xcscheme b/tests/NewTestApp.xcodeproj/xcshareddata/xcschemes/MediationAdapterApp.xcscheme index eec2eeb72..cc535db6a 100644 --- a/tests/NewTestApp.xcodeproj/xcshareddata/xcschemes/MediationAdapterApp.xcscheme +++ b/tests/NewTestApp.xcodeproj/xcshareddata/xcschemes/MediationAdapterApp.xcscheme @@ -34,6 +34,20 @@ ReferencedContainer = "container:NewTestApp.xcodeproj"> + + + + + + + + - + - + -#import -#import "ANMRAIDViewController.h" - -@interface ANMRAIDViewControllerTestCase : XCTestCase -@property (nonatomic, readwrite, strong) ANMRAIDViewController *viewController; -@end - -@implementation ANMRAIDViewControllerTestCase - -- (void)setUp { - [super setUp]; - self.viewController = [[ANMRAIDViewController alloc] init]; -} - -- (void)tearDown { - [super tearDown]; - [self.viewController dismissViewControllerAnimated:NO completion:nil]; -} - -- (void)testExample { - UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300.0f, 250.0f)]; - self.viewController.contentView = contentView; - [self.viewController.view addSubview:contentView]; - self.viewController.contentView.opaque = NO; - self.viewController.contentView.backgroundColor = [UIColor greenColor]; - self.viewController.allowOrientationChange = NO; - self.viewController.orientation = UIInterfaceOrientationPortrait; - - XCTestExpectation *expectation = [self expectationWithDescription:@"ANMRAIDViewController presented"]; - UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController; - - [rootViewController presentViewController:self.viewController - animated:YES - completion:^{ - XCTAssert(CGRectEqualToRect(contentView.frame, self.viewController.view.frame)); - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:5.0f - handler:nil]; -} - -@end \ No newline at end of file diff --git a/tests/OriginalUnitTestAppTests/MRAIDTests.m b/tests/OriginalUnitTestAppTests/MRAIDTests.m index 5420f9745..a3f8fe9b3 100644 --- a/tests/OriginalUnitTestAppTests/MRAIDTests.m +++ b/tests/OriginalUnitTestAppTests/MRAIDTests.m @@ -13,12 +13,13 @@ limitations under the License. */ -#import "ANWebView.h" #import "ANBaseTestCase.h" #import "ANMRAIDTestResponses.h" #import "ANLogging.h" #import "ANLogManager.h" #import "ANGlobal.h" +#import "ANMRAIDContainerView.h" +#import "ANMRAIDUtil.h" #define MRAID_TESTS_TIMEOUT 10.0 #define MRAID_TESTS_DEFAULT_DELAY 1.5 @@ -28,8 +29,13 @@ -(void)setOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animate -(void)setOrientation:(UIInterfaceOrientation)orientation; @end +@interface ANMRAIDContainerView (PrivateMethods) +- (CGRect)currentPosition; +@end + @interface MRAIDTests : ANBaseTestCase -@property (strong, nonatomic) ANWebView *webView; +@property (strong, nonatomic) UIWebView *webView; +@property (strong, nonatomic) ANMRAIDContainerView *standardAdView; @end @implementation MRAIDTests @@ -379,29 +385,33 @@ - (void)testCurrentPositionPortraitOriginOnResizeWithCustomOffsetAndSetFrameCall XCTAssertTrue(expectedX == originX && expectedY == originY, @"Expected origin %f x %f, received %f x %f", expectedX, expectedY, originX, originY); - [self moveBannerSubviewToOrigin:CGPointMake(150.0f, 60.0f)]; - - // maintain resize offset - expectedX = 140.0f; - expectedY = 50.0f; - - currentPosition = [self getCurrentPosition]; - originX = currentPosition.origin.x; - originY = currentPosition.origin.y; - - XCTAssertTrue(expectedX == originX && expectedY == originY, @"Expected origin %f x %f, received %f x %f", expectedX, expectedY, originX, originY); - - [self close]; - - // revert resize offset on default - expectedX = 150.0f; - expectedY = 60.0f; - - currentPosition = [self getCurrentPosition]; - originX = currentPosition.origin.x; - originY = currentPosition.origin.y; - - XCTAssertTrue(expectedX == originX && expectedY == originY, @"Expected origin %f x %f, received %f x %f", expectedX, expectedY, originX, originY); + if ([[UIScreen mainScreen] respondsToSelector:@selector(coordinateSpace)]) { + [self moveBannerSubviewToOrigin:CGPointMake(150.0f, 60.0f)]; + + // maintain resize offset + expectedX = 140.0f; + expectedY = 50.0f; + + currentPosition = [self getCurrentPosition]; + originX = currentPosition.origin.x; + originY = currentPosition.origin.y; + + XCTAssertTrue(expectedX == originX && expectedY == originY, @"Expected origin %f x %f, received %f x %f", expectedX, expectedY, originX, originY); + + [self close]; + + // revert resize offset on default + expectedX = 150.0f; + expectedY = 60.0f; + + currentPosition = [self getCurrentPosition]; + originX = currentPosition.origin.x; + originY = currentPosition.origin.y; + + XCTAssertTrue(expectedX == originX && expectedY == originY, @"Expected origin %f x %f, received %f x %f", expectedX, expectedY, originX, originY); + } else { + [self close]; + } [self clearTest]; } @@ -822,8 +832,11 @@ - (void)testBasicSetResizeProperties { // MS-525 [self resize]; [self assertState:@"resized"]; - XCTAssertTrue(self.banner.frame.size.width == resizeWidth, @"Expected new width of banner frame to be resized width"); - XCTAssertTrue(self.banner.frame.size.height == resizeHeight, @"Expected new height of banner frame to be resized height"); + + CGRect currentPosition = [self.standardAdView currentPosition]; + + XCTAssertTrue(currentPosition.size.width == resizeWidth, @"Expected new width of banner frame to be resized width"); + XCTAssertTrue(currentPosition.size.height == resizeHeight, @"Expected new height of banner frame to be resized height"); [self clearTest]; } @@ -832,7 +845,9 @@ - (void)testSetResizePropertiesOnlySizeAndOffset { // MS-525 CGFloat resizeHeight = 200.0f; [self setResizePropertiesResizeToSize:CGSizeMake(320.0f, resizeHeight) withOffset:CGPointZero]; [self resize]; - XCTAssertTrue(self.banner.frame.size.height == resizeHeight , @"Expected new height of banner frame to be resized height"); + + CGRect currentPosition = [self.standardAdView currentPosition]; + XCTAssertTrue(currentPosition.size.height == resizeHeight , @"Expected new height of banner frame to be resized height"); [self clearTest]; } @@ -899,10 +914,12 @@ - (void)testSetExpandPropertiesOnlySize { [self addBasicMRAIDBannerWithSelectorName:NSStringFromSelector(_cmd)]; CGFloat expandHeight = 200.0f; [self setExpandPropertiesExpandToSize:CGSizeMake(320.0f, expandHeight)]; + NSString *useCustomClose = [self getExpandPropertiesUseCustomClose]; XCTAssertTrue([useCustomClose isEqualToString:@"false"], @"Expected useCustomClose to be false"); [self expand]; - XCTAssertTrue(self.banner.frame.size.height == expandHeight , @"Expected new height of banner frame to be expanded height"); + + XCTAssertTrue([ANMRAIDUtil screenSize].height == [self.standardAdView currentPosition].size.height , @"Expected expand height to be ignored"); [self close]; [self clearTest]; } @@ -947,7 +964,7 @@ - (void)testSetExpandPropertiesToSizeZero { [self addBasicMRAIDBannerWithSelectorName:NSStringFromSelector(_cmd)]; [self setExpandPropertiesExpandToSize:CGSizeZero]; [self expand]; - [self assertState:@"default"]; + [self assertState:@"expanded"]; // Size is ignored in MRAID 2.0 [self clearTest]; } @@ -955,7 +972,7 @@ - (void)testSetExpandPropertiesToNegativeSize { [self addBasicMRAIDBannerWithSelectorName:NSStringFromSelector(_cmd)]; [self setExpandPropertiesExpandToSize:CGSizeMake(-10.0f, 250.0f)]; [self expand]; - [self assertState:@"default"]; + [self assertState:@"expanded"]; // Size is ignored in MRAID 2.0 [self clearTest]; } @@ -979,7 +996,7 @@ - (void)testSetExpandPropertiesMultipleTimes { width = [self getExpandPropertiesWidth]; height = [self getExpandPropertiesHeight]; isModal = [self getExpandPropertiesIsModal]; - XCTAssertTrue([useCustomClose isEqualToString:@"false"], @"Expected useCustomClose to be false"); + XCTAssertTrue([useCustomClose isEqualToString:@"true"], @"Expected useCustomClose to still be true"); XCTAssertTrue([width isEqualToString:@"500"], @"Expected width to be 320"); XCTAssertTrue([height isEqualToString:@"300"], @"Expected height to be 250"); XCTAssertTrue([isModal isEqualToString:@"true"], @"Expected isModal to be true"); @@ -1205,6 +1222,7 @@ - (void)testSupportStorePicture { - (void)clearTest { self.webView = nil; + self.standardAdView = nil; [self removeBannerFromSuperview]; if ([[UIApplication sharedApplication] statusBarOrientation] != UIInterfaceOrientationPortrait) { [self rotateDeviceToOrientation:UIInterfaceOrientationPortrait]; @@ -1265,9 +1283,12 @@ - (void)loadMRAIDBannerAtOrigin:(CGPoint)origin XCTAssertTrue([self waitForCompletion:MRAID_TESTS_TIMEOUT], @"Ad load timed out"); XCTAssertTrue(self.adDidLoadCalled, @"Success callback should be called"); XCTAssertFalse(self.adFailedToLoadCalled, @"Failure callback should not be called"); - id wv = [[self.banner subviews] firstObject]; - XCTAssertTrue([wv isKindOfClass:[ANWebView class]], @"Expected ANWebView as subview of BannerAdView"); - self.webView = (ANWebView *)wv; + id containerView = [[self.banner subviews] firstObject]; + XCTAssertTrue([containerView isKindOfClass:[ANMRAIDContainerView class]], @"Expected ANMRAIDContainerView as subview of BannerAdView"); + self.standardAdView = (ANMRAIDContainerView *)containerView; + ANAdWebViewController *webViewController = self.standardAdView.webViewController; + XCTAssertTrue([webViewController.contentView isKindOfClass:[UIWebView class]], @"No support for testing WKWebView MRAID because JavaScript callbacks are asynchronous"); + self.webView = (UIWebView *)webViewController.contentView; } - (void)addBannerAsSubview { diff --git a/tests/OriginalUnitTestAppTests/MediationTests.m b/tests/OriginalUnitTestAppTests/MediationTests.m index 89b1780d1..a7ffacd9f 100644 --- a/tests/OriginalUnitTestAppTests/MediationTests.m +++ b/tests/OriginalUnitTestAppTests/MediationTests.m @@ -15,10 +15,11 @@ #import "ANBaseTestCase.h" #import "ANAdFetcher.h" -#import "ANWebView.h" #import "ANMediatedAd.h" +#import "ANMRAIDContainerView.h" #import "ANMediationAdViewController.h" #import "ANSuccessfulBannerNeverCalled.h" +#import "ANBrowserViewController.h" static NSString *const kANSuccessfulBanner = @"ANSuccessfulBanner"; static NSString *const kANAdAdapterBannerDummy = @"ANAdAdapterBannerDummy"; @@ -32,8 +33,8 @@ @interface FetcherHelper : ANBannerAdView @property (nonatomic, assign) BOOL testComplete; @property (nonatomic, strong) ANAdFetcher *fetcher; @property (nonatomic, strong) id adapter; -@property (nonatomic, strong) ANWebView *webView; @property (nonatomic, strong) NSError *ANError; +@property (nonatomic, strong) ANMRAIDContainerView *standardAdView; //@property (nonatomic, strong) NSMutableURLRequest *successResultRequest; @property (nonatomic, strong) NSMutableURLRequest *request; @@ -50,7 +51,7 @@ @interface FetcherHelper () @interface ANAdFetcher () - (void)processResponseData:(NSData *)data; - (ANMediationAdViewController *)mediationController; -- (ANWebView *)webView; +- (ANMRAIDContainerView *)standardAdView; //- (NSMutableURLRequest *)successResultRequest; - (NSMutableURLRequest *)request; @end @@ -156,7 +157,7 @@ - (void)runChecks:(int)testNumber adapter:(id)adapter { case 7: { [self checkClass:kANSuccessfulBanner adapter:adapter]; - XCTAssertNotNil([self.helper webView], @"Expected webView to be non-nil"); + XCTAssertNotNil(self.helper.standardAdView, @"Expected webView to be non-nil"); } break; case 11: @@ -172,7 +173,7 @@ - (void)runChecks:(int)testNumber adapter:(id)adapter { case 13: { XCTAssertNil(adapter, @"Expected nil adapter"); - XCTAssertNotNil([self.helper webView], @"Expected webView to be non-nil"); + XCTAssertNotNil(self.helper.standardAdView, @"Expected webView to be non-nil"); } break; case 14: @@ -301,13 +302,11 @@ @implementation FetcherHelper @synthesize testComplete = __testComplete; @synthesize fetcher = __fetcher; @synthesize adapter = __adapter; -@synthesize webView = __webView; +@synthesize standardAdView = __standardAdView; @synthesize ANError = __ANError; //@synthesize successResultRequest = __successResultRequest; @synthesize request = __request; -@synthesize mraidEventReceiverDelegate = __mraidEventReceiverDelegate; - - (id)runTestForAdapter:(int)testNumber time:(NSTimeInterval)time { [self runBasicTest:testNumber]; @@ -360,13 +359,13 @@ - (void)adFetcher:(ANAdFetcher *)fetcher didFinishRequestWithResponse:(ANAdRespo case 70: { // don't set adapter here, because we want to retain the adapter from case 7 - self.webView = [fetcher webView]; + self.standardAdView = [fetcher standardAdView]; } break; case 13: { self.adapter = [[fetcher mediationController] currentAdapter]; - self.webView = [fetcher webView]; + self.standardAdView = [fetcher standardAdView]; } break; case 15: @@ -410,7 +409,7 @@ - (void)browserViewControllerShouldPresent:(ANBrowserViewController *)controller - (void)browserViewControllerWillLaunchExternalApplication{}; - (void)browserViewControllerWillNotPresent:(ANBrowserViewController *)controller{}; -#pragma mark ANAdViewDelegate +#pragma mark ANAdViewInternalDelegate - (void)adWasClicked{}; - (void)adWillPresent{}; @@ -420,6 +419,10 @@ - (void)adDidClose{}; - (void)adWillLeaveApplication{}; - (void)adFailedToDisplay{}; - (void)adDidReceiveAppEvent:(NSString *)name withData:(NSString *)data{}; +- (void)adDidReceiveAd{}; +- (void)adRequestFailedWithError:(NSError *)error{}; +- (void)adInteractionDidBegin{}; +- (void)adInteractionDidEnd{}; #pragma mark ANMRAIDAdViewDelegate diff --git a/tests/Shared/Categories/ANAdAdapterBannerAdMob+ANTest.m b/tests/Shared/Categories/ANAdAdapterBannerAdMob+ANTest.m index 50fb0139b..6af8e68dc 100644 --- a/tests/Shared/Categories/ANAdAdapterBannerAdMob+ANTest.m +++ b/tests/Shared/Categories/ANAdAdapterBannerAdMob+ANTest.m @@ -31,7 +31,7 @@ + (void)load { - (GADRequest *)test_createRequestFromTargetingParameters:(ANTargetingParameters *)targetingParameters { GADRequest *request = [self test_createRequestFromTargetingParameters:targetingParameters]; - request.testDevices = @[ GAD_SIMULATOR_ID ]; + //request.testDevices = @[ GAD_SIMULATOR_ID ]; //(Automatic in Google SDK Version 7.0.0) return request; } @@ -52,7 +52,7 @@ + (void)load { - (GADRequest *)test_createRequestFromTargetingParameters:(ANTargetingParameters *)targetingParameters { GADRequest *request = [self test_createRequestFromTargetingParameters:targetingParameters]; - request.testDevices = @[ GAD_SIMULATOR_ID ]; + //request.testDevices = @[ GAD_SIMULATOR_ID ]; //(Automatic in Google SDK Version 7.0.0) return request; } diff --git a/tests/Shared/Categories/ANAdFetcher+ANTest.h b/tests/Shared/Categories/ANAdFetcher+ANTest.h index 3c32f1e21..18f060b94 100644 --- a/tests/Shared/Categories/ANAdFetcher+ANTest.h +++ b/tests/Shared/Categories/ANAdFetcher+ANTest.h @@ -14,14 +14,14 @@ */ #import "ANAdFetcher.h" -#import "ANWebView.h" +#import "ANMRAIDContainerView.h" static NSString *const kANAdFetcherFireResultCBRequestedNotification = @"ANAdFetcherFireResultCBRequested"; static NSString *const kANAdFetcherFireResultCBRequestedReason = @"ANAdFetcherFireResultCBRequestedReason"; @interface ANAdFetcher (ANTest) -@property (nonatomic, readwrite, strong) ANWebView *webView; +@property (nonatomic, readwrite, strong) ANMRAIDContainerView *standardAdView; - (void)handleStandardAd:(ANAdResponse *)response; diff --git a/tests/Shared/Categories/ANAdFetcher+ANTest.m b/tests/Shared/Categories/ANAdFetcher+ANTest.m index 821f5b871..b308db61d 100644 --- a/tests/Shared/Categories/ANAdFetcher+ANTest.m +++ b/tests/Shared/Categories/ANAdFetcher+ANTest.m @@ -21,7 +21,7 @@ @implementation ANAdFetcher (ANTest) #pragma clang diagnostic pop -@dynamic webView; +@dynamic standardAdView; + (void)load { NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ diff --git a/tests/Shared/Categories/ANAdView+ANTest.h b/tests/Shared/Categories/ANAdView+ANTest.h index 09fa316e9..38702dc99 100644 --- a/tests/Shared/Categories/ANAdView+ANTest.h +++ b/tests/Shared/Categories/ANAdView+ANTest.h @@ -14,7 +14,7 @@ */ #import "ANAdView.h" -#import "ANAdViewDelegate.h" +#import "ANAdViewInternalDelegate.h" static NSString *const kANAdViewAdWasClickedNotification = @"adWasClicked"; static NSString *const kANAdViewAdWillPresentNotification = @"adWillPresent"; @@ -25,6 +25,6 @@ static NSString *const kANAdViewAdWillLeaveApplicationNotification = @"adWillLea static NSString *const kANAdViewAdDidReceiveAppEventNotification = @"adDidReceiveAppEvent"; static NSString *const kANAdViewAdFailedToDisplayNotification = @"adFailedToDisplay"; -@interface ANAdView (ANTest) +@interface ANAdView (ANTest) @end \ No newline at end of file diff --git a/tests/Shared/Categories/ANAdWebViewController+ANTest.h b/tests/Shared/Categories/ANAdWebViewController+ANTest.h index 4772b9548..9da7ea217 100644 --- a/tests/Shared/Categories/ANAdWebViewController+ANTest.h +++ b/tests/Shared/Categories/ANAdWebViewController+ANTest.h @@ -15,7 +15,7 @@ #import "ANAdWebViewController.h" -@interface ANMRAIDAdWebViewController (ANTest) +@interface ANAdWebViewController (ANTest) @property (nonatomic, readwrite, assign) BOOL completedFirstLoad; diff --git a/tests/Shared/Categories/ANAdWebViewController+ANTest.m b/tests/Shared/Categories/ANAdWebViewController+ANTest.m index 5e2174b2e..229a964b1 100644 --- a/tests/Shared/Categories/ANAdWebViewController+ANTest.m +++ b/tests/Shared/Categories/ANAdWebViewController+ANTest.m @@ -15,7 +15,7 @@ #import "ANAdWebViewController+ANTest.h" -@implementation ANMRAIDAdWebViewController (ANTest) +@implementation ANAdWebViewController (ANTest) @dynamic completedFirstLoad; diff --git a/tests/Shared/Categories/ANBannerAdView+ANTest.m b/tests/Shared/Categories/ANBannerAdView+ANTest.m index fa4d17d30..72fb0a64c 100644 --- a/tests/Shared/Categories/ANBannerAdView+ANTest.m +++ b/tests/Shared/Categories/ANBannerAdView+ANTest.m @@ -29,7 +29,6 @@ @implementation ANBannerAdView (ANTest) @dynamic age; @dynamic gender; @dynamic customKeywords; -@dynamic mraidEventReceiverDelegate; @dynamic contentView; @dynamic transitionInProgress; diff --git a/sdk/native/internal/ANNativeAdRequest+ANBaseUrlOverride.h b/tests/Shared/Categories/ANNativeAdRequest+ANBaseUrlOverride.h similarity index 95% rename from sdk/native/internal/ANNativeAdRequest+ANBaseUrlOverride.h rename to tests/Shared/Categories/ANNativeAdRequest+ANBaseUrlOverride.h index 8d20680d9..fab4ce0d1 100644 --- a/sdk/native/internal/ANNativeAdRequest+ANBaseUrlOverride.h +++ b/tests/Shared/Categories/ANNativeAdRequest+ANBaseUrlOverride.h @@ -1,4 +1,4 @@ -/* Copyright 2014 APPNEXUS INC +/* Copyright 2015 APPNEXUS INC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sdk/native/internal/ANNativeAdRequest+ANBaseUrlOverride.m b/tests/Shared/Categories/ANNativeAdRequest+ANBaseUrlOverride.m similarity index 76% rename from sdk/native/internal/ANNativeAdRequest+ANBaseUrlOverride.m rename to tests/Shared/Categories/ANNativeAdRequest+ANBaseUrlOverride.m index e7efe0f6e..af3c8248c 100644 --- a/sdk/native/internal/ANNativeAdRequest+ANBaseUrlOverride.m +++ b/tests/Shared/Categories/ANNativeAdRequest+ANBaseUrlOverride.m @@ -1,4 +1,4 @@ -/* Copyright 2014 APPNEXUS INC +/* Copyright 2015 APPNEXUS INC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,11 @@ - (void)createAdFetcherWithBaseUrlString:(NSString *)baseUrlString; @implementation ANNativeAdRequest (ANBaseUrlOverride) - (void)loadAdWithBaseUrlString:(NSString *)baseUrlString { - [self createAdFetcherWithBaseUrlString:baseUrlString]; + if (self.delegate) { + [self createAdFetcherWithBaseUrlString:baseUrlString]; + } else { + NSLog(@"ANNativeAdRequestDelegate must be set on ANNativeAdRequest in order for an ad to begin loading"); + } } @end \ No newline at end of file diff --git a/tests/Shared/Categories/ANNativeImpressionTrackerManager+ANTest.h b/tests/Shared/Categories/ANNativeImpressionTrackerManager+ANTest.h new file mode 100644 index 000000000..e0f068eb4 --- /dev/null +++ b/tests/Shared/Categories/ANNativeImpressionTrackerManager+ANTest.h @@ -0,0 +1,22 @@ +/* Copyright 2015 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANNativeImpressionTrackerManager.h" + +@interface ANNativeImpressionTrackerManager (ANTest) + +@property (nonatomic, readwrite, strong) NSTimer *impressionTrackerRetryTimer; + +@end diff --git a/tests/Shared/Categories/ANNativeImpressionTrackerManager+ANTest.m b/tests/Shared/Categories/ANNativeImpressionTrackerManager+ANTest.m new file mode 100644 index 000000000..25c21a003 --- /dev/null +++ b/tests/Shared/Categories/ANNativeImpressionTrackerManager+ANTest.m @@ -0,0 +1,22 @@ +/* Copyright 2015 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANNativeImpressionTrackerManager+ANTest.h" + +@implementation ANNativeImpressionTrackerManager (ANTest) + +@dynamic impressionTrackerRetryTimer; + +@end diff --git a/tests/Shared/Categories/ANReachability+ANTest.h b/tests/Shared/Categories/ANReachability+ANTest.h new file mode 100644 index 000000000..b613a8eef --- /dev/null +++ b/tests/Shared/Categories/ANReachability+ANTest.h @@ -0,0 +1,22 @@ +/* Copyright 2015 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANReachability.h" + +@interface ANReachability (ANTest) + ++ (void)toggleNonReachableNetworkStatusSimulationEnabled:(BOOL)simulationEnabled; + +@end diff --git a/tests/Shared/Categories/ANReachability+ANTest.m b/tests/Shared/Categories/ANReachability+ANTest.m new file mode 100644 index 000000000..0c9f773d0 --- /dev/null +++ b/tests/Shared/Categories/ANReachability+ANTest.m @@ -0,0 +1,44 @@ +/* Copyright 2015 APPNEXUS INC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "ANReachability+ANTest.h" +#import "NSObject+Swizzling.h" +#import + +static BOOL kANReachabilityNonReachableNetworkStatusSimulationEnabled = NO; + +@implementation ANReachability (ANTest) + ++ (void)toggleNonReachableNetworkStatusSimulationEnabled:(BOOL)simulationEnabled { + kANReachabilityNonReachableNetworkStatusSimulationEnabled = simulationEnabled; +} + ++ (void)load { + NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ + [[self class] exchangeInstanceSelector:@selector(currentReachabilityStatus) + withSelector:@selector(test_currentReachabilityStatus)]; + }]; + [operation start]; +} + +- (ANNetworkStatus)test_currentReachabilityStatus { + if (kANReachabilityNonReachableNetworkStatusSimulationEnabled) { + return ANNetworkStatusNotReachable; + } else { + return [self test_currentReachabilityStatus]; + } +} + +@end diff --git a/tests/Shared/Stubbing/ANHTTPStubURLProtocol.h b/tests/Shared/Stubbing/ANHTTPStubURLProtocol.h index a728083f2..ab210b6b4 100644 --- a/tests/Shared/Stubbing/ANHTTPStubURLProtocol.h +++ b/tests/Shared/Stubbing/ANHTTPStubURLProtocol.h @@ -15,6 +15,9 @@ #import +extern NSString *const kANHTTPStubURLProtocolRequestDidLoadNotification; +extern NSString *const kANHTTPStubURLProtocolRequest; + @interface ANHTTPStubURLProtocol : NSURLProtocol @end \ No newline at end of file diff --git a/tests/Shared/Stubbing/ANHTTPStubURLProtocol.m b/tests/Shared/Stubbing/ANHTTPStubURLProtocol.m index 83defc67a..c53430773 100644 --- a/tests/Shared/Stubbing/ANHTTPStubURLProtocol.m +++ b/tests/Shared/Stubbing/ANHTTPStubURLProtocol.m @@ -17,10 +17,18 @@ #import "ANHTTPStubbingManager.h" static NSString *const kANTestHTTPStubURLProtocolExceptionKey = @"ANTestHTTPStubURLProtocolException"; +NSString *const kANHTTPStubURLProtocolRequestDidLoadNotification = @"ANHTTPStubURLProtocolRequestDidLoad"; +NSString *const kANHTTPStubURLProtocolRequest = @"ANHTTPStubURLProtocolRequest"; @implementation ANHTTPStubURLProtocol + (BOOL)canInitWithRequest:(NSURLRequest *)request { + BOOL broadcastRequests = [ANHTTPStubbingManager sharedStubbingManager].broadcastRequests; + if (broadcastRequests && request) { + [[NSNotificationCenter defaultCenter] postNotificationName:kANHTTPStubURLProtocolRequestDidLoadNotification + object:nil + userInfo:@{kANHTTPStubURLProtocolRequest:request}]; + } BOOL isHttpOrHttps = [request.URL.scheme isEqualToString:@"http"] || [request.URL.scheme isEqualToString:@"https"]; if (!isHttpOrHttps) { return NO; diff --git a/tests/Shared/Stubbing/ANHTTPStubbingManager.h b/tests/Shared/Stubbing/ANHTTPStubbingManager.h index 425910ec1..e63a52d9d 100644 --- a/tests/Shared/Stubbing/ANHTTPStubbingManager.h +++ b/tests/Shared/Stubbing/ANHTTPStubbingManager.h @@ -32,7 +32,18 @@ /** If set to YES, then unstubbed requests will be ignored by this class and handled by the system. If set to NO (default), then unstubbed requests will result in didFailToLoad errors. + + Default is NO. */ @property (nonatomic) BOOL ignoreUnstubbedRequests; +/** + If set to YES, then all requests which trigger canInitWithRequest: will be broadcast + as kANHTTPStubURLProtocolRequestDidLoadNotification notifications. The request will be in the user info, + as the value of the kANHTTPStubURLProtocolRequest key. + + Default is NO. + */ +@property (nonatomic) BOOL broadcastRequests; + @end \ No newline at end of file