├── 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 | [](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 |
--------------------------------------------------------------------------------