424 lines
14 KiB
Objective-C
424 lines
14 KiB
Objective-C
/*
|
|
|
|
AdWhirlAdapterMdotM.m
|
|
|
|
Copyright 2009 AdMob, 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 "AdWhirlAdapterMdotM.h"
|
|
#import "AdWhirlView.h"
|
|
#import "AdWhirlConfig.h"
|
|
#import "AdWhirlAdNetworkConfig.h"
|
|
#import "AdWhirlDelegateProtocol.h"
|
|
#import "AdWhirlLog.h"
|
|
#import "AdWhirlAdNetworkAdapter+Helpers.h"
|
|
#import "AdWhirlAdNetworkRegistry.h"
|
|
#import "AdWhirlAdapterCustom.h"
|
|
#import "AdWhirlError.h"
|
|
#import "CJSONDeserializer.h"
|
|
#import "AdWhirlCustomAdView.h"
|
|
|
|
|
|
@interface AdWhirlAdapterMdotM ()
|
|
|
|
- (BOOL)parseAdData:(NSData *)data error:(NSError **)error;
|
|
|
|
@property (nonatomic,readonly) CLLocationManager *locationManager;
|
|
@property (nonatomic,retain) NSURLConnection *adConnection;
|
|
@property (nonatomic,retain) NSURLConnection *imageConnection;
|
|
@property (nonatomic,retain) AdWhirlCustomAdView *adView;
|
|
@property (nonatomic,retain) AdWhirlWebBrowserController *webBrowserController;
|
|
|
|
@end
|
|
|
|
|
|
@implementation AdWhirlAdapterMdotM
|
|
|
|
@synthesize adConnection;
|
|
@synthesize imageConnection;
|
|
@synthesize adView;
|
|
@synthesize webBrowserController;
|
|
|
|
|
|
+ (AdWhirlAdNetworkType)networkType {
|
|
return AdWhirlAdNetworkTypeMdotM;
|
|
}
|
|
|
|
+ (void)load {
|
|
[[AdWhirlAdNetworkRegistry sharedRegistry] registerClass:self];
|
|
}
|
|
|
|
- (BOOL)useTestAd {
|
|
if ([adWhirlDelegate respondsToSelector:@selector(adWhirlTestMode)])
|
|
return [adWhirlDelegate adWhirlTestMode];
|
|
return NO;
|
|
}
|
|
|
|
|
|
- (id)initWithAdWhirlDelegate:(id<AdWhirlDelegate>)delegate
|
|
view:(AdWhirlView *)view
|
|
config:(AdWhirlConfig *)config
|
|
networkConfig:(AdWhirlAdNetworkConfig *)netConf {
|
|
self = [super initWithAdWhirlDelegate:delegate
|
|
view:view
|
|
config:config
|
|
networkConfig:netConf];
|
|
if (self != nil) {
|
|
adData = [[NSMutableData alloc] init];
|
|
imageData = [[NSMutableData alloc] init];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (NSMutableString *)appendUserContextDic:(NSDictionary *)dic withUrl:(NSString *)sUrl {
|
|
NSArray *keyArray = [dic allKeys];
|
|
NSMutableString *str = [NSMutableString stringWithString:sUrl];
|
|
|
|
//Iterate over the context disctionary and for each kay-value pair create a string of the format &key=value
|
|
for (int i = 0; i < [keyArray count]; i++) {
|
|
[str appendFormat:@"&%@=%@",[keyArray objectAtIndex:i], [dic objectForKey:[keyArray objectAtIndex:i]]];
|
|
}
|
|
return str;
|
|
}
|
|
|
|
|
|
- (void)getAd {
|
|
@synchronized(self) {
|
|
if (requesting) return;
|
|
requesting = YES;
|
|
}
|
|
|
|
NSString *appKey = networkConfig.pubId;
|
|
|
|
if ([adWhirlDelegate respondsToSelector:@selector(MdotMApplicationKey)] ) {
|
|
appKey = [adWhirlDelegate MdotMApplicationKey];
|
|
}
|
|
|
|
UIDevice *device = [UIDevice currentDevice];
|
|
NSBundle *bundle = [NSBundle mainBundle];
|
|
NSLocale *locale = [NSLocale currentLocale];
|
|
NSString *userAgent = [NSString stringWithFormat:@"%@ %@ (%@; %@ %@; %@)",
|
|
[bundle objectForInfoDictionaryKey:@"CFBundleDisplayName"],
|
|
[bundle objectForInfoDictionaryKey:@"CFBundleVersion"],
|
|
[device model],
|
|
[device systemName], [device systemVersion],
|
|
[locale localeIdentifier]];
|
|
int test;
|
|
if ( [self useTestAd] ) {
|
|
test = 1;
|
|
} else
|
|
test = 0;
|
|
|
|
NSString *str = [NSString stringWithFormat:
|
|
@"http://ads.mdotm.com/ads/feed.php?appver=%d&v=%@&apikey=mdotm&appkey=%@&deviceid=%@&width=320&height=50&fmt=json&ua=%@&test=%d",
|
|
kAdWhirlAppVer, [[UIDevice currentDevice] systemVersion],
|
|
appKey, [[UIDevice currentDevice] uniqueIdentifier], userAgent, test];
|
|
|
|
NSMutableDictionary *userContextDic = [[NSMutableDictionary alloc] initWithCapacity:2];
|
|
if ( [userContextDic count] > 0 ) {
|
|
str = [self appendUserContextDic:userContextDic withUrl:str];
|
|
}
|
|
|
|
NSString *urlString = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
|
|
|
NSURL *adRequestURL = [[NSURL alloc] initWithString:urlString];
|
|
AWLogDebug(@"Requesting MdotM ad (%@) %@", str, adRequestURL);
|
|
NSURLRequest *adRequest = [NSURLRequest requestWithURL:adRequestURL];
|
|
|
|
|
|
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:adRequest
|
|
delegate:self];
|
|
self.adConnection = conn;
|
|
[conn release];
|
|
[adRequestURL release];
|
|
[userContextDic release];
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark MdotMDelegate optional methods
|
|
|
|
- (BOOL)respondsToSelector:(SEL)selector {
|
|
if (selector == @selector(location)
|
|
&& ![adWhirlDelegate respondsToSelector:@selector(location)]) {
|
|
return NO;
|
|
}
|
|
else if (selector == @selector(userContext)
|
|
&& ![adWhirlDelegate respondsToSelector:@selector(userContext)]) {
|
|
return NO;
|
|
} return [super respondsToSelector:selector];
|
|
}
|
|
|
|
|
|
- (CLLocationManager *)locationManager {
|
|
if (locationManager == nil) {
|
|
locationManager = [[CLLocationManager alloc] init];
|
|
}
|
|
return locationManager;
|
|
}
|
|
|
|
- (BOOL)parseEnums:(int *)val
|
|
adInfo:(NSDictionary*)info
|
|
minVal:(int)min
|
|
maxVal:(int)max
|
|
fieldName:(NSString *)name
|
|
error:(NSError **)error {
|
|
NSString *str = [info objectForKey:name];
|
|
if (str == nil) {
|
|
if (error != nil)
|
|
*error = [AdWhirlError errorWithCode:AdWhirlCustomAdDataError
|
|
description:[NSString stringWithFormat:
|
|
@"MdotM ad data has no '%@' field", name]];
|
|
return NO;
|
|
}
|
|
int intVal = [str intValue];
|
|
if (intVal <= min || intVal >= max) {
|
|
if (error != nil)
|
|
*error = [AdWhirlError errorWithCode:AdWhirlCustomAdDataError
|
|
description:[NSString stringWithFormat:
|
|
@"MdotM ad data: Invalid value for %@ - %d", name, intVal]];
|
|
return NO;
|
|
}
|
|
*val = intVal;
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL)parseAdData:(NSData *)data error:(NSError **)error {
|
|
NSError *jsonError = nil;
|
|
id parsed = [[CJSONDeserializer deserializer] deserialize:data error:&jsonError];
|
|
if (parsed == nil) {
|
|
if (error != nil)
|
|
*error = [AdWhirlError errorWithCode:AdWhirlCustomAdParseError
|
|
description:@"Error parsing MdotM ad JSON from server"
|
|
underlyingError:jsonError];
|
|
return NO;
|
|
}
|
|
if ([parsed isKindOfClass:[NSArray class]]) {
|
|
NSArray *ads = parsed;
|
|
NSDictionary *adInfo = nil;
|
|
if ( [ads count] == 0 ) {
|
|
return(NO);
|
|
} else {
|
|
id parsed0 =[ads objectAtIndex:0];
|
|
if ( [parsed0 isKindOfClass:[NSDictionary class]] ) {
|
|
adInfo = parsed0;
|
|
|
|
// gather up and validate ad info
|
|
NSString *text = [adInfo objectForKey:@"ad_text"];
|
|
NSString *redirectURLStr = [adInfo objectForKey:@"landing_url"];
|
|
|
|
int adTypeInt;
|
|
if (![self parseEnums:&adTypeInt
|
|
adInfo:adInfo
|
|
minVal:AWCustomAdTypeMIN
|
|
maxVal:AWCustomAdTypeMAX
|
|
fieldName:@"ad_type"
|
|
error:error]) {
|
|
return NO;
|
|
}
|
|
AWCustomAdType adType = adTypeInt;
|
|
|
|
int launchTypeInt;
|
|
if (![self parseEnums:&launchTypeInt
|
|
adInfo:adInfo
|
|
minVal:AWCustomAdLaunchTypeMIN
|
|
maxVal:AWCustomAdLaunchTypeMAX
|
|
fieldName:@"launch_type"
|
|
error:error]) {
|
|
return NO;
|
|
}
|
|
AWCustomAdLaunchType launchType = launchTypeInt;
|
|
AWCustomAdWebViewAnimType animType = AWCustomAdWebViewAnimTypeCurlDown;
|
|
|
|
NSURL *redirectURL = nil;
|
|
if (redirectURLStr == nil) {
|
|
AWLogWarn(@"No redirect URL for MdotM ad");
|
|
} else {
|
|
redirectURL = [[NSURL alloc] initWithString:redirectURLStr];
|
|
if (!redirectURL)
|
|
AWLogWarn(@"MdotM ad: Malformed redirect URL string %@", redirectURLStr);
|
|
}
|
|
AWLogDebug(@"Got MdotM ad %@ %@ %d %d %d", text, redirectURL,
|
|
adType, launchType, animType);
|
|
|
|
self.adView = [[AdWhirlCustomAdView alloc] initWithDelegate:self
|
|
text:text
|
|
redirectURL:redirectURL
|
|
clickMetricsURL:nil
|
|
adType:adType
|
|
launchType:launchType
|
|
animType:animType
|
|
backgroundColor:[self helperBackgroundColorToUse]
|
|
textColor:[self helperTextColorToUse]];
|
|
[self.adView release];
|
|
self.adNetworkView = adView;
|
|
[redirectURL release];
|
|
if (adView == nil) {
|
|
if (error != nil)
|
|
*error = [AdWhirlError errorWithCode:AdWhirlCustomAdDataError
|
|
description:@"Error initializing MdotM ad view"];
|
|
return NO;
|
|
}
|
|
|
|
// fetch image
|
|
id imageURL = [adInfo objectForKey:@"img_url"];
|
|
if ( [imageURL isKindOfClass:[NSString class]]) {
|
|
AWLogDebug(@"Request MdotM ad image at %@", imageURL);
|
|
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURL]];
|
|
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:imageRequest
|
|
delegate:self];
|
|
self.imageConnection = conn;
|
|
[conn release];
|
|
} else {
|
|
return(NO);
|
|
}
|
|
} else {
|
|
return(NO);
|
|
}
|
|
}
|
|
} else {
|
|
if (error != nil)
|
|
*error = [AdWhirlError errorWithCode:AdWhirlCustomAdDataError
|
|
description:@"Expected top-level dictionary in MdotM ad data"];
|
|
return NO;
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
- (void)stopBeingDelegate {
|
|
AdWhirlCustomAdView *theAdView = (AdWhirlCustomAdView *)self.adNetworkView;
|
|
if (theAdView != nil) {
|
|
theAdView.delegate = nil;
|
|
}
|
|
}
|
|
|
|
- (void)dealloc {
|
|
[locationManager release], locationManager = nil;
|
|
[adConnection release], adConnection = nil;
|
|
[adData release], adData = nil;
|
|
[imageConnection release], imageConnection = nil;
|
|
[imageData release], imageData = nil;
|
|
[adView release], adView = nil;
|
|
[webBrowserController release], webBrowserController = nil;
|
|
[super dealloc];
|
|
}
|
|
|
|
#pragma mark NSURLConnection delegate methods.
|
|
|
|
- (void)connection:(NSURLConnection *)conn didReceiveResponse:(NSURLResponse *)response {
|
|
if (conn == adConnection) {
|
|
[adData setLength:0];
|
|
}
|
|
else if (conn == imageConnection) {
|
|
[imageData setLength:0];
|
|
}
|
|
}
|
|
|
|
- (void)connection:(NSURLConnection *)conn didFailWithError:(NSError *)error {
|
|
if (conn == adConnection) {
|
|
[adWhirlView adapter:self didFailAd:[AdWhirlError errorWithCode:AdWhirlCustomAdConnectionError
|
|
description:@"Error connecting to MdotM ad server"
|
|
underlyingError:error]];
|
|
requesting = NO;
|
|
} else if (conn == imageConnection) {
|
|
[adWhirlView adapter:self didFailAd:[AdWhirlError errorWithCode:AdWhirlCustomAdConnectionError
|
|
description:@"Error connecting to MdotM to fetch image"
|
|
underlyingError:error]];
|
|
requesting = NO;
|
|
}
|
|
}
|
|
|
|
- (void)connectionDidFinishLoading:(NSURLConnection *)conn {
|
|
if (conn == adConnection) {
|
|
NSError *error = nil;
|
|
if (![self parseAdData:adData error:&error]) {
|
|
[adWhirlView adapter:self didFailAd:error];
|
|
requesting = NO;
|
|
return;
|
|
}
|
|
}
|
|
else if (conn == imageConnection) {
|
|
UIImage *image = [[UIImage alloc] initWithData:imageData];
|
|
if (image == nil) {
|
|
[adWhirlView adapter:self
|
|
didFailAd:[AdWhirlError errorWithCode:AdWhirlCustomAdImageError
|
|
description:@"Cannot initialize MdotM ad image from data"]];
|
|
requesting = NO;
|
|
return;
|
|
}
|
|
adView.image = image;
|
|
[adView setNeedsDisplay];
|
|
[image release];
|
|
requesting = NO;
|
|
[adWhirlView adapter:self didReceiveAdView:self.adView];
|
|
}
|
|
}
|
|
|
|
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data {
|
|
if (conn == adConnection) {
|
|
[adData appendData:data];
|
|
}
|
|
else if (conn == imageConnection) {
|
|
[imageData appendData:data];
|
|
}
|
|
}
|
|
|
|
#pragma mark AdWhirlCustomAdViewDelegate methods
|
|
|
|
- (void)adTapped:(AdWhirlCustomAdView *)ad {
|
|
if (ad != adView) return;
|
|
if (ad.clickMetricsURL != nil) {
|
|
NSURLRequest *metRequest = [NSURLRequest requestWithURL:ad.clickMetricsURL];
|
|
[NSURLConnection connectionWithRequest:metRequest
|
|
delegate:nil]; // fire and forget
|
|
}
|
|
if (ad.redirectURL == nil) {
|
|
AWLogError(@"MdotM ad redirect URL is nil");
|
|
return;
|
|
}
|
|
switch (ad.launchType) {
|
|
case AWCustomAdLaunchTypeSafari:
|
|
[[UIApplication sharedApplication] openURL:ad.redirectURL];
|
|
break;
|
|
case AWCustomAdLaunchTypeCanvas:
|
|
if (self.webBrowserController == nil) {
|
|
AdWhirlWebBrowserController *ctrlr = [[AdWhirlWebBrowserController alloc] init];
|
|
self.webBrowserController = ctrlr;
|
|
[ctrlr release];
|
|
}
|
|
webBrowserController.delegate = self;
|
|
[webBrowserController presentWithController:[adWhirlDelegate viewControllerForPresentingModalView]
|
|
transition:ad.animType];
|
|
[self helperNotifyDelegateOfFullScreenModal];
|
|
[webBrowserController loadURL:ad.redirectURL];
|
|
break;
|
|
default:
|
|
AWLogError(@"MdotM ad: Unsupported launch type %d", ad.launchType);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#pragma mark AdWhirlWebBrowserControllerDelegate methods
|
|
|
|
- (void)webBrowserClosed:(AdWhirlWebBrowserController *)controller {
|
|
if (controller != webBrowserController) return;
|
|
self.webBrowserController = nil; // don't keep around to save memory
|
|
[self helperNotifyDelegateOfFullScreenModalDismissal];
|
|
}
|
|
|
|
@end
|