├── ChimpKit.podspec ├── ChimpKit3 ├── ChimpKit.h ├── ChimpKit.m └── Helper Objects │ ├── CKAuthViewController.h │ ├── CKAuthViewController.m │ ├── CKAuthViewController.xib │ ├── CKScanViewController.h │ ├── CKScanViewController.m │ ├── CKSubscribeAlertView.h │ ├── CKSubscribeAlertView.m │ └── ChimpKit.xcassets │ └── qr_code.imageset │ ├── Contents.json │ ├── qr-code-@1x.png │ └── qr-code-@2x.png ├── LICENSE.txt ├── README.md └── Sample App ├── ChimpKitSampleApp.xcodeproj └── project.pbxproj └── ChimpKitSampleApp ├── AppDelegate.h ├── AppDelegate.m ├── ChimpKitSampleApp-Info.plist ├── ChimpKitSampleApp-Prefix.pch ├── Default-568h@2x.png ├── Default.png ├── Default@2x.png ├── ViewController.h ├── ViewController.m ├── en.lproj ├── InfoPlist.strings ├── MainStoryboard_iPad.storyboard └── MainStoryboard_iPhone.storyboard └── main.m /ChimpKit.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "ChimpKit" 3 | s.version = "3.1.1" 4 | s.summary = "ChimpKit is an API wrapper for the MailChimp API 2.0." 5 | 6 | s.description = <<-DESC 7 | ChimpKit lets you interact with MailChimp's API to subscribe users, 8 | fetch reports, send campaigns, and more. ChimpKit has OAuth2 baked in 9 | so your users can easily log into their MailChimp account. 10 | DESC 11 | 12 | s.homepage = "https://github.com/mailchimp/ChimpKit3" 13 | 14 | s.license = { :type => 'MIT', :file => 'LICENSE.TXT' } 15 | 16 | s.author = { "Drew Conner" => "drew@mailchimp.com" } 17 | 18 | s.platform = :ios, '7.0' 19 | s.ios.deployment_target = '7.0' 20 | 21 | s.source = { :git => "https://github.com/mailchimp/ChimpKit3.git", :tag => "3.1.1" } 22 | 23 | s.source_files = 'ChimpKit3', 'ChimpKit3/**/*.{h,m}' 24 | s.resources = ['ChimpKit3/**/*.{xib}'] 25 | s.requires_arc = true 26 | end 27 | -------------------------------------------------------------------------------- /ChimpKit3/ChimpKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // ChimpKit.h 3 | // ChimpKit3 4 | // 5 | // Created by Drew Conner on 1/7/13. 6 | // Copyright (c) 2013 MailChimp. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | #define kCKDebug 0 13 | #define kDefaultTimeoutInterval 15.0f 14 | 15 | 16 | typedef enum { 17 | kChimpKitErrorInvalidAPIKey = 0, 18 | kChimpKitErrorInvalidDelegate, 19 | kChimpKitErrorInvalidCompletionHandler 20 | } ChimpKitError; 21 | 22 | 23 | @protocol ChimpKitRequestDelegate 24 | 25 | @optional 26 | - (void)ckRequestIdentifier:(NSUInteger)requestIdentifier didUploadBytes:(int64_t)bytes outOfBytes:(int64_t)totalBytes; 27 | - (void)ckRequestIdentifier:(NSUInteger)requestIdentifier didSucceedWithResponse:(NSURLResponse *)response andData:(NSData *)data; 28 | - (void)ckRequestFailedWithIdentifier:(NSUInteger)requestIdentifier andError:(NSError *)anError; 29 | 30 | @end 31 | 32 | 33 | typedef void (^ChimpKitRequestCompletionBlock)(NSURLResponse *response, NSData *data, NSError *error); 34 | 35 | 36 | @interface ChimpKit : NSObject 37 | 38 | @property (nonatomic, strong) NSString *apiKey; 39 | @property (nonatomic, strong) NSString *apiURL; 40 | @property (nonatomic, assign) NSTimeInterval timeoutInterval; 41 | 42 | + (ChimpKit *)sharedKit; 43 | 44 | // Returns unique identifier for each request 45 | - (NSUInteger)callApiMethod:(NSString *)aMethod 46 | withParams:(NSDictionary *)someParams 47 | andCompletionHandler:(ChimpKitRequestCompletionBlock)aHandler; 48 | 49 | - (NSUInteger)callApiMethod:(NSString *)aMethod 50 | withParams:(NSDictionary *)someParams 51 | andDelegate:(id)aDelegate; 52 | 53 | // If these methods are called with a nil apikey, ChimpKit falls back to 54 | // using the global apikey 55 | - (NSUInteger)callApiMethod:(NSString *)aMethod 56 | withApiKey:(NSString *)anApiKey 57 | params:(NSDictionary *)someParams 58 | andCompletionHandler:(ChimpKitRequestCompletionBlock)aHandler; 59 | 60 | - (NSUInteger)callApiMethod:(NSString *)aMethod 61 | withApiKey:(NSString *)anApiKey 62 | params:(NSDictionary *)someParams 63 | andDelegate:(id)aDelegate; 64 | 65 | - (void)cancelRequestWithIdentifier:(NSUInteger)requestIdentifier; 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /ChimpKit3/ChimpKit.m: -------------------------------------------------------------------------------- 1 | // 2 | // ChimpKit.m 3 | // ChimpKit3 4 | // 5 | // Created by Drew Conner on 1/7/13. 6 | // Copyright (c) 2013 MailChimp. All rights reserved. 7 | // 8 | 9 | #import "ChimpKit.h" 10 | 11 | 12 | #define kAPI20Endpoint @"https://%@.api.mailchimp.com/2.0/" 13 | #define kErrorDomain @"com.MailChimp.ChimpKit.ErrorDomain" 14 | 15 | 16 | @interface ChimpKit () 17 | 18 | @property (nonatomic, strong) NSURLSession *urlSession; 19 | @property (nonatomic, strong) NSMutableDictionary *requests; 20 | 21 | @end 22 | 23 | 24 | @interface ChimpKitRequestWrapper : NSObject 25 | 26 | @property (nonatomic, strong) NSURLSessionDataTask *dataTask; 27 | @property (nonatomic, strong) NSMutableData *receivedData; 28 | 29 | @property (nonatomic, copy) ChimpKitRequestCompletionBlock completionHandler; 30 | @property (nonatomic, strong) id delegate; 31 | 32 | @end 33 | 34 | 35 | @implementation ChimpKit 36 | 37 | #pragma mark - Class Methods 38 | 39 | + (ChimpKit *)sharedKit { 40 | static dispatch_once_t pred = 0; 41 | __strong static ChimpKit *_sharedKit = nil; 42 | 43 | dispatch_once(&pred, ^{ 44 | _sharedKit = [[self alloc] init]; 45 | }); 46 | 47 | return _sharedKit; 48 | } 49 | 50 | - (id)init { 51 | if (self = [super init]) { 52 | self.timeoutInterval = kDefaultTimeoutInterval; 53 | self.requests = [[NSMutableDictionary alloc] init]; 54 | } 55 | 56 | return self; 57 | } 58 | 59 | 60 | #pragma mark - Properties 61 | 62 | - (NSURLSession *)urlSession { 63 | if (_urlSession == nil) { 64 | _urlSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] 65 | delegate:self 66 | delegateQueue:nil]; 67 | } 68 | 69 | return _urlSession; 70 | } 71 | 72 | - (void)setApiKey:(NSString *)apiKey { 73 | _apiKey = apiKey; 74 | 75 | if (_apiKey) { 76 | // Parse out the datacenter and template it into the URL. 77 | NSArray *apiKeyParts = [_apiKey componentsSeparatedByString:@"-"]; 78 | if ([apiKeyParts count] > 1) { 79 | self.apiURL = [NSString stringWithFormat:kAPI20Endpoint, [apiKeyParts objectAtIndex:1]]; 80 | } else { 81 | NSAssert(FALSE, @"Please provide a valid API Key"); 82 | } 83 | } 84 | } 85 | 86 | 87 | #pragma mark - API Methods 88 | 89 | - (NSUInteger)callApiMethod:(NSString *)aMethod withParams:(NSDictionary *)someParams andCompletionHandler:(ChimpKitRequestCompletionBlock)aHandler { 90 | return [self callApiMethod:aMethod withApiKey:nil params:someParams andCompletionHandler:aHandler]; 91 | } 92 | 93 | - (NSUInteger)callApiMethod:(NSString *)aMethod withApiKey:(NSString *)anApiKey params:(NSDictionary *)someParams andCompletionHandler:(ChimpKitRequestCompletionBlock)aHandler { 94 | if (aHandler == nil) { 95 | return 0; 96 | } 97 | 98 | return [self callApiMethod:aMethod withApiKey:anApiKey params:someParams andCompletionHandler:aHandler orDelegate:nil]; 99 | } 100 | 101 | - (NSUInteger)callApiMethod:(NSString *)aMethod withParams:(NSDictionary *)someParams andDelegate:(id)aDelegate { 102 | return [self callApiMethod:aMethod withApiKey:nil params:someParams andDelegate:aDelegate]; 103 | } 104 | 105 | - (NSUInteger)callApiMethod:(NSString *)aMethod withApiKey:(NSString *)anApiKey params:(NSDictionary *)someParams andDelegate:(id)aDelegate { 106 | if (aDelegate == nil) { 107 | return 0; 108 | } 109 | 110 | return [self callApiMethod:aMethod withApiKey:anApiKey params:someParams andCompletionHandler:nil orDelegate:aDelegate]; 111 | } 112 | 113 | - (NSUInteger)callApiMethod:(NSString *)aMethod withApiKey:(NSString *)anApiKey params:(NSDictionary *)someParams andCompletionHandler:(ChimpKitRequestCompletionBlock)aHandler orDelegate:(id)aDelegate { 114 | if ((anApiKey == nil) && (self.apiKey == nil)) { 115 | NSError *error = [NSError errorWithDomain:kErrorDomain code:kChimpKitErrorInvalidAPIKey userInfo:nil]; 116 | 117 | if (aDelegate && [aDelegate respondsToSelector:@selector(ckRequestFailedWithIdentifier:andError:)]) { 118 | [aDelegate ckRequestFailedWithIdentifier:0 andError:error]; 119 | } 120 | 121 | if (aHandler) { 122 | aHandler(nil, nil, error); 123 | } 124 | 125 | return 0; 126 | } 127 | 128 | NSString *urlString = nil; 129 | NSMutableDictionary *params = [NSMutableDictionary dictionaryWithDictionary:someParams]; 130 | 131 | if (anApiKey) { 132 | NSArray *apiKeyParts = [anApiKey componentsSeparatedByString:@"-"]; 133 | if ([apiKeyParts count] > 1) { 134 | NSString *apiURL = [NSString stringWithFormat:kAPI20Endpoint, [apiKeyParts objectAtIndex:1]]; 135 | urlString = [NSString stringWithFormat:@"%@%@", apiURL, aMethod]; 136 | } else { 137 | NSError *error = [NSError errorWithDomain:kErrorDomain code:kChimpKitErrorInvalidAPIKey userInfo:nil]; 138 | 139 | if (aDelegate && [aDelegate respondsToSelector:@selector(ckRequestFailedWithIdentifier:andError:)]) { 140 | [aDelegate ckRequestFailedWithIdentifier:0 andError:error]; 141 | } 142 | 143 | if (aHandler) { 144 | aHandler(nil, nil, error); 145 | } 146 | 147 | return 0; 148 | } 149 | 150 | [params setValue:anApiKey forKey:@"apikey"]; 151 | } else if (self.apiKey) { 152 | urlString = [NSString stringWithFormat:@"%@%@", self.apiURL, aMethod]; 153 | [params setValue:self.apiKey forKey:@"apikey"]; 154 | } 155 | 156 | if (kCKDebug) NSLog(@"URL: %@", urlString); 157 | 158 | NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString] 159 | cachePolicy:NSURLRequestUseProtocolCachePolicy 160 | timeoutInterval:self.timeoutInterval]; 161 | 162 | [request setHTTPMethod:@"POST"]; 163 | [request setHTTPBody:[self encodeRequestParams:params]]; 164 | 165 | NSURLSessionDataTask *dataTask = [self.urlSession dataTaskWithRequest:request]; 166 | 167 | ChimpKitRequestWrapper *requestWrapper = [[ChimpKitRequestWrapper alloc] init]; 168 | 169 | requestWrapper.dataTask = dataTask; 170 | requestWrapper.delegate = aDelegate; 171 | requestWrapper.completionHandler = aHandler; 172 | 173 | [dataTask resume]; 174 | 175 | dispatch_async(dispatch_get_main_queue(), ^{ 176 | [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; 177 | }); 178 | 179 | [self.requests setObject:requestWrapper forKey:[NSNumber numberWithUnsignedInteger:[dataTask taskIdentifier]]]; 180 | 181 | return [dataTask taskIdentifier]; 182 | } 183 | 184 | - (void)cancelRequestWithIdentifier:(NSUInteger)identifier { 185 | ChimpKitRequestWrapper *requestWrapper = [self.requests objectForKey:[NSNumber numberWithUnsignedInteger:identifier]]; 186 | 187 | [requestWrapper.dataTask cancel]; 188 | 189 | [self.requests removeObjectForKey:[NSNumber numberWithUnsignedInteger:identifier]]; 190 | } 191 | 192 | 193 | #pragma mark - Methods 194 | 195 | - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { 196 | ChimpKitRequestWrapper *requestWrapper = [self.requests objectForKey:[NSNumber numberWithUnsignedInteger:[task taskIdentifier]]]; 197 | 198 | if (requestWrapper.delegate && [requestWrapper.delegate respondsToSelector:@selector(ckRequestIdentifier:didUploadBytes:outOfBytes:)]) { 199 | [requestWrapper.delegate ckRequestIdentifier:[task taskIdentifier] 200 | didUploadBytes:totalBytesSent 201 | outOfBytes:totalBytesExpectedToSend]; 202 | } 203 | } 204 | 205 | - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { 206 | ChimpKitRequestWrapper *requestWrapper = [self.requests objectForKey:[NSNumber numberWithUnsignedInteger:[dataTask taskIdentifier]]]; 207 | [requestWrapper.receivedData appendData:data]; 208 | } 209 | 210 | - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { 211 | dispatch_async(dispatch_get_main_queue(), ^{ 212 | [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; 213 | }); 214 | 215 | ChimpKitRequestWrapper *requestWrapper = [self.requests objectForKey:[NSNumber numberWithUnsignedInteger:[task taskIdentifier]]]; 216 | 217 | if (requestWrapper.completionHandler) { 218 | requestWrapper.completionHandler(task.response, requestWrapper.receivedData, error); 219 | } else { 220 | if (error) { 221 | if (requestWrapper.delegate && [requestWrapper.delegate respondsToSelector:@selector(ckRequestFailedWithIdentifier:andError:)]) { 222 | [requestWrapper.delegate ckRequestFailedWithIdentifier:[task taskIdentifier] 223 | andError:error]; 224 | } 225 | } else { 226 | if (requestWrapper.delegate && [requestWrapper.delegate respondsToSelector:@selector(ckRequestIdentifier:didSucceedWithResponse:andData:)]) { 227 | [requestWrapper.delegate ckRequestIdentifier:[task taskIdentifier] 228 | didSucceedWithResponse:task.response 229 | andData:requestWrapper.receivedData]; 230 | } 231 | } 232 | } 233 | 234 | [self.requests removeObjectForKey:[NSNumber numberWithUnsignedInteger:[task taskIdentifier]]]; 235 | } 236 | 237 | 238 | #pragma mark - Private Methods 239 | 240 | - (NSMutableData *)encodeRequestParams:(NSDictionary *)params { 241 | NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:nil]; 242 | NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 243 | 244 | NSMutableData *postData = [NSMutableData dataWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]]; 245 | 246 | return postData; 247 | } 248 | 249 | 250 | @end 251 | 252 | 253 | @implementation ChimpKitRequestWrapper 254 | 255 | - (id)init { 256 | if (self = [super init]) { 257 | self.receivedData = [[NSMutableData alloc] init]; 258 | } 259 | 260 | return self; 261 | } 262 | 263 | @end 264 | -------------------------------------------------------------------------------- /ChimpKit3/Helper Objects/CKAuthViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CKAuthViewController.h 3 | // ChimpKit2 4 | // 5 | // Created by Amro Mousa on 8/16/11. 6 | // Copyright (c) 2011 MailChimp. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | #define kCKAuthDebug 1 13 | 14 | #define kAuthorizeUrl @"https://login.mailchimp.com/oauth2/authorize" 15 | #define kAccessTokenUrl @"https://login.mailchimp.com/oauth2/token" 16 | #define kMetaDataUrl @"https://login.mailchimp.com/oauth2/metadata" 17 | #define kDefaultRedirectUrl @"https://modev1.mailchimp.com/wait.html" 18 | 19 | 20 | @protocol CKAuthViewControllerDelegate 21 | 22 | // You must dismiss the Auth View in all of these methods 23 | - (void)ckAuthUserCanceled; 24 | - (void)ckAuthSucceededWithApiKey:(NSString *)apiKey andAccountData:(NSDictionary *)accountData; 25 | - (void)ckAuthFailedWithError:(NSError *)error; 26 | 27 | @end 28 | 29 | 30 | @interface CKAuthViewController : UIViewController 31 | 32 | @property (unsafe_unretained, readwrite) id delegate; 33 | 34 | @property (nonatomic, assign) BOOL enableMultipleLogin; 35 | 36 | @property (nonatomic, assign) BOOL disableCancelling; 37 | @property (nonatomic, assign) BOOL disableAPIKeyScanning; 38 | @property (nonatomic, assign) BOOL disableAccountDataFetching; 39 | 40 | @property (strong, nonatomic) NSString *clientId; 41 | @property (strong, nonatomic) NSString *clientSecret; 42 | @property (strong, nonatomic) NSString *redirectUrl; 43 | 44 | @property (strong, nonatomic) IBOutlet UIActivityIndicatorView *spinner; 45 | @property (strong, nonatomic) IBOutlet UIWebView *webview; 46 | 47 | - (id)initWithClientId:(NSString *)cId andClientSecret:(NSString *)cSecret; 48 | - (id)initWithClientId:(NSString *)cId clientSecret:(NSString *)cSecret andRedirectUrl:(NSString *)redirectUrl; 49 | 50 | @property (nonatomic, copy) void (^authSucceeded)(NSString *apiKey, NSDictionary *accountData); 51 | @property (nonatomic, copy) void (^authFailed)(NSError *error); 52 | @property (nonatomic, copy) void (^userCancelled)(void); 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /ChimpKit3/Helper Objects/CKAuthViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CKAuthViewController.m 3 | // ChimpKit2 4 | // 5 | // Created by Amro Mousa on 8/16/11. 6 | // Copyright (c) 2011 MailChimp. All rights reserved. 7 | // 8 | 9 | #import "CKAuthViewController.h" 10 | #import "CKScanViewController.h" 11 | #import "ChimpKit.h" 12 | 13 | 14 | @interface CKAuthViewController() 15 | 16 | @property (nonatomic, strong) NSURLSession *urlSession; 17 | @property (nonatomic, strong) ChimpKit *chimpKit; 18 | 19 | - (void)authWithClientId:(NSString *)clientId andSecret:(NSString *)secret; 20 | - (void)getAccessTokenMetaDataForAccessToken:(NSString *)accessToken; 21 | 22 | @end 23 | 24 | 25 | @implementation CKAuthViewController 26 | 27 | 28 | #pragma mark - Properties 29 | 30 | - (ChimpKit *)chimpKit { 31 | if (_chimpKit == nil) { 32 | _chimpKit = [[ChimpKit alloc] init]; 33 | } 34 | 35 | return _chimpKit; 36 | } 37 | 38 | 39 | #pragma mark - Initialization 40 | 41 | - (id)initWithClientId:(NSString *)cId clientSecret:(NSString *)cSecret andRedirectUrl:(NSString *)redirectUrl { 42 | self = [super init]; 43 | 44 | if (self) { 45 | self.clientId = cId; 46 | self.clientSecret = cSecret; 47 | self.redirectUrl = redirectUrl; 48 | 49 | self.urlSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; 50 | } 51 | 52 | return self; 53 | } 54 | 55 | - (id)initWithClientId:(NSString *)cId andClientSecret:(NSString *)cSecret { 56 | return [self initWithClientId:cId clientSecret:cSecret andRedirectUrl:kDefaultRedirectUrl]; 57 | } 58 | 59 | 60 | #pragma mark - View Lifecycle 61 | 62 | - (void)viewDidLoad { 63 | [super viewDidLoad]; 64 | 65 | self.title = @"Connect to MailChimp"; 66 | 67 | //If presented modally in a new VC, add the cancel button 68 | if (([self.navigationController.viewControllers objectAtIndex:0] == self) && (self.disableCancelling == NO)) { 69 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel 70 | target:self 71 | action:@selector(cancelButtonTapped:)]; 72 | } 73 | 74 | if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) && (self.disableAPIKeyScanning == NO)) { 75 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"qr_code"] 76 | style:UIBarButtonItemStylePlain 77 | target:self 78 | action:@selector(scanButtonTapped:)]; 79 | } 80 | } 81 | 82 | - (void)viewWillAppear:(BOOL)animated { 83 | [super viewWillAppear:animated]; 84 | 85 | [self authWithClientId:self.clientId andSecret:self.clientSecret]; 86 | } 87 | 88 | - (void)viewWillDisappear:(BOOL)animated { 89 | [super viewWillDisappear:animated]; 90 | [self.webview stopLoading]; 91 | } 92 | 93 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 94 | return YES; 95 | } 96 | 97 | 98 | #pragma mark - UI Actions 99 | 100 | - (void)cancelButtonTapped:(id)sender { 101 | if ([self.delegate respondsToSelector:@selector(ckAuthUserCanceled)]) { 102 | [self.delegate ckAuthUserCanceled]; 103 | } 104 | 105 | if (self.userCancelled) { 106 | self.userCancelled(); 107 | } 108 | } 109 | 110 | - (void)scanButtonTapped:(id)sender { 111 | CKScanViewController *scanViewController = [[CKScanViewController alloc] init]; 112 | 113 | [scanViewController setApiKeyFound:^(NSString *apiKey) { 114 | if (self.disableAccountDataFetching) { 115 | if (self.delegate && [self.delegate respondsToSelector:@selector(ckAuthSucceededWithApiKey:andAccountData:)]) { 116 | [self.delegate ckAuthSucceededWithApiKey:apiKey andAccountData:nil]; 117 | } 118 | 119 | if (self.authSucceeded) { 120 | self.authSucceeded(apiKey, nil); 121 | } 122 | } else { 123 | [self fetchAccountDataForAPIKey:apiKey]; 124 | } 125 | }]; 126 | 127 | [self.navigationController pushViewController:scanViewController animated:YES]; 128 | } 129 | 130 | 131 | #pragma mark - Private Methods 132 | 133 | - (void)authWithClientId:(NSString *)cliendId andSecret:(NSString *)secret { 134 | self.clientId = cliendId; 135 | self.clientSecret = secret; 136 | 137 | NSString *extraParam = @""; 138 | if (self.enableMultipleLogin) { 139 | extraParam = @"&multiple=true"; 140 | } 141 | 142 | //Kick off the auth process 143 | NSString *url = [NSString stringWithFormat:@"%@?response_type=code&client_id=%@&redirect_uri=%@%@", 144 | kAuthorizeUrl, 145 | self.clientId, 146 | self.redirectUrl, 147 | extraParam]; 148 | 149 | NSURLRequest *request = [[NSURLRequest alloc] initWithURL: 150 | [NSURL URLWithString:url]]; 151 | [self.webview loadRequest:request]; 152 | } 153 | 154 | - (void)getAccessTokenForAuthCode:(NSString *)authCode { 155 | [self.spinner setHidden:NO]; 156 | 157 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:kAccessTokenUrl]]; 158 | [request setHTTPMethod:@"POST"]; 159 | 160 | NSString *postBody = [NSString stringWithFormat:@"grant_type=authorization_code&client_id=%@&client_secret=%@&code=%@&redirect_uri=%@", 161 | self.clientId, 162 | self.clientSecret, 163 | authCode, 164 | self.redirectUrl]; 165 | 166 | [request setHTTPBody:[postBody dataUsingEncoding:NSUTF8StringEncoding]]; 167 | 168 | [[self.urlSession dataTaskWithRequest:request 169 | completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 170 | if (error) { 171 | [self connectionFailedWithError:error]; 172 | return; 173 | } 174 | 175 | id jsonValue = [NSJSONSerialization JSONObjectWithData:data 176 | options:NSJSONReadingMutableContainers | NSJSONReadingAllowFragments 177 | error:nil]; 178 | 179 | if (self.enableMultipleLogin) { 180 | for (NSDictionary *accessDictionary in jsonValue) { 181 | NSString *accessToken = [accessDictionary objectForKey:@"access_token"]; 182 | 183 | //Get the access token metadata so we can return a proper API key 184 | [self getAccessTokenMetaDataForAccessToken:accessToken]; 185 | } 186 | } else { 187 | NSString *accessToken = [jsonValue objectForKey:@"access_token"]; 188 | 189 | //Get the access token metadata so we can return a proper API key 190 | [self getAccessTokenMetaDataForAccessToken:accessToken]; 191 | } 192 | }] resume]; 193 | } 194 | 195 | - (void)getAccessTokenMetaDataForAccessToken:(NSString *)accessToken { 196 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:kMetaDataUrl]]; 197 | [request setHTTPMethod:@"GET"]; 198 | [request setValue:[NSString stringWithFormat:@"Bearer %@", accessToken] forHTTPHeaderField:@"Authorization"]; 199 | 200 | [[self.urlSession dataTaskWithRequest:request 201 | completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 202 | if (error) { 203 | [self connectionFailedWithError:error]; 204 | return; 205 | } 206 | 207 | id jsonValue = [NSJSONSerialization JSONObjectWithData:data 208 | options:NSJSONReadingMutableContainers | NSJSONReadingAllowFragments 209 | error:nil]; 210 | 211 | [self.spinner setHidden:YES]; 212 | 213 | //And we're done. We can now concat the access token and the data center 214 | //to form the MailChimp API key and notify our delegate 215 | NSString *dataCenter = [jsonValue objectForKey:@"dc"]; 216 | NSString *apiKey = [NSString stringWithFormat:@"%@-%@", accessToken, dataCenter]; 217 | 218 | if (self.disableAccountDataFetching) { 219 | if (self.delegate && [self.delegate respondsToSelector:@selector(ckAuthSucceededWithApiKey:andAccountData:)]) { 220 | [self.delegate ckAuthSucceededWithApiKey:apiKey andAccountData:nil]; 221 | } 222 | 223 | if (self.authSucceeded) { 224 | self.authSucceeded(apiKey, nil); 225 | } 226 | } else { 227 | [self fetchAccountDataForAPIKey:apiKey]; 228 | } 229 | }] resume]; 230 | } 231 | 232 | - (void)fetchAccountDataForAPIKey:(NSString *)apiKey { 233 | [self.chimpKit callApiMethod:@"users/profile" withApiKey:apiKey params:nil andCompletionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 234 | if (error) { 235 | if (self.delegate && [self.delegate respondsToSelector:@selector(ckAuthFailedWithError:)]) { 236 | [self.delegate ckAuthFailedWithError:error]; 237 | } 238 | 239 | if (self.authFailed) { 240 | self.authFailed(error); 241 | } 242 | } else { 243 | NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 244 | if (kCKDebug) NSLog(@"Response String: %@", responseString); 245 | 246 | NSError *error = nil; 247 | id responseData = [NSJSONSerialization JSONObjectWithData:data 248 | options:0 249 | error:&error]; 250 | 251 | if (responseData && [responseData isKindOfClass:[NSDictionary class]]) { 252 | if (self.delegate && [self.delegate respondsToSelector:@selector(ckAuthSucceededWithApiKey:andAccountData:)]) { 253 | [self.delegate ckAuthSucceededWithApiKey:apiKey andAccountData:responseData]; 254 | } 255 | 256 | if (self.authSucceeded) { 257 | self.authSucceeded(apiKey, responseData); 258 | } 259 | } else { 260 | if (self.delegate && [self.delegate respondsToSelector:@selector(ckAuthFailedWithError:)]) { 261 | [self.delegate ckAuthFailedWithError:nil]; 262 | } 263 | 264 | if (self.authFailed) { 265 | self.authFailed(nil); 266 | } 267 | } 268 | } 269 | }]; 270 | } 271 | 272 | - (void)connectionFailedWithError:(NSError *)error { 273 | [self.spinner setHidden:YES]; 274 | 275 | if (self.delegate && [self.delegate respondsToSelector:@selector(ckAuthFailedWithError:)]) { 276 | [self.delegate ckAuthFailedWithError:error]; 277 | } 278 | 279 | if (self.authFailed) { 280 | self.authFailed(error); 281 | } 282 | } 283 | 284 | 285 | #pragma mark - Methods 286 | 287 | - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { 288 | [self.spinner setHidden:YES]; 289 | 290 | NSString *currentUrl = request.URL.absoluteString; 291 | if (kCKAuthDebug) NSLog(@"CKAuthViewController webview shouldStartLoadWithRequest url: %@", currentUrl); 292 | 293 | //If MailChimp redirected us to our redirect url, then the user has been auth'd 294 | if ([currentUrl rangeOfString:self.redirectUrl].location == 0) { 295 | NSArray *urlSplit = [currentUrl componentsSeparatedByString:@"code="]; 296 | 297 | if (urlSplit.count > 1) { 298 | //The auth code must now be exchanged for an access token (the api key) 299 | NSString *authCode = [urlSplit objectAtIndex:1]; 300 | [self getAccessTokenForAuthCode:authCode]; 301 | } 302 | 303 | return NO; 304 | } 305 | 306 | return YES; 307 | } 308 | 309 | - (void)webViewDidStartLoad:(UIWebView *)aWebView { 310 | [self.spinner setHidden:NO]; 311 | } 312 | 313 | - (void)webViewDidFinishLoad:(UIWebView *)webView { 314 | [self.spinner setHidden:YES]; 315 | } 316 | 317 | 318 | - (void)webView:(UIWebView *)aWebView didFailLoadWithError:(NSError *)error { 319 | [self.spinner setHidden:YES]; 320 | 321 | //ToDo: Show error 322 | } 323 | 324 | 325 | @end 326 | -------------------------------------------------------------------------------- /ChimpKit3/Helper Objects/CKAuthViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1552 5 | 12F37 6 | 3084 7 | 1187.39 8 | 626.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 2083 12 | 13 | 14 | YES 15 | IBProxyObject 16 | IBUIActivityIndicatorView 17 | IBUIView 18 | IBUIWebView 19 | 20 | 21 | YES 22 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 23 | 24 | 25 | PluginDependencyRecalculationVersion 26 | 27 | 28 | 29 | YES 30 | 31 | IBFilesOwner 32 | IBCocoaTouchFramework 33 | 34 | 35 | IBFirstResponder 36 | IBCocoaTouchFramework 37 | 38 | 39 | 40 | 274 41 | 42 | YES 43 | 44 | 45 | 274 46 | {320, 416} 47 | 48 | 49 | 50 | _NS:603 51 | 52 | 1 53 | MSAxIDEAA 54 | 55 | IBCocoaTouchFramework 56 | 1 57 | YES 58 | 59 | 60 | 61 | -2147483347 62 | {{142, 189}, {37, 37}} 63 | 64 | 65 | 66 | _NS:980 67 | NO 68 | IBCocoaTouchFramework 69 | NO 70 | YES 71 | 0 72 | 73 | 3 74 | MC4zMzMzMzMzMzMzAA 75 | 76 | 77 | 78 | {{0, 64}, {320, 416}} 79 | 80 | 81 | 82 | 83 | 3 84 | MQA 85 | 86 | 2 87 | 88 | 89 | 90 | 91 | NO 92 | 93 | IBCocoaTouchFramework 94 | 95 | 96 | 97 | 98 | YES 99 | 100 | 101 | view 102 | 103 | 104 | 105 | 3 106 | 107 | 108 | 109 | webview 110 | 111 | 112 | 113 | 5 114 | 115 | 116 | 117 | spinner 118 | 119 | 120 | 121 | 8 122 | 123 | 124 | 125 | delegate 126 | 127 | 128 | 129 | 6 130 | 131 | 132 | 133 | 134 | YES 135 | 136 | 0 137 | 138 | YES 139 | 140 | 141 | 142 | 143 | 144 | 1 145 | 146 | 147 | YES 148 | 149 | 150 | 151 | 152 | 153 | 154 | -1 155 | 156 | 157 | File's Owner 158 | 159 | 160 | -2 161 | 162 | 163 | 164 | 165 | 4 166 | 167 | 168 | 169 | 170 | 7 171 | 172 | 173 | 174 | 175 | 176 | 177 | YES 178 | 179 | YES 180 | -1.CustomClassName 181 | -1.IBPluginDependency 182 | -2.CustomClassName 183 | -2.IBPluginDependency 184 | 1.IBPluginDependency 185 | 4.IBPluginDependency 186 | 7.IBPluginDependency 187 | 188 | 189 | YES 190 | CKAuthViewController 191 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 192 | UIResponder 193 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 194 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 195 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 196 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 197 | 198 | 199 | 200 | YES 201 | 202 | 203 | 204 | 205 | 206 | YES 207 | 208 | 209 | 210 | 211 | 8 212 | 213 | 214 | 215 | YES 216 | 217 | CKAuthViewController 218 | UIViewController 219 | 220 | YES 221 | 222 | YES 223 | spinner 224 | webview 225 | 226 | 227 | YES 228 | UIActivityIndicatorView 229 | UIWebView 230 | 231 | 232 | 233 | YES 234 | 235 | YES 236 | spinner 237 | webview 238 | 239 | 240 | YES 241 | 242 | spinner 243 | UIActivityIndicatorView 244 | 245 | 246 | webview 247 | UIWebView 248 | 249 | 250 | 251 | 252 | IBProjectSource 253 | ./Classes/CKAuthViewController.h 254 | 255 | 256 | 257 | 258 | 0 259 | IBCocoaTouchFramework 260 | 261 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 262 | 263 | 264 | YES 265 | 3 266 | 2083 267 | 268 | 269 | -------------------------------------------------------------------------------- /ChimpKit3/Helper Objects/CKScanViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CKScanViewController.h 3 | // ChimpKitSampleApp 4 | // 5 | // Created by Drew Conner on 10/29/13. 6 | // Copyright (c) 2013 MailChimp. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CKScanViewController : UIViewController 12 | 13 | @property (nonatomic, copy) void (^apiKeyFound)(NSString *apiKey); 14 | @property (nonatomic, copy) void (^userCancelled)(void); 15 | 16 | - (void)restartScanning; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /ChimpKit3/Helper Objects/CKScanViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CKScanViewController.m 3 | // ChimpKitSampleApp 4 | // 5 | // Created by Drew Conner on 10/29/13. 6 | // Copyright (c) 2013 MailChimp. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CKScanViewController.h" 11 | 12 | 13 | @interface CKScanViewController () 14 | 15 | @property (nonatomic, strong) AVCaptureSession *captureSession; 16 | @property (nonatomic, strong) AVCaptureMetadataOutput *metadataOutput; 17 | @property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer; 18 | 19 | @end 20 | 21 | 22 | @implementation CKScanViewController 23 | 24 | 25 | #pragma mark - View Lifecycle 26 | 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | 30 | self.title = @"Scan API Key"; 31 | 32 | if ([[[UIDevice currentDevice] systemVersion] floatValue] < 7.0) { 33 | // TODO: Show iOS7 Required Message 34 | } else { 35 | self.captureSession = [[AVCaptureSession alloc] init]; 36 | 37 | AVCaptureDevice *videoCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 38 | NSError *error = nil; 39 | AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoCaptureDevice error:&error]; 40 | 41 | if (videoInput) { 42 | [self.captureSession addInput:videoInput]; 43 | } else { 44 | NSLog(@"Video Capture Error: %@", error); 45 | } 46 | 47 | self.metadataOutput = [[AVCaptureMetadataOutput alloc] init]; 48 | [self.captureSession addOutput:self.metadataOutput]; 49 | [self.metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; 50 | [self.metadataOutput setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]]; 51 | 52 | self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession]; 53 | self.previewLayer.frame = self.view.layer.bounds; 54 | [self.view.layer addSublayer:self.previewLayer]; 55 | 56 | [self.captureSession startRunning]; 57 | } 58 | 59 | if ([self.navigationController.viewControllers objectAtIndex:0] == self) { 60 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel 61 | target:self 62 | action:@selector(cancelButtonTapped:)]; 63 | } 64 | } 65 | 66 | - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { 67 | [CATransaction begin]; 68 | [CATransaction setValue:[NSNumber numberWithFloat:duration] forKey:kCATransactionAnimationDuration]; 69 | 70 | if (self.previewLayer) { 71 | if (toInterfaceOrientation == UIInterfaceOrientationPortrait) { 72 | self.previewLayer.affineTransform = CGAffineTransformMakeRotation(0); 73 | } else if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) { 74 | self.previewLayer.affineTransform = CGAffineTransformMakeRotation(M_PI/2); 75 | } else if (toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) { 76 | self.previewLayer.affineTransform = CGAffineTransformMakeRotation(M_PI); 77 | } else if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) { 78 | self.previewLayer.affineTransform = CGAffineTransformMakeRotation(-M_PI/2); 79 | } 80 | 81 | self.previewLayer.frame = self.view.bounds; 82 | } 83 | 84 | [CATransaction commit]; 85 | } 86 | 87 | - (void)dealloc { 88 | [self.previewLayer removeFromSuperlayer]; 89 | self.previewLayer = nil; 90 | 91 | [self.captureSession stopRunning]; 92 | self.captureSession = nil; 93 | } 94 | 95 | 96 | #pragma mark - Public Methods 97 | 98 | - (void)restartScanning { 99 | if (self.metadataOutput == nil) { 100 | self.metadataOutput = [[AVCaptureMetadataOutput alloc] init]; 101 | [self.captureSession addOutput:self.metadataOutput]; 102 | [self.metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; 103 | [self.metadataOutput setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]]; 104 | } 105 | } 106 | 107 | 108 | #pragma mark - UI Actions 109 | 110 | - (void)cancelButtonTapped:(id)sender { 111 | if (self.userCancelled) { 112 | self.userCancelled(); 113 | } 114 | } 115 | 116 | 117 | #pragma mark Methods 118 | 119 | - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection { 120 | for(AVMetadataObject *metadataObject in metadataObjects) { 121 | AVMetadataMachineReadableCodeObject *readableObject = (AVMetadataMachineReadableCodeObject *)metadataObject; 122 | if ([metadataObject.type isEqualToString:AVMetadataObjectTypeQRCode]) { 123 | if (self.apiKeyFound) { 124 | self.apiKeyFound(readableObject.stringValue); 125 | 126 | [self.captureSession removeOutput:self.metadataOutput]; 127 | self.metadataOutput = nil; 128 | } 129 | } 130 | } 131 | } 132 | 133 | 134 | @end 135 | -------------------------------------------------------------------------------- /ChimpKit3/Helper Objects/CKSubscribeAlertView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CKSubscribeAlertView.h 3 | // ChimpKit3 4 | // 5 | // Created by Drew Conner on 1/7/13. 6 | // Copyright (c) 2013 MailChimp. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CKSubscribeAlertView : UIAlertView 12 | 13 | - (id)initWithTitle:(NSString *)title 14 | message:(NSString *)message 15 | listId:(NSString *)aListId 16 | cancelButtonTitle:(NSString *)cancelButtonTitle 17 | subscribeButtonTitle:(NSString *)subscribeButtonTitle; 18 | 19 | - (id)initWithTitle:(NSString *)title 20 | message:(NSString *)message 21 | listId:(NSString *)aListId 22 | cancelButtonTitle:(NSString *)cancelButtonTitle 23 | subscribeButtonTitle:(NSString *)subscribeButtonTitle 24 | doubleOptIn:(BOOL)doubleOptIn; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /ChimpKit3/Helper Objects/CKSubscribeAlertView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CKSubscribeAlertView.m 3 | // ChimpKit3 4 | // 5 | // Created by Drew Conner on 1/7/13. 6 | // Copyright (c) 2013 MailChimp. All rights reserved. 7 | // 8 | 9 | #import "CKSubscribeAlertView.h" 10 | #import "ChimpKit.h" 11 | 12 | 13 | @interface CKSubscribeAlertView() 14 | 15 | @property (nonatomic, strong) NSString *listId; 16 | @property (nonatomic) BOOL doubleOptIn; 17 | 18 | @end 19 | 20 | 21 | @implementation CKSubscribeAlertView 22 | 23 | 24 | #pragma mark - Initialization 25 | 26 | - (id)initWithTitle:(NSString *)title 27 | message:(NSString *)message 28 | listId:(NSString *)aListId 29 | cancelButtonTitle:(NSString *)cancelButtonTitle 30 | subscribeButtonTitle:(NSString *)subscribeButtonTitle 31 | doubleOptIn:(BOOL)doubleOptIn { 32 | 33 | self = [super initWithTitle:title 34 | message:message 35 | delegate:nil 36 | cancelButtonTitle:cancelButtonTitle 37 | otherButtonTitles:subscribeButtonTitle, nil]; 38 | 39 | if (self) { 40 | //Set the delegate to self so we can handle button presses 41 | self.delegate = self; 42 | 43 | self.alertViewStyle = UIAlertViewStylePlainTextInput; 44 | 45 | UITextField *textField = [self textFieldAtIndex:0]; 46 | 47 | // Common text field properties 48 | textField.placeholder = @"Email Address"; 49 | textField.keyboardType = UIKeyboardTypeEmailAddress; 50 | textField.autocorrectionType = UITextAutocorrectionTypeNo; 51 | textField.autocapitalizationType = UITextAutocapitalizationTypeNone; 52 | 53 | self.listId = aListId; 54 | 55 | self.doubleOptIn = doubleOptIn; 56 | } 57 | 58 | return self; 59 | } 60 | 61 | - (id)initWithTitle:(NSString *)title 62 | message:(NSString *)message 63 | listId:(NSString *)aListId 64 | cancelButtonTitle:(NSString *)cancelButtonTitle 65 | subscribeButtonTitle:(NSString *)subscribeButtonTitle { 66 | 67 | return [self initWithTitle:title 68 | message:message 69 | listId:aListId 70 | cancelButtonTitle:cancelButtonTitle 71 | subscribeButtonTitle:subscribeButtonTitle 72 | doubleOptIn:NO]; 73 | } 74 | 75 | 76 | #pragma mark - Private Methods 77 | 78 | - (void)showSubscribeError { 79 | UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Subscription Failed" 80 | message:@"We couldn't subscribe you to the list. Please check your email address and try again." 81 | delegate:nil 82 | cancelButtonTitle:@"OK" 83 | otherButtonTitles:nil]; 84 | [errorAlertView show]; 85 | } 86 | 87 | 88 | #pragma mark - Methods 89 | 90 | - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { 91 | if (buttonIndex == 1) { // Subscribe pressed 92 | UITextField *textField = [self textFieldAtIndex:0]; 93 | 94 | NSMutableDictionary *params = [NSMutableDictionary dictionary]; 95 | params[@"id"] = self.listId; 96 | params[@"email"] = @{@"email": textField.text}; 97 | params[@"double_optin"] = (self.doubleOptIn ? @"true" : @"false"); 98 | params[@"update_existing"] = @"true"; 99 | 100 | [[ChimpKit sharedKit] callApiMethod:@"lists/subscribe" 101 | withParams:params 102 | andCompletionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 103 | NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 104 | if (kCKDebug) NSLog(@"Response String: %@", responseString); 105 | 106 | id parsedResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 107 | 108 | if (![parsedResponse isKindOfClass:[NSDictionary class]] || ![parsedResponse[@"email"] isKindOfClass:[NSString class]] || error) { 109 | [self showSubscribeError]; 110 | } 111 | }]; 112 | } 113 | } 114 | 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /ChimpKit3/Helper Objects/ChimpKit.xcassets/qr_code.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "qr-code-@1x.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "qr-code-@2x.png" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | } 18 | } -------------------------------------------------------------------------------- /ChimpKit3/Helper Objects/ChimpKit.xcassets/qr_code.imageset/qr-code-@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchimp/ChimpKit3/c0819b3746b38683b8f52388658ab808715dc365/ChimpKit3/Helper Objects/ChimpKit.xcassets/qr_code.imageset/qr-code-@1x.png -------------------------------------------------------------------------------- /ChimpKit3/Helper Objects/ChimpKit.xcassets/qr_code.imageset/qr-code-@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchimp/ChimpKit3/c0819b3746b38683b8f52388658ab808715dc365/ChimpKit3/Helper Objects/ChimpKit.xcassets/qr_code.imageset/qr-code-@2x.png -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2014 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChimpKit 3.1.1 2 | 3 | ChimpKit is an API wrapper for the [MailChimp API 2.0](http://www.mailchimp.com/api). 4 | 5 | ##Requirements 6 | 7 | A MailChimp account and API key. You can see your API keys [here](http://admin.mailchimp.com/account/api). 8 | 9 | ChimpKit includes uses ARC. If your project doesn't use ARC, you can enable it per file using the `-fobjc-arc` compiler flag under "Build Phases" and "Compile Sources" on your project's target in Xcode. 10 | 11 | ##Installation 12 | 13 | There are two ways to add ChimpKit to your project: 14 | 15 | Using [Cocoapods](cocoapods.org): 16 | 17 | ```ruby 18 | pod 'ChimpKit' 19 | ``` 20 | 21 | Or using Git submodules. Add ChimpKit as a submodule of your git repository by doing something like: 22 | 23 | ```bash 24 | cd myrepo 25 | git submodule add https://github.com/mailchimp/ChimpKit3.git Libs/ChimpKit 26 | ``` 27 | 28 | Now add ChimpKit to your project by dragging the everything in the `ChimpKit3` directory into your project. 29 | 30 | ##Usage 31 | 32 | First, set an API key: 33 | 34 | ```objective-c 35 | [[ChimpKit sharedKit] setApiKey:apiKey]; 36 | ``` 37 | 38 | You can now make requests. For example, here's how to subscribe an email address: 39 | 40 | Using a block: 41 | 42 | ```objective-c 43 | NSDictionary *params = @{@"id": listId, @"email": @{@"email": @"foo@example.com"}, @"merge_vars": @{@"FNAME": @"Freddie", @"LName":@"von Chimpenheimer"}}; 44 | [[ChimpKit sharedKit] callApiMethod:@"lists/subscribe" withParams:params andCompletionHandler:^(ChimpKitRequest *request, NSError *error) { 45 | NSLog(@"HTTP Status Code: %d", request.response.statusCode); 46 | NSLog(@"Response String: %@", request.responseString); 47 | 48 | if (error) { 49 | //Handle connection error 50 | NSLog(@"Error, %@", error); 51 | dispatch_async(dispatch_get_main_queue(), ^{ 52 | //Update UI here 53 | }); 54 | } else { 55 | NSError *parseError = nil; 56 | id response = [NSJSONSerialization JSONObjectWithData:request.responseData 57 | options:0 58 | error:&parseError]; 59 | if ([response isKindOfClass:[NSDictionary class]]) { 60 | id email = [response objectForKey:@"email"]; 61 | if ([email isKindOfClass:[NSString class]]) { 62 | //Successfully subscribed email address 63 | dispatch_async(dispatch_get_main_queue(), ^{ 64 | //Update UI here 65 | }); 66 | } 67 | } 68 | } 69 | }]; 70 | ``` 71 | 72 | Using the delegate pattern: 73 | 74 | ```objective-c 75 | NSDictionary *params = @{@"id": listId, @"email": @{@"email": @"foo@example.com"}, @"merge_vars": @{@"FNAME": @"Freddie", @"LName":@"von Chimpenheimer"}}; 76 | [[ChimpKit sharedKit] callApiMethod:@"lists/subscribe" withParams:params andDelegate:self]; 77 | ``` 78 | 79 | And implement the `ChimpKitRequestDelegate` protocol: 80 | 81 | ```objective-c 82 | - (void)ckRequestSucceeded:(ChimpKitRequest *)aRequest { 83 | NSLog(@"HTTP Status Code: %d", aRequest.response.statusCode); 84 | NSLog(@"Response String: %@", aRequest.responseString); 85 | 86 | NSError *parseError = nil; 87 | id response = [NSJSONSerialization JSONObjectWithData:request.responseData 88 | options:0 89 | error:&parseError]; 90 | if ([response isKindOfClass:[NSDictionary class]]) { 91 | id email = [response objectForKey:@"email"]; 92 | if ([email isKindOfClass:[NSString class]]) { 93 | //Successfully subscribed email address 94 | dispatch_async(dispatch_get_main_queue(), ^{ 95 | //Update UI here 96 | }); 97 | } 98 | } 99 | } 100 | 101 | - (void)ckRequestFailed:(ChimpKitRequest *)aRequest andError:(NSError *)anError { 102 | //Handle connection error 103 | NSLog(@"Error, %@", anError); 104 | dispatch_async(dispatch_get_main_queue(), ^{ 105 | //Update UI here 106 | }); 107 | } 108 | ``` 109 | 110 | Calling other API endpoints works similarly. Read the API [documentation](http://apidocs.mailchimp.com/api/2.0/) for details. 111 | 112 | ###Blocks and delegate methods can be called from a background queue 113 | 114 | The examples above use dispatch_async to call back onto the main queue after parsing the response. If you've set `shouldUseBackgroundThread` to `YES` then ChimpKit will call your block from a background queue so you can parse the JSON response with low impact on interface responsiveness. You should dispatch_* back to the main queue before updating your UI as shown above. You can enable this behavior like so: 115 | 116 | ```objective-c 117 | [[ChimpKit sharedKit] setShouldUseBackgroundThread:YES]; 118 | ``` 119 | 120 | ### Controlling Timeout 121 | 122 | ChimpKit defaults to a 10 second timeout. You can change that (globally) to 30 seconds like so: 123 | 124 | ```objective-c 125 | [[ChimpKit sharedKit] setTimeoutInterval:30.0f]; 126 | ``` 127 | 128 | ### MailChimp now supports [OAuth2](http://apidocs.mailchimp.com/oauth2/) and so does ChimpKit: 129 | 130 | An example of logging in via OAuth is provided in the sample application. See `ViewController.m`. 131 | 132 | ##Copyrights 133 | 134 | * Copyright (c) 2010-2014 The Rocket Science Group. Please see LICENSE.txt for details. 135 | * MailChimp (c) 2001-2014 The Rocket Science Group. 136 | -------------------------------------------------------------------------------- /Sample App/ChimpKitSampleApp.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3A1DB20816CBF08700B5A662 /* CKAuthViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3A1DB20716CBF08700B5A662 /* CKAuthViewController.xib */; }; 11 | 3A3AFC16181FFC6300A0FD55 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A3AFC15181FFC6300A0FD55 /* AVFoundation.framework */; }; 12 | 3A3AFC1918200CBA00A0FD55 /* CKScanViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3AFC1818200CBA00A0FD55 /* CKScanViewController.m */; }; 13 | 3A9A6A6E169B135D00994BE6 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A9A6A6D169B135D00994BE6 /* UIKit.framework */; }; 14 | 3A9A6A70169B135D00994BE6 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A9A6A6F169B135D00994BE6 /* Foundation.framework */; }; 15 | 3A9A6A72169B135D00994BE6 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A9A6A71169B135D00994BE6 /* CoreGraphics.framework */; }; 16 | 3A9A6A78169B135D00994BE6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3A9A6A76169B135D00994BE6 /* InfoPlist.strings */; }; 17 | 3A9A6A7A169B135D00994BE6 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A9A6A79169B135D00994BE6 /* main.m */; }; 18 | 3A9A6A7E169B135D00994BE6 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A9A6A7D169B135D00994BE6 /* AppDelegate.m */; }; 19 | 3A9A6A80169B135D00994BE6 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 3A9A6A7F169B135D00994BE6 /* Default.png */; }; 20 | 3A9A6A82169B135D00994BE6 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3A9A6A81169B135D00994BE6 /* Default@2x.png */; }; 21 | 3A9A6A84169B135D00994BE6 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3A9A6A83169B135D00994BE6 /* Default-568h@2x.png */; }; 22 | 3A9A6A87169B135D00994BE6 /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3A9A6A85169B135D00994BE6 /* MainStoryboard_iPhone.storyboard */; }; 23 | 3A9A6A8A169B135D00994BE6 /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3A9A6A88169B135D00994BE6 /* MainStoryboard_iPad.storyboard */; }; 24 | 3A9A6A8D169B135D00994BE6 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A9A6A8C169B135D00994BE6 /* ViewController.m */; }; 25 | 3A9A6A9B169B145600994BE6 /* ChimpKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A9A6A9A169B145600994BE6 /* ChimpKit.m */; }; 26 | 3A9A6AB2169B262E00994BE6 /* CKAuthViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A9A6AAF169B262E00994BE6 /* CKAuthViewController.m */; }; 27 | 3A9A6AB3169B262E00994BE6 /* CKSubscribeAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A9A6AB1169B262E00994BE6 /* CKSubscribeAlertView.m */; }; 28 | 3AE6C5141850F9910031658A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AE6C5131850F9910031658A /* QuartzCore.framework */; }; 29 | 3AFD960B198FF377002C411A /* ChimpKit.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AFD960A198FF377002C411A /* ChimpKit.xcassets */; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 3A1DB20716CBF08700B5A662 /* CKAuthViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CKAuthViewController.xib; sourceTree = ""; }; 34 | 3A3AFC15181FFC6300A0FD55 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 35 | 3A3AFC1718200CBA00A0FD55 /* CKScanViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKScanViewController.h; sourceTree = ""; }; 36 | 3A3AFC1818200CBA00A0FD55 /* CKScanViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKScanViewController.m; sourceTree = ""; }; 37 | 3A9A6A69169B135D00994BE6 /* ChimpKitSampleApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ChimpKitSampleApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | 3A9A6A6D169B135D00994BE6 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 39 | 3A9A6A6F169B135D00994BE6 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 40 | 3A9A6A71169B135D00994BE6 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 41 | 3A9A6A75169B135D00994BE6 /* ChimpKitSampleApp-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ChimpKitSampleApp-Info.plist"; sourceTree = ""; }; 42 | 3A9A6A77169B135D00994BE6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 43 | 3A9A6A79169B135D00994BE6 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 44 | 3A9A6A7B169B135D00994BE6 /* ChimpKitSampleApp-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ChimpKitSampleApp-Prefix.pch"; sourceTree = ""; }; 45 | 3A9A6A7C169B135D00994BE6 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 46 | 3A9A6A7D169B135D00994BE6 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 47 | 3A9A6A7F169B135D00994BE6 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 48 | 3A9A6A81169B135D00994BE6 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 49 | 3A9A6A83169B135D00994BE6 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 50 | 3A9A6A86169B135D00994BE6 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPhone.storyboard; sourceTree = ""; }; 51 | 3A9A6A89169B135D00994BE6 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPad.storyboard; sourceTree = ""; }; 52 | 3A9A6A8B169B135D00994BE6 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 53 | 3A9A6A8C169B135D00994BE6 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 54 | 3A9A6A99169B145600994BE6 /* ChimpKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChimpKit.h; sourceTree = ""; }; 55 | 3A9A6A9A169B145600994BE6 /* ChimpKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChimpKit.m; sourceTree = ""; }; 56 | 3A9A6AAE169B262E00994BE6 /* CKAuthViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKAuthViewController.h; sourceTree = ""; }; 57 | 3A9A6AAF169B262E00994BE6 /* CKAuthViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKAuthViewController.m; sourceTree = ""; }; 58 | 3A9A6AB0169B262E00994BE6 /* CKSubscribeAlertView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKSubscribeAlertView.h; sourceTree = ""; }; 59 | 3A9A6AB1169B262E00994BE6 /* CKSubscribeAlertView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKSubscribeAlertView.m; sourceTree = ""; }; 60 | 3AE6C5131850F9910031658A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 61 | 3AFD960A198FF377002C411A /* ChimpKit.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = ChimpKit.xcassets; sourceTree = ""; }; 62 | /* End PBXFileReference section */ 63 | 64 | /* Begin PBXFrameworksBuildPhase section */ 65 | 3A9A6A66169B135D00994BE6 /* Frameworks */ = { 66 | isa = PBXFrameworksBuildPhase; 67 | buildActionMask = 2147483647; 68 | files = ( 69 | 3AE6C5141850F9910031658A /* QuartzCore.framework in Frameworks */, 70 | 3A3AFC16181FFC6300A0FD55 /* AVFoundation.framework in Frameworks */, 71 | 3A9A6A6E169B135D00994BE6 /* UIKit.framework in Frameworks */, 72 | 3A9A6A70169B135D00994BE6 /* Foundation.framework in Frameworks */, 73 | 3A9A6A72169B135D00994BE6 /* CoreGraphics.framework in Frameworks */, 74 | ); 75 | runOnlyForDeploymentPostprocessing = 0; 76 | }; 77 | /* End PBXFrameworksBuildPhase section */ 78 | 79 | /* Begin PBXGroup section */ 80 | 3A9A6A5E169B135D00994BE6 = { 81 | isa = PBXGroup; 82 | children = ( 83 | 3A9A6A97169B143400994BE6 /* ChimpKit3 */, 84 | 3A9A6A73169B135D00994BE6 /* ChimpKitSampleApp */, 85 | 3A9A6A6C169B135D00994BE6 /* Frameworks */, 86 | 3A9A6A6A169B135D00994BE6 /* Products */, 87 | ); 88 | sourceTree = ""; 89 | }; 90 | 3A9A6A6A169B135D00994BE6 /* Products */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 3A9A6A69169B135D00994BE6 /* ChimpKitSampleApp.app */, 94 | ); 95 | name = Products; 96 | sourceTree = ""; 97 | }; 98 | 3A9A6A6C169B135D00994BE6 /* Frameworks */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 3AE6C5131850F9910031658A /* QuartzCore.framework */, 102 | 3A3AFC15181FFC6300A0FD55 /* AVFoundation.framework */, 103 | 3A9A6A6D169B135D00994BE6 /* UIKit.framework */, 104 | 3A9A6A6F169B135D00994BE6 /* Foundation.framework */, 105 | 3A9A6A71169B135D00994BE6 /* CoreGraphics.framework */, 106 | ); 107 | name = Frameworks; 108 | sourceTree = ""; 109 | }; 110 | 3A9A6A73169B135D00994BE6 /* ChimpKitSampleApp */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 3A9A6A7C169B135D00994BE6 /* AppDelegate.h */, 114 | 3A9A6A7D169B135D00994BE6 /* AppDelegate.m */, 115 | 3A9A6A85169B135D00994BE6 /* MainStoryboard_iPhone.storyboard */, 116 | 3A9A6A88169B135D00994BE6 /* MainStoryboard_iPad.storyboard */, 117 | 3A9A6A8B169B135D00994BE6 /* ViewController.h */, 118 | 3A9A6A8C169B135D00994BE6 /* ViewController.m */, 119 | 3A9A6A74169B135D00994BE6 /* Supporting Files */, 120 | ); 121 | path = ChimpKitSampleApp; 122 | sourceTree = ""; 123 | }; 124 | 3A9A6A74169B135D00994BE6 /* Supporting Files */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 3A9A6A75169B135D00994BE6 /* ChimpKitSampleApp-Info.plist */, 128 | 3A9A6A76169B135D00994BE6 /* InfoPlist.strings */, 129 | 3A9A6A79169B135D00994BE6 /* main.m */, 130 | 3A9A6A7B169B135D00994BE6 /* ChimpKitSampleApp-Prefix.pch */, 131 | 3A9A6A7F169B135D00994BE6 /* Default.png */, 132 | 3A9A6A81169B135D00994BE6 /* Default@2x.png */, 133 | 3A9A6A83169B135D00994BE6 /* Default-568h@2x.png */, 134 | ); 135 | name = "Supporting Files"; 136 | sourceTree = ""; 137 | }; 138 | 3A9A6A97169B143400994BE6 /* ChimpKit3 */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 3A9A6AAD169B262E00994BE6 /* Helper Objects */, 142 | 3A9A6A99169B145600994BE6 /* ChimpKit.h */, 143 | 3A9A6A9A169B145600994BE6 /* ChimpKit.m */, 144 | ); 145 | name = ChimpKit3; 146 | path = ../ChimpKit3; 147 | sourceTree = SOURCE_ROOT; 148 | }; 149 | 3A9A6AAD169B262E00994BE6 /* Helper Objects */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | 3A9A6AAE169B262E00994BE6 /* CKAuthViewController.h */, 153 | 3A9A6AAF169B262E00994BE6 /* CKAuthViewController.m */, 154 | 3A1DB20716CBF08700B5A662 /* CKAuthViewController.xib */, 155 | 3A9A6AB0169B262E00994BE6 /* CKSubscribeAlertView.h */, 156 | 3A9A6AB1169B262E00994BE6 /* CKSubscribeAlertView.m */, 157 | 3A3AFC1718200CBA00A0FD55 /* CKScanViewController.h */, 158 | 3A3AFC1818200CBA00A0FD55 /* CKScanViewController.m */, 159 | 3AFD960A198FF377002C411A /* ChimpKit.xcassets */, 160 | ); 161 | path = "Helper Objects"; 162 | sourceTree = ""; 163 | }; 164 | /* End PBXGroup section */ 165 | 166 | /* Begin PBXNativeTarget section */ 167 | 3A9A6A68169B135D00994BE6 /* ChimpKitSampleApp */ = { 168 | isa = PBXNativeTarget; 169 | buildConfigurationList = 3A9A6A90169B135D00994BE6 /* Build configuration list for PBXNativeTarget "ChimpKitSampleApp" */; 170 | buildPhases = ( 171 | 3A9A6A65169B135D00994BE6 /* Sources */, 172 | 3A9A6A66169B135D00994BE6 /* Frameworks */, 173 | 3A9A6A67169B135D00994BE6 /* Resources */, 174 | ); 175 | buildRules = ( 176 | ); 177 | dependencies = ( 178 | ); 179 | name = ChimpKitSampleApp; 180 | productName = ChimpKitSampleApp; 181 | productReference = 3A9A6A69169B135D00994BE6 /* ChimpKitSampleApp.app */; 182 | productType = "com.apple.product-type.application"; 183 | }; 184 | /* End PBXNativeTarget section */ 185 | 186 | /* Begin PBXProject section */ 187 | 3A9A6A60169B135D00994BE6 /* Project object */ = { 188 | isa = PBXProject; 189 | attributes = { 190 | LastUpgradeCheck = 0450; 191 | ORGANIZATIONNAME = MailChimp; 192 | }; 193 | buildConfigurationList = 3A9A6A63169B135D00994BE6 /* Build configuration list for PBXProject "ChimpKitSampleApp" */; 194 | compatibilityVersion = "Xcode 3.2"; 195 | developmentRegion = English; 196 | hasScannedForEncodings = 0; 197 | knownRegions = ( 198 | en, 199 | ); 200 | mainGroup = 3A9A6A5E169B135D00994BE6; 201 | productRefGroup = 3A9A6A6A169B135D00994BE6 /* Products */; 202 | projectDirPath = ""; 203 | projectRoot = ""; 204 | targets = ( 205 | 3A9A6A68169B135D00994BE6 /* ChimpKitSampleApp */, 206 | ); 207 | }; 208 | /* End PBXProject section */ 209 | 210 | /* Begin PBXResourcesBuildPhase section */ 211 | 3A9A6A67169B135D00994BE6 /* Resources */ = { 212 | isa = PBXResourcesBuildPhase; 213 | buildActionMask = 2147483647; 214 | files = ( 215 | 3A9A6A78169B135D00994BE6 /* InfoPlist.strings in Resources */, 216 | 3A9A6A80169B135D00994BE6 /* Default.png in Resources */, 217 | 3A9A6A82169B135D00994BE6 /* Default@2x.png in Resources */, 218 | 3A9A6A84169B135D00994BE6 /* Default-568h@2x.png in Resources */, 219 | 3A9A6A87169B135D00994BE6 /* MainStoryboard_iPhone.storyboard in Resources */, 220 | 3A9A6A8A169B135D00994BE6 /* MainStoryboard_iPad.storyboard in Resources */, 221 | 3AFD960B198FF377002C411A /* ChimpKit.xcassets in Resources */, 222 | 3A1DB20816CBF08700B5A662 /* CKAuthViewController.xib in Resources */, 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | }; 226 | /* End PBXResourcesBuildPhase section */ 227 | 228 | /* Begin PBXSourcesBuildPhase section */ 229 | 3A9A6A65169B135D00994BE6 /* Sources */ = { 230 | isa = PBXSourcesBuildPhase; 231 | buildActionMask = 2147483647; 232 | files = ( 233 | 3A9A6A7A169B135D00994BE6 /* main.m in Sources */, 234 | 3A9A6A7E169B135D00994BE6 /* AppDelegate.m in Sources */, 235 | 3A9A6A8D169B135D00994BE6 /* ViewController.m in Sources */, 236 | 3A3AFC1918200CBA00A0FD55 /* CKScanViewController.m in Sources */, 237 | 3A9A6A9B169B145600994BE6 /* ChimpKit.m in Sources */, 238 | 3A9A6AB2169B262E00994BE6 /* CKAuthViewController.m in Sources */, 239 | 3A9A6AB3169B262E00994BE6 /* CKSubscribeAlertView.m in Sources */, 240 | ); 241 | runOnlyForDeploymentPostprocessing = 0; 242 | }; 243 | /* End PBXSourcesBuildPhase section */ 244 | 245 | /* Begin PBXVariantGroup section */ 246 | 3A9A6A76169B135D00994BE6 /* InfoPlist.strings */ = { 247 | isa = PBXVariantGroup; 248 | children = ( 249 | 3A9A6A77169B135D00994BE6 /* en */, 250 | ); 251 | name = InfoPlist.strings; 252 | sourceTree = ""; 253 | }; 254 | 3A9A6A85169B135D00994BE6 /* MainStoryboard_iPhone.storyboard */ = { 255 | isa = PBXVariantGroup; 256 | children = ( 257 | 3A9A6A86169B135D00994BE6 /* en */, 258 | ); 259 | name = MainStoryboard_iPhone.storyboard; 260 | sourceTree = ""; 261 | }; 262 | 3A9A6A88169B135D00994BE6 /* MainStoryboard_iPad.storyboard */ = { 263 | isa = PBXVariantGroup; 264 | children = ( 265 | 3A9A6A89169B135D00994BE6 /* en */, 266 | ); 267 | name = MainStoryboard_iPad.storyboard; 268 | sourceTree = ""; 269 | }; 270 | /* End PBXVariantGroup section */ 271 | 272 | /* Begin XCBuildConfiguration section */ 273 | 3A9A6A8E169B135D00994BE6 /* Debug */ = { 274 | isa = XCBuildConfiguration; 275 | buildSettings = { 276 | ALWAYS_SEARCH_USER_PATHS = NO; 277 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 278 | CLANG_CXX_LIBRARY = "libc++"; 279 | CLANG_ENABLE_OBJC_ARC = YES; 280 | CLANG_WARN_EMPTY_BODY = YES; 281 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 282 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 283 | COPY_PHASE_STRIP = NO; 284 | GCC_C_LANGUAGE_STANDARD = gnu99; 285 | GCC_DYNAMIC_NO_PIC = NO; 286 | GCC_OPTIMIZATION_LEVEL = 0; 287 | GCC_PREPROCESSOR_DEFINITIONS = ( 288 | "DEBUG=1", 289 | "$(inherited)", 290 | ); 291 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 292 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 293 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 294 | GCC_WARN_UNUSED_VARIABLE = YES; 295 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 296 | ONLY_ACTIVE_ARCH = YES; 297 | SDKROOT = iphoneos; 298 | TARGETED_DEVICE_FAMILY = "1,2"; 299 | }; 300 | name = Debug; 301 | }; 302 | 3A9A6A8F169B135D00994BE6 /* Release */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ALWAYS_SEARCH_USER_PATHS = NO; 306 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 307 | CLANG_CXX_LIBRARY = "libc++"; 308 | CLANG_ENABLE_OBJC_ARC = YES; 309 | CLANG_WARN_EMPTY_BODY = YES; 310 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 311 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 312 | COPY_PHASE_STRIP = YES; 313 | GCC_C_LANGUAGE_STANDARD = gnu99; 314 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 315 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 316 | GCC_WARN_UNUSED_VARIABLE = YES; 317 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 318 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 319 | SDKROOT = iphoneos; 320 | TARGETED_DEVICE_FAMILY = "1,2"; 321 | VALIDATE_PRODUCT = YES; 322 | }; 323 | name = Release; 324 | }; 325 | 3A9A6A91169B135D00994BE6 /* Debug */ = { 326 | isa = XCBuildConfiguration; 327 | buildSettings = { 328 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 329 | GCC_PREFIX_HEADER = "ChimpKitSampleApp/ChimpKitSampleApp-Prefix.pch"; 330 | INFOPLIST_FILE = "ChimpKitSampleApp/ChimpKitSampleApp-Info.plist"; 331 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 332 | PRODUCT_NAME = "$(TARGET_NAME)"; 333 | WRAPPER_EXTENSION = app; 334 | }; 335 | name = Debug; 336 | }; 337 | 3A9A6A92169B135D00994BE6 /* Release */ = { 338 | isa = XCBuildConfiguration; 339 | buildSettings = { 340 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 341 | GCC_PREFIX_HEADER = "ChimpKitSampleApp/ChimpKitSampleApp-Prefix.pch"; 342 | INFOPLIST_FILE = "ChimpKitSampleApp/ChimpKitSampleApp-Info.plist"; 343 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 344 | PRODUCT_NAME = "$(TARGET_NAME)"; 345 | WRAPPER_EXTENSION = app; 346 | }; 347 | name = Release; 348 | }; 349 | /* End XCBuildConfiguration section */ 350 | 351 | /* Begin XCConfigurationList section */ 352 | 3A9A6A63169B135D00994BE6 /* Build configuration list for PBXProject "ChimpKitSampleApp" */ = { 353 | isa = XCConfigurationList; 354 | buildConfigurations = ( 355 | 3A9A6A8E169B135D00994BE6 /* Debug */, 356 | 3A9A6A8F169B135D00994BE6 /* Release */, 357 | ); 358 | defaultConfigurationIsVisible = 0; 359 | defaultConfigurationName = Release; 360 | }; 361 | 3A9A6A90169B135D00994BE6 /* Build configuration list for PBXNativeTarget "ChimpKitSampleApp" */ = { 362 | isa = XCConfigurationList; 363 | buildConfigurations = ( 364 | 3A9A6A91169B135D00994BE6 /* Debug */, 365 | 3A9A6A92169B135D00994BE6 /* Release */, 366 | ); 367 | defaultConfigurationIsVisible = 0; 368 | defaultConfigurationName = Release; 369 | }; 370 | /* End XCConfigurationList section */ 371 | }; 372 | rootObject = 3A9A6A60169B135D00994BE6 /* Project object */; 373 | } 374 | -------------------------------------------------------------------------------- /Sample App/ChimpKitSampleApp/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ChimpKitSampleApp 4 | // 5 | // Created by Drew Conner on 1/7/13. 6 | // Copyright (c) 2013 MailChimp. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Sample App/ChimpKitSampleApp/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ChimpKitSampleApp 4 | // 5 | // Created by Drew Conner on 1/7/13. 6 | // Copyright (c) 2013 MailChimp. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ChimpKit.h" 11 | 12 | @implementation AppDelegate 13 | 14 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 15 | // Set your API Key here 16 | [[ChimpKit sharedKit] setApiKey:@"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-XXX"]; 17 | 18 | return YES; 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Sample App/ChimpKitSampleApp/ChimpKitSampleApp-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.MailChimp.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | MainStoryboard_iPhone 29 | UIMainStoryboardFile~ipad 30 | MainStoryboard_iPad 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Sample App/ChimpKitSampleApp/ChimpKitSampleApp-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'ChimpKitSampleApp' target in the 'ChimpKitSampleApp' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_5_0 8 | #warning "This project uses features only available in iOS SDK 5.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /Sample App/ChimpKitSampleApp/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchimp/ChimpKit3/c0819b3746b38683b8f52388658ab808715dc365/Sample App/ChimpKitSampleApp/Default-568h@2x.png -------------------------------------------------------------------------------- /Sample App/ChimpKitSampleApp/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchimp/ChimpKit3/c0819b3746b38683b8f52388658ab808715dc365/Sample App/ChimpKitSampleApp/Default.png -------------------------------------------------------------------------------- /Sample App/ChimpKitSampleApp/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchimp/ChimpKit3/c0819b3746b38683b8f52388658ab808715dc365/Sample App/ChimpKitSampleApp/Default@2x.png -------------------------------------------------------------------------------- /Sample App/ChimpKitSampleApp/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // ChimpKitSampleApp 4 | // 5 | // Created by Drew Conner on 1/7/13. 6 | // Copyright (c) 2013 MailChimp. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CKAuthViewController.h" 11 | 12 | @interface ViewController : UIViewController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Sample App/ChimpKitSampleApp/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // ChimpKitSampleApp 4 | // 5 | // Created by Drew Conner on 1/7/13. 6 | // Copyright (c) 2013 MailChimp. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "ChimpKit.h" 11 | #import "CKSubscribeAlertView.h" 12 | #import "CKScanViewController.h" 13 | 14 | 15 | @implementation ViewController 16 | 17 | 18 | #pragma mark - View Lifecycle 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | 23 | // This call fetches lists 24 | [[ChimpKit sharedKit] callApiMethod:@"lists/list" 25 | withParams:nil 26 | andCompletionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 27 | NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 28 | NSLog(@"Here are my lists: %@", responseString); 29 | }]; 30 | } 31 | 32 | 33 | #pragma mark - UI Actions 34 | 35 | - (IBAction)subscribeButtonTapped:(id)sender { 36 | CKSubscribeAlertView *alert = [[CKSubscribeAlertView alloc] initWithTitle:@"Subscribe" 37 | message:@"Enter your email address to subscribe to our mailing list." 38 | listId:@"" 39 | cancelButtonTitle:@"Cancel" 40 | subscribeButtonTitle:@"Subscribe"]; 41 | 42 | [alert show]; 43 | } 44 | 45 | - (IBAction)loginButtonTapped:(id)sender { 46 | CKAuthViewController *authViewController = [[CKAuthViewController alloc] initWithClientId:@"" 47 | andClientSecret:@""]; 48 | 49 | authViewController.enableMultipleLogin = YES; 50 | 51 | authViewController.delegate = self; 52 | 53 | UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:authViewController]; 54 | 55 | [self presentViewController:navigationController animated:YES completion:nil]; 56 | } 57 | 58 | - (IBAction)scanBarcodeButtonTapped:(id)sender { 59 | CKScanViewController *scanViewController = [[CKScanViewController alloc] init]; 60 | 61 | [scanViewController setApiKeyFound:^(NSString *apiKey) { 62 | UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil 63 | message:[NSString stringWithFormat:@"API Key: %@", apiKey] 64 | delegate:nil 65 | cancelButtonTitle:@"OK" 66 | otherButtonTitles:nil]; 67 | 68 | [self dismissViewControllerAnimated:YES completion:^{ 69 | [alertView show]; 70 | }]; 71 | }]; 72 | 73 | [scanViewController setUserCancelled:^{ 74 | [self dismissViewControllerAnimated:YES completion:nil]; 75 | }]; 76 | 77 | UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:scanViewController]; 78 | 79 | [self presentViewController:navigationController animated:YES completion:nil]; 80 | } 81 | 82 | 83 | #pragma mark - Methods 84 | 85 | - (void)ckAuthUserCanceled { 86 | if (kCKDebug) NSLog(@"Auth Cancelled"); 87 | 88 | [self dismissViewControllerAnimated:YES completion:nil]; 89 | } 90 | 91 | - (void)ckAuthSucceededWithApiKey:(NSString *)apiKey andAccountData:(NSDictionary *)accountData { 92 | if (kCKDebug) NSLog(@"Auth Data: %@", accountData); 93 | 94 | [self dismissViewControllerAnimated:YES completion:nil]; 95 | } 96 | 97 | - (void)ckAuthFailedWithError:(NSError *)error { 98 | if (kCKDebug) NSLog(@"Auth Failed: %@", [error description]); 99 | 100 | [self dismissViewControllerAnimated:YES completion:nil]; 101 | } 102 | 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /Sample App/ChimpKitSampleApp/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Sample App/ChimpKitSampleApp/en.lproj/MainStoryboard_iPad.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 29 | 38 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Sample App/ChimpKitSampleApp/en.lproj/MainStoryboard_iPhone.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 29 | 38 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Sample App/ChimpKitSampleApp/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ChimpKitSampleApp 4 | // 5 | // Created by Drew Conner on 1/7/13. 6 | // Copyright (c) 2013 MailChimp. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | --------------------------------------------------------------------------------