Commit 5c18d974 by Rune Madsen

Merge pull request #61 from Shopify/develop

Version 1.2.2
parents 52178ebb 2ef81528
......@@ -7,14 +7,14 @@
objects = {
/* Begin PBXBuildFile section */
902C9B8C1BB06BF300FC456E /* GetShopOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 902C9B8B1BB06BF300FC456E /* GetShopOperation.m */; settings = {ASSET_TAGS = (); }; };
902C9B8F1BB0729F00FC456E /* ShippingRateTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 902C9B8E1BB0729F00FC456E /* ShippingRateTableViewCell.m */; settings = {ASSET_TAGS = (); }; };
902C9B921BB08FF500FC456E /* SummaryItemsTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 902C9B911BB08FF500FC456E /* SummaryItemsTableViewCell.m */; settings = {ASSET_TAGS = (); }; };
9079F5F41BB1AAA100CB1B35 /* CollectionListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9079F5F31BB1AAA100CB1B35 /* CollectionListViewController.m */; settings = {ASSET_TAGS = (); }; };
902C9B8C1BB06BF300FC456E /* GetShopOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 902C9B8B1BB06BF300FC456E /* GetShopOperation.m */; };
902C9B8F1BB0729F00FC456E /* ShippingRateTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 902C9B8E1BB0729F00FC456E /* ShippingRateTableViewCell.m */; };
902C9B921BB08FF500FC456E /* SummaryItemsTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 902C9B911BB08FF500FC456E /* SummaryItemsTableViewCell.m */; };
9079F5F41BB1AAA100CB1B35 /* CollectionListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9079F5F31BB1AAA100CB1B35 /* CollectionListViewController.m */; };
90A6F42D1BA8BCAC003E7C4F /* PassKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90A6F42C1BA8BCAC003E7C4F /* PassKit.framework */; };
90B2623E1BB0A47B006D888F /* ProductViewControllerThemeStyleTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 90B2623D1BB0A47B006D888F /* ProductViewControllerThemeStyleTableViewCell.m */; settings = {ASSET_TAGS = (); }; };
90B262411BB0A726006D888F /* ProductViewControllerToggleTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 90B262401BB0A726006D888F /* ProductViewControllerToggleTableViewCell.m */; settings = {ASSET_TAGS = (); }; };
90B262441BB18B10006D888F /* ProductViewControllerThemeTintColorTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 90B262431BB18B10006D888F /* ProductViewControllerThemeTintColorTableViewCell.m */; settings = {ASSET_TAGS = (); }; };
90B2623E1BB0A47B006D888F /* ProductViewControllerThemeStyleTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 90B2623D1BB0A47B006D888F /* ProductViewControllerThemeStyleTableViewCell.m */; };
90B262411BB0A726006D888F /* ProductViewControllerToggleTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 90B262401BB0A726006D888F /* ProductViewControllerToggleTableViewCell.m */; };
90B262441BB18B10006D888F /* ProductViewControllerThemeTintColorTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 90B262431BB18B10006D888F /* ProductViewControllerThemeTintColorTableViewCell.m */; };
BE3437A21BC5C19D00C71330 /* Buy.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE34379F1BC5C18400C71330 /* Buy.framework */; };
BE3437A31BC5C19D00C71330 /* Buy.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BE34379F1BC5C18400C71330 /* Buy.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
BE8B82511B8CF49D00E3F871 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BE8B82501B8CF49D00E3F871 /* main.m */; };
......@@ -31,13 +31,6 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
BE3437981BC5C18400C71330 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BE34378F1BC5C18400C71330 /* Mobile Buy SDK.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 90F7BA681B0D1DAF0067864D;
remoteInfo = Playground;
};
BE34379A1BC5C18400C71330 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BE34378F1BC5C18400C71330 /* Mobile Buy SDK.xcodeproj */;
......@@ -162,7 +155,6 @@
BE3437901BC5C18400C71330 /* Products */ = {
isa = PBXGroup;
children = (
BE3437991BC5C18400C71330 /* Playground.app */,
BE34379B1BC5C18400C71330 /* Mobile Buy SDK Tests.xctest */,
BE34379D1BC5C18400C71330 /* Buy.framework */,
BE34379F1BC5C18400C71330 /* Buy.framework */,
......@@ -311,13 +303,6 @@
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
BE3437991BC5C18400C71330 /* Playground.app */ = {
isa = PBXReferenceProxy;
fileType = wrapper.application;
path = Playground.app;
remoteRef = BE3437981BC5C18400C71330 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
BE34379B1BC5C18400C71330 /* Mobile Buy SDK Tests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
......
......@@ -175,17 +175,29 @@ NSString * const MerchantId = @"";
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Checkout complete" message:nil preferredStyle:UIAlertControllerStyleAlert];;
[alertController addAction:[UIAlertAction actionWithTitle:@"OK"
[alertController addAction:[UIAlertAction actionWithTitle:@"Start over"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[self.navigationController popToRootViewControllerAnimated:YES];
}]];
[alertController addAction:[UIAlertAction actionWithTitle:@"Show order status page"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
SFSafariViewController *safariViewController = [[SFSafariViewController alloc] initWithURL:self.checkout.order.statusURL];
safariViewController.delegate = self;
[self presentViewController:safariViewController animated:YES completion:NULL];
}]];
[self presentViewController:alertController animated:YES completion:nil];
}
#pragma mark - SafariViewControllerDelegate
- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller
{
[self.navigationController popToRootViewControllerAnimated:YES];
}
#pragma mark Native Checkout
- (void)checkoutWithCreditCard
......@@ -228,7 +240,7 @@ NSString * const MerchantId = @"";
NSLog(@"Successfully got completion status: %lu", (unsigned long)completionStatus);
[self showCheckoutConfirmation];
[self getCompletedCheckout];
}
- (void)operation:(GetCompletionStatusOperation *)operation failedToReceiveCompletionStatus:(NSError *)error
......@@ -295,16 +307,8 @@ NSString * const MerchantId = @"";
// Add additional methods if needed and forward the callback to BUYApplePayHelpers
[self.applePayHelper paymentAuthorizationViewController:controller didAuthorizePayment:payment completion:completion];
// Get the completed checkout
[self.client getCheckout:self.applePayHelper.checkout completion:^(BUYCheckout *checkout, NSError *error) {
if (error) {
NSLog(@"Unable to get completed checkout");
NSLog(@"%@", error);
}
if (checkout) {
NSLog(@"%@", checkout);
}
}];
self.checkout = self.applePayHelper.checkout;
[self getCompletedCheckout];
}
- (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller
......@@ -363,9 +367,8 @@ NSString * const MerchantId = @"";
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if (error == nil && status == BUYStatusComplete) {
NSLog(@"Successfully completed checkout");
[welf showCheckoutConfirmation];
[welf getCompletedCheckout];
}
else {
NSLog(@"Error completing checkout: %@", error);
......@@ -374,4 +377,27 @@ NSString * const MerchantId = @"";
[[NSNotificationCenter defaultCenter] removeObserver:self name:CheckoutCallbackNotification object:nil];
}
- (void)getCompletedCheckout
{
__weak CheckoutViewController *welf = self;
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[self.client getCheckout:self.checkout completion:^(BUYCheckout *checkout, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if (error) {
NSLog(@"Unable to get completed checkout");
NSLog(@"%@", error);
}
if (checkout) {
welf.checkout = checkout;
[welf showCheckoutConfirmation];
NSLog(@"%@", checkout);
}
}];
}
@end
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.2.1</string>
<string>1.2.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
......
# Mobile Buy SDK - Product View
The SDK includes an easy-to-use product view to make selling simple in any app.
![Product View Screenshot](https://raw.github.com/Shopify/mobile-buy-sdk-ios/master/Assets/Product_View_Screenshot_1.png)
![Product View Screenshot](https://raw.github.com/Shopify/mobile-buy-sdk-ios/master/Assets/Product_View_Screenshot_2.png)
Simply initialize the `BUYProductViewController` and present it from any view controller in your app to sell a product from you shop.
### Getting started
The `BUYProductViewController` needs a `BUYClient` setup with your shop's credentials to work, so first create a `BUYClient` object:
```objc
BUYClient *client = [[BUYClient alloc] initWithShopDomain:@"yourshop.myshopify.com"
apiKey:@"aaaaaaaaaaaaaaaaaa"
channelId:@"99999"];
```
Now, create a `BUYProductViewController` with the `BUYClient`, and optionally add Apple Pay and a custom theme.
```objc
// Optionally customize the UI:
BUYTheme *theme = [[BUYTheme alloc] init];
theme.style = BUYThemeStyleLight;
theme.tintColor = [UIColor redColor];
BUYProductViewController *productViewController = [[BUYProductViewController alloc] initWithClient:self.client theme:theme];
// Optionally enable Apple Pay:
productViewController.merchantId = @"MERCHANT_ID";
```
Now the `BUYProductViewController` is ready to load a product and be presented in your app:
```objc
[productViewController loadProduct:@"PRODUCT_ID" completion:^(BOOL success, NSError *error) {
if (success) {
[self presentViewController:self.productViewController animated:YES completion:nil];
} else {
NSLog(@"Error: %@", error.userInfo);
}
}];
```
If you have already loaded a product, you can call `loadWithProduct:completion:` instead.
For a complete demo, check out the [Advanced Sample App](https://github.com/Shopify/mobile-buy-sdk-ios/tree/master/Mobile Buy SDK Sample Apps/Sample App Advanced/README.md), which demoes more UI customization with `BUYTheme` and both modal and navigation controller push presentations.
......@@ -17,13 +17,6 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
BE3437B11BC5C20700C71330 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BE3437A81BC5C20700C71330 /* Mobile Buy SDK.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 90F7BA681B0D1DAF0067864D;
remoteInfo = Playground;
};
BE3437B31BC5C20700C71330 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BE3437A81BC5C20700C71330 /* Mobile Buy SDK.xcodeproj */;
......@@ -101,7 +94,6 @@
BE3437A91BC5C20700C71330 /* Products */ = {
isa = PBXGroup;
children = (
BE3437B21BC5C20700C71330 /* Playground.app */,
BE3437B41BC5C20700C71330 /* Mobile Buy SDK Tests.xctest */,
BE3437B61BC5C20700C71330 /* Buy.framework */,
BE3437B81BC5C20700C71330 /* Buy.framework */,
......@@ -210,13 +202,6 @@
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
BE3437B21BC5C20700C71330 /* Playground.app */ = {
isa = PBXReferenceProxy;
fileType = wrapper.application;
path = Playground.app;
remoteRef = BE3437B11BC5C20700C71330 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
BE3437B41BC5C20700C71330 /* Mobile Buy SDK Tests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
......
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.2.1</string>
<string>1.2.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
......
......@@ -23,13 +23,6 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
9019318E1BC5C62800D1134E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 901931851BC5C62700D1134E /* Mobile Buy SDK.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 90F7BA681B0D1DAF0067864D;
remoteInfo = Playground;
};
901931901BC5C62800D1134E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 901931851BC5C62700D1134E /* Mobile Buy SDK.xcodeproj */;
......@@ -131,7 +124,6 @@
901931861BC5C62700D1134E /* Products */ = {
isa = PBXGroup;
children = (
9019318F1BC5C62800D1134E /* Playground.app */,
901931911BC5C62800D1134E /* Mobile Buy SDK Tests.xctest */,
901931931BC5C62800D1134E /* Buy.framework */,
901931951BC5C62800D1134E /* Buy.framework */,
......@@ -267,13 +259,6 @@
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
9019318F1BC5C62800D1134E /* Playground.app */ = {
isa = PBXReferenceProxy;
fileType = wrapper.application;
path = Playground.app;
remoteRef = 9019318E1BC5C62800D1134E /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
901931911BC5C62800D1134E /* Mobile Buy SDK Tests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
......
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.2.1</string>
<string>1.2.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
......
......@@ -364,13 +364,13 @@
{
BUYAddress *newAddress = [self buyAddressWithTestRecordFullDetails:NO];
XCTAssertNotNil(newAddress);
XCTAssertEqualObjects(BUYPartialAddressPlaceholder, newAddress.address1);
XCTAssertEqualObjects(nil, newAddress.address1);
XCTAssertEqualObjects(@"Ottawa", newAddress.city);
XCTAssertEqualObjects(@"Ontario", newAddress.province);
XCTAssertEqualObjects(@"K1N5T5", newAddress.zip);
XCTAssertNil(newAddress.country);
XCTAssertEqualObjects(@"CA", newAddress.countryCode);
XCTAssertEqualObjects(BUYPartialAddressPlaceholder, newAddress.phone);
XCTAssertEqualObjects(nil, newAddress.phone);
}
- (void)testAddressFromContact
......
......@@ -109,7 +109,11 @@
checkout = [[BUYCheckout alloc] initWithCart:cart];
BUYAddress *partialAddress = [[BUYAddress alloc] init];
partialAddress.address1 = BUYPartialAddressPlaceholder;
partialAddress.address1 = nil;
if ([partialAddress isPartialAddress]) {
checkout.partialAddresses = YES;
}
checkout.shippingAddress = partialAddress;
task = [self.client createCheckout:checkout completion:nil];
......
......@@ -967,6 +967,10 @@
_checkout = [[BUYCheckout alloc] initWithCart:_cart];
_checkout.shippingAddress = [self partialShippingAddress];
if ([_checkout.shippingAddress isPartialAddress]) {
_checkout.partialAddresses = YES;
}
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) {
return [self shouldUseMocks];
} withStubResponse:^OHHTTPStubsResponse * _Nonnull(NSURLRequest * _Nonnull request) {
......@@ -994,6 +998,7 @@
//Update with full addresses
_checkout.shippingAddress = [self shippingAddress];
_checkout.billingAddress = [self billingAddress];
[self updateCheckout];
//We use a credit card here because we're not generating apple pay tokens in the tests
......@@ -1211,14 +1216,14 @@
- (BUYAddress *)partialShippingAddress
{
BUYAddress *address = [[BUYAddress alloc] init];
address.address1 = BUYPartialAddressPlaceholder;
address.address1 = nil;
address.city = @"Ottawa";
address.firstName = BUYPartialAddressPlaceholder;
address.lastName = BUYPartialAddressPlaceholder;
address.firstName = nil;
address.lastName = nil;
address.countryCode = @"CA";
address.provinceCode = @"ON";
address.zip = @"K1N5T5";
address.phone = BUYPartialAddressPlaceholder;
address.phone = nil;
return address;
}
......
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "90F7BA671B0D1DAF0067864D"
BuildableName = "Playground.app"
BlueprintName = "Playground"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "90F592401B0D569F0026B382"
BuildableName = "BuyTests.xctest"
BlueprintName = "BuyTests"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "90F592A61B0D585D0026B382"
BuildableName = "TESTTests.xctest"
BlueprintName = "TESTTests"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "90F592401B0D569F0026B382"
BuildableName = "BuyTests.xctest"
BlueprintName = "BuyTests"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "90F592A61B0D585D0026B382"
BuildableName = "TESTTests.xctest"
BlueprintName = "TESTTests"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "90F7BA671B0D1DAF0067864D"
BuildableName = "Playground.app"
BlueprintName = "Playground"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "90F7BA671B0D1DAF0067864D"
BuildableName = "Playground.app"
BlueprintName = "Playground"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "90F7BA671B0D1DAF0067864D"
BuildableName = "Playground.app"
BlueprintName = "Playground"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
......@@ -24,36 +24,40 @@
// THE SOFTWARE.
//
/**
* Umbrella header used for Cocoapods
*/
#import <UIKit/UIKit.h>
#import "BUYApplePayAdditions.h"
#import "BUYApplePayHelpers.h"
#import "BUYAddress.h"
#import "BUYCart.h"
#import "BUYCartLineItem.h"
#import "BUYCheckout.h"
#import "BUYClient+Test.h"
#import "BUYClient.h"
#import "BUYCollection.h"
#import "BUYCreditCard.h"
#import "BUYDiscount.h"
#import "BUYError.h"
#import "BUYGiftCard.h"
#import "BUYImage.h"
#import "BUYLineItem.h"
#import "BUYMaskedCreditCard.h"
#import "BUYOption.h"
#import "BUYOptionValue.h"
#import "BUYOrder.h"
#import "BUYPaymentButton.h"
#import "BUYProduct.h"
#import "BUYProductVariant.h"
#import "BUYProductViewController.h"
#import "BUYShippingRate.h"
#import "BUYShop.h"
#import "BUYStoreViewController.h"
#import "BUYTaxLine.h"
#import "BUYTheme.h"
#import "BUYViewController.h"
//! Project version number for Buy.
FOUNDATION_EXPORT double BuyVersionNumber;
//! Project version string for Buy.
FOUNDATION_EXPORT const unsigned char BuyVersionString[];
#import <Buy/BUYAddress.h>
#import <Buy/BUYCart.h>
#import <Buy/BUYCheckout.h>
#import <Buy/BUYCreditCard.h>
#import <Buy/BUYDiscount.h>
#import <Buy/BUYGiftCard.h>
#import <Buy/BUYLineItem.h>
#import <Buy/BUYClient.h>
#import <Buy/BUYClient+Test.h>
#import <Buy/BUYImage.h>
#import <Buy/BUYOption.h>
#import <Buy/BUYOptionValue.h>
#import <Buy/BUYOrder.h>
#import <Buy/BUYProduct.h>
#import <Buy/BUYProductVariant.h>
#import <Buy/BUYShippingRate.h>
#import <Buy/BUYShop.h>
#import <Buy/BUYStoreViewController.h>
#import <Buy/BUYTaxLine.h>
#import <Buy/BUYViewController.h>
#import <Buy/BUYApplePayAdditions.h>
#import <Buy/BUYApplePayHelpers.h>
#import <Buy/BUYPaymentButton.h>
#import <Buy/BUYProductViewController.h>
#import <Buy/BUYTheme.h>
#import <Buy/BUYCartLineItem.h>
#import <Buy/BUYCollection.h>
#import <Buy/BUYMaskedCreditCard.h>
#import <Buy/BUYError.h>
......@@ -33,7 +33,6 @@
#import "BUYProduct.h"
#import "BUYShippingRate.h"
#import "BUYShop.h"
#import "BUYCheckout+Additions.h"
#import "BUYCheckout_Private.h"
#import "NSDecimalNumber+BUYAdditions.h"
#import "BUYError.h"
......@@ -54,7 +53,7 @@
#define kMinSuccessfulStatusCode 200
#define kMaxSuccessfulStatusCode 299
NSString * const BUYVersionString = @"1.2.1";
NSString * const BUYVersionString = @"1.2.2";
@interface BUYClient () <NSURLSessionDelegate>
......@@ -252,7 +251,7 @@ NSString * const BUYVersionString = @"1.2.1";
// Inject channel and marketing attributions
[self configureCheckout:checkout];
NSDictionary *json = [checkout jsonDictionaryForUpdatingCheckout];
NSDictionary *json = [checkout jsonDictionaryForCheckout];
return [self postCheckout:json completion:block];
}
......@@ -261,7 +260,7 @@ NSString * const BUYVersionString = @"1.2.1";
BUYCheckout *checkout = [[BUYCheckout alloc] initWithCartToken:cartToken];
[self configureCheckout:checkout];
NSDictionary *json = [checkout jsonDictionaryForUpdatingCheckout];
NSDictionary *json = [checkout jsonDictionaryForCheckout];
return [self postCheckout:json completion:block];
}
......@@ -343,7 +342,7 @@ NSString * const BUYVersionString = @"1.2.1";
- (NSURLSessionDataTask *)updateCheckout:(BUYCheckout *)checkout completion:(BUYDataCheckoutBlock)block
{
NSDictionary *json = [checkout jsonDictionaryForUpdatingCheckout];
NSDictionary *json = [checkout jsonDictionaryForCheckout];
NSData *data = [NSJSONSerialization dataWithJSONObject:json options:0 error:nil];
NSURLSessionDataTask *task = nil;
......
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.2.1</string>
<string>1.2.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
......
......@@ -26,6 +26,7 @@
#import "BUYAddress.h"
#import "NSString+Trim.h"
#import "NSDictionary+Additions.h"
@implementation BUYAddress
......@@ -41,8 +42,8 @@
self.country = dictionary[@"country"];
self.countryCode = dictionary[@"country_code"];
self.province = dictionary[@"province"];
self.provinceCode = dictionary[@"province_code"];
self.province = [dictionary buy_objectForKey:@"province"];
self.provinceCode = [dictionary buy_objectForKey:@"province_code"];
self.zip = dictionary[@"zip"];
}
......
......@@ -249,6 +249,11 @@
@property (nonatomic, strong, readonly) BUYOrder *order;
/**
* Flag used to inform server that the shipping address is partially filled, suitable to retrieve shipping rates
*/
@property (nonatomic, assign) BOOL partialAddresses;
/**
* It is recommended to instantiate a checkout with a cart, or cart token
*
* @return Checkout
......
......@@ -41,6 +41,7 @@
#import "BUYCheckout_Private.h"
#import "NSDateFormatter+BUYAdditions.h"
#import "NSURL+BUYAdditions.h"
#import "NSDictionary+Additions.h"
@implementation BUYCheckout
......@@ -159,7 +160,7 @@
self.createdAtDate = [dateFormatter dateFromString:dictionary[@"created_at"]];
self.updatedAtDate = [dateFormatter dateFromString:dictionary[@"updated_at"]];
self.creditCard = [BUYMaskedCreditCard convertObject:dictionary[@"credit_card"]];
self.customerId = [dictionary[@"customer_id"] copy];
self.customerId = [dictionary buy_objectForKey:@"customer_id"];
self.note = dictionary[@"note"];
self.privacyPolicyURL = [NSURL buy_urlWithString:dictionary[@"privacy_policy_url"]];
......
......@@ -27,6 +27,7 @@
#import "BUYCollection.h"
#import "NSDateFormatter+BUYAdditions.h"
#import "NSURL+BUYAdditions.h"
#import "NSDictionary+Additions.h"
@interface BUYCollection ()
@property (nonatomic, strong) NSString *title;
......@@ -44,7 +45,7 @@
_title = dictionary[@"title"];
_htmlDescription = dictionary[@"body_html"];
_imageURL = [dictionary[@"image"] isKindOfClass:[NSNull class]] ? nil : [NSURL buy_urlWithString:dictionary[@"image"][@"src"]];
_imageURL = [NSURL buy_urlWithString:[dictionary buy_objectForKey:@"image"][@"src"]];
_handle = dictionary[@"handle"];
_published = [dictionary[@"published"] boolValue];
_collectionId = dictionary[@"collection_id"];
......
......@@ -26,6 +26,7 @@
#import "BUYOrder.h"
#import "NSURL+BUYAdditions.h"
#import "NSDictionary+Additions.h"
@interface BUYOrder ()
......@@ -42,7 +43,7 @@
[super updateWithDictionary:dictionary];
NSString *statusURLString = dictionary[@"status_url"];
self.statusURL = [NSURL buy_urlWithString:statusURLString];
self.name = [dictionary[@"name"] isKindOfClass:[NSNull class]] ? nil : dictionary[@"name"];
self.name = [dictionary buy_objectForKey:@"name"];
}
@end
......@@ -29,6 +29,7 @@
#import "BUYProduct.h"
#import "BUYProductVariant.h"
#import "NSDateFormatter+BUYAdditions.h"
#import "NSDictionary+Additions.h"
@implementation BUYProduct
......@@ -46,7 +47,7 @@
}];
_images = [BUYImage convertJSONArray:dictionary[@"images"]];
_options = [BUYOption convertJSONArray:dictionary[@"options"]];
_htmlDescription = [dictionary[@"body_html"] isKindOfClass:[NSNull class]] ? nil : dictionary[@"body_html"];
_htmlDescription = [dictionary buy_objectForKey:@"body_html"];
_available = [dictionary[@"available"] boolValue];
_published = [dictionary[@"published"] boolValue];
NSDateFormatter *dateFormatter = [NSDateFormatter dateFormatterForPublications];
......
......@@ -24,40 +24,36 @@
// THE SOFTWARE.
//
#import <UIKit/UIKit.h>
/**
* Umbrella header used for Cocoapods
*/
//! Project version number for BuyDynamic.
FOUNDATION_EXPORT double BuyDynamicVersionNumber;
//! Project version string for BuyDynamic.
FOUNDATION_EXPORT const unsigned char BuyDynamicVersionString[];
#import <Buy/BUYAddress.h>
#import <Buy/BUYCart.h>
#import <Buy/BUYCheckout.h>
#import <Buy/BUYCreditCard.h>
#import <Buy/BUYDiscount.h>
#import <Buy/BUYGiftCard.h>
#import <Buy/BUYLineItem.h>
#import <Buy/BUYClient.h>
#import <Buy/BUYClient+Test.h>
#import <Buy/BUYImage.h>
#import <Buy/BUYOption.h>
#import <Buy/BUYOptionValue.h>
#import <Buy/BUYOrder.h>
#import <Buy/BUYProduct.h>
#import <Buy/BUYProductVariant.h>
#import <Buy/BUYShippingRate.h>
#import <Buy/BUYShop.h>
#import <Buy/BUYStoreViewController.h>
#import <Buy/BUYTaxLine.h>
#import <Buy/BUYViewController.h>
#import <Buy/BUYApplePayAdditions.h>
#import <Buy/BUYApplePayHelpers.h>
#import <Buy/BUYPaymentButton.h>
#import <Buy/BUYProductViewController.h>
#import <Buy/BUYTheme.h>
#import <Buy/BUYCartLineItem.h>
#import <Buy/BUYCollection.h>
#import <Buy/BUYMaskedCreditCard.h>
#import <Buy/BUYError.h>
#import "BUYApplePayAdditions.h"
#import "BUYApplePayHelpers.h"
#import "BUYAddress.h"
#import "BUYCart.h"
#import "BUYCartLineItem.h"
#import "BUYCheckout.h"
#import "BUYClient+Test.h"
#import "BUYClient.h"
#import "BUYCollection.h"
#import "BUYCreditCard.h"
#import "BUYDiscount.h"
#import "BUYError.h"
#import "BUYGiftCard.h"
#import "BUYImage.h"
#import "BUYLineItem.h"
#import "BUYMaskedCreditCard.h"
#import "BUYOption.h"
#import "BUYOptionValue.h"
#import "BUYOrder.h"
#import "BUYPaymentButton.h"
#import "BUYProduct.h"
#import "BUYProductVariant.h"
#import "BUYProductViewController.h"
#import "BUYShippingRate.h"
#import "BUYShop.h"
#import "BUYStoreViewController.h"
#import "BUYTaxLine.h"
#import "BUYTheme.h"
#import "BUYViewController.h"
// Buy.modedulemap
//
// Buy.modulemap
// Mobile Buy SDK
//
// Created by Shopify.
......
......@@ -27,8 +27,6 @@
@import Foundation;
#import "BUYAddress.h"
extern NSString * const BUYPartialAddressPlaceholder;
@interface BUYAddress (Additions)
/**
......
......@@ -26,16 +26,14 @@
#import "BUYAddress+Additions.h"
NSString * const BUYPartialAddressPlaceholder = @"---";
@implementation BUYAddress (Additions)
- (BOOL)isPartialAddress
{
if ([self.address1 isEqualToString:BUYPartialAddressPlaceholder] ||
[self.firstName isEqualToString:BUYPartialAddressPlaceholder] ||
[self.lastName isEqualToString:BUYPartialAddressPlaceholder]) {
if (self.address1.length == 0 ||
self.firstName.length == 0 ||
self.lastName.length == 0) {
return YES;
}
......
......@@ -47,7 +47,7 @@
if (hasDiscount || [self.lineItems count] > 1) {
NSDecimalNumber *lineItemSubtotal = [NSDecimalNumber zero];
for (BUYLineItem *lineItem in self.lineItems) {
lineItemSubtotal = [lineItemSubtotal decimalNumberByAdding:lineItem.price];
lineItemSubtotal = [lineItemSubtotal decimalNumberByAdding:lineItem.linePrice];
}
[summaryItems addObject:[PKPaymentSummaryItem summaryItemWithLabel:@"CART TOTAL" amount:lineItemSubtotal]];
}
......@@ -143,14 +143,7 @@
//Grab the simple information
address.firstName = (__bridge_transfer NSString *)ABRecordCopyValue(record, kABPersonFirstNameProperty);
if ([address.firstName length] == 0) {
address.firstName = BUYPartialAddressPlaceholder;
}
address.lastName = (__bridge_transfer NSString *)ABRecordCopyValue(record, kABPersonLastNameProperty);
if ([[address lastName] length] == 0) {
address.lastName = BUYPartialAddressPlaceholder;
}
//Grab the address information
ABMultiValueRef addressMultiValue = ABRecordCopyValue(record, kABPersonAddressProperty);
......@@ -160,10 +153,6 @@
//NOTE: We do not receive an address1 line right now via this partial address, as Apple deemds it unimportant to calculate the shipping rates. We get the actual address later on in a later step.
address.address1 = (__bridge NSString *)CFDictionaryGetValue(firstAddress, kABPersonAddressStreetKey);
if (address.address1 == nil) {
address.address1 = BUYPartialAddressPlaceholder;
}
address.city = (__bridge NSString *)CFDictionaryGetValue(firstAddress, kABPersonAddressCityKey);
address.province = (__bridge NSString *)CFDictionaryGetValue(firstAddress, kABPersonAddressStateKey);
address.zip = (__bridge NSString *)CFDictionaryGetValue(firstAddress, kABPersonAddressZIPKey);
......@@ -185,9 +174,7 @@
if (allPhoneNumbers && CFArrayGetCount(allPhoneNumbers) > 0) {
address.phone = (__bridge NSString *)CFArrayGetValueAtIndex(allPhoneNumbers, 0);
}
if ([address.phone length] == 0) {
address.phone = BUYPartialAddressPlaceholder;
}
CFSafeRelease(phoneMultiValue);
CFSafeRelease(allPhoneNumbers);
......@@ -198,15 +185,15 @@
{
BUYAddress *address = [[BUYAddress alloc] init];
address.firstName = [contact.name.givenName length] ? contact.name.givenName : BUYPartialAddressPlaceholder;
address.lastName = [contact.name.familyName length] ? contact.name.familyName : BUYPartialAddressPlaceholder;
address.firstName = contact.name.givenName;
address.lastName = contact.name.familyName;
if (contact.postalAddress) {
// break up the address:
NSArray *addressComponents = [contact.postalAddress.street componentsSeparatedByString:@"\n"];
address.address1 = [addressComponents[0] length] ? addressComponents[0] : BUYPartialAddressPlaceholder;
address.address2 = ([addressComponents count] > 1 && addressComponents[1]) ? addressComponents[1] : nil;
address.city = [contact.postalAddress.city length] ? contact.postalAddress.city : BUYPartialAddressPlaceholder;
address.address1 = addressComponents[0];
address.address2 = (addressComponents.count > 1) ? addressComponents[1] : nil;
address.city = contact.postalAddress.city;
address.province = contact.postalAddress.state;
address.zip = contact.postalAddress.postalCode;
// The Checkout API accepts country OR ISO country code.
......@@ -219,7 +206,7 @@
}
}
address.phone = contact.phoneNumber.stringValue ?: BUYPartialAddressPlaceholder;
address.phone = contact.phoneNumber.stringValue;
return address;
}
......
......@@ -90,11 +90,18 @@ const NSTimeInterval PollDelay = 0.5;
// Update the checkout with the rest of the information. Apple has now provided us with a FULL billing address and a FULL shipping address.
// We now update the checkout with our new found data so that you can ship the products to the right address, and we collect whatever else we need.
self.checkout.shippingAddress = self.checkout.requiresShipping ? [BUYAddress buy_addressFromRecord:[payment shippingAddress]] : nil;
self.checkout.billingAddress = [BUYAddress buy_addressFromRecord:[payment billingAddress]];
self.checkout.email = [BUYAddress buy_emailFromRecord:[payment billingAddress]];
if (self.checkout.email == nil) {
self.checkout.email = [BUYAddress buy_emailFromRecord:[payment shippingAddress]];
self.checkout.partialAddresses = NO;
if ([payment respondsToSelector:@selector(shippingContact)]) {
self.checkout.email = payment.shippingContact.emailAddress;
self.checkout.shippingAddress = self.checkout.requiresShipping ? [BUYAddress buy_addressFromContact:payment.shippingContact] : nil;
} else {
self.checkout.email = [BUYAddress buy_emailFromRecord:payment.shippingAddress];
self.checkout.shippingAddress = self.checkout.requiresShipping ? [BUYAddress buy_addressFromRecord:payment.shippingAddress] : nil;
}
if ([payment respondsToSelector:@selector(billingContact)]) {
self.checkout.billingAddress = [BUYAddress buy_addressFromContact:payment.billingContact];
} else {
self.checkout.billingAddress = [BUYAddress buy_addressFromRecord:payment.billingAddress];
}
[self.client updateCheckout:self.checkout completion:^(BUYCheckout *checkout, NSError *error) {
......@@ -159,6 +166,8 @@ const NSTimeInterval PollDelay = 0.5;
- (void)updateCheckoutWithAddressCompletion:(void (^)(PKPaymentAuthorizationStatus, NSArray *shippingMethods, NSArray *summaryItems))completion
{
self.checkout.partialAddresses = [self.checkout.shippingAddress isPartialAddress];
if ([self.checkout.shippingAddress isValidAddressForShippingRates]) {
[self.client updateCheckout:self.checkout completion:^(BUYCheckout *checkout, NSError *error) {
......
//
// BUYCheckout+Additions.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "BUYCheckout+Additions.h"
#import "BUYAddress+Additions.h"
@implementation BUYCheckout (Additions)
- (NSDictionary *)jsonDictionaryForUpdatingCheckout
{
NSMutableDictionary *json = [[self jsonDictionaryForCheckout] mutableCopy];
if ([self.shippingAddress isPartialAddress]) {
json[@"checkout"][@"partial_addresses"] = @YES;
}
return [json copy];
}
@end
......@@ -71,7 +71,11 @@
{
if ([self.variants count] == 1) {
BUYProductVariant *productVariant = [self.variants firstObject];
if ([productVariant.title isEqualToString:@"Default Title"]) {
BUYOptionValue *optionValue = [productVariant.options firstObject];
NSString *defaultTitleString = @"Default Title";
NSString *defaultString = @"Default";
if ([productVariant.title isEqualToString:defaultTitleString] &&
([optionValue.value isEqualToString:defaultTitleString] || [optionValue.value isEqualToString:defaultString])) {
return YES;
}
}
......
//
// BUYCheckout+Additions.h
// NSDictionary+Additions.h
//
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,16 +25,17 @@
// THE SOFTWARE.
//
#import "BUYCheckout.h"
#import <Foundation/Foundation.h>
@interface BUYCheckout (Additions)
@interface NSDictionary (Additions)
/**
* Used for Apple Pay, specifically, to append true for
* the payload to set whether the address(es) are partial.
* Alernative to objectForKey, where NSNull is replaced with nil
*
* @param key The key for which to return the corresponding value.
*
* @return A jsonDictionaryForCheckout JSON with optional "checkout.partial_addresses" key.
* @return The value associated with key
*/
- (NSDictionary *)jsonDictionaryForUpdatingCheckout;
- (id)buy_objectForKey:(NSString *)key;
@end
//
// FirstViewController.h
// NSDictionary+Additions.m
//
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,9 +25,13 @@
// THE SOFTWARE.
//
@import UIKit;
#import "NSDictionary+Additions.h"
@interface FirstViewController : UIViewController
@implementation NSDictionary (Additions)
@end
- (id)buy_objectForKey:(NSString *)key
{
return ([self[key] isKindOfClass:[NSNull class]]) ? nil : self[key];
}
@end
......@@ -117,6 +117,8 @@ NSString * BUYURLKey = @"url";
- (void)startApplePayCheckout:(BUYCheckout *)checkout
{
// Default to the failure state, since cancelling a payment would not update the state and thus appear as a success
self.paymentAuthorizationStatus = PKPaymentAuthorizationStatusFailure;
if (self.shop == nil && self.isLoadingShop == NO) {
// since requests are sent serially, this will return before the checkout is created
......
//
// AppDelegate.h
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
@import UIKit;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
//
// AppDelegate.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// 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.
// 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.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// 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.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// 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.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// 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.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 Shopify Inc. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Playground" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14E46" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="9pv-A4-QxB">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
</dependencies>
<scenes>
<!--First-->
<scene sceneID="hNz-n2-bh7">
<objects>
<viewController id="9pv-A4-QxB" customClass="FirstViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ia1-K6-d13"/>
<viewControllerLayoutGuide type="bottom" id="4ug-Mw-9AY"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="tsR-hK-woN">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2El-PP-Jfr">
<rect key="frame" x="277" y="285" width="46" height="30"/>
<state key="normal" title="Button">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="buttonAction:" destination="9pv-A4-QxB" eventType="touchUpInside" id="EOa-8G-Lqn"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="centerX" secondItem="2El-PP-Jfr" secondAttribute="centerX" id="OeO-pC-gHW"/>
<constraint firstAttribute="centerY" secondItem="2El-PP-Jfr" secondAttribute="centerY" id="xQc-2f-hrm"/>
</constraints>
</view>
<tabBarItem key="tabBarItem" title="First" image="first" id="acW-dT-cKf"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="W5J-7L-Pyd" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="750" y="-320"/>
</scene>
</scenes>
<resources>
<image name="first" width="30" height="30"/>
</resources>
</document>
//
// FirstViewController.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "FirstViewController.h"
@import Buy;
@interface FirstViewController ()
@property (nonatomic, strong) BUYClient *client;
@end
@implementation FirstViewController
- (IBAction)buttonAction:(id)sender {
}
@end
{
"images" : [
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-Small@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-Small@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-Small-40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-Small-40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-60@3x.png",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-76.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-76@2x.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
{
"images" : [
{
"idiom" : "universal",
"filename" : "first.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
{
"images" : [
{
"idiom" : "universal",
"filename" : "second.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
<?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.shopify.$(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.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>playground</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarTintParameters</key>
<dict>
<key>UINavigationBar</key>
<dict>
<key>Style</key>
<string>UIBarStyleDefault</string>
<key>Translucent</key>
<false/>
</dict>
</dict>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
</dict>
</plist>
<?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>com.apple.developer.in-app-payments</key>
<array/>
</dict>
</plist>
//
// main.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
@import UIKit;
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
......@@ -6,7 +6,6 @@
<title>{{page.title}}</title>
<link rel="stylesheet" href="{{page.cssPath}}">
<link rel="stylesheet" href="/api/mobile-buy-sdk/ios/api/css/style.css">
<meta name="viewport" content="initial-scale=1, maximum-scale=1.4">
{{#strings.appledocData}}<meta name="generator" content="{{tool}} {{version}} (build {{build}})">{{/strings.appledocData}}
</head>
......@@ -58,7 +57,6 @@
</div>
</article>
<script src="/api/mobile-buy-sdk/ios/api/script.js"></script>
<script src="{{page.jsPath}}"></script>
</body>
</html>
......
......@@ -6,7 +6,6 @@
<title>{{page.title}}</title>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="/api/mobile-buy-sdk/ios/api/css/style.css">
<meta name="viewport" content="initial-scale=1, maximum-scale=1.4">
{{#strings.appledocData}}<meta name="generator" content="{{tool}} {{version}} (build {{build}})">{{/strings.appledocData}}
</head>
......@@ -92,7 +91,6 @@
</div>
</article>
<script src="/api/mobile-buy-sdk/ios/api/script.js"></script>
<script src="js/script.js"></script>
</body>
</html>
......@@ -108,5 +106,5 @@ Section Classes
EndSection
Section Navigation
<li><a href="/api/mobile-buy-sdk/ios/api/index.html">Home</a></li>
<li><a href="index.html">Home</a></li>
EndSection
......@@ -6,7 +6,6 @@
<title>{{page.title}}</title>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="/api/mobile-buy-sdk/ios/api/css/style.css">
<meta name="viewport" content="initial-scale=1, maximum-scale=1.4">
{{#strings.appledocData}}<meta name="generator" content="{{tool}} {{version}} (build {{build}})">{{/strings.appledocData}}
</head>
......@@ -57,7 +56,7 @@
<h2 class="index-title">{{page.docsTitle}}</h2>
<ul>
{{#docs}}
<li><a href="/api/mobile-buy-sdk/ios/api/{{href}}">{{title}}</a></li>
<li><a href="{{href}}">{{title}}</a></li>
{{/docs}}
</ul>
</div>
......@@ -68,7 +67,7 @@
<h2 class="index-title">{{strings.indexPage.classesTitle}}</h2>
<ul>
{{#classes}}
<li><a href="/api/mobile-buy-sdk/ios/api/{{href}}">{{title}}</a></li>
<li><a href="{{href}}">{{title}}</a></li>
{{/classes}}
</ul>
</div>
......@@ -80,7 +79,7 @@
<h2 class="index-title">{{strings.indexPage.protocolsTitle}}</h2>
<ul>
{{#protocols}}
<li><a href="/api/mobile-buy-sdk/ios/api/{{href}}">{{title}}</a></li>
<li><a href="{{href}}">{{title}}</a></li>
{{/protocols}}
</ul>
{{/hasProtocols}}
......@@ -89,7 +88,7 @@
<h2 class="index-title">{{strings.indexPage.constantsTitle}}</h2>
<ul>
{{#constants}}
<li><a href="/api/mobile-buy-sdk/ios/api/{{href}}">{{title}}</a></li>
<li><a href="{{href}}">{{title}}</a></li>
{{/constants}}
</ul>
{{/hasConstants}}
......@@ -98,7 +97,7 @@
<h2 class="index-title">{{strings.indexPage.categoriesTitle}}</h2>
<ul>
{{#categories}}
<li><a href="/api/mobile-buy-sdk/ios/api/{{href}}">{{title}}</a></li>
<li><a href="{{href}}">{{title}}</a></li>
{{/categories}}
</ul>
{{/hasCategories}}
......@@ -121,11 +120,10 @@
</div>
</article>
<script src="/api/mobile-buy-sdk/ios/api/script.js"></script>
<script src="js/script.js"></script>
</body>
</html>
Section Navigation
<li><a href="/api/mobile-buy-sdk/ios/api/hierarchy.html">Hierarchy</a></li>
<li><a href="hierarchy.html">Hierarchy</a></li>
EndSection
......@@ -6,7 +6,6 @@
<title>{{page.title}}</title>
<link rel="stylesheet" href="../css/style.css">
<link rel="stylesheet" href="/api/mobile-buy-sdk/ios/api/css/style.css">
<meta name="viewport" content="initial-scale=1, maximum-scale=1.4">
{{#strings.appledocData}}<meta name="generator" content="{{tool}} {{version}} (build {{build}})">{{/strings.appledocData}}
</head>
......@@ -370,8 +369,8 @@ EndSection
Section Navigation
<li><a href="/api/mobile-buy-sdk/ios/api/index.html">Index</a></li>
<li><a href="/api/mobile-buy-sdk/ios/api/hierarchy.html">Hierarchy</a></li>
<li><a href="../index.html">Index</a></li>
<li><a href="../hierarchy.html">Hierarchy</a></li>
EndSection
Section JumpTo
......
Pod::Spec.new do |s|
s.name = 'Mobile-Buy-SDK'
s.version = '1.2.1'
s.version = '1.2.2'
s.summary = 'Sell with Shopify in iOS apps'
s.description = 'Shopify’s Mobile Buy SDK makes it simple to sell physical products inside your mobile app. With a few lines of code, you can connect your app with the Shopify platform and let your users buy your products using Apple Pay or their credit card.'
s.homepage = 'https://developers.shopify.com/mobile-buy-sdk'
......@@ -10,7 +10,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://github.com/Shopify/mobile-buy-sdk-ios.git', :tag => s.version }
s.source_files = 'Mobile Buy SDK/Mobile Buy SDK/**/*.{h,m,mm}'
s.public_header_files = 'Mobile Buy SDK/Mobile Buy SDK/**/*.h'
s.exclude_files = 'Mobile Buy SDK/Mobile Buy SDK/Static Framework/*'
s.exclude_files = 'Mobile Buy SDK/Mobile Buy SDK/Buy.h'
s.module_name = 'Buy'
s.frameworks = 'PassKit'
s.libraries = 'c++'
......
![Mobile Buy SDK](http://s3.amazonaws.com/shopify-marketing_assets/static/mbsdk-github.png)
![Mobile Buy SDK](https://raw.github.com/Shopify/mobile-buy-sdk-ios/master/Assets/Mobile_Buy_SDK_Github_banner.png)
[![Build status](https://badge.buildkite.com/3951692121947fbf7bb06c4b741601fc091efea3fa119a4f88.svg)](https://buildkite.com/shopify/mobile-buy-sdk-ios)
[![GitHub license](https://img.shields.io/badge/license-MIT-lightgrey.svg)](https://github.com/Shopify/mobile-buy-sdk-ios/blob/master/LICENSE)
......@@ -12,11 +12,15 @@ Shopify’s Mobile Buy SDK makes it simple to sell physical products inside your
### Documentation
Please find all documentation on the [Mobile Buy SDK for iOS page](https://docs.shopify.com/mobile-buy-sdk/ios).
Official documentation can be found on the [Mobile Buy SDK for iOS page](https://docs.shopify.com/mobile-buy-sdk/ios).
#### API Documentation
API docs can be generated with the `Documentation` scheme or viewed on Cocoadocs: [http://cocoadocs.org/docsets/Mobile-Buy-SDK/](http://cocoadocs.org/docsets/Mobile-Buy-SDK/).
### Installation
<a href="../../releases/latest">Download the latest version</a>
<a href="https://github.com/Shopify/mobile-buy-sdk-ios/releases/latest">Download the latest version</a>
#### Dynamic Framework Installation
......@@ -24,7 +28,7 @@ Please find all documentation on the [Mobile Buy SDK for iOS page](https://docs.
2. Add the `Buy` target as a `Target Dependancy` in the `Build Phases` of your project's target
3. Add the `Buy` (second target on the list is the Dynamic framework) target in the `Embedded Binaries` section in `Build Phases`
See the [Sample Apps](/Mobile Buy SDK Sample Apps/) for an example of Dynamic Framework usage.
See the [Sample Apps](https://github.com/Shopify/mobile-buy-sdk-ios/tree/master/Mobile Buy SDK Sample Apps/) for an example of Dynamic Framework usage.
#### Static Framework Installation
......@@ -108,18 +112,25 @@ The Mobile Buy SDK includes a number of targets and schemes:
* **Documentation**: This generates appledoc documentation for the framework
* **Playground**: This is a basic app that depends directly on the `Buy` dynamic framework. You may use this app and target to play around with the SDK. Be sure not to check in any changes you may have made in files related to this app
### Sample Apps
The repo includes 3 sample apps. Each sample apps embeds the dynamic framework and includes readme files with more information:
* [Advanced Sample App](/Mobile Buy SDK Sample Apps/Sample App Advanced/README.md)
* [Swift Sample App](/Mobile Buy SDK Sample Apps/Sample App Swift/README.md)
* [Web Sample App](/Mobile Buy SDK Sample Apps/Sample App Web/README.md)
* [Advanced Sample App](https://github.com/Shopify/mobile-buy-sdk-ios/tree/master/Mobile Buy SDK Sample Apps/Sample App Advanced/README.md)
* [Swift Sample App](https://github.com/Shopify/mobile-buy-sdk-ios/tree/master/Mobile Buy SDK Sample Apps/Sample App Swift/README.md)
* [Web Sample App](https://github.com/Shopify/mobile-buy-sdk-ios/tree/master/Mobile Buy SDK Sample Apps/Sample App Web/README.md)
We suggest you take a look at the **Advanced Sample App** and test your shop with the sample app before you begin. If you run into any issues, the **Advanced Sample App** is also a great resource for debugging integration issues and checkout.
### Product View
The SDK includes an easy-to-use product view to make selling simple in any app.
![Product View Screenshot](https://raw.github.com/Shopify/mobile-buy-sdk-ios/master/Assets/Product_View_Screenshot_1.png)
![Product View Screenshot](https://raw.github.com/Shopify/mobile-buy-sdk-ios/master/Assets/Product_View_Screenshot_2.png)
The [Advanced Sample App](https://github.com/Shopify/mobile-buy-sdk-ios/tree/master/Mobile Buy SDK Sample Apps/Sample App Advanced/) includes a demo of the `BUYProductViewController`. Documentation on how to use the `BUYProductViewController` is also available [here](https://github.com/Shopify/mobile-buy-sdk-ios/tree/master/Mobile Buy SDK Sample Apps/Sample App Advanced/PRODUCT_VIEW_README.md).
### Unit Tests
To run the Mobile Buy SDK integration tests against an actual shop, you will need a Shopify shop that is publicly accessible (not password protected). Please note that the integration tests **will create an order** on that shop. This is to validate that the SDK works properly with Shopify. Modify the **test_shop_data.json** file to contain your shop's credentials and the required product IDs, gift cards, and discounts as necessary.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment