osx support!

This commit is contained in:
Jack Flintermann 2014-12-28 20:20:48 +01:00 committed by James Reggio
parent f4d1441161
commit 47ae4d4051
22 changed files with 1996 additions and 94 deletions

@ -1 +0,0 @@
Subproject commit c49f8229094731fd00b593f448dab861bf5c08ee

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
04006F2B1A4ECC92009711A9 /* PSPDFKitMainThreadGuard.m in Sources */ = {isa = PBXBuildFile; fileRef = 04006F2A1A4ECC92009711A9 /* PSPDFKitMainThreadGuard.m */; };
04365D4D1A4CF8EC00A3E1D4 /* STPCheckoutOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 04365D301A4CF8EC00A3E1D4 /* STPCheckoutOptions.m */; };
04365D4E1A4CF8EC00A3E1D4 /* STPCheckoutViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04365D331A4CF8EC00A3E1D4 /* STPCheckoutViewController.m */; };
04365D4F1A4CF8EC00A3E1D4 /* STPColorUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 04365D351A4CF8EC00A3E1D4 /* STPColorUtils.m */; };
@ -53,6 +54,7 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
04006F2A1A4ECC92009711A9 /* PSPDFKitMainThreadGuard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSPDFKitMainThreadGuard.m; sourceTree = "<group>"; };
04365D2F1A4CF8EC00A3E1D4 /* STPCheckoutOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCheckoutOptions.h; sourceTree = "<group>"; };
04365D301A4CF8EC00A3E1D4 /* STPCheckoutOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPCheckoutOptions.m; sourceTree = "<group>"; };
04365D311A4CF8EC00A3E1D4 /* STPCheckoutProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCheckoutProtocols.h; sourceTree = "<group>"; };
@ -205,6 +207,7 @@
04365D471A4CF8EC00A3E1D4 /* Stripe.m */,
04365D481A4CF8EC00A3E1D4 /* StripeError.h */,
04365D491A4CF8EC00A3E1D4 /* StripeError.m */,
04006F2A1A4ECC92009711A9 /* PSPDFKitMainThreadGuard.m */,
04365D4B1A4CF8EC00A3E1D4 /* Supporting Files */,
);
name = Stripe;
@ -433,6 +436,7 @@
0470A2A819A5D5DB00B66DB7 /* main.m in Sources */,
04BA873119F89D5400B79DAF /* STPTestDataTableViewController.m in Sources */,
04BA873219F89D5400B79DAF /* STPTestPaymentAuthorizationViewController.m in Sources */,
04006F2B1A4ECC92009711A9 /* PSPDFKitMainThreadGuard.m in Sources */,
04365D571A4CF8EC00A3E1D4 /* Stripe.m in Sources */,
04365D561A4CF8EC00A3E1D4 /* STPToken.m in Sources */,
04365D4F1A4CF8EC00A3E1D4 /* STPColorUtils.m in Sources */,

View File

@ -10,7 +10,7 @@
#warning Replace these with your own values and then remove this warning. Make sure to replace the values in StripeExample/Parse/config/global.json as well if you want to use Parse.
// This can be found at https://dashboard.stripe.com/account/apikeys
NSString *const StripePublishableKey = nil; // TODO: replace nil with your own value
NSString *const StripePublishableKey = @"asd"; // TODO: replace nil with your own value
// These can be found at https://www.parse.com/apps/stripe-test/edit#app_keys
NSString *const ParseApplicationId = nil; // TODO: replace nil with your own value

View File

@ -0,0 +1,96 @@
// Taken from the commercial iOS PDF framework http://pspdfkit.com.
// Copyright (c) 2014 Peter Steinberger, PSPDFKit GmbH. All rights reserved.
// Licensed under MIT (http://opensource.org/licenses/MIT)
//
// You should only use this in debug builds. It doesn't use private API, but I wouldn't ship it.
#import <objc/runtime.h>
#import <objc/message.h>
// Compile-time selector checks.
#if DEBUG
#define PROPERTY(propName) NSStringFromSelector(@selector(propName))
#else
#define PROPERTY(propName) @#propName
#endif
// http://www.mikeash.com/pyblog/friday-qa-2010-01-29-method-replacement-for-fun-and-profit.html
BOOL PSPDFReplaceMethodWithBlock(Class c, SEL origSEL, SEL newSEL, id block) {
PSPDFAssert(c && origSEL && newSEL && block);
if ([c instancesRespondToSelector:newSEL]) return YES; // Selector already implemented, skip silently.
Method origMethod = class_getInstanceMethod(c, origSEL);
// Add the new method.
IMP impl = imp_implementationWithBlock(block);
if (!class_addMethod(c, newSEL, impl, method_getTypeEncoding(origMethod))) {
PSPDFLogError(@"Failed to add method: %@ on %@", NSStringFromSelector(newSEL), c);
return NO;
}else {
Method newMethod = class_getInstanceMethod(c, newSEL);
// If original doesn't implement the method we want to swizzle, create it.
if (class_addMethod(c, origSEL, method_getImplementation(newMethod), method_getTypeEncoding(origMethod))) {
class_replaceMethod(c, newSEL, method_getImplementation(origMethod), method_getTypeEncoding(newMethod));
}else {
method_exchangeImplementations(origMethod, newMethod);
}
}
return YES;
}
SEL _PSPDFPrefixedSelector(SEL selector) {
return NSSelectorFromString([NSString stringWithFormat:@"pspdf_%@", NSStringFromSelector(selector)]);
}
#define PSPDFAssert(expression, ...) \
do { if(!(expression)) { \
NSLog(@"%@", [NSString stringWithFormat: @"Assertion failure: %s in %s on line %s:%d. %@", #expression, __PRETTY_FUNCTION__, __FILE__, __LINE__, [NSString stringWithFormat:@"" __VA_ARGS__]]); \
abort(); }} while(0)
void PSPDFAssertIfNotMainThread(void) {
PSPDFAssert(NSThread.isMainThread, @"\nERROR: All calls to UIKit need to happen on the main thread. You have a bug in your code. Use dispatch_async(dispatch_get_main_queue(), ^{ ... }); if you're unsure what thread you're in.\n\nBreak on PSPDFAssertIfNotMainThread to find out where.\n\nStacktrace: %@", NSThread.callStackSymbols);
}
__attribute__((constructor)) static void PSPDFUIKitMainThreadGuard(void) {
@autoreleasepool {
for (NSString *selStr in @[PROPERTY(setNeedsLayout), PROPERTY(setNeedsDisplay), PROPERTY(setNeedsDisplayInRect:)]) {
SEL selector = NSSelectorFromString(selStr);
SEL newSelector = NSSelectorFromString([NSString stringWithFormat:@"pspdf_%@", selStr]);
if ([selStr hasSuffix:@":"]) {
PSPDFReplaceMethodWithBlock(UIView.class, selector, newSelector, ^(__unsafe_unretained UIView *_self, CGRect r) {
// Check for window, since *some* UIKit methods are indeed thread safe.
// https://developer.apple.com/library/ios/#releasenotes/General/WhatsNewIniPhoneOS/Articles/iPhoneOS4.html
/*
Drawing to a graphics context in UIKit is now thread-safe. Specifically:
The routines used to access and manipulate the graphics context can now correctly handle contexts residing on different threads.
String and image drawing is now thread-safe.
Using color and font objects in multiple threads is now safe to do.
*/
if (_self.window) PSPDFAssertIfNotMainThread();
((void ( *)(id, SEL, CGRect))objc_msgSend)(_self, newSelector, r);
});
}else {
PSPDFReplaceMethodWithBlock(UIView.class, selector, newSelector, ^(__unsafe_unretained UIView *_self) {
if (_self.window) {
if (!NSThread.isMainThread) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
dispatch_queue_t queue = dispatch_get_current_queue();
#pragma clang diagnostic pop
// iOS 8 layouts the MFMailComposeController in a background thread on an UIKit queue.
// https://github.com/PSPDFKit/PSPDFKit/issues/1423
if (!queue || !strstr(dispatch_queue_get_label(queue), "UIKit")) {
PSPDFAssertIfNotMainThread();
}
}
}
((void ( *)(id, SEL))objc_msgSend)(_self, newSelector);
});
}
}
}
}

View File

@ -0,0 +1,543 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
04006F1B1A4E887D009711A9 /* STPCheckoutOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 04006EFE1A4E887D009711A9 /* STPCheckoutOptions.m */; };
04006F1C1A4E887D009711A9 /* STPCheckoutViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04006F011A4E887D009711A9 /* STPCheckoutViewController.m */; };
04006F1D1A4E887D009711A9 /* STPColorUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 04006F031A4E887D009711A9 /* STPColorUtils.m */; };
04006F1E1A4E887D009711A9 /* STPPaymentPresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 04006F051A4E887D009711A9 /* STPPaymentPresenter.m */; };
04006F1F1A4E887D009711A9 /* STPAPIClient+ApplePay.m in Sources */ = {isa = PBXBuildFile; fileRef = 04006F081A4E887D009711A9 /* STPAPIClient+ApplePay.m */; };
04006F201A4E887D009711A9 /* Stripe+ApplePay.m in Sources */ = {isa = PBXBuildFile; fileRef = 04006F0A1A4E887D009711A9 /* Stripe+ApplePay.m */; };
04006F211A4E887D009711A9 /* STPAPIClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 04006F0D1A4E887D009711A9 /* STPAPIClient.m */; };
04006F221A4E887D009711A9 /* STPBankAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = 04006F0F1A4E887D009711A9 /* STPBankAccount.m */; };
04006F231A4E887D009711A9 /* STPCard.m in Sources */ = {isa = PBXBuildFile; fileRef = 04006F111A4E887D009711A9 /* STPCard.m */; };
04006F241A4E887D009711A9 /* STPToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 04006F131A4E887D009711A9 /* STPToken.m */; };
04006F251A4E887D009711A9 /* Stripe.m in Sources */ = {isa = PBXBuildFile; fileRef = 04006F151A4E887D009711A9 /* Stripe.m */; };
04006F261A4E887D009711A9 /* StripeError.m in Sources */ = {isa = PBXBuildFile; fileRef = 04006F171A4E887D009711A9 /* StripeError.m */; };
04FCF64B1A41F76D00DBF696 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FCF64A1A41F76D00DBF696 /* AppDelegate.m */; };
04FCF64D1A41F76D00DBF696 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FCF64C1A41F76D00DBF696 /* main.m */; };
04FCF64F1A41F76D00DBF696 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 04FCF64E1A41F76D00DBF696 /* Images.xcassets */; };
04FCF6521A41F76D00DBF696 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 04FCF6501A41F76D00DBF696 /* MainMenu.xib */; };
04FCF65E1A41F76D00DBF696 /* OSXExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FCF65D1A41F76D00DBF696 /* OSXExampleTests.m */; };
04FCF6731A41FB7700DBF696 /* ExampleWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FCF6711A41FB7700DBF696 /* ExampleWindowController.m */; };
04FCF6741A41FB7700DBF696 /* ExampleWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 04FCF6721A41FB7700DBF696 /* ExampleWindowController.xib */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
04FCF6581A41F76D00DBF696 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 04FCF63C1A41F76D00DBF696 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 04FCF6431A41F76D00DBF696;
remoteInfo = OSXExample;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
04006EFD1A4E887D009711A9 /* STPCheckoutOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCheckoutOptions.h; sourceTree = "<group>"; };
04006EFE1A4E887D009711A9 /* STPCheckoutOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPCheckoutOptions.m; sourceTree = "<group>"; };
04006EFF1A4E887D009711A9 /* STPCheckoutProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCheckoutProtocols.h; sourceTree = "<group>"; };
04006F001A4E887D009711A9 /* STPCheckoutViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCheckoutViewController.h; sourceTree = "<group>"; };
04006F011A4E887D009711A9 /* STPCheckoutViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPCheckoutViewController.m; sourceTree = "<group>"; };
04006F021A4E887D009711A9 /* STPColorUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPColorUtils.h; sourceTree = "<group>"; };
04006F031A4E887D009711A9 /* STPColorUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPColorUtils.m; sourceTree = "<group>"; };
04006F041A4E887D009711A9 /* STPPaymentPresenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPPaymentPresenter.h; sourceTree = "<group>"; };
04006F051A4E887D009711A9 /* STPPaymentPresenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPPaymentPresenter.m; sourceTree = "<group>"; };
04006F071A4E887D009711A9 /* STPAPIClient+ApplePay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "STPAPIClient+ApplePay.h"; sourceTree = "<group>"; };
04006F081A4E887D009711A9 /* STPAPIClient+ApplePay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "STPAPIClient+ApplePay.m"; sourceTree = "<group>"; };
04006F091A4E887D009711A9 /* Stripe+ApplePay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Stripe+ApplePay.h"; sourceTree = "<group>"; };
04006F0A1A4E887D009711A9 /* Stripe+ApplePay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Stripe+ApplePay.m"; sourceTree = "<group>"; };
04006F0C1A4E887D009711A9 /* STPAPIClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPAPIClient.h; sourceTree = "<group>"; };
04006F0D1A4E887D009711A9 /* STPAPIClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPAPIClient.m; sourceTree = "<group>"; };
04006F0E1A4E887D009711A9 /* STPBankAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPBankAccount.h; sourceTree = "<group>"; };
04006F0F1A4E887D009711A9 /* STPBankAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPBankAccount.m; sourceTree = "<group>"; };
04006F101A4E887D009711A9 /* STPCard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCard.h; sourceTree = "<group>"; };
04006F111A4E887D009711A9 /* STPCard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPCard.m; sourceTree = "<group>"; };
04006F121A4E887D009711A9 /* STPToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPToken.h; sourceTree = "<group>"; };
04006F131A4E887D009711A9 /* STPToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPToken.m; sourceTree = "<group>"; };
04006F141A4E887D009711A9 /* Stripe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Stripe.h; sourceTree = "<group>"; };
04006F151A4E887D009711A9 /* Stripe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Stripe.m; sourceTree = "<group>"; };
04006F161A4E887D009711A9 /* StripeError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StripeError.h; sourceTree = "<group>"; };
04006F171A4E887D009711A9 /* StripeError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StripeError.m; sourceTree = "<group>"; };
04006F181A4E887D009711A9 /* Stripe-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Stripe-Prefix.pch"; sourceTree = "<group>"; };
04FCF6441A41F76D00DBF696 /* OSXExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OSXExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
04FCF6481A41F76D00DBF696 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
04FCF6491A41F76D00DBF696 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
04FCF64A1A41F76D00DBF696 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
04FCF64C1A41F76D00DBF696 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
04FCF64E1A41F76D00DBF696 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
04FCF6511A41F76D00DBF696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
04FCF6571A41F76D00DBF696 /* OSXExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OSXExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
04FCF65C1A41F76D00DBF696 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
04FCF65D1A41F76D00DBF696 /* OSXExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OSXExampleTests.m; sourceTree = "<group>"; };
04FCF6701A41FB7700DBF696 /* ExampleWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleWindowController.h; sourceTree = "<group>"; };
04FCF6711A41FB7700DBF696 /* ExampleWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleWindowController.m; sourceTree = "<group>"; };
04FCF6721A41FB7700DBF696 /* ExampleWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ExampleWindowController.xib; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
04FCF6411A41F76D00DBF696 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
04FCF6541A41F76D00DBF696 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
04006F061A4E887D009711A9 /* Checkout */ = {
isa = PBXGroup;
children = (
04006EFD1A4E887D009711A9 /* STPCheckoutOptions.h */,
04006EFE1A4E887D009711A9 /* STPCheckoutOptions.m */,
04006EFF1A4E887D009711A9 /* STPCheckoutProtocols.h */,
04006F001A4E887D009711A9 /* STPCheckoutViewController.h */,
04006F011A4E887D009711A9 /* STPCheckoutViewController.m */,
04006F021A4E887D009711A9 /* STPColorUtils.h */,
04006F031A4E887D009711A9 /* STPColorUtils.m */,
04006F041A4E887D009711A9 /* STPPaymentPresenter.h */,
04006F051A4E887D009711A9 /* STPPaymentPresenter.m */,
);
path = Checkout;
sourceTree = "<group>";
};
04006F0B1A4E887D009711A9 /* ApplePay */ = {
isa = PBXGroup;
children = (
04006F071A4E887D009711A9 /* STPAPIClient+ApplePay.h */,
04006F081A4E887D009711A9 /* STPAPIClient+ApplePay.m */,
04006F091A4E887D009711A9 /* Stripe+ApplePay.h */,
04006F0A1A4E887D009711A9 /* Stripe+ApplePay.m */,
);
path = ApplePay;
sourceTree = "<group>";
};
04006F191A4E887D009711A9 /* Supporting Files */ = {
isa = PBXGroup;
children = (
04006F181A4E887D009711A9 /* Stripe-Prefix.pch */,
);
path = "Supporting Files";
sourceTree = "<group>";
};
04006F1A1A4E887D009711A9 /* Stripe */ = {
isa = PBXGroup;
children = (
04006F061A4E887D009711A9 /* Checkout */,
04006F0B1A4E887D009711A9 /* ApplePay */,
04006F0C1A4E887D009711A9 /* STPAPIClient.h */,
04006F0D1A4E887D009711A9 /* STPAPIClient.m */,
04006F0E1A4E887D009711A9 /* STPBankAccount.h */,
04006F0F1A4E887D009711A9 /* STPBankAccount.m */,
04006F101A4E887D009711A9 /* STPCard.h */,
04006F111A4E887D009711A9 /* STPCard.m */,
04006F121A4E887D009711A9 /* STPToken.h */,
04006F131A4E887D009711A9 /* STPToken.m */,
04006F141A4E887D009711A9 /* Stripe.h */,
04006F151A4E887D009711A9 /* Stripe.m */,
04006F161A4E887D009711A9 /* StripeError.h */,
04006F171A4E887D009711A9 /* StripeError.m */,
04006F191A4E887D009711A9 /* Supporting Files */,
);
name = Stripe;
path = ../Stripe;
sourceTree = "<group>";
};
04FCF63B1A41F76D00DBF696 = {
isa = PBXGroup;
children = (
04FCF6461A41F76D00DBF696 /* OSXExample */,
04FCF65A1A41F76D00DBF696 /* OSXExampleTests */,
04FCF6451A41F76D00DBF696 /* Products */,
);
sourceTree = "<group>";
};
04FCF6451A41F76D00DBF696 /* Products */ = {
isa = PBXGroup;
children = (
04FCF6441A41F76D00DBF696 /* OSXExample.app */,
04FCF6571A41F76D00DBF696 /* OSXExampleTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
04FCF6461A41F76D00DBF696 /* OSXExample */ = {
isa = PBXGroup;
children = (
04FCF66F1A41FA7300DBF696 /* Vendor */,
04FCF6491A41F76D00DBF696 /* AppDelegate.h */,
04FCF64A1A41F76D00DBF696 /* AppDelegate.m */,
04FCF6701A41FB7700DBF696 /* ExampleWindowController.h */,
04FCF6711A41FB7700DBF696 /* ExampleWindowController.m */,
04FCF6721A41FB7700DBF696 /* ExampleWindowController.xib */,
04FCF64E1A41F76D00DBF696 /* Images.xcassets */,
04FCF6501A41F76D00DBF696 /* MainMenu.xib */,
04FCF6471A41F76D00DBF696 /* Supporting Files */,
);
path = OSXExample;
sourceTree = "<group>";
};
04FCF6471A41F76D00DBF696 /* Supporting Files */ = {
isa = PBXGroup;
children = (
04FCF6481A41F76D00DBF696 /* Info.plist */,
04FCF64C1A41F76D00DBF696 /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
04FCF65A1A41F76D00DBF696 /* OSXExampleTests */ = {
isa = PBXGroup;
children = (
04FCF65D1A41F76D00DBF696 /* OSXExampleTests.m */,
04FCF65B1A41F76D00DBF696 /* Supporting Files */,
);
path = OSXExampleTests;
sourceTree = "<group>";
};
04FCF65B1A41F76D00DBF696 /* Supporting Files */ = {
isa = PBXGroup;
children = (
04FCF65C1A41F76D00DBF696 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
04FCF66F1A41FA7300DBF696 /* Vendor */ = {
isa = PBXGroup;
children = (
04006F1A1A4E887D009711A9 /* Stripe */,
);
name = Vendor;
path = ..;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
04FCF6431A41F76D00DBF696 /* OSXExample */ = {
isa = PBXNativeTarget;
buildConfigurationList = 04FCF6611A41F76D00DBF696 /* Build configuration list for PBXNativeTarget "OSXExample" */;
buildPhases = (
04FCF6401A41F76D00DBF696 /* Sources */,
04FCF6411A41F76D00DBF696 /* Frameworks */,
04FCF6421A41F76D00DBF696 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = OSXExample;
productName = OSXExample;
productReference = 04FCF6441A41F76D00DBF696 /* OSXExample.app */;
productType = "com.apple.product-type.application";
};
04FCF6561A41F76D00DBF696 /* OSXExampleTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 04FCF6641A41F76D00DBF696 /* Build configuration list for PBXNativeTarget "OSXExampleTests" */;
buildPhases = (
04FCF6531A41F76D00DBF696 /* Sources */,
04FCF6541A41F76D00DBF696 /* Frameworks */,
04FCF6551A41F76D00DBF696 /* Resources */,
);
buildRules = (
);
dependencies = (
04FCF6591A41F76D00DBF696 /* PBXTargetDependency */,
);
name = OSXExampleTests;
productName = OSXExampleTests;
productReference = 04FCF6571A41F76D00DBF696 /* OSXExampleTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
04FCF63C1A41F76D00DBF696 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
ORGANIZATIONNAME = Stripe;
TargetAttributes = {
04FCF6431A41F76D00DBF696 = {
CreatedOnToolsVersion = 6.1.1;
};
04FCF6561A41F76D00DBF696 = {
CreatedOnToolsVersion = 6.1.1;
TestTargetID = 04FCF6431A41F76D00DBF696;
};
};
};
buildConfigurationList = 04FCF63F1A41F76D00DBF696 /* Build configuration list for PBXProject "OSXExample" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 04FCF63B1A41F76D00DBF696;
productRefGroup = 04FCF6451A41F76D00DBF696 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
04FCF6431A41F76D00DBF696 /* OSXExample */,
04FCF6561A41F76D00DBF696 /* OSXExampleTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
04FCF6421A41F76D00DBF696 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
04FCF64F1A41F76D00DBF696 /* Images.xcassets in Resources */,
04FCF6741A41FB7700DBF696 /* ExampleWindowController.xib in Resources */,
04FCF6521A41F76D00DBF696 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
04FCF6551A41F76D00DBF696 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
04FCF6401A41F76D00DBF696 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
04006F221A4E887D009711A9 /* STPBankAccount.m in Sources */,
04006F201A4E887D009711A9 /* Stripe+ApplePay.m in Sources */,
04006F1E1A4E887D009711A9 /* STPPaymentPresenter.m in Sources */,
04006F1F1A4E887D009711A9 /* STPAPIClient+ApplePay.m in Sources */,
04006F1B1A4E887D009711A9 /* STPCheckoutOptions.m in Sources */,
04006F241A4E887D009711A9 /* STPToken.m in Sources */,
04006F1D1A4E887D009711A9 /* STPColorUtils.m in Sources */,
04006F261A4E887D009711A9 /* StripeError.m in Sources */,
04FCF6731A41FB7700DBF696 /* ExampleWindowController.m in Sources */,
04FCF64D1A41F76D00DBF696 /* main.m in Sources */,
04FCF64B1A41F76D00DBF696 /* AppDelegate.m in Sources */,
04006F231A4E887D009711A9 /* STPCard.m in Sources */,
04006F1C1A4E887D009711A9 /* STPCheckoutViewController.m in Sources */,
04006F251A4E887D009711A9 /* Stripe.m in Sources */,
04006F211A4E887D009711A9 /* STPAPIClient.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
04FCF6531A41F76D00DBF696 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
04FCF65E1A41F76D00DBF696 /* OSXExampleTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
04FCF6591A41F76D00DBF696 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 04FCF6431A41F76D00DBF696 /* OSXExample */;
targetProxy = 04FCF6581A41F76D00DBF696 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
04FCF6501A41F76D00DBF696 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
04FCF6511A41F76D00DBF696 /* Base */,
);
name = MainMenu.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
04FCF65F1A41F76D00DBF696 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.10;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
};
04FCF6601A41F76D00DBF696 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.10;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
};
name = Release;
};
04FCF6621A41F76D00DBF696 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = OSXExample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
04FCF6631A41F76D00DBF696 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = OSXExample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
04FCF6651A41F76D00DBF696 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = OSXExampleTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/OSXExample.app/Contents/MacOS/OSXExample";
};
name = Debug;
};
04FCF6661A41F76D00DBF696 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
INFOPLIST_FILE = OSXExampleTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/OSXExample.app/Contents/MacOS/OSXExample";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
04FCF63F1A41F76D00DBF696 /* Build configuration list for PBXProject "OSXExample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
04FCF65F1A41F76D00DBF696 /* Debug */,
04FCF6601A41F76D00DBF696 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
04FCF6611A41F76D00DBF696 /* Build configuration list for PBXNativeTarget "OSXExample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
04FCF6621A41F76D00DBF696 /* Debug */,
04FCF6631A41F76D00DBF696 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
04FCF6641A41F76D00DBF696 /* Build configuration list for PBXNativeTarget "OSXExampleTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
04FCF6651A41F76D00DBF696 /* Debug */,
04FCF6661A41F76D00DBF696 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 04FCF63C1A41F76D00DBF696 /* Project object */;
}

View File

@ -0,0 +1,15 @@
//
// AppDelegate.h
// OSXExample
//
// Created by Jack Flintermann on 12/17/14.
// Copyright (c) 2014 Stripe. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSObject <NSApplicationDelegate>
@end

View File

@ -0,0 +1,29 @@
//
// AppDelegate.m
// OSXExample
//
// Created by Jack Flintermann on 12/17/14.
// Copyright (c) 2014 Stripe. All rights reserved.
//
#import "AppDelegate.h"
#import "ExampleWindowController.h"
@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@property ExampleWindowController *windowController;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.windowController = [[ExampleWindowController alloc] initWithWindowNibName:@"ExampleWindowController"];
[self.windowController showWindow:nil];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
@end

View File

@ -0,0 +1,666 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6254" systemVersion="14B25" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6254"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate"/>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="OSXExample" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="OSXExample" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About OSXExample" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide OSXExample" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit OSXExample" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="File" id="dMs-cI-mzQ">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="File" id="bib-Uj-vzu">
<items>
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
<connections>
<action selector="newDocument:" target="-1" id="4Si-XN-c54"/>
</connections>
</menuItem>
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
<connections>
<action selector="openDocument:" target="-1" id="bVn-NM-KNZ"/>
</connections>
</menuItem>
<menuItem title="Open Recent" id="tXI-mr-wws">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
<items>
<menuItem title="Clear Menu" id="vNY-rz-j42">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="clearRecentDocuments:" target="-1" id="Daa-9d-B3U"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
<connections>
<action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/>
</connections>
</menuItem>
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
<connections>
<action selector="saveDocument:" target="-1" id="teZ-XB-qJY"/>
</connections>
</menuItem>
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
<connections>
<action selector="saveDocumentAs:" target="-1" id="mDf-zr-I0C"/>
</connections>
</menuItem>
<menuItem title="Revert to Saved" id="KaW-ft-85H">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="revertDocumentToSaved:" target="-1" id="iJ3-Pv-kwq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="runPageLayout:" target="-1" id="Din-rz-gC5"/>
</connections>
</menuItem>
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
<connections>
<action selector="print:" target="-1" id="qaZ-4w-aoO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Format" id="jxT-CU-nIS">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Format" id="GEO-Iw-cKr">
<items>
<menuItem title="Font" id="Gi5-1S-RQB">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
<items>
<menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq">
<connections>
<action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/>
</connections>
</menuItem>
<menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27">
<connections>
<action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/>
</connections>
</menuItem>
<menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq">
<connections>
<action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/>
</connections>
</menuItem>
<menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
<connections>
<action selector="underline:" target="-1" id="FYS-2b-JAY"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL">
<connections>
<action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/>
</connections>
</menuItem>
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST">
<connections>
<action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
<menuItem title="Kern" id="jBQ-r6-VK2">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Kern" id="tlD-Oa-oAM">
<items>
<menuItem title="Use Default" id="GUa-eO-cwY">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardKerning:" target="-1" id="6dk-9l-Ckg"/>
</connections>
</menuItem>
<menuItem title="Use None" id="cDB-IK-hbR">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffKerning:" target="-1" id="U8a-gz-Maa"/>
</connections>
</menuItem>
<menuItem title="Tighten" id="46P-cB-AYj">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="tightenKerning:" target="-1" id="hr7-Nz-8ro"/>
</connections>
</menuItem>
<menuItem title="Loosen" id="ogc-rX-tC1">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="loosenKerning:" target="-1" id="8i4-f9-FKE"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Ligatures" id="o6e-r0-MWq">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
<items>
<menuItem title="Use Default" id="agt-UL-0e3">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardLigatures:" target="-1" id="7uR-wd-Dx6"/>
</connections>
</menuItem>
<menuItem title="Use None" id="J7y-lM-qPV">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffLigatures:" target="-1" id="iX2-gA-Ilz"/>
</connections>
</menuItem>
<menuItem title="Use All" id="xQD-1f-W4t">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useAllLigatures:" target="-1" id="KcB-kA-TuK"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Baseline" id="OaQ-X3-Vso">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Baseline" id="ijk-EB-dga">
<items>
<menuItem title="Use Default" id="3Om-Ey-2VK">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unscript:" target="-1" id="0vZ-95-Ywn"/>
</connections>
</menuItem>
<menuItem title="Superscript" id="Rqc-34-cIF">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="superscript:" target="-1" id="3qV-fo-wpU"/>
</connections>
</menuItem>
<menuItem title="Subscript" id="I0S-gh-46l">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="subscript:" target="-1" id="Q6W-4W-IGz"/>
</connections>
</menuItem>
<menuItem title="Raise" id="2h7-ER-AoG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="raiseBaseline:" target="-1" id="4sk-31-7Q9"/>
</connections>
</menuItem>
<menuItem title="Lower" id="1tx-W0-xDw">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowerBaseline:" target="-1" id="OF1-bc-KW4"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
<menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
<connections>
<action selector="orderFrontColorPanel:" target="-1" id="mSX-Xz-DV3"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
<menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="copyFont:" target="-1" id="GJO-xA-L4q"/>
</connections>
</menuItem>
<menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteFont:" target="-1" id="JfD-CL-leO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Text" id="Fal-I4-PZk">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Text" id="d9c-me-L2H">
<items>
<menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
<connections>
<action selector="alignLeft:" target="-1" id="zUv-R1-uAa"/>
</connections>
</menuItem>
<menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
<connections>
<action selector="alignCenter:" target="-1" id="spX-mk-kcS"/>
</connections>
</menuItem>
<menuItem title="Justify" id="J5U-5w-g23">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="alignJustified:" target="-1" id="ljL-7U-jND"/>
</connections>
</menuItem>
<menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
<connections>
<action selector="alignRight:" target="-1" id="r48-bG-YeY"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
<menuItem title="Writing Direction" id="H1b-Si-o9J">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
<items>
<menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="YGs-j5-SAR">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionNatural:" target="-1" id="qtV-5e-UBP"/>
</connections>
</menuItem>
<menuItem id="Lbh-J2-qVU">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionLeftToRight:" target="-1" id="S0X-9S-QSf"/>
</connections>
</menuItem>
<menuItem id="jFq-tB-4Kx">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionRightToLeft:" target="-1" id="5fk-qB-AqJ"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
<menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="Nop-cj-93Q">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionNatural:" target="-1" id="lPI-Se-ZHp"/>
</connections>
</menuItem>
<menuItem id="BgM-ve-c93">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionLeftToRight:" target="-1" id="caW-Bv-w94"/>
</connections>
</menuItem>
<menuItem id="RB4-Sm-HuC">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionRightToLeft:" target="-1" id="EXD-6r-ZUu"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
<menuItem title="Show Ruler" id="vLm-3I-IUL">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleRuler:" target="-1" id="FOx-HJ-KwY"/>
</connections>
</menuItem>
<menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="copyRuler:" target="-1" id="71i-fW-3W2"/>
</connections>
</menuItem>
<menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="pasteRuler:" target="-1" id="cSh-wd-qM2"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="toggleToolbarShown:" target="-1" id="BXY-wc-z0C"/>
</connections>
</menuItem>
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="runToolbarCustomizationPalette:" target="-1" id="pQI-g3-MTW"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="wpr-3q-Mcd">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items>
<menuItem title="OSXExample Help" keyEquivalent="?" id="FKE-Sm-Kum">
<connections>
<action selector="showHelp:" target="-1" id="y7X-2Q-9no"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</objects>
</document>

View File

@ -0,0 +1,13 @@
//
// ExampleWindowController.h
// OSXExample
//
// Created by Jack Flintermann on 12/17/14.
// Copyright (c) 2014 Stripe. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface ExampleWindowController : NSWindowController
@end

View File

@ -0,0 +1,64 @@
//
// ExampleWindowController.m
// OSXExample
//
// Created by Jack Flintermann on 12/17/14.
// Copyright (c) 2014 Stripe. All rights reserved.
//
#import "ExampleWindowController.h"
#import "STPCheckoutViewController.h"
#import "STPCheckoutOptions.h"
@interface ExampleWindowController () <STPCheckoutViewControllerDelegate>
@property STPCheckoutViewController *checkoutController;
@end
@implementation ExampleWindowController
- (IBAction)beginPayment:(id)sender {
STPCheckoutOptions *options = [STPCheckoutOptions new];
options.publishableKey = @"pk_test_09IUAkhSGIz8mQP3prdgKm06";
options.appleMerchantId = @"<#Replace me with your Apple Merchant ID #>";
options.purchaseDescription = @"Tasty Llama food";
options.purchaseAmount = @1000;
options.purchaseLabel = @"Pay {{amount}} for that food";
options.enablePostalCode = @YES;
options.logoColor = [NSColor purpleColor];
self.checkoutController = [[STPCheckoutViewController alloc] initWithOptions:options];
self.checkoutController.checkoutDelegate = self;
NSView *webView = self.checkoutController.view;
[self.window.contentView addSubview:webView];
webView.translatesAutoresizingMaskIntoConstraints = NO;
[self.window.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[webView]-0-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:NSDictionaryOfVariableBindings(webView)]];
[self.window.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[webView]-0-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:NSDictionaryOfVariableBindings(webView)]];
[self.window.contentViewController addChildViewController:self.checkoutController];
}
- (void)checkoutController:(STPCheckoutViewController *)controller didCreateToken:(STPToken *)token completion:(STPTokenSubmissionHandler)completion {
completion(STPBackendChargeResultSuccess, nil);
}
- (void)checkoutController:(STPCheckoutViewController *)controller didFailWithError:(NSError *)error {
[controller.view removeFromSuperview];
[controller removeFromParentViewController];
}
- (void)checkoutControllerDidCancel:(STPCheckoutViewController *)controller {
[controller.view removeFromSuperview];
[controller removeFromParentViewController];
}
- (void)checkoutControllerDidFinish:(STPCheckoutViewController *)controller {
[controller.view removeFromSuperview];
[controller removeFromParentViewController];
}
@end

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6254" systemVersion="14B25" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6254"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="ExampleWindowController">
<connections>
<outlet property="window" destination="F0z-JX-Cv5" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" animationBehavior="default" id="F0z-JX-Cv5">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<view key="contentView" id="se5-gp-TjO">
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xya-P8-w67">
<rect key="frame" x="208" y="118" width="64" height="32"/>
<buttonCell key="cell" type="push" title="Buy" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Oym-6K-yXB">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="beginPayment:" target="-2" id="pDm-hS-g00"/>
</connections>
</button>
</subviews>
</view>
<connections>
<outlet property="delegate" destination="-2" id="0bl-1N-AYu"/>
</connections>
</window>
</objects>
</document>

View File

@ -0,0 +1,58 @@
{
"images" : [
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>com.stripe.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2014 Stripe. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View File

@ -0,0 +1,13 @@
//
// main.m
// OSXExample
//
// Created by Jack Flintermann on 12/17/14.
// Copyright (c) 2014 Stripe. All rights reserved.
//
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[]) {
return NSApplicationMain(argc, argv);
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>com.stripe.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,40 @@
//
// OSXExampleTests.m
// OSXExampleTests
//
// Created by Jack Flintermann on 12/17/14.
// Copyright (c) 2014 Stripe. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <XCTest/XCTest.h>
@interface OSXExampleTests : XCTestCase
@end
@implementation OSXExampleTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testExample {
// This is an example of a functional test case.
XCTAssert(YES, @"Pass");
}
- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}
@end

View File

@ -1,6 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:OSXExample/OSXExample.xcodeproj">
</FileRef>
<FileRef
location = "group:Stripe.xcodeproj">
</FileRef>

View File

@ -6,7 +6,11 @@
//
#import <Foundation/Foundation.h>
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#else
#import <AppKit/AppKit.h>
#endif
/**
* This class represents a configurable set of options that you can pass to an STPCheckoutViewController or an STPPaymentPresenter to control the appearance of
@ -38,13 +42,21 @@
/**
* You can also specify a local UIImage to be used as the Checkout logo header (see logoURL).
*/
#if TARGET_OS_IPHONE
@property (nonatomic) UIImage *logoImage;
#else
@property (nonatomic) NSImage *logoImage;
#endif
/**
* This specifies the color of the header shown in Stripe Checkout. If you specify a logoURL (but not a logoImage) and leave this property nil, Checkout will
* auto-detect the background color of the image you point to and use that as the header color.
*/
#if TARGET_OS_IPHONE
@property (nonatomic, copy) UIColor *logoColor;
#else
@property (nonatomic, copy) NSColor *logoColor;
#endif
/**
* The name of your company or website. Displayed in the header. Defaults to your app's name. This property needs to be set in order to use Apple Pay with

View File

@ -5,7 +5,11 @@
// Created by Jack Flintermann on 9/15/14.
//
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#else
#import <AppKit/AppKit.h>
#endif
#import "STPCheckoutProtocols.h"
@class STPCheckoutOptions, STPToken;
@ -15,7 +19,11 @@
Controls a UIWebView that loads an iOS-optimized version of Stripe Checkout that you can present modally. Note
that if you're using an STPPaymentPresenter to collect your user's payment details (highly recommended), you do not have to use this class directly.
*/
#if TARGET_OS_IPHONE
@interface STPCheckoutViewController : UINavigationController
#else
@interface STPCheckoutViewController : NSViewController
#endif
/**
* Creates an STPCheckoutViewController with the desired options. The options are copied at this step, so changing any of their values after instantiating an

View File

@ -35,6 +35,23 @@
- (void)checkoutAdapter:(id<STPCheckoutWebViewAdapter>)adapter didError:(NSError *)error;
@end
static NSString *const checkoutOptionsGlobal = @"StripeCheckoutOptions";
static NSString *const checkoutRedirectPrefix = @"/-/";
static NSString *const STPCheckoutURLProtocolRequestScheme = @"beginstripecheckout";
static NSString *const checkoutRPCScheme = @"stripecheckout";
static NSString *const checkoutUserAgent = @"Stripe";
// TODO replace these
static NSString *const checkoutHost = @"localhost:5394";
// static NSString *const checkoutHost = @"checkout.stripe.com";
static NSString *const checkoutURL = @"localhost:5394/v3/ios/index.html";
// static NSString *const checkoutURL = @"checkout.stripe.com/v3/ios";
@interface STPCheckoutURLProtocol : NSURLProtocol<NSURLConnectionDataDelegate>
@property (nonatomic, strong) NSURLConnection *connection;
@end
#if TARGET_OS_IPHONE
@interface STPCheckoutUIWebViewAdapter : NSObject<STPCheckoutWebViewAdapter, UIWebViewDelegate>
@property (nonatomic) UIWebView *webView;
@end
@ -47,18 +64,14 @@
@property (weak, nonatomic) STP_VIEW_CLASS *webView;
@property (nonatomic) id<STPCheckoutWebViewAdapter> adapter;
@property (weak, nonatomic) UIActivityIndicatorView *activityIndicator;
@property (weak, nonatomic) UIView *headerBackground;
@property (nonatomic) STPCheckoutOptions *options;
@property (nonatomic) NSURL *logoURL;
@property (nonatomic) NSURL *url;
@property (weak, nonatomic) UIView *headerBackground;
@property (nonatomic, weak) id<STPCheckoutViewControllerDelegate> delegate;
@end
@interface STPCheckoutURLProtocol : NSURLProtocol<NSURLConnectionDataDelegate>
@property (nonatomic, strong) NSURLConnection *connection;
@end
@interface STPCheckoutViewController ()
@property (nonatomic, weak) STPCheckoutWebViewController *webViewController;
@property (nonatomic) UIStatusBarStyle previousStyle;
@ -108,18 +121,6 @@
@end
static NSString *const checkoutOptionsGlobal = @"StripeCheckoutOptions";
static NSString *const checkoutRedirectPrefix = @"/-/";
static NSString *const STPCheckoutURLProtocolRequestScheme = @"beginstripecheckout";
static NSString *const checkoutRPCScheme = @"stripecheckout";
static NSString *const checkoutUserAgent = @"Stripe";
// TODO replace these
static NSString *const checkoutHost = @"localhost:5394";
// static NSString *const checkoutHost = @"checkout.stripe.com";
static NSString *const checkoutURL = @"localhost:5394/v3/ios/index.html";
// static NSString *const checkoutURL = @"checkout.stripe.com/v3/ios";
@implementation STPCheckoutWebViewController
- (instancetype)initWithCheckoutViewController:(STPCheckoutViewController *)checkoutViewController {
@ -233,7 +234,7 @@ static NSString *const checkoutURL = @"localhost:5394/v3/ios/index.html";
constant:0]];
}
- (void)cancel:(__unused UIBarButtonItem *)sender {
- (void)cancel:(__unused id)sender {
[self.delegate checkoutControllerDidCancel:self.checkoutController];
[self cleanup];
}
@ -253,7 +254,7 @@ static NSString *const checkoutURL = @"localhost:5394/v3/ios/index.html";
return UIStatusBarStyleDefault;
}
- (void)setLogoColor:(UIColor *)color {
- (void)setLogoColor:(STP_COLOR_CLASS *)color {
self.options.logoColor = color;
self.headerBackground.backgroundColor = color;
if ([self.checkoutController respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
@ -323,71 +324,6 @@ static NSString *const checkoutURL = @"localhost:5394/v3/ios/index.html";
@end
#pragma mark - STPCheckoutURLProtocol
/**
* This URL protocol treats any non-20x or 30x response from checkout as an error (unlike the default UIWebView behavior, which e.g. displays a 404 page).
*/
@implementation STPCheckoutURLProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
return [request.URL.scheme.lowercaseString isEqualToString:STPCheckoutURLProtocolRequestScheme.lowercaseString];
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
- (void)startLoading {
NSMutableURLRequest *newRequest = [self.request mutableCopy];
NSString *oldURLString = [[newRequest.URL absoluteString] lowercaseString];
//#warning todo: https
newRequest.URL =
[NSURL URLWithString:[oldURLString stringByReplacingOccurrencesOfString:STPCheckoutURLProtocolRequestScheme.lowercaseString withString:@"http"]];
self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}
- (void)stopLoading {
[self.connection cancel];
self.connection = nil;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
// 30x redirects are automatically followed and will not reach here,
// so we only need to check for successful 20x status codes.
if (httpResponse.statusCode / 100 != 2 && httpResponse.statusCode != 301) {
NSError *error = [[NSError alloc] initWithDomain:StripeDomain
code:STPConnectionError
userInfo:@{
NSLocalizedDescriptionKey: STPUnexpectedError,
STPErrorMessageKey: @"Stripe Checkout couldn't open. Please check your internet connection and try "
@"again. If the problem persists, please contact support@stripe.com."
}];
[self.client URLProtocol:self didFailWithError:error];
[connection cancel];
self.connection = nil;
return;
}
}
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}
- (void)connection:(__unused NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.client URLProtocol:self didLoadData:data];
}
- (void)connectionDidFinishLoading:(__unused NSURLConnection *)connection {
[self.client URLProtocolDidFinishLoading:self];
}
- (void)connection:(__unused NSURLConnection *)connection didFailWithError:(NSError *)error {
[self.client URLProtocol:self didFailWithError:error];
}
@end
@implementation STPCheckoutUIWebViewAdapter
@synthesize delegate;
@ -469,3 +405,302 @@ static NSString *const checkoutURL = @"localhost:5394/v3/ios/index.html";
}
@end
#else // OSX
#import <WebKit/WebKit.h>
@interface STPCheckoutOSXWebViewAdapter : NSObject<STPCheckoutWebViewAdapter>
@property (nonatomic) WebView *webView;
@end
@interface STPCheckoutViewController () <STPCheckoutDelegate>
@property (nonatomic) STPCheckoutOSXWebViewAdapter *adapter;
@end
@implementation STPCheckoutViewController
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
return [self initWithOptions:nil];
}
- (instancetype)initWithCoder:(NSCoder *)coder {
return [self initWithOptions:nil];
}
- (instancetype)initWithOptions:(STPCheckoutOptions *)options {
self = [super initWithNibName:nil bundle:nil];
if (self) {
_options = options;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ [NSURLProtocol registerClass:[STPCheckoutURLProtocol class]]; });
}
return self;
}
- (void)loadView {
NSView *view = [[NSView alloc] initWithFrame:CGRectZero];
self.view = view;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self preload];
NSView *webView = self.adapter.webView;
[self.view addSubview:webView];
webView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[webView]-0-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:NSDictionaryOfVariableBindings(webView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[webView]-0-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:NSDictionaryOfVariableBindings(webView)]];
}
- (void)viewDidAppear {
[super viewDidAppear];
}
- (void)preload {
if (!self.adapter) {
self.adapter = [STPCheckoutOSXWebViewAdapter new];
self.adapter.delegate = self;
NSString *fullURLString = [NSString stringWithFormat:@"%@://%@", STPCheckoutURLProtocolRequestScheme, checkoutURL];
NSURL *url = [NSURL URLWithString:fullURLString];
[self.adapter loadRequest:[NSURLRequest requestWithURL:url]];
}
}
#pragma mark - STPCheckoutAdapterDelegate
- (void)checkoutAdapterDidStartLoad:(id<STPCheckoutWebViewAdapter>)adapter {
NSString *optionsJavaScript = [NSString stringWithFormat:@"window.%@ = %@;", checkoutOptionsGlobal, [self.options stringifiedJSONRepresentation]];
[adapter evaluateJavaScript:optionsJavaScript];
}
- (void)checkoutAdapter:(id<STPCheckoutWebViewAdapter>)adapter didTriggerEvent:(NSString *)event withPayload:(NSDictionary *)payload {
if ([event isEqualToString:@"CheckoutDidOpen"]) {
// no-op for now
} else if ([event isEqualToString:@"CheckoutDidTokenize"]) {
STPToken *token = nil;
if (payload != nil && payload[@"token"] != nil) {
token = [[STPToken alloc] initWithAttributeDictionary:payload[@"token"]];
}
[self.checkoutDelegate checkoutController:self
didCreateToken:token
completion:^(STPBackendChargeResult status, NSError *error) {
if (status == STPBackendChargeResultSuccess) {
[adapter evaluateJavaScript:payload[@"success"]];
} else {
NSString *failure = payload[@"failure"];
NSString *script = [NSString stringWithFormat:failure, error.localizedDescription];
[adapter evaluateJavaScript:script];
}
}];
} else if ([event isEqualToString:@"CheckoutDidFinish"]) {
[self.checkoutDelegate checkoutControllerDidFinish:self];
} else if ([event isEqualToString:@"CheckoutDidCancel"]) {
[self.checkoutDelegate checkoutControllerDidCancel:self];
} else if ([event isEqualToString:@"CheckoutDidError"]) {
NSError *error = [[NSError alloc] initWithDomain:StripeDomain code:STPCheckoutError userInfo:payload];
[self.checkoutDelegate checkoutController:self didFailWithError:error];
}
}
- (void)checkoutAdapterDidFinishLoad:(__unused id<STPCheckoutWebViewAdapter>)adapter {
}
- (void)checkoutAdapter:(__unused id<STPCheckoutWebViewAdapter>)adapter didError:(__unused NSError *)error {
[self.checkoutDelegate checkoutController:self didFailWithError:error];
}
@end
@implementation STPCheckoutOSXWebViewAdapter
@synthesize delegate;
- (instancetype)init {
self = [super init];
if (self) {
_webView = [[WebView alloc] initWithFrame:CGRectZero];
_webView.drawsBackground = NO;
_webView.frameLoadDelegate = self;
_webView.policyDelegate = self;
_webView.resourceLoadDelegate = self;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ [NSURLProtocol registerClass:[STPCheckoutURLProtocol class]]; });
}
return self;
}
- (void)dealloc {
_webView.frameLoadDelegate = nil;
_webView.policyDelegate = nil;
_webView.resourceLoadDelegate = nil;
}
- (void)loadRequest:(NSURLRequest *)request {
[self.webView.mainFrame loadRequest:request];
}
- (void)evaluateJavaScript:(NSString *)js {
[self.webView.windowScriptObject evaluateWebScript:js];
}
- (void)cleanup {
if ([self.webView isLoading]) {
[self.webView stopLoading:nil];
}
}
#pragma mark - ResourceLoadDelegate
- (NSURLRequest *)webView:(WebView *)sender
resource:(id)identifier
willSendRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)redirectResponse
fromDataSource:(WebDataSource *)dataSource {
return request;
}
- (id)webView:(WebView *)sender identifierForInitialRequest:(NSURLRequest *)request fromDataSource:(WebDataSource *)dataSource {
return request.URL;
}
- (void)webView:(WebView *)sender resource:(id)identifier didFailLoadingWithError:(NSError *)error fromDataSource:(WebDataSource *)dataSource {
if ([identifier isEqual:dataSource.initialRequest.URL]) {
[self.delegate checkoutAdapter:self didError:error];
}
}
#pragma mark - WebPolicyDelegate
- (void)webView:(WebView *)webView
decidePolicyForNavigationAction:(NSDictionary *)actionInformation
request:(NSURLRequest *)request
frame:(WebFrame *)frame
decisionListener:(id<WebPolicyDecisionListener>)listener {
NSURL *url = request.URL;
if ([url.scheme.lowercaseString isEqualToString:STPCheckoutURLProtocolRequestScheme.lowercaseString]) {
[listener use];
return;
}
WebNavigationType navigationType = [actionInformation[WebActionNavigationTypeKey] integerValue];
switch (navigationType) {
case WebNavigationTypeLinkClicked: {
if ([url.host isEqualToString:checkoutHost]) {
if ([url.path rangeOfString:checkoutRedirectPrefix].location == 0) {
[[NSWorkspace sharedWorkspace] openURL:url];
[listener ignore];
return;
}
[listener use];
return;
}
[listener ignore];
break;
}
case WebNavigationTypeOther: {
if ([url.scheme isEqualToString:checkoutRPCScheme]) {
NSString *event = url.host;
NSString *path = [url.path componentsSeparatedByString:@"/"][1];
NSDictionary *payload = nil;
if (path != nil) {
payload = [NSJSONSerialization JSONObjectWithData:[path dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
}
[self.delegate checkoutAdapter:self didTriggerEvent:event withPayload:payload];
[listener ignore];
return;
}
[listener use];
break;
}
default:
// add tracking
[listener ignore];
break;
}
}
#pragma mark - WebFrameLoadDelegate
- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
[self.delegate checkoutAdapterDidStartLoad:self];
}
- (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
[self.delegate checkoutAdapter:self didError:error];
}
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
[self.delegate checkoutAdapterDidFinishLoad:self];
}
@end
#endif
#pragma mark - STPCheckoutURLProtocol
/**
* This URL protocol treats any non-20x or 30x response from checkout as an error (unlike the default UIWebView behavior, which e.g. displays a 404 page).
*/
@implementation STPCheckoutURLProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
return [request.URL.scheme.lowercaseString isEqualToString:STPCheckoutURLProtocolRequestScheme.lowercaseString];
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
- (void)startLoading {
NSMutableURLRequest *newRequest = [self.request mutableCopy];
NSString *oldURLString = [[newRequest.URL absoluteString] lowercaseString];
//#warning todo: https
newRequest.URL =
[NSURL URLWithString:[oldURLString stringByReplacingOccurrencesOfString:STPCheckoutURLProtocolRequestScheme.lowercaseString withString:@"http"]];
self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}
- (void)stopLoading {
[self.connection cancel];
self.connection = nil;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
// 30x redirects are automatically followed and will not reach here,
// so we only need to check for successful 20x status codes.
if (httpResponse.statusCode / 100 != 2 && httpResponse.statusCode != 301) {
NSError *error = [[NSError alloc] initWithDomain:StripeDomain
code:STPConnectionError
userInfo:@{
NSLocalizedDescriptionKey: STPUnexpectedError,
STPErrorMessageKey: @"Stripe Checkout couldn't open. Please check your internet connection and try "
@"again. If the problem persists, please contact support@stripe.com."
}];
[self.client URLProtocol:self didFailWithError:error];
[connection cancel];
self.connection = nil;
return;
}
}
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}
- (void)connection:(__unused NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.client URLProtocol:self didLoadData:data];
}
- (void)connectionDidFinishLoading:(__unused NSURLConnection *)connection {
[self.client URLProtocolDidFinishLoading:self];
}
- (void)connection:(__unused NSURLConnection *)connection didFailWithError:(NSError *)error {
[self.client URLProtocol:self didFailWithError:error];
}
@end

View File

@ -7,13 +7,19 @@
//
#import <Foundation/Foundation.h>
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#define STP_COLOR_CLASS UIColor
#else
#import <AppKit/AppKit.h>
#define STP_COLOR_CLASS NSColor
#endif
@interface STPColorUtils : NSObject
+ (BOOL)colorIsLight:(UIColor *)color;
+ (BOOL)colorIsLight:(STP_COLOR_CLASS *)color;
+ (UIColor *)colorForHexCode:(NSString *)hexCode;
+ (NSString *)hexCodeForColor:(UIColor *)color;
+ (STP_COLOR_CLASS *)colorForHexCode:(NSString *)hexCode;
+ (NSString *)hexCodeForColor:(STP_COLOR_CLASS *)color;
@end

View File

@ -12,7 +12,7 @@
// Some of this code is adapted from https://github.com/nicklockwood/ColorUtils
+ (BOOL)colorIsLight:(UIColor *)color {
+ (BOOL)colorIsLight:(STP_COLOR_CLASS *)color {
CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(color.CGColor));
const CGFloat *components = CGColorGetComponents(color.CGColor);
switch (model) {
@ -27,10 +27,10 @@
}
}
+ (UIColor *)colorForHexCode:(NSString *)aHexCode {
+ (STP_COLOR_CLASS *)colorForHexCode:(NSString *)aHexCode {
NSString *hexCode = [aHexCode stringByReplacingOccurrencesOfString:@"#" withString:@""];
if (hexCode.length != 6) {
return [UIColor blackColor];
return [STP_COLOR_CLASS blackColor];
}
uint32_t rgb;
NSScanner *scanner = [NSScanner scannerWithString:hexCode];
@ -38,10 +38,10 @@
CGFloat red = ((rgb & 0xFF0000) >> 16) / 255.0f;
CGFloat green = ((rgb & 0x00FF00) >> 8) / 255.0f;
CGFloat blue = (rgb & 0x0000FF) / 255.0f;
return [[UIColor alloc] initWithRed:red green:green blue:blue alpha:1.0f];
return [STP_COLOR_CLASS colorWithRed:red green:green blue:blue alpha:1.0f];
}
+ (NSString *)hexCodeForColor:(UIColor *)color {
+ (NSString *)hexCodeForColor:(STP_COLOR_CLASS *)color {
uint8_t rgb[3];
CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(color.CGColor));
const CGFloat *components = CGColorGetComponents(color.CGColor);