├── PaymentKit Example ├── PaymentKit Example │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── Default.png │ ├── Default@2x.png │ ├── Default-568h@2x.png │ ├── AppDelegate.h │ ├── ViewController.h │ ├── PaymentKit Example-Prefix.pch │ ├── main.m │ ├── PaymentViewController.h │ ├── ViewController.m │ ├── PaymentKit Example-Info.plist │ ├── PaymentViewController.m │ ├── AppDelegate.m │ └── Storyboard.storyboard ├── PaymentKit Test │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── PaymentKit Test-Prefix.pch │ ├── PKTest.h │ ├── PKCardCVCTest.h │ ├── PKCardExpiryTest.h │ ├── PKCardNumberTest.h │ ├── PKTest.m │ ├── PaymentKit Test-Info.plist │ ├── PKCardCVCTest.m │ ├── PKCardExpiryTest.m │ └── PKCardNumberTest.m └── PaymentKit Example.xcodeproj │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── Alex.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ ├── xcuserdata │ └── Alex.xcuserdatad │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ ├── PaymentKit Test.xcscheme │ │ └── PaymentKit Example.xcscheme │ └── project.pbxproj ├── PaymentKit ├── Resources │ └── Cards │ │ ├── amex.png │ │ ├── cvc.png │ │ ├── jcb.png │ │ ├── visa.png │ │ ├── cvc@2x.png │ │ ├── diners.png │ │ ├── jcb@2x.png │ │ ├── amex@2x.png │ │ ├── cvc-amex.png │ │ ├── diners@2x.png │ │ ├── discover.png │ │ ├── visa@2x.png │ │ ├── cvc-amex@2x.png │ │ ├── discover@2x.png │ │ ├── mastercard.png │ │ ├── placeholder.png │ │ ├── jcb-outline@2x.png │ │ ├── mastercard@2x.png │ │ ├── placeholder@2x.png │ │ ├── amex-outline@2x.png │ │ ├── visa-outline@2x.png │ │ ├── mastercard-outline@2x.png │ │ └── placeholder-outline@2x.png ├── PKUSAddressZip.h ├── PKTextField.h ├── PKCardType.h ├── PKCard.m ├── PKAddressZip.h ├── PKCard.h ├── PKCardCVC.h ├── PKUSAddressZip.m ├── PKCardExpiry.h ├── PKCardNumber.h ├── PKAddressZip.m ├── PKCardCVC.m ├── PKTextField.m ├── PKView.h ├── PKCardExpiry.m ├── PKCardNumber.m └── PKView.m ├── .gitignore ├── PaymentKit.podspec ├── LICENSE └── README.md /PaymentKit Example/PaymentKit Example/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Test/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/amex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/amex.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/cvc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/cvc.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/jcb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/jcb.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/visa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/visa.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/cvc@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/cvc@2x.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/diners.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/diners.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/jcb@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/jcb@2x.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/amex@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/amex@2x.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/cvc-amex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/cvc-amex.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/diners@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/diners@2x.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/discover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/discover.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/visa@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/visa@2x.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/cvc-amex@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/cvc-amex@2x.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/discover@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/discover@2x.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/mastercard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/mastercard.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/placeholder.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/jcb-outline@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/jcb-outline@2x.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/mastercard@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/mastercard@2x.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/placeholder@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/placeholder@2x.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/amex-outline@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/amex-outline@2x.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/visa-outline@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/visa-outline@2x.png -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit Example/PaymentKit Example/Default.png -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit Example/PaymentKit Example/Default@2x.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/mastercard-outline@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/mastercard-outline@2x.png -------------------------------------------------------------------------------- /PaymentKit/Resources/Cards/placeholder-outline@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit/Resources/Cards/placeholder-outline@2x.png -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit Example/PaymentKit Example/Default-568h@2x.png -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Test/PaymentKit Test-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'PKPayment Test' target in the 'PKPayment Test' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example.xcodeproj/project.xcworkspace/xcuserdata/Alex.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcd/LMPaymentKit/HEAD/PaymentKit Example/PaymentKit Example.xcodeproj/project.xcworkspace/xcuserdata/Alex.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Test/PKTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // PKPayment_Test.h 3 | // PKPayment Test 4 | // 5 | // Created by Alex MacCaw on 2/6/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PKTest : SenTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | */build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | profile 14 | *.moved-aside 15 | DerivedData 16 | .idea/ 17 | *.hmap 18 | *.xccheckout 19 | 20 | #CocoaPods 21 | Pods -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Test/PKCardCVCTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // PKCardCVCTest.h 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 2/6/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PKCardCVCTest : SenTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /PaymentKit/PKUSAddressZip.h: -------------------------------------------------------------------------------- 1 | // 2 | // PKUSAddressZip.h 3 | // PaymentKit Example 4 | // 5 | // Created by Alex MacCaw on 2/17/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PKAddressZip.h" 11 | 12 | @interface PKUSAddressZip : PKAddressZip 13 | @end 14 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Test/PKCardExpiryTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // PKCardExpiryTest.h 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 2/6/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PKCardExpiryTest : SenTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Test/PKCardNumberTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // PKCardNumberTest.h 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 2/6/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PKCardNumberTest : SenTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/21/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /PaymentKit/PKTextField.h: -------------------------------------------------------------------------------- 1 | // 2 | // PKTextField.h 3 | // PaymentKit Example 4 | // 5 | // Created by Michaël Villar on 3/20/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class PKTextField; 12 | 13 | @interface PKTextField : UITextField 14 | 15 | + (NSString *)textByRemovingUselessSpacesFromString:(NSString *)string; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 2/5/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UITableViewController 12 | 13 | @property (nonatomic, strong) IBOutlet UITableViewCell *paymentCell; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example/PaymentKit Example-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'PKPayment Example' target in the 'PKPayment Example' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/21/13. 6 | // Copyright (c) 2013 Stripe. 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 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example/PaymentViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/21/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PKView.h" 11 | 12 | @interface PaymentViewController : UIViewController 13 | 14 | @property IBOutlet UILabel *helpLabel; 15 | @property IBOutlet PKView *paymentView; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /PaymentKit/PKCardType.h: -------------------------------------------------------------------------------- 1 | // 2 | // PKCardType.h 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/22/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #ifndef PKCardType_h 10 | #define PKCardType_h 11 | 12 | typedef enum { 13 | PKCardTypeVisa, 14 | PKCardTypeMasterCard, 15 | PKCardTypeAmex, 16 | PKCardTypeDiscover, 17 | PKCardTypeJCB, 18 | PKCardTypeDinersClub, 19 | PKCardTypeUnknown 20 | } PKCardType; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /PaymentKit/PKCard.m: -------------------------------------------------------------------------------- 1 | // 2 | // PKCard.m 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/31/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import "PKCard.h" 10 | 11 | @implementation PKCard 12 | 13 | @synthesize number, cvc, expMonth, expYear, addressZip; 14 | 15 | - (NSString *)last4 16 | { 17 | if (number.length >= 4) { 18 | return [number substringFromIndex:([number length] - 4)]; 19 | } else { 20 | return nil; 21 | } 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /PaymentKit/PKAddressZip.h: -------------------------------------------------------------------------------- 1 | // 2 | // PKZip.h 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 2/1/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PKAddressZip : NSObject { 12 | @protected 13 | NSString *zip; 14 | } 15 | 16 | @property (nonatomic, readonly) NSString *string; 17 | 18 | + (instancetype)addressZipWithString:(NSString *)string; 19 | - (instancetype)initWithString:(NSString *)string; 20 | - (NSString *)string; 21 | - (BOOL)isValid; 22 | - (BOOL)isPartiallyValid; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /PaymentKit/PKCard.h: -------------------------------------------------------------------------------- 1 | // 2 | // PKCard.h 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/31/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PKCard : NSObject 12 | 13 | @property (nonatomic, copy) NSString *number; 14 | @property (nonatomic, copy) NSString *cvc; 15 | @property (nonatomic, copy) NSString *addressZip; 16 | @property (nonatomic, assign) NSUInteger expMonth; 17 | @property (nonatomic, assign) NSUInteger expYear; 18 | @property (nonatomic, readonly) NSString* last4; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Test/PKTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // PKPayment_Test.m 3 | // PKPayment Test 4 | // 5 | // Created by Alex MacCaw on 2/6/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import "PKTest.h" 10 | 11 | @implementation PKTest 12 | 13 | - (void)setUp 14 | { 15 | [super setUp]; 16 | 17 | // Set-up code here. 18 | } 19 | 20 | - (void)tearDown 21 | { 22 | // Tear-down code here. 23 | 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample 28 | { 29 | //STFail(@"Unit tests are not implemented yet in PKPayment Test"); 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /PaymentKit/PKCardCVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // PKCardCVC.h 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/22/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PKCardType.h" 11 | 12 | @interface PKCardCVC : NSObject 13 | 14 | @property (nonatomic, readonly) NSString* string; 15 | 16 | + (instancetype)cardCVCWithString:(NSString *)string; 17 | - (instancetype)initWithString:(NSString *)string; 18 | - (NSString *)string; 19 | - (BOOL)isValid; 20 | - (BOOL)isValidWithType:(PKCardType)type; 21 | - (BOOL)isPartiallyValid; 22 | - (BOOL)isPartiallyValidWithType:(PKCardType)type; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /PaymentKit.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "PaymentKit" 3 | s.version = "1.0.0" 4 | s.summary = "Utility library for creating credit card payment forms." 5 | s.license = { :type => 'MIT', :file => 'LICENSE' } 6 | s.homepage = "https://stripe.com" 7 | s.author = { "Alex MacCaw" => "alex@stripe.com" } 8 | s.source = { :git => "https://github.com/stripe/PaymentKit.git", :tag => "v1.0.0"} 9 | s.source_files = 'PaymentKit/*.{h,m}' 10 | s.public_header_files = 'PaymentKit/*.h' 11 | s.resources = 'PaymentKit/Resources/Cards/*.png', 'PaymentKit/Resources/*.png' 12 | s.platform = :ios 13 | s.requires_arc = true 14 | end -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Test/PaymentKit Test-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | stripe.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example.xcodeproj/xcuserdata/Alex.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PaymentKit Example.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | PaymentKit Test.xcscheme 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | FA45AC6B16AE350D0003A41D 21 | 22 | primary 23 | 24 | 25 | FA6A2F8916C2D6F400915AEB 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /PaymentKit/PKUSAddressZip.m: -------------------------------------------------------------------------------- 1 | // 2 | // PKUSAddressZip.m 3 | // PaymentKit Example 4 | // 5 | // Created by Alex MacCaw on 2/17/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import "PKUSAddressZip.h" 10 | 11 | @implementation PKUSAddressZip 12 | 13 | - (instancetype)initWithString:(NSString *)string 14 | { 15 | self = [super init]; 16 | if (self) { 17 | // Strip non-digits 18 | zip = [string stringByReplacingOccurrencesOfString:@"\\D" 19 | withString:@"" 20 | options:NSRegularExpressionSearch 21 | range:NSMakeRange(0, string.length)]; 22 | } 23 | return self; 24 | } 25 | 26 | - (BOOL)isValid 27 | { 28 | return zip.length == 5; 29 | } 30 | 31 | - (BOOL)isPartiallyValid 32 | { 33 | return zip.length <= 5; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /PaymentKit/PKCardExpiry.h: -------------------------------------------------------------------------------- 1 | // 2 | // PKCardExpiry.h 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/22/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PKCardExpiry : NSObject 12 | 13 | @property (nonatomic, readonly) NSUInteger month; 14 | @property (nonatomic, readonly) NSUInteger year; 15 | @property (nonatomic, readonly) NSString *formattedString; 16 | @property (nonatomic, readonly) NSString *formattedStringWithTrail; 17 | 18 | + (instancetype)cardExpiryWithString:(NSString *)string; 19 | - (instancetype)initWithString:(NSString *)string; 20 | - (instancetype)initWithMonth:(NSString *)monthStr andYear:(NSString *)yearStr; 21 | 22 | - (NSString *)formattedString; 23 | - (NSString *)formattedStringWithTrail; 24 | - (BOOL)isValid; 25 | - (BOOL)isValidLength; 26 | - (BOOL)isValidDate; 27 | - (BOOL)isPartiallyValid; 28 | - (NSUInteger)month; 29 | - (NSUInteger)year; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /PaymentKit/PKCardNumber.h: -------------------------------------------------------------------------------- 1 | // 2 | // CardNumber.h 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/22/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PKCardType.h" 11 | 12 | @interface PKCardNumber : NSObject 13 | 14 | @property (nonatomic, readonly) PKCardType cardType; 15 | @property (nonatomic, readonly) NSString *last4; 16 | @property (nonatomic, readonly) NSString *lastGroup; 17 | @property (nonatomic, readonly) NSString *string; 18 | @property (nonatomic, readonly) NSString *formattedString; 19 | @property (nonatomic, readonly) NSString *formattedStringWithTrail; 20 | 21 | + (instancetype)cardNumberWithString:(NSString *)string; 22 | - (instancetype)initWithString:(NSString *)string; 23 | - (PKCardType)cardType; 24 | - (NSString *)last4; 25 | - (NSString *)lastGroup; 26 | - (NSString *)string; 27 | - (NSString *)formattedString; 28 | - (NSString *)formattedStringWithTrail; 29 | - (BOOL)isValid; 30 | - (BOOL)isValidLength; 31 | - (BOOL)isValidLuhn; 32 | - (BOOL)isPartiallyValid; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /PaymentKit/PKAddressZip.m: -------------------------------------------------------------------------------- 1 | // 2 | // PKZip.m 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 2/1/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import "PKAddressZip.h" 10 | 11 | @implementation PKAddressZip 12 | 13 | + (instancetype)addressZipWithString:(NSString *)string 14 | { 15 | return [[self alloc] initWithString:string]; 16 | } 17 | 18 | - (instancetype)initWithString:(NSString *)string 19 | { 20 | self = [super init]; 21 | if (self) { 22 | zip = string; 23 | } 24 | return self; 25 | } 26 | 27 | - (NSString *)string 28 | { 29 | return zip; 30 | } 31 | 32 | - (BOOL)isValid 33 | { 34 | NSString* stripped = [zip stringByReplacingOccurrencesOfString:@"\\s" 35 | withString:@"" 36 | options:NSRegularExpressionSearch 37 | range:NSMakeRange(0, zip.length)]; 38 | 39 | return stripped.length > 2; 40 | } 41 | 42 | - (BOOL)isPartiallyValid 43 | { 44 | return zip.length < 10; 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013- Stripe, Inc. (https://stripe.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 2/5/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "PaymentViewController.h" 11 | 12 | @implementation ViewController 13 | 14 | @synthesize paymentCell; 15 | 16 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 17 | { 18 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 19 | return self; 20 | } 21 | 22 | - (void)viewDidLoad 23 | { 24 | [super viewDidLoad]; 25 | [self updatePaymentCell]; 26 | } 27 | 28 | - (void)updatePaymentCell 29 | { 30 | NSString* last4 = [[NSUserDefaults standardUserDefaults] stringForKey:@"card.last4"]; 31 | self.paymentCell.detailTextLabel.text = last4; 32 | } 33 | 34 | - (void)viewWillAppear:(BOOL)animated 35 | { 36 | [self updatePaymentCell]; 37 | } 38 | 39 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 40 | { 41 | [self performSegueWithIdentifier:@"ChangeCard" sender:self]; 42 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example/PaymentKit Example-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | stripe.${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 | Storyboard 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example/PaymentViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/21/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import "PaymentViewController.h" 10 | 11 | @implementation PaymentViewController 12 | 13 | - (void)viewDidLoad 14 | { 15 | [super viewDidLoad]; 16 | self.paymentView.delegate = self; 17 | [self.paymentView becomeFirstResponder]; 18 | } 19 | 20 | - (void)paymentView:(PKView *)paymentView withCard:(PKCard *)card isValid:(BOOL)valid 21 | { 22 | self.navigationItem.rightBarButtonItem.enabled = valid; 23 | } 24 | 25 | - (void)paymentView:(PKView *)paymentView didChangeState:(PKViewState)state 26 | { 27 | switch (state) { 28 | case PKViewStateCardNumber: 29 | self.helpLabel.text = @"Enter card number"; 30 | break; 31 | 32 | case PKViewStateExpiry: 33 | self.helpLabel.text = @"Enter expiry date"; 34 | break; 35 | 36 | case PKViewStateCVC: 37 | self.helpLabel.text = @"Enter security code"; 38 | break; 39 | } 40 | } 41 | 42 | - (void)didReceiveMemoryWarning 43 | { 44 | [super didReceiveMemoryWarning]; 45 | // Dispose of any resources that can be recreated. 46 | } 47 | 48 | - (IBAction)save:(id)sender 49 | { 50 | PKCard *card = self.paymentView.card; 51 | 52 | NSLog(@"Card last4: %@", card.last4); 53 | NSLog(@"Card expiry: %lu/%lu", (unsigned long)card.expMonth, (unsigned long)card.expYear); 54 | NSLog(@"Card cvc: %@", card.cvc); 55 | 56 | [[NSUserDefaults standardUserDefaults] setValue:card.last4 forKey:@"card.last4"]; 57 | [self.navigationController popViewControllerAnimated:YES]; 58 | } 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /PaymentKit/PKCardCVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // PKCardCVC.m 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/22/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import "PKCardCVC.h" 10 | 11 | @interface PKCardCVC () { 12 | @private 13 | NSString *cvc; 14 | } 15 | @end 16 | 17 | @implementation PKCardCVC 18 | 19 | + (instancetype)cardCVCWithString:(NSString *)string 20 | { 21 | return [[self alloc] initWithString:string]; 22 | } 23 | 24 | - (instancetype)initWithString:(NSString *)string 25 | { 26 | self = [super init]; 27 | if (self) { 28 | // Strip non-digits 29 | if (string) { 30 | cvc = [string stringByReplacingOccurrencesOfString:@"\\D" 31 | withString:@"" 32 | options:NSRegularExpressionSearch 33 | range:NSMakeRange(0, string.length)]; 34 | } else { 35 | cvc = [NSString string]; 36 | } 37 | } 38 | return self; 39 | } 40 | 41 | - (NSString *)string 42 | { 43 | return cvc; 44 | } 45 | 46 | - (BOOL)isValid 47 | { 48 | return cvc.length >= 3 && cvc.length <= 4; 49 | } 50 | 51 | - (BOOL)isValidWithType:(PKCardType)type { 52 | if (type == PKCardTypeAmex) { 53 | return cvc.length == 4; 54 | } else { 55 | return cvc.length == 3; 56 | } 57 | } 58 | 59 | - (BOOL)isPartiallyValid 60 | { 61 | return cvc.length <= 4; 62 | } 63 | 64 | - (BOOL)isPartiallyValidWithType:(PKCardType)type { 65 | if (type == PKCardTypeAmex) { 66 | return cvc.length <= 4; 67 | } else { 68 | return cvc.length <= 3; 69 | } 70 | } 71 | @end 72 | -------------------------------------------------------------------------------- /PaymentKit/PKTextField.m: -------------------------------------------------------------------------------- 1 | // 2 | // PKTextField.m 3 | // PaymentKit Example 4 | // 5 | // Created by Michaël Villar on 3/20/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import "PKTextField.h" 10 | 11 | #define kPKTextFieldSpaceChar @"\u200B" 12 | 13 | @implementation PKTextField 14 | 15 | + (NSString *)textByRemovingUselessSpacesFromString:(NSString *)string { 16 | return [string stringByReplacingOccurrencesOfString:kPKTextFieldSpaceChar withString:@""]; 17 | } 18 | 19 | - (instancetype)initWithFrame:(CGRect)frame { 20 | self = [super initWithFrame:frame]; 21 | if(self) { 22 | self.text = kPKTextFieldSpaceChar; 23 | [self addObserver:self forKeyPath:@"text" options:0 context:NULL]; 24 | } 25 | return self; 26 | } 27 | 28 | - (void)dealloc { 29 | [self removeObserver:self forKeyPath:@"text"]; 30 | } 31 | 32 | - (void)drawPlaceholderInRect:(CGRect)rect { 33 | 34 | } 35 | 36 | - (void)drawRect:(CGRect)rect { 37 | if(self.text.length == 0 || [self.text isEqualToString:kPKTextFieldSpaceChar]) { 38 | CGRect placeholderRect = self.bounds; 39 | [super drawPlaceholderInRect:placeholderRect]; 40 | } 41 | else 42 | [super drawRect:rect]; 43 | } 44 | 45 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 46 | change:(NSDictionary *)change context:(void *)context { 47 | if([keyPath isEqualToString:@"text"] && object == self) { 48 | if(self.text.length == 0) { 49 | if([self.delegate respondsToSelector:@selector(pkTextFieldDidBackSpaceWhileTextIsEmpty:)]) 50 | [self.delegate performSelector:@selector(pkTextFieldDidBackSpaceWhileTextIsEmpty:) 51 | withObject:self]; 52 | self.text = kPKTextFieldSpaceChar; 53 | } 54 | [self setNeedsDisplay]; 55 | } 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /PaymentKit/PKView.h: -------------------------------------------------------------------------------- 1 | // 2 | // PKPaymentField.h 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/22/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PKCard.h" 11 | #import "PKCardNumber.h" 12 | #import "PKCardExpiry.h" 13 | #import "PKCardCVC.h" 14 | #import "PKAddressZip.h" 15 | #import "PKUSAddressZip.h" 16 | 17 | @class PKView, PKTextField; 18 | 19 | typedef enum { 20 | PKViewStateCardNumber, 21 | PKViewStateExpiry, 22 | PKViewStateCVC 23 | } PKViewState; 24 | 25 | typedef enum { 26 | PKViewImageStyleNormal, 27 | PKViewImageStyleOutline 28 | } PKViewImageStyle; 29 | 30 | @protocol PKViewDelegate 31 | @optional 32 | - (void)paymentView:(PKView *)paymentView withCard:(PKCard *)card isValid:(BOOL)valid; 33 | - (void)paymentView:(PKView *)paymentView didChangeState:(PKViewState)state; 34 | @end 35 | 36 | @interface PKView : UIView 37 | 38 | - (BOOL)isValid; 39 | 40 | @property(nonatomic) UITextBorderStyle borderStyle; 41 | @property(nonatomic) PKViewImageStyle imageStyle; 42 | @property(nonatomic) UIFont *font; 43 | @property(nonatomic) UIColor *textColor; 44 | @property(nonatomic, copy) NSDictionary *defaultTextAttributes; 45 | 46 | @property (nonatomic, readonly) UIView *opaqueOverGradientView; 47 | @property (nonatomic, readonly) PKCardNumber *cardNumber; 48 | @property (nonatomic, readonly) PKCardExpiry *cardExpiry; 49 | @property (nonatomic, readonly) PKCardCVC *cardCVC; 50 | @property (nonatomic, readonly) PKAddressZip *addressZip; 51 | 52 | @property UIView *innerView; 53 | @property UIView *clipView; 54 | @property PKTextField *cardNumberField; 55 | @property UITextField *cardLastFourField; 56 | @property PKTextField *cardExpiryField; 57 | @property PKTextField *cardCVCField; 58 | @property UIImageView *placeholderView; 59 | @property (weak) id delegate; 60 | @property (retain) PKCard *card; 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Test/PKCardCVCTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // PKCardCVCTest.m 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 2/6/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import "PKCardCVCTest.h" 10 | #import "PKCardCVC.h" 11 | #define CCVC(string) [PKCardCVC cardCVCWithString:string] 12 | 13 | @implementation PKCardCVCTest 14 | 15 | //@property (readonly) NSString* string; 16 | // 17 | //+ (id)cardCVCWithString:(NSString *)string; 18 | //- (id)initWithString:(NSString *)string; 19 | //- (NSString*)string; 20 | //- (BOOL)isValid; 21 | //- (BOOL)isValidWithType:(PKCardType)type; 22 | //- (BOOL)isPartiallyValid; 23 | //- (BOOL)isPartiallyValidWithType:(PKCardType)type; 24 | 25 | - (void) testStripsNonIntegers 26 | { 27 | 28 | STAssertEqualObjects([CCVC(@"123") string], @"123", @"Strips non integers"); 29 | STAssertEqualObjects([CCVC(@"12d3") string], @"123", @"Strips non integers"); 30 | } 31 | 32 | - (void) testIsValid 33 | { 34 | STAssertTrue([CCVC(@"123") isValid], @"Test is valid"); 35 | STAssertTrue(![CCVC(@"12334") isValid], @"Test is valid"); 36 | STAssertTrue(![CCVC(@"34") isValid], @"Test is valid"); 37 | } 38 | 39 | - (void) testIsPartiallyValid 40 | { 41 | STAssertTrue([CCVC(@"123") isPartiallyValid], @"Test is valid"); 42 | STAssertTrue(![CCVC(@"12334") isPartiallyValid], @"Test is valid"); 43 | STAssertTrue([CCVC(@"1234") isPartiallyValid], @"Test is valid"); 44 | STAssertTrue([CCVC(@"34")isPartiallyValid], @"Test is valid"); 45 | } 46 | 47 | - (void) testIsPartiallyValidWithType 48 | { 49 | STAssertTrue([CCVC(@"123") isPartiallyValidWithType:PKCardTypeVisa], @"Test is valid"); 50 | STAssertTrue(![CCVC(@"1234") isPartiallyValidWithType:PKCardTypeVisa], @"Test is valid"); 51 | 52 | STAssertTrue([CCVC(@"123") isPartiallyValidWithType:PKCardTypeAmex], @"Test is valid"); 53 | STAssertTrue([CCVC(@"1234") isPartiallyValidWithType:PKCardTypeAmex], @"Test is valid"); 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example.xcodeproj/xcuserdata/Alex.xcuserdatad/xcschemes/PaymentKit Test.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 36 | 37 | 38 | 39 | 45 | 46 | 48 | 49 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/21/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application 42 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Test/PKCardExpiryTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // PKCardExpiryTest.m 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 2/6/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import "PKCardExpiryTest.h" 10 | #import "PKCardExpiry.h" 11 | #define CEXPIRY(string) [PKCardExpiry cardExpiryWithString:string] 12 | 13 | @implementation PKCardExpiryTest 14 | 15 | //@property (readonly) NSUInteger month; 16 | //@property (readonly) NSUInteger year; 17 | //@property (readonly) NSString* formattedString; 18 | //@property (readonly) NSString* formattedStringWithTrail; 19 | // 20 | //+ (id)cardExpiryWithString:(NSString *)string; 21 | //- (id)initWithString:(NSString *)string; 22 | //- (NSString *)formattedString; 23 | //- (NSString *)formattedStringWithTrail; 24 | //- (BOOL)isValid; 25 | //- (BOOL)isValidLength; 26 | //- (BOOL)isValidDate; 27 | //- (BOOL)isPartiallyValid; 28 | //- (NSUInteger)month; 29 | //- (NSUInteger)year; 30 | 31 | - (void)testFromString 32 | { 33 | STAssertEquals([CEXPIRY(@"01") month], 1, @"Strips month"); 34 | STAssertEquals([CEXPIRY(@"05/") month], 5, @"Strips month"); 35 | 36 | STAssertEquals([CEXPIRY(@"03 / 2020") year], 2020, @"Strips year"); 37 | STAssertEquals([CEXPIRY(@"03/20") year], 2020, @"Strips year"); 38 | } 39 | 40 | - (void)testFormattedString 41 | { 42 | STAssertEqualObjects([CEXPIRY(@"01") formattedString], @"01", @"Formatted"); 43 | STAssertEqualObjects([CEXPIRY(@"05/") formattedString], @"05", @"Formatted"); 44 | 45 | STAssertEqualObjects([CEXPIRY(@"05/20") formattedString], @"05/20", @"Formatted"); 46 | STAssertEqualObjects([CEXPIRY(@"05 / 20") formattedString], @"05/20", @"Formatted"); 47 | 48 | STAssertEqualObjects([CEXPIRY(@"/ 2020") formattedString], @"/2020", @"Formatted"); 49 | } 50 | 51 | - (void)testFormattedStringWithTrail 52 | { 53 | STAssertEqualObjects([CEXPIRY(@"01") formattedStringWithTrail], @"01/", @"Formatted"); 54 | STAssertEqualObjects([CEXPIRY(@"05/") formattedStringWithTrail], @"05/", @"Formatted"); 55 | 56 | STAssertEqualObjects([CEXPIRY(@"05/20") formattedStringWithTrail], @"05/20", @"Formatted"); 57 | STAssertEqualObjects([CEXPIRY(@"05 / 20") formattedStringWithTrail], @"05/20", @"Formatted"); 58 | } 59 | 60 | - (void)testIsValid 61 | { 62 | STAssertTrue(![CEXPIRY(@"01") isValid], @"Is valid"); 63 | STAssertTrue(![CEXPIRY(@"") isValid], @"Is valid"); 64 | STAssertTrue(![CEXPIRY(@"01/") isValid], @"Is valid"); 65 | STAssertTrue(![CEXPIRY(@"01/0") isValid], @"Is valid"); 66 | STAssertTrue(![CEXPIRY(@"13/20") isValid], @"Is valid"); 67 | STAssertTrue(![CEXPIRY(@"12/2010") isValid], @"Is valid"); 68 | 69 | STAssertTrue([CEXPIRY(@"12/2050") isValid], @"Is valid"); 70 | STAssertTrue([CEXPIRY(@"12/50") isValid], @"Is valid"); 71 | } 72 | 73 | - (void)testIsPartialyValid 74 | { 75 | STAssertTrue([CEXPIRY(@"01") isPartiallyValid], @"Is valid"); 76 | STAssertTrue([CEXPIRY(@"") isPartiallyValid], @"Is valid"); 77 | STAssertTrue([CEXPIRY(@"01/") isPartiallyValid], @"Is valid"); 78 | STAssertTrue(![CEXPIRY(@"13") isPartiallyValid], @"Is valid"); 79 | STAssertTrue(![CEXPIRY(@"12/2010") isPartiallyValid], @"Is valid"); 80 | 81 | STAssertTrue([CEXPIRY(@"12/2050") isPartiallyValid], @"Is valid"); 82 | STAssertTrue([CEXPIRY(@"12/50") isPartiallyValid], @"Is valid"); 83 | } 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example.xcodeproj/xcuserdata/Alex.xcuserdatad/xcschemes/PaymentKit Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /PaymentKit/PKCardExpiry.m: -------------------------------------------------------------------------------- 1 | // 2 | // PKCardExpiry.m 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/22/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import "PKCardExpiry.h" 10 | 11 | @interface PKCardExpiry () { 12 | @private 13 | NSString* month; 14 | NSString* year; 15 | } 16 | @end 17 | 18 | @implementation PKCardExpiry 19 | 20 | + (instancetype)cardExpiryWithString:(NSString *)string 21 | { 22 | return [[self alloc] initWithString:string]; 23 | } 24 | 25 | - (instancetype)initWithString:(NSString *)string 26 | { 27 | if (!string) { 28 | return [self initWithMonth:@"" andYear:@""]; 29 | } 30 | 31 | NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^(\\d{1,2})?[\\s/]*(\\d{1,4})?" options:0 error:NULL]; 32 | 33 | NSTextCheckingResult *match = [regex firstMatchInString:string options:0 range:NSMakeRange(0, string.length)]; 34 | 35 | NSString *monthStr = [NSString string]; 36 | NSString *yearStr = [NSString string]; 37 | 38 | if (match) { 39 | NSRange monthRange = [match rangeAtIndex:1]; 40 | if (monthRange.length > 0) { 41 | monthStr = [string substringWithRange:monthRange]; 42 | } 43 | 44 | NSRange yearRange = [match rangeAtIndex:2]; 45 | if (yearRange.length > 0) { 46 | yearStr = [string substringWithRange:yearRange]; 47 | } 48 | } 49 | 50 | return [self initWithMonth:monthStr andYear:yearStr]; 51 | } 52 | 53 | - (instancetype)initWithMonth:(NSString *)monthStr andYear:(NSString *)yearStr 54 | { 55 | self = [super init]; 56 | if (self) { 57 | month = monthStr; 58 | year = yearStr; 59 | 60 | if (month.length == 1) { 61 | if ( !([month isEqualToString:@"0"] || [month isEqualToString:@"1"]) ){ 62 | month = [NSString stringWithFormat:@"0%@", month]; 63 | } 64 | } 65 | } 66 | return self; 67 | } 68 | 69 | - (NSString *)formattedString 70 | { 71 | if (year.length > 0) { 72 | return [NSString stringWithFormat:@"%@/%@", month, year]; 73 | } 74 | 75 | return [NSString stringWithFormat:@"%@", month]; 76 | } 77 | 78 | - (NSString *)formattedStringWithTrail 79 | { 80 | if (month.length == 2 && year.length == 0) { 81 | return [NSString stringWithFormat:@"%@/", [self formattedString]]; 82 | } else { 83 | return [self formattedString]; 84 | } 85 | } 86 | 87 | - (BOOL)isValid 88 | { 89 | return [self isValidLength] && [self isValidDate]; 90 | } 91 | 92 | - (BOOL)isValidLength 93 | { 94 | return month.length == 2 && (year.length == 2 || year.length == 4); 95 | } 96 | 97 | - (BOOL)isValidDate 98 | { 99 | if ([self month] <= 0 || [self month] > 12) { 100 | return false; 101 | } 102 | 103 | NSDate *now = [NSDate date]; 104 | return [[self expiryDate] compare:now] == NSOrderedDescending; 105 | } 106 | 107 | - (BOOL)isPartiallyValid 108 | { 109 | if ([self isValidLength]) { 110 | return [self isValidDate]; 111 | } else { 112 | return [self month] <= 12 && year.length <= 4; 113 | } 114 | } 115 | 116 | - (NSDate *)expiryDate 117 | { 118 | NSDateComponents *comps = [[NSDateComponents alloc] init]; 119 | 120 | [comps setDay:1]; 121 | [comps setMonth:[self month]]; 122 | [comps setYear:[self year]]; 123 | 124 | static NSCalendar *gregorian = nil; 125 | 126 | if (!gregorian) { 127 | gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 128 | } 129 | 130 | return [gregorian dateFromComponents:comps]; 131 | } 132 | 133 | - (NSUInteger)month 134 | { 135 | if (!month) { 136 | return 0; 137 | } 138 | return [month integerValue]; 139 | } 140 | 141 | - (NSUInteger)year 142 | { 143 | if (!year) { 144 | return 0; 145 | } 146 | 147 | NSString *yearStr = [NSString stringWithString:year]; 148 | 149 | if (yearStr.length == 2) { 150 | static NSDateFormatter *formatter = nil; 151 | if (!formatter) { 152 | formatter = [[NSDateFormatter alloc] init]; 153 | [formatter setDateFormat:@"yyyy"]; 154 | } 155 | 156 | NSString *prefix = [formatter stringFromDate:[NSDate date]]; 157 | prefix = [prefix substringWithRange:NSMakeRange(0, 2)]; 158 | yearStr = [NSString stringWithFormat:@"%@%@", prefix, yearStr]; 159 | } 160 | 161 | return [yearStr integerValue]; 162 | } 163 | 164 | @end 165 | -------------------------------------------------------------------------------- /PaymentKit/PKCardNumber.m: -------------------------------------------------------------------------------- 1 | // 2 | // CardNumber.m 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/22/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import "PKCardNumber.h" 10 | 11 | @interface PKCardNumber() { 12 | @private 13 | NSString *number; 14 | } 15 | @end 16 | 17 | @implementation PKCardNumber 18 | 19 | + (instancetype)cardNumberWithString:(NSString *)string 20 | { 21 | return [[self alloc] initWithString:string]; 22 | } 23 | 24 | - (instancetype)initWithString:(NSString *)string 25 | { 26 | self = [super init]; 27 | if (self) { 28 | // Strip non-digits 29 | number = [string stringByReplacingOccurrencesOfString:@"\\D" 30 | withString:@"" 31 | options:NSRegularExpressionSearch 32 | range:NSMakeRange(0, string.length)]; 33 | } 34 | return self; 35 | } 36 | 37 | - (PKCardType)cardType 38 | { 39 | if (number.length < 2) return PKCardTypeUnknown; 40 | 41 | NSString* firstChars = [number substringWithRange:NSMakeRange(0, 2)]; 42 | 43 | int range = [firstChars integerValue]; 44 | 45 | if (range >= 40 && range <= 49) { 46 | return PKCardTypeVisa; 47 | } else if (range >= 50 && range <= 59) { 48 | return PKCardTypeMasterCard; 49 | } else if (range == 34 || range == 37) { 50 | return PKCardTypeAmex; 51 | } else if (range == 60 || range == 62 || range == 64 || range == 65) { 52 | return PKCardTypeDiscover; 53 | } else if (range == 35) { 54 | return PKCardTypeJCB; 55 | } else if (range == 30 || range == 36 || range == 38 || range == 39) { 56 | return PKCardTypeDinersClub; 57 | } else { 58 | return PKCardTypeUnknown; 59 | } 60 | } 61 | 62 | - (NSString *)last4 63 | { 64 | if (number.length >= 4) { 65 | return [number substringFromIndex:([number length] - 4)]; 66 | } else { 67 | return nil; 68 | } 69 | } 70 | 71 | - (NSString *)lastGroup 72 | { 73 | if (self.cardType == PKCardTypeAmex) { 74 | if (number.length >= 5) { 75 | return [number substringFromIndex:([number length] - 5)]; 76 | } 77 | } else { 78 | if (number.length >= 4) { 79 | return [number substringFromIndex:([number length] - 4)]; 80 | } 81 | } 82 | 83 | return nil; 84 | } 85 | 86 | 87 | - (NSString *)string 88 | { 89 | return number; 90 | } 91 | 92 | - (NSString *)formattedString 93 | { 94 | NSRegularExpression* regex; 95 | 96 | if ([self cardType] == PKCardTypeAmex) { 97 | regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d{1,4})(\\d{1,6})?(\\d{1,5})?" options:0 error:NULL]; 98 | } else if ([self cardType] == PKCardTypeDinersClub) { 99 | regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d{1,4})(\\d{1,6})?(\\d{1,4})?" options:0 error:NULL]; 100 | } 101 | else { 102 | regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d{1,4})" options:0 error:NULL]; 103 | } 104 | 105 | NSArray* matches = [regex matchesInString:number options:0 range:NSMakeRange(0, number.length)]; 106 | NSMutableArray* result = [NSMutableArray arrayWithCapacity:matches.count]; 107 | 108 | for (NSTextCheckingResult *match in matches) { 109 | for (int i=1; i < [match numberOfRanges]; i++) { 110 | NSRange range = [match rangeAtIndex:i]; 111 | 112 | if (range.length > 0) { 113 | NSString* matchText = [number substringWithRange:range]; 114 | [result addObject:matchText]; 115 | } 116 | } 117 | } 118 | 119 | return [result componentsJoinedByString:@" "]; 120 | } 121 | 122 | - (NSString *)formattedStringWithTrail 123 | { 124 | NSString *string = [self formattedString]; 125 | NSRegularExpression* regex; 126 | 127 | // No trailing space needed 128 | if ([self isValidLength]) { 129 | return string; 130 | } 131 | 132 | if ([self cardType] == PKCardTypeAmex) { 133 | regex = [NSRegularExpression regularExpressionWithPattern:@"^(\\d{4}|\\d{4}\\s\\d{6})$" options:0 error:NULL]; 134 | } else { 135 | regex = [NSRegularExpression regularExpressionWithPattern:@"(?:^|\\s)(\\d{4})$" options:0 error:NULL]; 136 | } 137 | 138 | NSUInteger numberOfMatches = [regex numberOfMatchesInString:string options:0 range:NSMakeRange(0, string.length)]; 139 | 140 | if (numberOfMatches == 0) { 141 | // Not at the end of a group of digits 142 | return string; 143 | } else { 144 | return [NSString stringWithFormat:@"%@ ", string]; 145 | } 146 | } 147 | 148 | - (BOOL)isValid 149 | { 150 | return [self isValidLength] && [self isValidLuhn]; 151 | } 152 | 153 | - (BOOL)isValidLength 154 | { 155 | return number.length == [self lengthForCardType]; 156 | } 157 | 158 | - (BOOL)isValidLuhn 159 | { 160 | BOOL odd = true; 161 | int sum = 0; 162 | NSMutableArray* digits = [NSMutableArray arrayWithCapacity:number.length]; 163 | 164 | for (int i=0; i < number.length; i++) { 165 | [digits addObject:[number substringWithRange:NSMakeRange(i, 1)]]; 166 | } 167 | 168 | for (NSString* digitStr in [digits reverseObjectEnumerator]) { 169 | int digit = [digitStr intValue]; 170 | if ((odd = !odd)) digit *= 2; 171 | if (digit > 9) digit -= 9; 172 | sum += digit; 173 | } 174 | 175 | return sum % 10 == 0; 176 | } 177 | 178 | - (BOOL)isPartiallyValid 179 | { 180 | return number.length <= [self lengthForCardType]; 181 | } 182 | 183 | - (NSInteger)lengthForCardType { 184 | PKCardType type = self.cardType; 185 | NSInteger length; 186 | if (type == PKCardTypeAmex) { 187 | length = 15; 188 | } else if (type == PKCardTypeDinersClub) { 189 | length = 14; 190 | } else { 191 | length = 16; 192 | } 193 | return length; 194 | } 195 | 196 | @end 197 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Test/PKCardNumberTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // PKCardNumberTest.m 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 2/6/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #import "PKCardNumberTest.h" 10 | #import "PKCardNumber.h" 11 | #define CNUMBER(string) [PKCardNumber cardNumberWithString:string] 12 | 13 | @implementation PKCardNumberTest 14 | 15 | //@property (readonly) PKCardType cardType; 16 | //@property (readonly) NSString * last4; 17 | //@property (readonly) NSString * lastGroup; 18 | //@property (readonly) NSString * string; 19 | //@property (readonly) NSString * formattedString; 20 | //@property (readonly) NSString * formattedStringWithTrail; 21 | // 22 | //+ (id) cardNumberWithString:(NSString *)string; 23 | //- (id) initWithString:(NSString *)string; 24 | //- (PKCardType)cardType; 25 | //- (NSString *)last4; 26 | //- (NSString *)lastGroup; 27 | //- (NSString *)string; 28 | //- (NSString *)formattedString; 29 | //- (NSString *)formattedStringWithTrail; 30 | //- (BOOL)isValid; 31 | //- (BOOL)isValidLength; 32 | //- (BOOL)isValidLuhn; 33 | //- (BOOL)isPartiallyValid; 34 | 35 | - (void)testCardType 36 | { 37 | STAssertEquals([CNUMBER(@"378282246310005") cardType], PKCardTypeAmex, @"Detects Amex"); 38 | STAssertEquals([CNUMBER(@"371449635398431") cardType], PKCardTypeAmex, @"Detects Amex"); 39 | STAssertEquals([CNUMBER(@"30569309025904") cardType], PKCardTypeDinersClub, @"Detects Diners Club"); 40 | STAssertEquals([CNUMBER(@"6011111111111117") cardType], PKCardTypeDiscover, @"Detects Discover"); 41 | STAssertEquals([CNUMBER(@"6011000990139424") cardType], PKCardTypeDiscover, @"Detects Discover"); 42 | STAssertEquals([CNUMBER(@"3530111333300000") cardType], PKCardTypeJCB, @"Detects JCB"); 43 | STAssertEquals([CNUMBER(@"5555555555554444") cardType], PKCardTypeMasterCard, @"Detects MasterCard"); 44 | STAssertEquals([CNUMBER(@"4111111111111111") cardType], PKCardTypeVisa, @"Detects Visa"); 45 | STAssertEquals([CNUMBER(@"4012888888881881") cardType], PKCardTypeVisa, @"Detects Visa"); 46 | } 47 | 48 | - (void)testLast4 49 | { 50 | STAssertEqualObjects([CNUMBER(@"378282246310005") last4], @"0005", @"Asserts last 4"); 51 | STAssertEqualObjects([CNUMBER(@"4012888888881881") last4], @"1881", @"Asserts last 4"); 52 | } 53 | 54 | - (void)testLastGroup 55 | { 56 | STAssertEqualObjects([CNUMBER(@"4111111111111111") lastGroup], @"1111", @"Asserts last group for visa"); 57 | STAssertEqualObjects([CNUMBER(@"378282246310005") lastGroup], @"10005", @"Asserts last group for amex"); 58 | } 59 | 60 | - (void)testStripsNonIntegers 61 | { 62 | STAssertEqualObjects([CNUMBER(@"411111ddd1111111111") string], @"4111111111111111", @"Strips non integers"); 63 | } 64 | 65 | - (void)testFormattedString 66 | { 67 | STAssertEqualObjects([CNUMBER(@"4012888888881881") formattedString], @"4012 8888 8888 1881", @"Formats Visa"); 68 | STAssertEqualObjects([CNUMBER(@"378734493671000") formattedString], @"3787 344936 71000", @"Formats Amex"); 69 | } 70 | 71 | - (void)testFormttedStringWithTrail 72 | { 73 | STAssertEqualObjects([CNUMBER(@"4012888888881881") formattedStringWithTrail], @"4012 8888 8888 1881", @"Formats Visa"); 74 | STAssertEqualObjects([CNUMBER(@"378734493671000") formattedStringWithTrail], @"3787 344936 71000", @"Formats Amex"); 75 | 76 | STAssertEqualObjects([CNUMBER(@"4012") formattedStringWithTrail], @"4012 ", @"Formats Visa"); 77 | STAssertEqualObjects([CNUMBER(@"4012 8") formattedStringWithTrail], @"4012 8", @"Formats Visa"); 78 | 79 | STAssertEqualObjects([CNUMBER(@"3787344936") formattedStringWithTrail], @"3787 344936 ", @"Formats Amex"); 80 | STAssertEqualObjects([CNUMBER(@"37873449367") formattedStringWithTrail], @"3787 344936 7", @"Formats Amex"); 81 | } 82 | 83 | - (void)testIsValid 84 | { 85 | STAssertTrue([CNUMBER(@"378282246310005") isValid], @"Detects Amex"); 86 | STAssertTrue([CNUMBER(@"371449635398431") isValid], @"Detects Amex"); 87 | STAssertTrue([CNUMBER(@"30569309025904") isValid], @"Detects Diners Club"); 88 | STAssertTrue([CNUMBER(@"6011111111111117") isValid], @"Detects Discover"); 89 | STAssertTrue([CNUMBER(@"6011000990139424") isValid], @"Detects Discover"); 90 | STAssertTrue([CNUMBER(@"3530111333300000") isValid], @"Detects JCB"); 91 | STAssertTrue([CNUMBER(@"5555555555554444") isValid], @"Detects MasterCard"); 92 | STAssertTrue([CNUMBER(@"4111111111111111") isValid], @"Detects Visa"); 93 | STAssertTrue([CNUMBER(@"4012888888881881") isValid], @"Detects Visa"); 94 | 95 | STAssertTrue(![CNUMBER(@"401288888881881") isValid], @"Assert fails Luhn invalid"); 96 | STAssertTrue(![CNUMBER(@"60110990139424") isValid], @"Assert fails Luhn invalid"); 97 | STAssertTrue(![CNUMBER(@"424242424242") isValid], @"Assert fails length test invalid"); 98 | } 99 | 100 | - (void)testIsPartiallyValidWhenGivenValidNumber 101 | { 102 | STAssertTrue([CNUMBER(@"378282246310005") isPartiallyValid], @"Detects Amex"); 103 | STAssertTrue([CNUMBER(@"371449635398431") isPartiallyValid], @"Detects Amex"); 104 | STAssertTrue([CNUMBER(@"30569309025904") isPartiallyValid], @"Detects Diners Club"); 105 | STAssertTrue([CNUMBER(@"6011111111111117") isPartiallyValid], @"Detects Discover"); 106 | STAssertTrue([CNUMBER(@"6011000990139424") isPartiallyValid], @"Detects Discover"); 107 | STAssertTrue([CNUMBER(@"3530111333300000") isPartiallyValid], @"Detects JCB"); 108 | STAssertTrue([CNUMBER(@"5555555555554444") isPartiallyValid], @"Detects MasterCard"); 109 | STAssertTrue([CNUMBER(@"4111111111111111") isPartiallyValid], @"Detects Visa"); 110 | STAssertTrue([CNUMBER(@"4012888888881881") isPartiallyValid], @"Detects Visa"); 111 | } 112 | 113 | - (void)testIsPartiallyValidWhenGivenValidNumberMissingDigits 114 | { 115 | STAssertTrue([CNUMBER(@"3") isPartiallyValid], @"Too short to determine type"); 116 | STAssertTrue([CNUMBER(@"411111") isPartiallyValid], @"Visa many digits short"); 117 | STAssertTrue([CNUMBER(@"37828224631000") isPartiallyValid], @"Amex one digit short"); 118 | STAssertTrue([CNUMBER(@"3056930902590") isPartiallyValid], @"Diners Club one digit short"); 119 | STAssertTrue([CNUMBER(@"601111111111111") isPartiallyValid], @"Discover one digit short"); 120 | STAssertTrue([CNUMBER(@"353011133330000") isPartiallyValid], @"JCB one digit short"); 121 | STAssertTrue([CNUMBER(@"555555555555444") isPartiallyValid], @"MasterCard one digit short"); 122 | STAssertTrue([CNUMBER(@"411111111111111") isPartiallyValid], @"Visa one digit short"); 123 | } 124 | 125 | - (void)testIsPartiallyValidIsFalseWhenOverMaxDigitLengthForCardType 126 | { 127 | STAssertTrue(![CNUMBER(@"3782822463100053") isPartiallyValid], @"Amex cannot be more than 15 digits"); 128 | STAssertTrue(![CNUMBER(@"305693090259042") isPartiallyValid], @"Diners Club cannot be more than 14 digits"); 129 | STAssertTrue(![CNUMBER(@"41111111111111111") isPartiallyValid], @"Visa cannot be more than 16 digits"); 130 | } 131 | 132 | @end 133 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LMPaymentKit 2 | 3 | LMPaymentKit is a fork of PaymentKit by Stripe - a utility library for writing payment forms in iOS apps. Development over there seems to have stopped, with PRs from contributors being ignored for nearly a year. I'll be picking up from where they left off here :) 4 | 5 | Just add `PKView` to your application, and it'll take care accepting card numbers, expiry, cvc and zip. 6 | Alternatively, we've provided a bunch of classes that you can use yourself to add formatting, validation and restricting input of `UITextField`s. 7 | 8 | In short, PaymentKit should greatly simplify your life when dealing with iOS payments. 9 | 10 | 11 | 12 | *For purchases related to the app, such as premium features, Apple's TOS require that you use their native In-App Purchase API. PaymentKits is only for purchasing products or services outside the app.* 13 | 14 | # Changes from stripe/PaymentKit 15 | 16 | * PKView can now be any size, with subviews laid out accordingly 17 | * Updated assets for all the different card types 18 | * UIResponder methods have been implemented 19 | * Fix for Diner's Club cards being unrecognised 20 | * Fix incorrect validation of AMEX CVC numbers 21 | * The look and feel of PKView has been updated to reflect the design of iOS 7 22 | * Lots of optimisations, cleanups and code modernization 23 | * A storyboard is now used in the example project 24 | * .gitignore is now useful! 25 | * PKView delegate is now notified when a field/state change occurs. This is useful for implementing helper labels 26 | * Can now set borderStyle of a PKView 27 | * Can now set the defaultTextAttributes of a PKView 28 | 29 | ## Installation 30 | 31 | ### Install with CocoaPods 32 | 33 | [CocoaPods](http://cocoapods.org/) is a library dependency management tool for Objective-C. To use PaymentKit with CocoaPods, simply add the following to your Podfile and run pod install: 34 | 35 | pod 'PaymentKit', :git => 'https://github.com/lmcd/PaymentKit.git' 36 | 37 | ### Install by adding files to project 38 | 39 | 1. Clone this repository 40 | 1. In the menubar, click on 'File' then 'Add files to "Project"...' 41 | 1. Select the 'PaymentKit' directory in your cloned PaymentKit repository 42 | 1. Make sure "Copy items into destination group's folder (if needed)" is checked" 43 | 1. Click "Add" 44 | 45 | ## PaymentKit View 46 | 47 | **1)** Add the `QuartzCore` framework to your application. 48 | 49 | **2)** Create a new `ViewController`, for example `PaymentViewController`. 50 | 51 | #import 52 | #import "PKView.h" 53 | 54 | @interface PaymentViewController : UIViewController 55 | @property IBOutlet PKView* paymentView; 56 | @end 57 | 58 | Notice we're importing `PKView.h`, the class conforms to `PKViewDelegate`, and lastly we have a `paymentView` property of type `PKView`. 59 | 60 | **3)** Instantiate and add `PKView`. We recommend you use the same frame. 61 | 62 | - (void)viewDidLoad 63 | { 64 | [super viewDidLoad]; 65 | 66 | self.paymentView = [[PKView alloc] initWithFrame:CGRectMake(15, 25, 290, 55)]; 67 | self.paymentView.delegate = self; 68 | [self.view addSubview:self.paymentView]; 69 | } 70 | 71 | **4)** Implement `PKViewDelegate` method `paymentView:withCard:isValid:`. This gets passed a `PKCard` instance, and a `BOOL` indicating whether the card is valid. You can enable or disable a navigational button depending on the value of `valid`, for example: 72 | 73 | - (void) paymentView:(PKView*)paymentView withCard:(PKCard *)card isValid:(BOOL)valid 74 | { 75 | NSLog(@"Card number: %@", card.number); 76 | NSLog(@"Card expiry: %lu/%lu", (unsigned long)card.expMonth, (unsigned long)card.expYear); 77 | NSLog(@"Card cvc: %@", card.cvc); 78 | NSLog(@"Address zip: %@", card.addressZip); 79 | 80 | // self.navigationItem.rightBarButtonItem.enabled = valid; 81 | } 82 | 83 | That's all! No further reading is required, unless you want more flexibility by using the raw API. For more, please see the included example. 84 | 85 | ---------- 86 | 87 | # Full API 88 | 89 | ## API Example 90 | 91 | // Format a card number 92 | [[PKCardNumber cardNumberWithString:@"4242424242424242"] formattedString]; //=> '4242 4242 4242 4242' 93 | [[PKCardNumber cardNumberWithString:@"4242424242"] formattedString]; //=> '4242 4242 42' 94 | 95 | // Amex support 96 | [[PKCardNumber cardNumberWithString:@"378282246310005"] formattedString]; //=> '3782 822463 10005' 97 | [[PKCardNumber cardNumberWithString:@"378282246310005"] cardType] == PKCardTypeAmex; //=> YES 98 | 99 | // Check a card number is valid using the Luhn algorithm 100 | [[PKCardNumber cardNumberWithString:@"4242424242424242"] isValid]; //=> YES 101 | [[PKCardNumber cardNumberWithString:@"4242424242424243"] isValid]; //=> NO 102 | 103 | // Check to see if a card expiry is valid 104 | [[PKCardExpiry cardExpiryWithString:@"05 / 20"] isValid]; //=> YES 105 | [[PKCardExpiry cardExpiryWithString:@"05 / 02"] isValid]; //=> NO 106 | 107 | // Return a card expiry's month 108 | [[PKCardExpiry cardExpiryWithString:@"05 / 02"] month]; //=> 5 109 | 110 | ## API Delegates 111 | 112 | Included are a number of `UITextFieldDelegate` delegates: `PKCardCVCDelegate`, `PKCardExpiryDelegate` and `PKCardNumberDelegate`. You can set these as the delegates of `UITextField` inputs, which ensures that input is limited and formatted. 113 | 114 | ## PKCardNumber 115 | 116 | #### `+ (id) cardNumberWithString:(NSString *)string` 117 | #### `- (id) initWithString:(NSString *)string` 118 | 119 | Create a `PKCardNumber` object, passing a `NSString` representing the card number. For example: 120 | 121 | PKCardNumber* cardNumber = [PKCardNumber cardNumberWithString:@"4242424242424242"]; 122 | 123 | #### `- (PKCardType)cardType` 124 | 125 | Returns a `PKCardType` representing the card type (Visa, Amex etc). 126 | 127 | PKCardType cardType = [[PKCardNumber cardNumberWithString:@"4242424242424242"] cardType]; 128 | 129 | if (cardType == PKCardTypeAmex) { 130 | 131 | } 132 | 133 | Available types are: 134 | 135 | PKCardTypeVisa 136 | PKCardTypeMasterCard 137 | PKCardTypeAmex 138 | PKCardTypeDiscover 139 | PKCardTypeJCB 140 | PKCardTypeDinersClub 141 | PKCardTypeUnknown 142 | 143 | #### `- (NSString *)string` 144 | 145 | Returns the card number as a string. 146 | 147 | #### `- (NSString *)formattedString` 148 | 149 | Returns a formatted card number, in the same space format as it appears on the card. 150 | 151 | NSString* number = [[PKCardNumber cardNumberWithString:@"4242424242424242"] formattedString]; 152 | number //=> '4242 4242 4242 4242' 153 | 154 | #### `- (NSString *)formattedStringWithTrail` 155 | 156 | Returns a formatted card number with a trailing space, if appropriate. Useful for formatting `UITextField` input. 157 | 158 | #### `- (BOOL)isValid` 159 | 160 | Helper method which calls `isValidLength` and `isValidLuhn`. 161 | 162 | #### `- (BOOL)isValidLength` 163 | 164 | Returns a `BOOL` depending on whether the card number is a valid length. Takes into account the different lengths of Amex and Visa, for example. 165 | 166 | #### `- (BOOL)isValidLuhn` 167 | 168 | Returns a `BOOL` indicating whether the number passed a [Luhn check](http://en.wikipedia.org/wiki/Luhn_algorithm). 169 | 170 | #### `- (BOOL)isPartiallyValid` 171 | 172 | Returns a `BOOL` indicating whether the number is too long or not. 173 | 174 | ## PKCardCVC 175 | 176 | #### `+ (id) cardCVCWithString:(NSString *)string` 177 | #### `- (id) initWithString:(NSString *)string` 178 | 179 | Returns a `PKCardCVC` instance, representing the card CVC. For example: 180 | 181 | PKCardCVC* cardCVC = [PKCardCVC cardCVCWithString:@"123"]; 182 | 183 | #### `- (NSString*)string` 184 | 185 | Returns the CVC as a string. 186 | 187 | #### `- (BOOL)isValid` 188 | 189 | Returns a `BOOL` indicating whether the CVC is valid universally. 190 | 191 | #### `- (BOOL)isValidWithType:(PKCardType)type` 192 | 193 | Returns a `BOOL` indicating whether the CVC is valid for a particular card type. 194 | 195 | #### `- (BOOL)isPartiallyValid` 196 | 197 | Returns a `BOOL` indicating whether the cvc is too long or not. 198 | 199 | ## PKCardExpiry 200 | 201 | #### `+ (id)cardExpiryWithString:(NSString *)string` 202 | #### `- (id)initWithString:(NSString *)string` 203 | 204 | Create a `PKCardExpiry` object, passing a `NSString` representing the card expiry. For example: 205 | 206 | PKCardExpiry* cardExpiry = [PKCardExpiry cardExpiryWithString:@"10 / 2015"]; 207 | 208 | #### `- (NSString *)formattedString` 209 | 210 | Returns a formatted representation of the card expiry. For example: 211 | 212 | [[PKCardExpiry cardExpiryWithString:@"10/2015"] formattedString]; //=> "10 / 2015" 213 | 214 | #### `- (NSString *)formattedStringWithTrail` 215 | 216 | Returns a formatted representation of the card expiry, with a trailing slash if appropriate. Useful for formatting `UITextField` inputs. 217 | 218 | #### `- (BOOL)isValid` 219 | 220 | Returns a `BOOL` if the expiry has a valid month, a valid year and is in the future. 221 | 222 | #### `- (NSUInteger)month` 223 | 224 | Returns an integer representing the expiry's month. Returns `0` if the month can't be determined. 225 | 226 | #### `- (NSUInteger)year` 227 | 228 | Returns an integer representing the expiry's year. Returns `0` if the year can't be determined. 229 | 230 | 231 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/lmcd/paymentkit/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 232 | 233 | -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example/Storyboard.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 33 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /PaymentKit/PKView.m: -------------------------------------------------------------------------------- 1 | // 2 | // PKPaymentField.m 3 | // PKPayment Example 4 | // 5 | // Created by Alex MacCaw on 1/22/13. 6 | // Copyright (c) 2013 Stripe. All rights reserved. 7 | // 8 | 9 | #define kPKRedColor [UIColor colorWithRed:253.0/255.0 green:0.0 blue:17.0/255.0 alpha:1.0] 10 | 11 | #import 12 | #import "PKView.h" 13 | #import "PKTextField.h" 14 | 15 | @interface PKView () { 16 | 17 | @private 18 | BOOL isInitialState; 19 | BOOL isValidState; 20 | } 21 | 22 | - (void)setup; 23 | - (void)setupPlaceholderView; 24 | - (void)setupCardNumberField; 25 | - (void)setupCardExpiryField; 26 | - (void)setupCardCVCField; 27 | 28 | - (void)stateCardNumber; 29 | - (void)stateMeta; 30 | - (void)stateCardCVC; 31 | 32 | - (void)setPlaceholderViewImage:(UIImage *)image; 33 | - (void)setPlaceholderToCVC; 34 | - (void)setPlaceholderToCardType; 35 | 36 | - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)replacementString; 37 | - (BOOL)cardNumberFieldShouldChangeCharactersInRange: (NSRange)range replacementString:(NSString *)replacementString; 38 | - (BOOL)cardExpiryShouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)replacementString; 39 | - (BOOL)cardCVCShouldChangeCharactersInRange: (NSRange)range replacementString:(NSString *)replacementString; 40 | 41 | - (void)checkValid; 42 | - (void)textFieldIsValid:(UITextField *)textField; 43 | - (void)textFieldIsInvalid:(UITextField *)textField withErrors:(BOOL)errors; 44 | @end 45 | 46 | @implementation PKView 47 | 48 | @dynamic card; 49 | 50 | - (instancetype)initWithFrame:(CGRect)frame 51 | { 52 | self = [super initWithFrame:frame]; 53 | if (self) { 54 | [self setup]; 55 | } 56 | return self; 57 | } 58 | 59 | - (void)awakeFromNib 60 | { 61 | [super awakeFromNib]; 62 | [self setup]; 63 | } 64 | 65 | - (void)setBorderStyle:(UITextBorderStyle)borderStyle 66 | { 67 | _borderStyle = borderStyle; 68 | 69 | if (borderStyle == UITextBorderStyleRoundedRect) { 70 | self.layer.borderColor = [UIColor colorWithRed:191/255.0 green:192/255.0 blue:194/255.0 alpha:1.0].CGColor; 71 | self.layer.cornerRadius = 6.0; 72 | self.layer.borderWidth = 0.5; 73 | } 74 | else { 75 | self.layer.borderColor = nil; 76 | self.layer.cornerRadius = 0.0; 77 | self.layer.borderWidth = 0.0; 78 | } 79 | } 80 | 81 | - (void)setDefaultTextAttributes:(NSDictionary *)defaultTextAttributes 82 | { 83 | _defaultTextAttributes = [defaultTextAttributes copy]; 84 | 85 | // We shouldn't need to set the font and textColor attributes, but a bug exists in 7.0 (fixed in 7.1/) 86 | 87 | NSArray *textFields = @[_cardNumberField, _cardExpiryField, _cardCVCField, _cardLastFourField]; 88 | for (PKTextField *textField in textFields) { 89 | textField.defaultTextAttributes = _defaultTextAttributes; 90 | textField.font = _defaultTextAttributes[NSFontAttributeName]; 91 | textField.textColor = _defaultTextAttributes[NSForegroundColorAttributeName]; 92 | textField.textAlignment = NSTextAlignmentLeft; 93 | } 94 | 95 | _cardExpiryField.textAlignment = NSTextAlignmentCenter; 96 | _cardCVCField.textAlignment = NSTextAlignmentCenter; 97 | 98 | [self setNeedsLayout]; 99 | } 100 | 101 | - (void)setFont:(UIFont *)font 102 | { 103 | NSMutableDictionary *defaultTextAttributes = [self.defaultTextAttributes mutableCopy]; 104 | defaultTextAttributes[NSFontAttributeName] = font; 105 | 106 | self.defaultTextAttributes = [defaultTextAttributes copy]; 107 | } 108 | 109 | - (UIFont *)font 110 | { 111 | return self.defaultTextAttributes[NSFontAttributeName]; 112 | } 113 | 114 | - (void)setTextColor:(UIColor *)textColor 115 | { 116 | NSMutableDictionary *defaultTextAttributes = [self.defaultTextAttributes mutableCopy]; 117 | defaultTextAttributes[NSForegroundColorAttributeName] = textColor; 118 | 119 | self.defaultTextAttributes = [defaultTextAttributes copy]; 120 | } 121 | 122 | - (UIColor *)textColor 123 | { 124 | return self.defaultTextAttributes[NSForegroundColorAttributeName]; 125 | } 126 | 127 | - (void)setup 128 | { 129 | self.imageStyle = PKViewImageStyleNormal; 130 | self.borderStyle = UITextBorderStyleRoundedRect; 131 | self.layer.masksToBounds = YES; 132 | self.backgroundColor = [UIColor whiteColor]; 133 | 134 | isInitialState = YES; 135 | isValidState = NO; 136 | 137 | [self setupPlaceholderView]; 138 | 139 | self.innerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, self.frame.size.height)]; 140 | self.innerView.clipsToBounds = YES; 141 | 142 | _cardLastFourField = [UITextField new]; 143 | _cardLastFourField.defaultTextAttributes = _defaultTextAttributes; 144 | _cardLastFourField.backgroundColor = self.backgroundColor; 145 | 146 | [self setupCardNumberField]; 147 | [self setupCardExpiryField]; 148 | [self setupCardCVCField]; 149 | 150 | self.defaultTextAttributes = @{ 151 | NSFontAttributeName: [UIFont boldSystemFontOfSize:16.0], 152 | NSForegroundColorAttributeName: [UIColor blackColor]}; 153 | 154 | [self.innerView addSubview:_cardNumberField]; 155 | 156 | [self addSubview:self.innerView]; 157 | [self addSubview:_placeholderView]; 158 | 159 | if (self.imageStyle == PKViewImageStyleNormal) { 160 | UIView *line = [[UIView alloc] initWithFrame:CGRectMake(_placeholderView.frame.size.width - 0.5, 0, 0.5, _innerView.frame.size.height)]; 161 | line.backgroundColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.3]; 162 | [self addSubview:line]; 163 | } 164 | 165 | [self stateCardNumber]; 166 | } 167 | 168 | - (PKTextField *)textFieldWithPlaceholder:(NSString *)placeholder 169 | { 170 | PKTextField *textField = [PKTextField new]; 171 | 172 | textField.delegate = self; 173 | textField.placeholder = placeholder; 174 | textField.keyboardType = UIKeyboardTypeNumberPad; 175 | textField.defaultTextAttributes = _defaultTextAttributes; 176 | textField.layer.masksToBounds = NO; 177 | 178 | return textField; 179 | } 180 | 181 | - (void)setupPlaceholderView 182 | { 183 | _placeholderView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"placeholder"]]; 184 | _placeholderView.backgroundColor = [UIColor whiteColor]; 185 | } 186 | 187 | - (void)setupCardNumberField 188 | { 189 | _cardNumberField = [self textFieldWithPlaceholder:@"1234 5678 9012 3456"]; 190 | } 191 | 192 | - (void)setupCardExpiryField 193 | { 194 | UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, -6.0, 0.5, _innerView.frame.size.height)]; 195 | line.backgroundColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.3]; 196 | 197 | _cardExpiryField = [self textFieldWithPlaceholder:@"MM/YY"]; 198 | _cardExpiryField.leftView = line; 199 | _cardExpiryField.leftViewMode = UITextFieldViewModeAlways; 200 | } 201 | 202 | - (void)setupCardCVCField 203 | { 204 | UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, -6.0, 0.5, _innerView.frame.size.height)]; 205 | line.backgroundColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.3]; 206 | 207 | _cardCVCField = [self textFieldWithPlaceholder:@"CVC"]; 208 | _cardCVCField.leftView = line; 209 | _cardCVCField.leftViewMode = UITextFieldViewModeAlways; 210 | } 211 | 212 | // Accessors 213 | 214 | - (PKCardNumber *)cardNumber 215 | { 216 | return [PKCardNumber cardNumberWithString:_cardNumberField.text]; 217 | } 218 | 219 | - (PKCardExpiry *)cardExpiry 220 | { 221 | return [PKCardExpiry cardExpiryWithString:_cardExpiryField.text]; 222 | } 223 | 224 | - (PKCardCVC *)cardCVC 225 | { 226 | return [PKCardCVC cardCVCWithString:_cardCVCField.text]; 227 | } 228 | 229 | - (void)layoutSubviews 230 | { 231 | if (self.imageStyle == PKViewImageStyleOutline) { 232 | CGFloat height = 18; 233 | CGFloat y = (self.frame.size.height - height) / 2; 234 | CGFloat width = 25 + y; 235 | 236 | _placeholderView.frame = CGRectMake(0, y, width, height); 237 | _placeholderView.contentMode = UIViewContentModeRight; 238 | } 239 | else { 240 | _placeholderView.frame = CGRectMake(0, (self.frame.size.height - 32) / 2, 51, 32); 241 | } 242 | 243 | NSDictionary *attributes = self.defaultTextAttributes; 244 | 245 | CGSize lastGroupSize, cvcSize, cardNumberSize; 246 | 247 | if (self.cardNumber.cardType == PKCardTypeAmex) { 248 | cardNumberSize = [@"1234 567890 12345" sizeWithAttributes:attributes]; 249 | lastGroupSize = [@"00000" sizeWithAttributes:attributes]; 250 | cvcSize = [@"0000" sizeWithAttributes:attributes]; 251 | } 252 | else { 253 | if (self.cardNumber.cardType == PKCardTypeDinersClub) { 254 | cardNumberSize = [@"1234 567890 1234" sizeWithAttributes:attributes]; 255 | } 256 | else { 257 | cardNumberSize = [_cardNumberField.placeholder sizeWithAttributes:attributes]; 258 | } 259 | 260 | lastGroupSize = [@"0000" sizeWithAttributes:attributes]; 261 | cvcSize = [_cardCVCField.placeholder sizeWithAttributes:attributes]; 262 | } 263 | 264 | CGSize expirySize = [_cardExpiryField.placeholder sizeWithAttributes:attributes]; 265 | 266 | CGFloat textFieldY = (self.frame.size.height - lastGroupSize.height) / 2.0; 267 | 268 | CGFloat totalWidth = lastGroupSize.width + expirySize.width + cvcSize.width; 269 | 270 | CGFloat innerWidth = self.frame.size.width - _placeholderView.frame.size.width; 271 | CGFloat multiplier = (100.0 / totalWidth); 272 | 273 | CGFloat newLastGroupWidth = (innerWidth * multiplier * lastGroupSize.width) / 100.0; 274 | CGFloat newExpiryWidth = (innerWidth * multiplier * expirySize.width) / 100.0; 275 | CGFloat newCVCWidth = (innerWidth * multiplier * cvcSize.width) / 100.0; 276 | 277 | CGFloat lastGroupSidePadding = (newLastGroupWidth - lastGroupSize.width) / 2.0; 278 | 279 | _cardNumberField.frame = CGRectMake((innerWidth / 2.0) - (cardNumberSize.width / 2.0), 280 | textFieldY, 281 | cardNumberSize.width, 282 | cardNumberSize.height); 283 | 284 | _cardLastFourField.frame = CGRectMake(CGRectGetMaxX(_cardNumberField.frame) - lastGroupSize.width, 285 | textFieldY, 286 | lastGroupSize.width, 287 | lastGroupSize.height); 288 | 289 | _cardExpiryField.frame = CGRectMake(CGRectGetMaxX(_cardNumberField.frame) + lastGroupSidePadding, 290 | textFieldY, 291 | newExpiryWidth, 292 | expirySize.height); 293 | 294 | _cardCVCField.frame = CGRectMake(CGRectGetMaxX(_cardExpiryField.frame), 295 | textFieldY, 296 | newCVCWidth, 297 | cvcSize.height); 298 | 299 | CGFloat x; 300 | 301 | if (isInitialState) { 302 | x = _placeholderView.frame.size.width; 303 | } 304 | else { 305 | x = _innerView.frame.origin.x; 306 | } 307 | 308 | _innerView.frame = CGRectMake(x, 309 | 0.0, 310 | CGRectGetMaxX(_cardCVCField.frame), 311 | self.frame.size.height); 312 | } 313 | 314 | // State 315 | 316 | - (void)stateCardNumber 317 | { 318 | if ([self.delegate respondsToSelector:@selector(paymentView:didChangeState:)]) { 319 | [self.delegate paymentView:self didChangeState:PKViewStateCardNumber]; 320 | } 321 | 322 | if (!isInitialState) { 323 | // Animate left 324 | isInitialState = YES; 325 | 326 | [UIView animateWithDuration:0.200 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 327 | _cardExpiryField.leftView.alpha = 0.0; 328 | } completion:nil]; 329 | 330 | [UIView animateWithDuration:0.400 331 | delay:0 332 | options:(UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionAllowUserInteraction) 333 | animations:^{ 334 | _innerView.frame = CGRectMake(_placeholderView.frame.size.width, 335 | 0, 336 | _innerView.frame.size.width, 337 | _innerView.frame.size.height); 338 | 339 | _cardNumberField.alpha = 1.0; 340 | } 341 | completion:^(BOOL completed) { 342 | [_cardExpiryField removeFromSuperview]; 343 | [_cardCVCField removeFromSuperview]; 344 | [_cardLastFourField removeFromSuperview]; 345 | }]; 346 | } 347 | 348 | if (self.isFirstResponder) { 349 | [self.cardNumberField becomeFirstResponder]; 350 | } 351 | } 352 | 353 | - (void)stateMeta 354 | { 355 | if ([self.delegate respondsToSelector:@selector(paymentView:didChangeState:)]) { 356 | [self.delegate paymentView:self didChangeState:PKViewStateExpiry]; 357 | } 358 | 359 | isInitialState = NO; 360 | 361 | _cardLastFourField.text = self.cardNumber.lastGroup; 362 | 363 | [_innerView addSubview:_cardLastFourField]; 364 | 365 | [UIView animateWithDuration:0.200 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 366 | _cardExpiryField.leftView.alpha = 1.0; 367 | } completion:nil]; 368 | 369 | CGFloat difference = -(_innerView.frame.size.width - self.frame.size.width + _placeholderView.frame.size.width); 370 | 371 | [UIView animateWithDuration:0.400 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 372 | _cardNumberField.alpha = 0.0; 373 | _innerView.frame = CGRectOffset(_innerView.frame, difference, 0); 374 | } completion:nil]; 375 | 376 | [self.innerView addSubview:_cardExpiryField]; 377 | [self.innerView addSubview:_cardCVCField]; 378 | [_cardExpiryField becomeFirstResponder]; 379 | } 380 | 381 | - (void)stateCardCVC 382 | { 383 | if ([self.delegate respondsToSelector:@selector(paymentView:didChangeState:)]) { 384 | [self.delegate paymentView:self didChangeState:PKViewStateCVC]; 385 | } 386 | 387 | [_cardCVCField becomeFirstResponder]; 388 | } 389 | 390 | - (BOOL)isValid 391 | { 392 | return [self.cardNumber isValid] && [self.cardExpiry isValid] && 393 | [self.cardCVC isValidWithType:self.cardNumber.cardType]; 394 | } 395 | 396 | - (PKCard *)card 397 | { 398 | PKCard *card = [[PKCard alloc] init]; 399 | card.number = [self.cardNumber string]; 400 | card.cvc = [self.cardCVC string]; 401 | card.expMonth = [self.cardExpiry month]; 402 | card.expYear = [self.cardExpiry year]; 403 | 404 | return card; 405 | } 406 | 407 | -(void) setCard:(PKCard *)card { 408 | [self reset]; 409 | PKCardNumber *number = [[PKCardNumber alloc] initWithString:card.number]; 410 | self.cardNumberField.text = [number formattedString]; 411 | [self setPlaceholderToCardType]; 412 | 413 | NSString *month = [NSString stringWithFormat:@"%02d", (int)card.expMonth]; 414 | NSString *year = [[NSString stringWithFormat:@"%lu", (unsigned long)card.expYear] substringFromIndex:2]; 415 | 416 | self.cardExpiryField.text = [NSString stringWithFormat:@"%@/%@", month, year]; 417 | self.cardCVCField.text = card.cvc; 418 | [self stateMeta]; 419 | [self.cardExpiryField resignFirstResponder]; 420 | } 421 | 422 | -(void) reset { 423 | [[self subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; 424 | [self setup]; 425 | [self layoutSubviews]; 426 | } 427 | 428 | - (void)setPlaceholderViewImage:(UIImage *)image 429 | { 430 | if (![_placeholderView.image isEqual:image]) { 431 | __block __unsafe_unretained UIView *previousPlaceholderView = _placeholderView; 432 | [UIView animateWithDuration:0.25 delay:0 433 | options:UIViewAnimationOptionCurveEaseInOut 434 | animations:^{ 435 | _placeholderView.layer.opacity = 0.0; 436 | _placeholderView.layer.transform = CATransform3DMakeScale(1.2, 1.2, 1.2); 437 | } completion:^(BOOL finished) { 438 | [previousPlaceholderView removeFromSuperview]; 439 | }]; 440 | 441 | _placeholderView = nil; 442 | 443 | [self setupPlaceholderView]; 444 | _placeholderView.image = image; 445 | _placeholderView.layer.opacity = 0.0; 446 | _placeholderView.layer.transform = CATransform3DMakeScale(0.8, 0.8, 0.8); 447 | [self insertSubview:_placeholderView belowSubview:previousPlaceholderView]; 448 | [UIView animateWithDuration:0.25 delay:0 449 | options:UIViewAnimationOptionCurveEaseInOut 450 | animations:^{ 451 | _placeholderView.layer.opacity = 1.0; 452 | _placeholderView.layer.transform = CATransform3DIdentity; 453 | } completion:^(BOOL finished) {}]; 454 | } 455 | } 456 | 457 | - (void)setPlaceholderToCVC 458 | { 459 | PKCardNumber *cardNumber = [PKCardNumber cardNumberWithString:_cardNumberField.text]; 460 | PKCardType cardType = [cardNumber cardType]; 461 | 462 | if (cardType == PKCardTypeAmex) { 463 | [self setPlaceholderViewImage:[UIImage imageNamed:@"cvc-amex"]]; 464 | } else { 465 | [self setPlaceholderViewImage:[UIImage imageNamed:@"cvc"]]; 466 | } 467 | } 468 | 469 | - (void)setPlaceholderToCardType 470 | { 471 | PKCardNumber *cardNumber = [PKCardNumber cardNumberWithString:_cardNumberField.text]; 472 | PKCardType cardType = [cardNumber cardType]; 473 | NSString *cardTypeName = @"placeholder"; 474 | 475 | switch (cardType) { 476 | case PKCardTypeAmex: 477 | cardTypeName = @"amex"; 478 | break; 479 | case PKCardTypeDinersClub: 480 | cardTypeName = @"diners"; 481 | break; 482 | case PKCardTypeDiscover: 483 | cardTypeName = @"discover"; 484 | break; 485 | case PKCardTypeJCB: 486 | cardTypeName = @"jcb"; 487 | break; 488 | case PKCardTypeMasterCard: 489 | cardTypeName = @"mastercard"; 490 | break; 491 | case PKCardTypeVisa: 492 | cardTypeName = @"visa"; 493 | break; 494 | default: 495 | break; 496 | } 497 | 498 | if (self.imageStyle == PKViewImageStyleOutline) { 499 | cardTypeName = [NSString stringWithFormat:@"%@-outline", cardTypeName]; 500 | } 501 | 502 | [self setPlaceholderViewImage:[UIImage imageNamed:cardTypeName]]; 503 | } 504 | 505 | // Delegates 506 | 507 | - (void)textFieldDidBeginEditing:(UITextField *)textField 508 | { 509 | if ([textField isEqual:_cardCVCField]) { 510 | [self setPlaceholderToCVC]; 511 | } else { 512 | [self setPlaceholderToCardType]; 513 | } 514 | 515 | if ([textField isEqual:_cardNumberField] && !isInitialState) { 516 | [self stateCardNumber]; 517 | } 518 | } 519 | 520 | - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)replacementString 521 | { 522 | if ([textField isEqual:_cardNumberField]) { 523 | return [self cardNumberFieldShouldChangeCharactersInRange:range replacementString:replacementString]; 524 | } 525 | else if ([textField isEqual:_cardExpiryField]) { 526 | return [self cardExpiryShouldChangeCharactersInRange:range replacementString:replacementString]; 527 | } 528 | else if ([textField isEqual:_cardCVCField]) { 529 | return [self cardCVCShouldChangeCharactersInRange:range replacementString:replacementString]; 530 | } 531 | 532 | return YES; 533 | } 534 | 535 | - (void)pkTextFieldDidBackSpaceWhileTextIsEmpty:(PKTextField *)textField 536 | { 537 | if ([textField isEqual:_cardCVCField]) { 538 | [self.cardExpiryField becomeFirstResponder]; 539 | } 540 | else if ([textField isEqual:_cardExpiryField]) { 541 | [self stateCardNumber]; 542 | } 543 | } 544 | 545 | - (BOOL)cardNumberFieldShouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)replacementString 546 | { 547 | NSString *resultString = [_cardNumberField.text stringByReplacingCharactersInRange:range withString:replacementString]; 548 | resultString = [PKTextField textByRemovingUselessSpacesFromString:resultString]; 549 | PKCardNumber *cardNumber = [PKCardNumber cardNumberWithString:resultString]; 550 | 551 | if (![cardNumber isPartiallyValid]) { 552 | return NO; 553 | } 554 | 555 | if (replacementString.length > 0) { 556 | _cardNumberField.text = [cardNumber formattedStringWithTrail]; 557 | } 558 | else { 559 | _cardNumberField.text = [cardNumber formattedString]; 560 | } 561 | 562 | [self setPlaceholderToCardType]; 563 | 564 | if ([cardNumber isValid]) { 565 | [self textFieldIsValid:_cardNumberField]; 566 | [self stateMeta]; 567 | } else if ([cardNumber isValidLength] && ![cardNumber isValidLuhn]) { 568 | [self textFieldIsInvalid:_cardNumberField withErrors:YES]; 569 | } else if (![cardNumber isValidLength]) { 570 | [self textFieldIsInvalid:_cardNumberField withErrors:NO]; 571 | } 572 | 573 | return NO; 574 | } 575 | 576 | - (BOOL)cardExpiryShouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)replacementString 577 | { 578 | NSString *resultString = [_cardExpiryField.text stringByReplacingCharactersInRange:range withString:replacementString]; 579 | resultString = [PKTextField textByRemovingUselessSpacesFromString:resultString]; 580 | PKCardExpiry *cardExpiry = [PKCardExpiry cardExpiryWithString:resultString]; 581 | 582 | if (![cardExpiry isPartiallyValid]) { 583 | return NO; 584 | } 585 | 586 | // Only support shorthand year 587 | if ([cardExpiry formattedString].length > 5) return NO; 588 | 589 | if (replacementString.length > 0) { 590 | _cardExpiryField.text = [cardExpiry formattedStringWithTrail]; 591 | } else { 592 | _cardExpiryField.text = [cardExpiry formattedString]; 593 | } 594 | 595 | if ([cardExpiry isValid]) { 596 | [self textFieldIsValid:_cardExpiryField]; 597 | [self stateCardCVC]; 598 | } else if ([cardExpiry isValidLength] && ![cardExpiry isValidDate]) { 599 | [self textFieldIsInvalid:_cardExpiryField withErrors:YES]; 600 | } else if (![cardExpiry isValidLength]) { 601 | [self textFieldIsInvalid:_cardExpiryField withErrors:NO]; 602 | } 603 | 604 | return NO; 605 | } 606 | 607 | - (BOOL)cardCVCShouldChangeCharactersInRange: (NSRange)range replacementString:(NSString *)replacementString 608 | { 609 | NSString *resultString = [_cardCVCField.text stringByReplacingCharactersInRange:range withString:replacementString]; 610 | resultString = [PKTextField textByRemovingUselessSpacesFromString:resultString]; 611 | PKCardCVC *cardCVC = [PKCardCVC cardCVCWithString:resultString]; 612 | PKCardType cardType = [[PKCardNumber cardNumberWithString:_cardNumberField.text] cardType]; 613 | 614 | // Restrict length 615 | if (![cardCVC isPartiallyValidWithType:cardType]) { 616 | return NO; 617 | } 618 | 619 | // Strip non-digits 620 | _cardCVCField.text = [cardCVC string]; 621 | 622 | if ([cardCVC isValidWithType:cardType]) { 623 | [self textFieldIsValid:_cardCVCField]; 624 | } else { 625 | [self textFieldIsInvalid:_cardCVCField withErrors:NO]; 626 | } 627 | 628 | return NO; 629 | } 630 | 631 | // Validations 632 | 633 | - (void)checkValid 634 | { 635 | if ([self isValid]) { 636 | isValidState = YES; 637 | 638 | if ([self.delegate respondsToSelector:@selector(paymentView:withCard:isValid:)]) { 639 | [self.delegate paymentView:self withCard:self.card isValid:YES]; 640 | } 641 | } else if (![self isValid] && isValidState) { 642 | isValidState = NO; 643 | 644 | if ([self.delegate respondsToSelector:@selector(paymentView:withCard:isValid:)]) { 645 | [self.delegate paymentView:self withCard:self.card isValid:NO]; 646 | } 647 | } 648 | } 649 | 650 | - (void)textFieldIsValid:(UITextField *)textField { 651 | textField.textColor = _defaultTextAttributes[NSForegroundColorAttributeName]; 652 | [self checkValid]; 653 | } 654 | 655 | - (void)textFieldIsInvalid:(UITextField *)textField withErrors:(BOOL)errors { 656 | if (errors) { 657 | textField.textColor = kPKRedColor; 658 | } else { 659 | textField.textColor = _defaultTextAttributes[NSForegroundColorAttributeName];; 660 | } 661 | 662 | [self checkValid]; 663 | } 664 | 665 | #pragma mark - 666 | #pragma mark UIResponder 667 | - (UIResponder *)firstResponderField; 668 | { 669 | NSArray *responders = @[self.cardNumberField, self.cardExpiryField, self.cardCVCField]; 670 | for (UIResponder *responder in responders) { 671 | if (responder.isFirstResponder) { 672 | return responder; 673 | } 674 | } 675 | 676 | return nil; 677 | } 678 | 679 | - (PKTextField *)firstInvalidField; 680 | { 681 | if (![[PKCardNumber cardNumberWithString:self.cardNumberField.text] isValid]) { 682 | return self.cardNumberField; 683 | } 684 | else if (![[PKCardExpiry cardExpiryWithString:self.cardExpiryField.text] isValid]) { 685 | return self.cardExpiryField; 686 | } 687 | else if (![[PKCardCVC cardCVCWithString:self.cardCVCField.text] isValid]) { 688 | return self.cardCVCField; 689 | } 690 | 691 | return nil; 692 | } 693 | 694 | - (PKTextField *)nextFirstResponder; 695 | { 696 | if (self.firstInvalidField) { 697 | return self.firstInvalidField; 698 | } 699 | 700 | return self.cardCVCField; 701 | } 702 | 703 | - (BOOL)isFirstResponder; 704 | { 705 | return self.firstResponderField.isFirstResponder; 706 | } 707 | 708 | - (BOOL)canBecomeFirstResponder; 709 | { 710 | return self.nextFirstResponder.canBecomeFirstResponder; 711 | } 712 | 713 | - (BOOL)becomeFirstResponder; 714 | { 715 | return [self.nextFirstResponder becomeFirstResponder]; 716 | } 717 | 718 | - (BOOL)canResignFirstResponder; 719 | { 720 | return self.firstResponderField.canResignFirstResponder; 721 | } 722 | 723 | - (BOOL)resignFirstResponder; 724 | { 725 | return [self.firstResponderField resignFirstResponder]; 726 | } 727 | 728 | @end -------------------------------------------------------------------------------- /PaymentKit Example/PaymentKit Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 161409A31871300900387BB8 /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 161409A21871300900387BB8 /* Storyboard.storyboard */; }; 11 | 16B159AF187A0376000D3033 /* amex-outline@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 16B159AE187A0376000D3033 /* amex-outline@2x.png */; }; 12 | 16B159B1187A0385000D3033 /* jcb-outline@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 16B159B0187A0385000D3033 /* jcb-outline@2x.png */; }; 13 | 16B159B3187A038A000D3033 /* mastercard-outline@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 16B159B2187A038A000D3033 /* mastercard-outline@2x.png */; }; 14 | 16B159B5187A0390000D3033 /* placeholder-outline@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 16B159B4187A0390000D3033 /* placeholder-outline@2x.png */; }; 15 | 16B159B7187A0395000D3033 /* visa-outline@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 16B159B6187A0395000D3033 /* visa-outline@2x.png */; }; 16 | 16F373391875698F00290ABF /* diners@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 16F373381875698F00290ABF /* diners@2x.png */; }; 17 | 16F3733B18756A5F00290ABF /* jcb@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 16F3733A18756A5F00290ABF /* jcb@2x.png */; }; 18 | 4C332B4E16FA923E009C782D /* PKTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C332B4D16FA923E009C782D /* PKTextField.m */; }; 19 | FA007D1F16FA3B82006DD86E /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA6F1A5916C19BF700835C75 /* QuartzCore.framework */; }; 20 | FA06D14C16AFC0AA00C46291 /* PKView.m in Sources */ = {isa = PBXBuildFile; fileRef = FA06D14B16AFC0AA00C46291 /* PKView.m */; }; 21 | FA2A74A016BB1EDD00AF0078 /* PKCard.m in Sources */ = {isa = PBXBuildFile; fileRef = FA2A749F16BB1EDD00AF0078 /* PKCard.m */; }; 22 | FA3A8C5A16D208E300A9C346 /* PKUSAddressZip.m in Sources */ = {isa = PBXBuildFile; fileRef = FA3A8C5916D208E300A9C346 /* PKUSAddressZip.m */; }; 23 | FA45AC7116AE350D0003A41D /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA45AC7016AE350D0003A41D /* UIKit.framework */; }; 24 | FA45AC7316AE350D0003A41D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA45AC7216AE350D0003A41D /* Foundation.framework */; }; 25 | FA45AC7516AE350D0003A41D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA45AC7416AE350D0003A41D /* CoreGraphics.framework */; }; 26 | FA45AC7B16AE350D0003A41D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FA45AC7916AE350D0003A41D /* InfoPlist.strings */; }; 27 | FA45AC7D16AE350D0003A41D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = FA45AC7C16AE350D0003A41D /* main.m */; }; 28 | FA45AC8116AE350D0003A41D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FA45AC8016AE350D0003A41D /* AppDelegate.m */; }; 29 | FA45AC8316AE350D0003A41D /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = FA45AC8216AE350D0003A41D /* Default.png */; }; 30 | FA45AC8516AE350D0003A41D /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA45AC8416AE350D0003A41D /* Default@2x.png */; }; 31 | FA45AC8716AE350E0003A41D /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA45AC8616AE350E0003A41D /* Default-568h@2x.png */; }; 32 | FA45AC8A16AE350E0003A41D /* PaymentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FA45AC8916AE350E0003A41D /* PaymentViewController.m */; }; 33 | FA45ACA416AF1EE80003A41D /* PKCardNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = FA45ACA316AF1EE80003A41D /* PKCardNumber.m */; }; 34 | FA45ACA716AF33750003A41D /* PKCardCVC.m in Sources */ = {isa = PBXBuildFile; fileRef = FA45ACA616AF33750003A41D /* PKCardCVC.m */; }; 35 | FA45ACAC16AF37420003A41D /* PKCardExpiry.m in Sources */ = {isa = PBXBuildFile; fileRef = FA45ACAB16AF37420003A41D /* PKCardExpiry.m */; }; 36 | FA6A2F8C16C2D6F400915AEB /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA6A2F8B16C2D6F400915AEB /* SenTestingKit.framework */; }; 37 | FA6A2F8D16C2D6F400915AEB /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA45AC7016AE350D0003A41D /* UIKit.framework */; }; 38 | FA6A2F8E16C2D6F400915AEB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA45AC7216AE350D0003A41D /* Foundation.framework */; }; 39 | FA6A2F9416C2D6F400915AEB /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FA6A2F9216C2D6F400915AEB /* InfoPlist.strings */; }; 40 | FA6A2F9716C2D6F400915AEB /* PKTest.m in Sources */ = {isa = PBXBuildFile; fileRef = FA6A2F9616C2D6F400915AEB /* PKTest.m */; }; 41 | FA6A2F9E16C2D89600915AEB /* PKCardNumberTest.m in Sources */ = {isa = PBXBuildFile; fileRef = FA6A2F9D16C2D89600915AEB /* PKCardNumberTest.m */; }; 42 | FA6A2F9F16C2D9F000915AEB /* PKCardNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = FA45ACA316AF1EE80003A41D /* PKCardNumber.m */; }; 43 | FA6A2FA216C2E00E00915AEB /* PKCardCVCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = FA6A2FA116C2E00E00915AEB /* PKCardCVCTest.m */; }; 44 | FA6A2FA316C2E01500915AEB /* PKCardCVC.m in Sources */ = {isa = PBXBuildFile; fileRef = FA45ACA616AF33750003A41D /* PKCardCVC.m */; }; 45 | FA6A2FA616C2E1F400915AEB /* PKCardExpiryTest.m in Sources */ = {isa = PBXBuildFile; fileRef = FA6A2FA516C2E1F400915AEB /* PKCardExpiryTest.m */; }; 46 | FA6A2FA716C2E20200915AEB /* PKCardExpiry.m in Sources */ = {isa = PBXBuildFile; fileRef = FA45ACAB16AF37420003A41D /* PKCardExpiry.m */; }; 47 | FA6F1A5E16C1B21000835C75 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FA6F1A5C16C1B21000835C75 /* ViewController.m */; }; 48 | FAA3610816C9F21C00049C6F /* amex.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA360F616C9F21C00049C6F /* amex.png */; }; 49 | FAA3610916C9F21C00049C6F /* amex@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA360F716C9F21C00049C6F /* amex@2x.png */; }; 50 | FAA3610A16C9F21C00049C6F /* cvc-amex.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA360F816C9F21C00049C6F /* cvc-amex.png */; }; 51 | FAA3610B16C9F21C00049C6F /* cvc-amex@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA360F916C9F21C00049C6F /* cvc-amex@2x.png */; }; 52 | FAA3610C16C9F21C00049C6F /* cvc.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA360FA16C9F21C00049C6F /* cvc.png */; }; 53 | FAA3610D16C9F21C00049C6F /* cvc@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA360FB16C9F21C00049C6F /* cvc@2x.png */; }; 54 | FAA3610E16C9F21C00049C6F /* diners.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA360FC16C9F21C00049C6F /* diners.png */; }; 55 | FAA3611016C9F21C00049C6F /* discover.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA360FE16C9F21C00049C6F /* discover.png */; }; 56 | FAA3611116C9F21C00049C6F /* discover@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA360FF16C9F21C00049C6F /* discover@2x.png */; }; 57 | FAA3611216C9F21C00049C6F /* jcb.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA3610016C9F21C00049C6F /* jcb.png */; }; 58 | FAA3611416C9F21C00049C6F /* mastercard.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA3610216C9F21C00049C6F /* mastercard.png */; }; 59 | FAA3611516C9F21C00049C6F /* mastercard@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA3610316C9F21C00049C6F /* mastercard@2x.png */; }; 60 | FAA3611616C9F21C00049C6F /* placeholder.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA3610416C9F21C00049C6F /* placeholder.png */; }; 61 | FAA3611716C9F21C00049C6F /* placeholder@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA3610516C9F21C00049C6F /* placeholder@2x.png */; }; 62 | FAA3611816C9F21C00049C6F /* visa.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA3610616C9F21C00049C6F /* visa.png */; }; 63 | FAA3611916C9F21C00049C6F /* visa@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FAA3610716C9F21C00049C6F /* visa@2x.png */; }; 64 | FAADE6CF16BC44D9006FF4D1 /* PKAddressZip.m in Sources */ = {isa = PBXBuildFile; fileRef = FAADE6CE16BC44D9006FF4D1 /* PKAddressZip.m */; }; 65 | FADC4C1D16E1B3080048064A /* PaymentKit Test-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = FA6A2F9116C2D6F400915AEB /* PaymentKit Test-Info.plist */; }; 66 | /* End PBXBuildFile section */ 67 | 68 | /* Begin PBXFileReference section */ 69 | 161409A21871300900387BB8 /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = ""; }; 70 | 16B159AE187A0376000D3033 /* amex-outline@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "amex-outline@2x.png"; sourceTree = ""; }; 71 | 16B159B0187A0385000D3033 /* jcb-outline@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "jcb-outline@2x.png"; sourceTree = ""; }; 72 | 16B159B2187A038A000D3033 /* mastercard-outline@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "mastercard-outline@2x.png"; sourceTree = ""; }; 73 | 16B159B4187A0390000D3033 /* placeholder-outline@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "placeholder-outline@2x.png"; sourceTree = ""; }; 74 | 16B159B6187A0395000D3033 /* visa-outline@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "visa-outline@2x.png"; sourceTree = ""; }; 75 | 16F373381875698F00290ABF /* diners@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "diners@2x.png"; sourceTree = ""; }; 76 | 16F3733A18756A5F00290ABF /* jcb@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "jcb@2x.png"; sourceTree = ""; }; 77 | 4C332B4C16FA923E009C782D /* PKTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PKTextField.h; sourceTree = ""; }; 78 | 4C332B4D16FA923E009C782D /* PKTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PKTextField.m; sourceTree = ""; }; 79 | FA06D14A16AFC0AA00C46291 /* PKView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PKView.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 80 | FA06D14B16AFC0AA00C46291 /* PKView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PKView.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 81 | FA2A749E16BB1EDD00AF0078 /* PKCard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PKCard.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 82 | FA2A749F16BB1EDD00AF0078 /* PKCard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PKCard.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 83 | FA3A8C5816D208E300A9C346 /* PKUSAddressZip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PKUSAddressZip.h; sourceTree = ""; }; 84 | FA3A8C5916D208E300A9C346 /* PKUSAddressZip.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PKUSAddressZip.m; sourceTree = ""; }; 85 | FA45AC6C16AE350D0003A41D /* PaymentKit Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "PaymentKit Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 86 | FA45AC7016AE350D0003A41D /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 87 | FA45AC7216AE350D0003A41D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 88 | FA45AC7416AE350D0003A41D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 89 | FA45AC7816AE350D0003A41D /* PaymentKit Example-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PaymentKit Example-Info.plist"; sourceTree = ""; }; 90 | FA45AC7A16AE350D0003A41D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; lineEnding = 0; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.simpleColoring; }; 91 | FA45AC7C16AE350D0003A41D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = main.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 92 | FA45AC7E16AE350D0003A41D /* PaymentKit Example-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "PaymentKit Example-Prefix.pch"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 93 | FA45AC7F16AE350D0003A41D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = AppDelegate.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 94 | FA45AC8016AE350D0003A41D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = AppDelegate.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 95 | FA45AC8216AE350D0003A41D /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 96 | FA45AC8416AE350D0003A41D /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 97 | FA45AC8616AE350E0003A41D /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 98 | FA45AC8816AE350E0003A41D /* PaymentViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PaymentViewController.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 99 | FA45AC8916AE350E0003A41D /* PaymentViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PaymentViewController.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 100 | FA45ACA216AF1EE80003A41D /* PKCardNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PKCardNumber.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 101 | FA45ACA316AF1EE80003A41D /* PKCardNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PKCardNumber.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 102 | FA45ACA516AF33750003A41D /* PKCardCVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PKCardCVC.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 103 | FA45ACA616AF33750003A41D /* PKCardCVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PKCardCVC.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 104 | FA45ACA916AF367B0003A41D /* PKCardType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PKCardType.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 105 | FA45ACAA16AF37420003A41D /* PKCardExpiry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PKCardExpiry.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 106 | FA45ACAB16AF37420003A41D /* PKCardExpiry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PKCardExpiry.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 107 | FA6A2F8A16C2D6F400915AEB /* PaymentKit Test.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "PaymentKit Test.octest"; sourceTree = BUILT_PRODUCTS_DIR; }; 108 | FA6A2F8B16C2D6F400915AEB /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; 109 | FA6A2F9116C2D6F400915AEB /* PaymentKit Test-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PaymentKit Test-Info.plist"; sourceTree = ""; }; 110 | FA6A2F9316C2D6F400915AEB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; lineEnding = 0; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.simpleColoring; }; 111 | FA6A2F9516C2D6F400915AEB /* PKTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PKTest.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 112 | FA6A2F9616C2D6F400915AEB /* PKTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PKTest.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 113 | FA6A2F9816C2D6F400915AEB /* PaymentKit Test-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "PaymentKit Test-Prefix.pch"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 114 | FA6A2F9C16C2D89600915AEB /* PKCardNumberTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PKCardNumberTest.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 115 | FA6A2F9D16C2D89600915AEB /* PKCardNumberTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PKCardNumberTest.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 116 | FA6A2FA016C2E00E00915AEB /* PKCardCVCTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PKCardCVCTest.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 117 | FA6A2FA116C2E00E00915AEB /* PKCardCVCTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PKCardCVCTest.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 118 | FA6A2FA416C2E1F400915AEB /* PKCardExpiryTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PKCardExpiryTest.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 119 | FA6A2FA516C2E1F400915AEB /* PKCardExpiryTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PKCardExpiryTest.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 120 | FA6F1A5916C19BF700835C75 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 121 | FA6F1A5B16C1B21000835C75 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ViewController.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 122 | FA6F1A5C16C1B21000835C75 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ViewController.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 123 | FAA360F616C9F21C00049C6F /* amex.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = amex.png; sourceTree = ""; }; 124 | FAA360F716C9F21C00049C6F /* amex@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "amex@2x.png"; sourceTree = ""; }; 125 | FAA360F816C9F21C00049C6F /* cvc-amex.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cvc-amex.png"; sourceTree = ""; }; 126 | FAA360F916C9F21C00049C6F /* cvc-amex@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cvc-amex@2x.png"; sourceTree = ""; }; 127 | FAA360FA16C9F21C00049C6F /* cvc.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cvc.png; sourceTree = ""; }; 128 | FAA360FB16C9F21C00049C6F /* cvc@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cvc@2x.png"; sourceTree = ""; }; 129 | FAA360FC16C9F21C00049C6F /* diners.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = diners.png; sourceTree = ""; }; 130 | FAA360FE16C9F21C00049C6F /* discover.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = discover.png; sourceTree = ""; }; 131 | FAA360FF16C9F21C00049C6F /* discover@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "discover@2x.png"; sourceTree = ""; }; 132 | FAA3610016C9F21C00049C6F /* jcb.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = jcb.png; sourceTree = ""; }; 133 | FAA3610216C9F21C00049C6F /* mastercard.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = mastercard.png; sourceTree = ""; }; 134 | FAA3610316C9F21C00049C6F /* mastercard@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "mastercard@2x.png"; sourceTree = ""; }; 135 | FAA3610416C9F21C00049C6F /* placeholder.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = placeholder.png; sourceTree = ""; }; 136 | FAA3610516C9F21C00049C6F /* placeholder@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "placeholder@2x.png"; sourceTree = ""; }; 137 | FAA3610616C9F21C00049C6F /* visa.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = visa.png; sourceTree = ""; }; 138 | FAA3610716C9F21C00049C6F /* visa@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "visa@2x.png"; sourceTree = ""; }; 139 | FAADE6CD16BC44D9006FF4D1 /* PKAddressZip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PKAddressZip.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 140 | FAADE6CE16BC44D9006FF4D1 /* PKAddressZip.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PKAddressZip.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 141 | /* End PBXFileReference section */ 142 | 143 | /* Begin PBXFrameworksBuildPhase section */ 144 | FA45AC6916AE350D0003A41D /* Frameworks */ = { 145 | isa = PBXFrameworksBuildPhase; 146 | buildActionMask = 2147483647; 147 | files = ( 148 | FA007D1F16FA3B82006DD86E /* QuartzCore.framework in Frameworks */, 149 | FA45AC7116AE350D0003A41D /* UIKit.framework in Frameworks */, 150 | FA45AC7316AE350D0003A41D /* Foundation.framework in Frameworks */, 151 | FA45AC7516AE350D0003A41D /* CoreGraphics.framework in Frameworks */, 152 | ); 153 | runOnlyForDeploymentPostprocessing = 0; 154 | }; 155 | FA6A2F8616C2D6F400915AEB /* Frameworks */ = { 156 | isa = PBXFrameworksBuildPhase; 157 | buildActionMask = 2147483647; 158 | files = ( 159 | FA6A2F8C16C2D6F400915AEB /* SenTestingKit.framework in Frameworks */, 160 | FA6A2F8D16C2D6F400915AEB /* UIKit.framework in Frameworks */, 161 | FA6A2F8E16C2D6F400915AEB /* Foundation.framework in Frameworks */, 162 | ); 163 | runOnlyForDeploymentPostprocessing = 0; 164 | }; 165 | /* End PBXFrameworksBuildPhase section */ 166 | 167 | /* Begin PBXGroup section */ 168 | FA45AC6116AE350D0003A41D = { 169 | isa = PBXGroup; 170 | children = ( 171 | FA45AC9616AE35210003A41D /* PaymentKit */, 172 | FA45AC7616AE350D0003A41D /* PaymentKit Example */, 173 | FA6A2F8F16C2D6F400915AEB /* PaymentKit Test */, 174 | FA45AC6F16AE350D0003A41D /* Frameworks */, 175 | FA45AC6D16AE350D0003A41D /* Products */, 176 | ); 177 | sourceTree = ""; 178 | }; 179 | FA45AC6D16AE350D0003A41D /* Products */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | FA45AC6C16AE350D0003A41D /* PaymentKit Example.app */, 183 | FA6A2F8A16C2D6F400915AEB /* PaymentKit Test.octest */, 184 | ); 185 | name = Products; 186 | sourceTree = ""; 187 | }; 188 | FA45AC6F16AE350D0003A41D /* Frameworks */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | FA6F1A5916C19BF700835C75 /* QuartzCore.framework */, 192 | FA45AC7016AE350D0003A41D /* UIKit.framework */, 193 | FA45AC7216AE350D0003A41D /* Foundation.framework */, 194 | FA45AC7416AE350D0003A41D /* CoreGraphics.framework */, 195 | FA6A2F8B16C2D6F400915AEB /* SenTestingKit.framework */, 196 | ); 197 | name = Frameworks; 198 | sourceTree = ""; 199 | }; 200 | FA45AC7616AE350D0003A41D /* PaymentKit Example */ = { 201 | isa = PBXGroup; 202 | children = ( 203 | FA45AC7F16AE350D0003A41D /* AppDelegate.h */, 204 | FA45AC8016AE350D0003A41D /* AppDelegate.m */, 205 | 161409A21871300900387BB8 /* Storyboard.storyboard */, 206 | FA45AC8816AE350E0003A41D /* PaymentViewController.h */, 207 | FA45AC8916AE350E0003A41D /* PaymentViewController.m */, 208 | FA45AC7716AE350D0003A41D /* Supporting Files */, 209 | FA6F1A5B16C1B21000835C75 /* ViewController.h */, 210 | FA6F1A5C16C1B21000835C75 /* ViewController.m */, 211 | ); 212 | path = "PaymentKit Example"; 213 | sourceTree = ""; 214 | }; 215 | FA45AC7716AE350D0003A41D /* Supporting Files */ = { 216 | isa = PBXGroup; 217 | children = ( 218 | FA45AC7816AE350D0003A41D /* PaymentKit Example-Info.plist */, 219 | FA45AC7916AE350D0003A41D /* InfoPlist.strings */, 220 | FA45AC7C16AE350D0003A41D /* main.m */, 221 | FA45AC7E16AE350D0003A41D /* PaymentKit Example-Prefix.pch */, 222 | FA45AC8216AE350D0003A41D /* Default.png */, 223 | FA45AC8416AE350D0003A41D /* Default@2x.png */, 224 | FA45AC8616AE350E0003A41D /* Default-568h@2x.png */, 225 | ); 226 | name = "Supporting Files"; 227 | sourceTree = ""; 228 | }; 229 | FA45AC9616AE35210003A41D /* PaymentKit */ = { 230 | isa = PBXGroup; 231 | children = ( 232 | FAA360F416C9F21C00049C6F /* Resources */, 233 | FA45ACA216AF1EE80003A41D /* PKCardNumber.h */, 234 | FA45ACA316AF1EE80003A41D /* PKCardNumber.m */, 235 | FA45ACA516AF33750003A41D /* PKCardCVC.h */, 236 | FA45ACA616AF33750003A41D /* PKCardCVC.m */, 237 | FA45ACA916AF367B0003A41D /* PKCardType.h */, 238 | FA45ACAA16AF37420003A41D /* PKCardExpiry.h */, 239 | FA45ACAB16AF37420003A41D /* PKCardExpiry.m */, 240 | FA06D14A16AFC0AA00C46291 /* PKView.h */, 241 | FA06D14B16AFC0AA00C46291 /* PKView.m */, 242 | FA2A749E16BB1EDD00AF0078 /* PKCard.h */, 243 | FA2A749F16BB1EDD00AF0078 /* PKCard.m */, 244 | FAADE6CD16BC44D9006FF4D1 /* PKAddressZip.h */, 245 | FAADE6CE16BC44D9006FF4D1 /* PKAddressZip.m */, 246 | FA3A8C5816D208E300A9C346 /* PKUSAddressZip.h */, 247 | FA3A8C5916D208E300A9C346 /* PKUSAddressZip.m */, 248 | 4C332B4C16FA923E009C782D /* PKTextField.h */, 249 | 4C332B4D16FA923E009C782D /* PKTextField.m */, 250 | ); 251 | name = PaymentKit; 252 | path = ../PaymentKit; 253 | sourceTree = ""; 254 | }; 255 | FA6A2F8F16C2D6F400915AEB /* PaymentKit Test */ = { 256 | isa = PBXGroup; 257 | children = ( 258 | FA6A2F9516C2D6F400915AEB /* PKTest.h */, 259 | FA6A2F9616C2D6F400915AEB /* PKTest.m */, 260 | FA6A2F9016C2D6F400915AEB /* Supporting Files */, 261 | FA6A2F9C16C2D89600915AEB /* PKCardNumberTest.h */, 262 | FA6A2F9D16C2D89600915AEB /* PKCardNumberTest.m */, 263 | FA6A2FA016C2E00E00915AEB /* PKCardCVCTest.h */, 264 | FA6A2FA116C2E00E00915AEB /* PKCardCVCTest.m */, 265 | FA6A2FA416C2E1F400915AEB /* PKCardExpiryTest.h */, 266 | FA6A2FA516C2E1F400915AEB /* PKCardExpiryTest.m */, 267 | ); 268 | path = "PaymentKit Test"; 269 | sourceTree = ""; 270 | }; 271 | FA6A2F9016C2D6F400915AEB /* Supporting Files */ = { 272 | isa = PBXGroup; 273 | children = ( 274 | FA6A2F9116C2D6F400915AEB /* PaymentKit Test-Info.plist */, 275 | FA6A2F9216C2D6F400915AEB /* InfoPlist.strings */, 276 | FA6A2F9816C2D6F400915AEB /* PaymentKit Test-Prefix.pch */, 277 | ); 278 | name = "Supporting Files"; 279 | sourceTree = ""; 280 | }; 281 | FAA360F416C9F21C00049C6F /* Resources */ = { 282 | isa = PBXGroup; 283 | children = ( 284 | FAA360F516C9F21C00049C6F /* Cards */, 285 | ); 286 | path = Resources; 287 | sourceTree = ""; 288 | }; 289 | FAA360F516C9F21C00049C6F /* Cards */ = { 290 | isa = PBXGroup; 291 | children = ( 292 | FAA360F616C9F21C00049C6F /* amex.png */, 293 | FAA360F716C9F21C00049C6F /* amex@2x.png */, 294 | 16B159AE187A0376000D3033 /* amex-outline@2x.png */, 295 | FAA360F816C9F21C00049C6F /* cvc-amex.png */, 296 | FAA360F916C9F21C00049C6F /* cvc-amex@2x.png */, 297 | FAA360FA16C9F21C00049C6F /* cvc.png */, 298 | FAA360FB16C9F21C00049C6F /* cvc@2x.png */, 299 | FAA360FC16C9F21C00049C6F /* diners.png */, 300 | 16F373381875698F00290ABF /* diners@2x.png */, 301 | FAA360FE16C9F21C00049C6F /* discover.png */, 302 | FAA360FF16C9F21C00049C6F /* discover@2x.png */, 303 | FAA3610016C9F21C00049C6F /* jcb.png */, 304 | 16F3733A18756A5F00290ABF /* jcb@2x.png */, 305 | 16B159B0187A0385000D3033 /* jcb-outline@2x.png */, 306 | FAA3610216C9F21C00049C6F /* mastercard.png */, 307 | FAA3610316C9F21C00049C6F /* mastercard@2x.png */, 308 | 16B159B2187A038A000D3033 /* mastercard-outline@2x.png */, 309 | FAA3610416C9F21C00049C6F /* placeholder.png */, 310 | FAA3610516C9F21C00049C6F /* placeholder@2x.png */, 311 | 16B159B4187A0390000D3033 /* placeholder-outline@2x.png */, 312 | FAA3610616C9F21C00049C6F /* visa.png */, 313 | FAA3610716C9F21C00049C6F /* visa@2x.png */, 314 | 16B159B6187A0395000D3033 /* visa-outline@2x.png */, 315 | ); 316 | path = Cards; 317 | sourceTree = ""; 318 | }; 319 | /* End PBXGroup section */ 320 | 321 | /* Begin PBXNativeTarget section */ 322 | FA45AC6B16AE350D0003A41D /* PaymentKit Example */ = { 323 | isa = PBXNativeTarget; 324 | buildConfigurationList = FA45AC9316AE350E0003A41D /* Build configuration list for PBXNativeTarget "PaymentKit Example" */; 325 | buildPhases = ( 326 | FA45AC6816AE350D0003A41D /* Sources */, 327 | FA45AC6916AE350D0003A41D /* Frameworks */, 328 | FA45AC6A16AE350D0003A41D /* Resources */, 329 | ); 330 | buildRules = ( 331 | ); 332 | dependencies = ( 333 | ); 334 | name = "PaymentKit Example"; 335 | productName = "PaymentKit Example"; 336 | productReference = FA45AC6C16AE350D0003A41D /* PaymentKit Example.app */; 337 | productType = "com.apple.product-type.application"; 338 | }; 339 | FA6A2F8916C2D6F400915AEB /* PaymentKit Test */ = { 340 | isa = PBXNativeTarget; 341 | buildConfigurationList = FA6A2F9B16C2D6F400915AEB /* Build configuration list for PBXNativeTarget "PaymentKit Test" */; 342 | buildPhases = ( 343 | FA6A2F8516C2D6F400915AEB /* Sources */, 344 | FA6A2F8616C2D6F400915AEB /* Frameworks */, 345 | FA6A2F8716C2D6F400915AEB /* Resources */, 346 | FA6A2F8816C2D6F400915AEB /* ShellScript */, 347 | ); 348 | buildRules = ( 349 | ); 350 | dependencies = ( 351 | ); 352 | name = "PaymentKit Test"; 353 | productName = "PaymentKit Test"; 354 | productReference = FA6A2F8A16C2D6F400915AEB /* PaymentKit Test.octest */; 355 | productType = "com.apple.product-type.bundle"; 356 | }; 357 | /* End PBXNativeTarget section */ 358 | 359 | /* Begin PBXProject section */ 360 | FA45AC6316AE350D0003A41D /* Project object */ = { 361 | isa = PBXProject; 362 | attributes = { 363 | LastUpgradeCheck = 0450; 364 | ORGANIZATIONNAME = Stripe; 365 | }; 366 | buildConfigurationList = FA45AC6616AE350D0003A41D /* Build configuration list for PBXProject "PaymentKit Example" */; 367 | compatibilityVersion = "Xcode 3.2"; 368 | developmentRegion = English; 369 | hasScannedForEncodings = 0; 370 | knownRegions = ( 371 | en, 372 | ); 373 | mainGroup = FA45AC6116AE350D0003A41D; 374 | productRefGroup = FA45AC6D16AE350D0003A41D /* Products */; 375 | projectDirPath = ""; 376 | projectRoot = ""; 377 | targets = ( 378 | FA45AC6B16AE350D0003A41D /* PaymentKit Example */, 379 | FA6A2F8916C2D6F400915AEB /* PaymentKit Test */, 380 | ); 381 | }; 382 | /* End PBXProject section */ 383 | 384 | /* Begin PBXResourcesBuildPhase section */ 385 | FA45AC6A16AE350D0003A41D /* Resources */ = { 386 | isa = PBXResourcesBuildPhase; 387 | buildActionMask = 2147483647; 388 | files = ( 389 | 16B159B1187A0385000D3033 /* jcb-outline@2x.png in Resources */, 390 | 16B159AF187A0376000D3033 /* amex-outline@2x.png in Resources */, 391 | FA45AC7B16AE350D0003A41D /* InfoPlist.strings in Resources */, 392 | FA45AC8316AE350D0003A41D /* Default.png in Resources */, 393 | FA45AC8516AE350D0003A41D /* Default@2x.png in Resources */, 394 | FA45AC8716AE350E0003A41D /* Default-568h@2x.png in Resources */, 395 | FAA3610816C9F21C00049C6F /* amex.png in Resources */, 396 | FAA3610916C9F21C00049C6F /* amex@2x.png in Resources */, 397 | 16B159B7187A0395000D3033 /* visa-outline@2x.png in Resources */, 398 | FAA3610A16C9F21C00049C6F /* cvc-amex.png in Resources */, 399 | 16B159B3187A038A000D3033 /* mastercard-outline@2x.png in Resources */, 400 | 16F373391875698F00290ABF /* diners@2x.png in Resources */, 401 | 161409A31871300900387BB8 /* Storyboard.storyboard in Resources */, 402 | 16F3733B18756A5F00290ABF /* jcb@2x.png in Resources */, 403 | FAA3610B16C9F21C00049C6F /* cvc-amex@2x.png in Resources */, 404 | FAA3610C16C9F21C00049C6F /* cvc.png in Resources */, 405 | FAA3610D16C9F21C00049C6F /* cvc@2x.png in Resources */, 406 | FAA3610E16C9F21C00049C6F /* diners.png in Resources */, 407 | FAA3611016C9F21C00049C6F /* discover.png in Resources */, 408 | FAA3611116C9F21C00049C6F /* discover@2x.png in Resources */, 409 | FAA3611216C9F21C00049C6F /* jcb.png in Resources */, 410 | FAA3611416C9F21C00049C6F /* mastercard.png in Resources */, 411 | 16B159B5187A0390000D3033 /* placeholder-outline@2x.png in Resources */, 412 | FAA3611516C9F21C00049C6F /* mastercard@2x.png in Resources */, 413 | FAA3611616C9F21C00049C6F /* placeholder.png in Resources */, 414 | FAA3611716C9F21C00049C6F /* placeholder@2x.png in Resources */, 415 | FAA3611816C9F21C00049C6F /* visa.png in Resources */, 416 | FAA3611916C9F21C00049C6F /* visa@2x.png in Resources */, 417 | ); 418 | runOnlyForDeploymentPostprocessing = 0; 419 | }; 420 | FA6A2F8716C2D6F400915AEB /* Resources */ = { 421 | isa = PBXResourcesBuildPhase; 422 | buildActionMask = 2147483647; 423 | files = ( 424 | FA6A2F9416C2D6F400915AEB /* InfoPlist.strings in Resources */, 425 | FADC4C1D16E1B3080048064A /* PaymentKit Test-Info.plist in Resources */, 426 | ); 427 | runOnlyForDeploymentPostprocessing = 0; 428 | }; 429 | /* End PBXResourcesBuildPhase section */ 430 | 431 | /* Begin PBXShellScriptBuildPhase section */ 432 | FA6A2F8816C2D6F400915AEB /* ShellScript */ = { 433 | isa = PBXShellScriptBuildPhase; 434 | buildActionMask = 2147483647; 435 | files = ( 436 | ); 437 | inputPaths = ( 438 | ); 439 | outputPaths = ( 440 | ); 441 | runOnlyForDeploymentPostprocessing = 0; 442 | shellPath = /bin/sh; 443 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 444 | }; 445 | /* End PBXShellScriptBuildPhase section */ 446 | 447 | /* Begin PBXSourcesBuildPhase section */ 448 | FA45AC6816AE350D0003A41D /* Sources */ = { 449 | isa = PBXSourcesBuildPhase; 450 | buildActionMask = 2147483647; 451 | files = ( 452 | FA45AC7D16AE350D0003A41D /* main.m in Sources */, 453 | FA45AC8116AE350D0003A41D /* AppDelegate.m in Sources */, 454 | FA45AC8A16AE350E0003A41D /* PaymentViewController.m in Sources */, 455 | FA45ACA416AF1EE80003A41D /* PKCardNumber.m in Sources */, 456 | FA45ACA716AF33750003A41D /* PKCardCVC.m in Sources */, 457 | FA45ACAC16AF37420003A41D /* PKCardExpiry.m in Sources */, 458 | FA06D14C16AFC0AA00C46291 /* PKView.m in Sources */, 459 | FA2A74A016BB1EDD00AF0078 /* PKCard.m in Sources */, 460 | FAADE6CF16BC44D9006FF4D1 /* PKAddressZip.m in Sources */, 461 | FA6F1A5E16C1B21000835C75 /* ViewController.m in Sources */, 462 | FA3A8C5A16D208E300A9C346 /* PKUSAddressZip.m in Sources */, 463 | 4C332B4E16FA923E009C782D /* PKTextField.m in Sources */, 464 | ); 465 | runOnlyForDeploymentPostprocessing = 0; 466 | }; 467 | FA6A2F8516C2D6F400915AEB /* Sources */ = { 468 | isa = PBXSourcesBuildPhase; 469 | buildActionMask = 2147483647; 470 | files = ( 471 | FA6A2F9716C2D6F400915AEB /* PKTest.m in Sources */, 472 | FA6A2F9E16C2D89600915AEB /* PKCardNumberTest.m in Sources */, 473 | FA6A2F9F16C2D9F000915AEB /* PKCardNumber.m in Sources */, 474 | FA6A2FA216C2E00E00915AEB /* PKCardCVCTest.m in Sources */, 475 | FA6A2FA316C2E01500915AEB /* PKCardCVC.m in Sources */, 476 | FA6A2FA616C2E1F400915AEB /* PKCardExpiryTest.m in Sources */, 477 | FA6A2FA716C2E20200915AEB /* PKCardExpiry.m in Sources */, 478 | ); 479 | runOnlyForDeploymentPostprocessing = 0; 480 | }; 481 | /* End PBXSourcesBuildPhase section */ 482 | 483 | /* Begin PBXVariantGroup section */ 484 | FA45AC7916AE350D0003A41D /* InfoPlist.strings */ = { 485 | isa = PBXVariantGroup; 486 | children = ( 487 | FA45AC7A16AE350D0003A41D /* en */, 488 | ); 489 | name = InfoPlist.strings; 490 | sourceTree = ""; 491 | }; 492 | FA6A2F9216C2D6F400915AEB /* InfoPlist.strings */ = { 493 | isa = PBXVariantGroup; 494 | children = ( 495 | FA6A2F9316C2D6F400915AEB /* en */, 496 | ); 497 | name = InfoPlist.strings; 498 | sourceTree = ""; 499 | }; 500 | /* End PBXVariantGroup section */ 501 | 502 | /* Begin XCBuildConfiguration section */ 503 | FA45AC9116AE350E0003A41D /* Debug */ = { 504 | isa = XCBuildConfiguration; 505 | buildSettings = { 506 | ALWAYS_SEARCH_USER_PATHS = NO; 507 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 508 | CLANG_CXX_LIBRARY = "libc++"; 509 | CLANG_ENABLE_OBJC_ARC = YES; 510 | CLANG_WARN_EMPTY_BODY = YES; 511 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 512 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 513 | COPY_PHASE_STRIP = NO; 514 | GCC_C_LANGUAGE_STANDARD = gnu99; 515 | GCC_DYNAMIC_NO_PIC = NO; 516 | GCC_OPTIMIZATION_LEVEL = 0; 517 | GCC_PREPROCESSOR_DEFINITIONS = ( 518 | "DEBUG=1", 519 | "$(inherited)", 520 | ); 521 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 522 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 523 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 524 | GCC_WARN_UNUSED_VARIABLE = YES; 525 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 526 | ONLY_ACTIVE_ARCH = YES; 527 | SDKROOT = iphoneos; 528 | TARGETED_DEVICE_FAMILY = "1,2"; 529 | }; 530 | name = Debug; 531 | }; 532 | FA45AC9216AE350E0003A41D /* Release */ = { 533 | isa = XCBuildConfiguration; 534 | buildSettings = { 535 | ALWAYS_SEARCH_USER_PATHS = NO; 536 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 537 | CLANG_CXX_LIBRARY = "libc++"; 538 | CLANG_ENABLE_OBJC_ARC = YES; 539 | CLANG_WARN_EMPTY_BODY = YES; 540 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 541 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 542 | COPY_PHASE_STRIP = YES; 543 | GCC_C_LANGUAGE_STANDARD = gnu99; 544 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 545 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 546 | GCC_WARN_UNUSED_VARIABLE = YES; 547 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 548 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 549 | SDKROOT = iphoneos; 550 | TARGETED_DEVICE_FAMILY = "1,2"; 551 | VALIDATE_PRODUCT = YES; 552 | }; 553 | name = Release; 554 | }; 555 | FA45AC9416AE350E0003A41D /* Debug */ = { 556 | isa = XCBuildConfiguration; 557 | buildSettings = { 558 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 559 | GCC_PREFIX_HEADER = "PaymentKit Example/PaymentKit Example-Prefix.pch"; 560 | INFOPLIST_FILE = "PaymentKit Example/PaymentKit Example-Info.plist"; 561 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 562 | PRODUCT_NAME = "PaymentKit Example"; 563 | TARGETED_DEVICE_FAMILY = 1; 564 | WRAPPER_EXTENSION = app; 565 | }; 566 | name = Debug; 567 | }; 568 | FA45AC9516AE350E0003A41D /* Release */ = { 569 | isa = XCBuildConfiguration; 570 | buildSettings = { 571 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 572 | GCC_PREFIX_HEADER = "PaymentKit Example/PaymentKit Example-Prefix.pch"; 573 | INFOPLIST_FILE = "PaymentKit Example/PaymentKit Example-Info.plist"; 574 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 575 | PRODUCT_NAME = "PaymentKit Example"; 576 | TARGETED_DEVICE_FAMILY = 1; 577 | WRAPPER_EXTENSION = app; 578 | }; 579 | name = Release; 580 | }; 581 | FA6A2F9916C2D6F400915AEB /* Debug */ = { 582 | isa = XCBuildConfiguration; 583 | buildSettings = { 584 | CLANG_WARN_CONSTANT_CONVERSION = YES; 585 | CLANG_WARN_ENUM_CONVERSION = YES; 586 | CLANG_WARN_INT_CONVERSION = YES; 587 | FRAMEWORK_SEARCH_PATHS = ( 588 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 589 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 590 | ); 591 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 592 | GCC_PREFIX_HEADER = "PaymentKit Test/PaymentKit Test-Prefix.pch"; 593 | INFOPLIST_FILE = "PaymentKit Test/PaymentKit Test-Info.plist"; 594 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 595 | PRODUCT_NAME = "$(TARGET_NAME)"; 596 | WRAPPER_EXTENSION = octest; 597 | }; 598 | name = Debug; 599 | }; 600 | FA6A2F9A16C2D6F400915AEB /* Release */ = { 601 | isa = XCBuildConfiguration; 602 | buildSettings = { 603 | CLANG_WARN_CONSTANT_CONVERSION = YES; 604 | CLANG_WARN_ENUM_CONVERSION = YES; 605 | CLANG_WARN_INT_CONVERSION = YES; 606 | FRAMEWORK_SEARCH_PATHS = ( 607 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 608 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 609 | ); 610 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 611 | GCC_PREFIX_HEADER = "PaymentKit Test/PaymentKit Test-Prefix.pch"; 612 | INFOPLIST_FILE = "PaymentKit Test/PaymentKit Test-Info.plist"; 613 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 614 | PRODUCT_NAME = "$(TARGET_NAME)"; 615 | WRAPPER_EXTENSION = octest; 616 | }; 617 | name = Release; 618 | }; 619 | /* End XCBuildConfiguration section */ 620 | 621 | /* Begin XCConfigurationList section */ 622 | FA45AC6616AE350D0003A41D /* Build configuration list for PBXProject "PaymentKit Example" */ = { 623 | isa = XCConfigurationList; 624 | buildConfigurations = ( 625 | FA45AC9116AE350E0003A41D /* Debug */, 626 | FA45AC9216AE350E0003A41D /* Release */, 627 | ); 628 | defaultConfigurationIsVisible = 0; 629 | defaultConfigurationName = Release; 630 | }; 631 | FA45AC9316AE350E0003A41D /* Build configuration list for PBXNativeTarget "PaymentKit Example" */ = { 632 | isa = XCConfigurationList; 633 | buildConfigurations = ( 634 | FA45AC9416AE350E0003A41D /* Debug */, 635 | FA45AC9516AE350E0003A41D /* Release */, 636 | ); 637 | defaultConfigurationIsVisible = 0; 638 | defaultConfigurationName = Release; 639 | }; 640 | FA6A2F9B16C2D6F400915AEB /* Build configuration list for PBXNativeTarget "PaymentKit Test" */ = { 641 | isa = XCConfigurationList; 642 | buildConfigurations = ( 643 | FA6A2F9916C2D6F400915AEB /* Debug */, 644 | FA6A2F9A16C2D6F400915AEB /* Release */, 645 | ); 646 | defaultConfigurationIsVisible = 0; 647 | defaultConfigurationName = Release; 648 | }; 649 | /* End XCConfigurationList section */ 650 | }; 651 | rootObject = FA45AC6316AE350D0003A41D /* Project object */; 652 | } 653 | --------------------------------------------------------------------------------