Commit 49cae34f by Rune Madsen

Merge pull request #26 from Shopify/develop

1.2.1 Release
parents e6b482d0 04b442c2
Ibuild/* # Xcode
*/Output/* #
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData
## Various settings
*.pbxuser *.pbxuser
!default.pbxuser !default.pbxuser
*.mode1v3 *.mode1v3
...@@ -9,14 +16,16 @@ Ibuild/* ...@@ -9,14 +16,16 @@ Ibuild/*
*.perspectivev3 *.perspectivev3
!default.perspectivev3 !default.perspectivev3
xcuserdata xcuserdata
## Other
*.xccheckout *.xccheckout
*.moved-aside *.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate *.xcuserstate
Pods/ *.xcscmblueprint
.DS_Store
.ruby-version .ruby-version
*Sample*/Buy.framework *Sample*/Buy.framework
*-INTERNAL.* *-INTERNAL.*
## Obj-C/Swift specific
*.hmap
*.ipa
...@@ -38,6 +38,7 @@ NSString * const MerchantId = @""; ...@@ -38,6 +38,7 @@ NSString * const MerchantId = @"";
@property (nonatomic, strong) BUYCheckout *checkout; @property (nonatomic, strong) BUYCheckout *checkout;
@property (nonatomic, strong) BUYClient *client; @property (nonatomic, strong) BUYClient *client;
@property (nonatomic, strong) BUYShop *shop;
@property (nonatomic, strong) NSArray *summaryItems; @property (nonatomic, strong) NSArray *summaryItems;
@property (nonatomic, strong) BUYApplePayHelpers *applePayHelper; @property (nonatomic, strong) BUYApplePayHelpers *applePayHelper;
...@@ -100,6 +101,11 @@ NSString * const MerchantId = @""; ...@@ -100,6 +101,11 @@ NSString * const MerchantId = @"";
self.tableView.tableFooterView = footerView; self.tableView.tableFooterView = footerView;
[self.tableView registerClass:[SummaryItemsTableViewCell class] forCellReuseIdentifier:@"SummaryCell"]; [self.tableView registerClass:[SummaryItemsTableViewCell class] forCellReuseIdentifier:@"SummaryCell"];
// Prefetch the shop object for Apple Pay
[self.client getShop:^(BUYShop *shop, NSError *error) {
_shop = shop;
}];
} }
- (void)setCheckout:(BUYCheckout *)checkout - (void)setCheckout:(BUYCheckout *)checkout
...@@ -240,7 +246,7 @@ NSString * const MerchantId = @""; ...@@ -240,7 +246,7 @@ NSString * const MerchantId = @"";
PKPaymentAuthorizationViewController *paymentController = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:request]; PKPaymentAuthorizationViewController *paymentController = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:request];
self.applePayHelper = [[BUYApplePayHelpers alloc] initWithClient:self.client checkout:self.checkout]; self.applePayHelper = [[BUYApplePayHelpers alloc] initWithClient:self.client checkout:self.checkout shop:self.shop];
paymentController.delegate = self; paymentController.delegate = self;
/** /**
...@@ -272,10 +278,10 @@ NSString * const MerchantId = @""; ...@@ -272,10 +278,10 @@ NSString * const MerchantId = @"";
[paymentRequest setRequiredShippingAddressFields:self.checkout.requiresShipping ? PKAddressFieldAll : PKAddressFieldEmail|PKAddressFieldPhone]; [paymentRequest setRequiredShippingAddressFields:self.checkout.requiresShipping ? PKAddressFieldAll : PKAddressFieldEmail|PKAddressFieldPhone];
[paymentRequest setSupportedNetworks:@[PKPaymentNetworkVisa, PKPaymentNetworkMasterCard]]; [paymentRequest setSupportedNetworks:@[PKPaymentNetworkVisa, PKPaymentNetworkMasterCard]];
[paymentRequest setMerchantCapabilities:PKMerchantCapability3DS]; [paymentRequest setMerchantCapabilities:PKMerchantCapability3DS];
[paymentRequest setCountryCode:@"US"]; [paymentRequest setCountryCode:self.shop.country ?: @"US"];
[paymentRequest setCurrencyCode:@"USD"]; [paymentRequest setCurrencyCode:self.shop.currency ?: @"USD"];
[paymentRequest setPaymentSummaryItems: [self.checkout buy_summaryItems]]; [paymentRequest setPaymentSummaryItems:[self.checkout buy_summaryItemsWithShopName:self.shop.name]];
return paymentRequest; return paymentRequest;
} }
...@@ -288,6 +294,17 @@ NSString * const MerchantId = @""; ...@@ -288,6 +294,17 @@ NSString * const MerchantId = @"";
{ {
// Add additional methods if needed and forward the callback to BUYApplePayHelpers // Add additional methods if needed and forward the callback to BUYApplePayHelpers
[self.applePayHelper paymentAuthorizationViewController:controller didAuthorizePayment:payment completion:completion]; [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);
}
}];
} }
- (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller - (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
// THE SOFTWARE. // THE SOFTWARE.
// //
#import <Foundation/Foundation.h> @import Foundation;
@import Buy; @import Buy;
@class GetShopOperation; @class GetShopOperation;
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.2</string> <string>1.2.1</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
...@@ -43,6 +43,8 @@ ...@@ -43,6 +43,8 @@
<array> <array>
<string>armv7</string> <string>armv7</string>
</array> </array>
<key>UIRequiresFullScreen</key>
<true/>
<key>UIStatusBarTintParameters</key> <key>UIStatusBarTintParameters</key>
<dict> <dict>
<key>UINavigationBar</key> <key>UINavigationBar</key>
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
@property (nonatomic, strong) NSArray *themeTintColors; @property (nonatomic, strong) NSArray *themeTintColors;
@property (nonatomic, assign) NSInteger themeTintColorSelectedIndex; @property (nonatomic, assign) NSInteger themeTintColorSelectedIndex;
@property (nonatomic, assign) BOOL showsProductImageBackground; @property (nonatomic, assign) BOOL showsProductImageBackground;
@property (nonatomic, assign) BOOL presentViewController;
@end @end
...@@ -66,17 +67,23 @@ ...@@ -66,17 +67,23 @@
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
self.title = @"Products"; if (self.collection) {
self.title = self.collection.title;
} else {
self.title = @"All Products";
}
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"]; [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
[self.tableView registerClass:[ProductViewControllerToggleTableViewCell class] forCellReuseIdentifier:@"ProductViewControllerToggleCell"]; [self.tableView registerClass:[ProductViewControllerToggleTableViewCell class] forCellReuseIdentifier:@"ProductViewControllerToggleCell"];
[self.tableView registerClass:[ProductViewControllerThemeStyleTableViewCell class] forCellReuseIdentifier:@"ThemeStyleCell"]; [self.tableView registerClass:[ProductViewControllerThemeStyleTableViewCell class] forCellReuseIdentifier:@"ThemeStyleCell"];
[self.tableView registerClass:[ProductViewControllerThemeTintColorTableViewCell class] forCellReuseIdentifier:@"ThemeTintColorCell"]; [self.tableView registerClass:[ProductViewControllerThemeTintColorTableViewCell class] forCellReuseIdentifier:@"ThemeTintColorCell"];
[self.tableView registerClass:[ProductViewControllerToggleTableViewCell class] forCellReuseIdentifier:@"ThemeShowsBackgroundToggleCell"]; [self.tableView registerClass:[ProductViewControllerToggleTableViewCell class] forCellReuseIdentifier:@"ThemeShowsBackgroundToggleCell"];
[self.tableView registerClass:[ProductViewControllerToggleTableViewCell class] forCellReuseIdentifier:@"ProductViewControllerPresentViewControllerToggleCell"];
self.themeTintColors = @[[UIColor colorWithRed:0.48f green:0.71f blue:0.36f alpha:1.0f], [UIColor colorWithRed:0.88 green:0.06 blue:0.05 alpha:1], [UIColor colorWithRed:0.02 green:0.54 blue:1 alpha:1]]; self.themeTintColors = @[[UIColor colorWithRed:0.48f green:0.71f blue:0.36f alpha:1.0f], [UIColor colorWithRed:0.88 green:0.06 blue:0.05 alpha:1], [UIColor colorWithRed:0.02 green:0.54 blue:1 alpha:1]];
self.themeTintColorSelectedIndex = 0; self.themeTintColorSelectedIndex = 0;
self.showsProductImageBackground = YES; self.showsProductImageBackground = YES;
self.presentViewController = YES;
if (self.collection) { if (self.collection) {
// If we're presenting with a collection, add the ability to sort // If we're presenting with a collection, add the ability to sort
...@@ -175,7 +182,7 @@ ...@@ -175,7 +182,7 @@
switch (section) { switch (section) {
case 0: case 0:
if (self.demoProductViewController) { if (self.demoProductViewController) {
return 4; return 5;
} else { } else {
return 1; return 1;
} }
...@@ -225,6 +232,15 @@ ...@@ -225,6 +232,15 @@
cell = toggleCell; cell = toggleCell;
} }
break; break;
case 4: {
ProductViewControllerToggleTableViewCell *toggleCell = (ProductViewControllerToggleTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"ProductViewControllerPresentViewControllerToggleCell" forIndexPath:indexPath];
toggleCell.textLabel.text = @"Modal Presentation";
[toggleCell.toggleSwitch setOn:self.presentViewController];
[toggleCell.toggleSwitch addTarget:self action:@selector(togglePresentViewController:) forControlEvents:UIControlEventValueChanged];
cell = toggleCell;
}
break;
default: default:
break; break;
} }
...@@ -295,7 +311,11 @@ ...@@ -295,7 +311,11 @@
BUYProductViewController *productViewController = [self productViewController]; BUYProductViewController *productViewController = [self productViewController];
[productViewController loadWithProduct:product completion:^(BOOL success, NSError *error) { [productViewController loadWithProduct:product completion:^(BOOL success, NSError *error) {
if (error == nil) { if (error == nil) {
if (self.presentViewController) {
[productViewController presentPortraitInViewController:self]; [productViewController presentPortraitInViewController:self];
} else {
[self.navigationController pushViewController:productViewController animated:YES];
}
} }
}]; }];
} }
...@@ -339,6 +359,11 @@ ...@@ -339,6 +359,11 @@
self.showsProductImageBackground = toggleSwitch.on; self.showsProductImageBackground = toggleSwitch.on;
} }
- (void)togglePresentViewController:(UISwitch*)toggleSwitch
{
self.presentViewController = toggleSwitch.on;
}
- (BUYAddress *)address - (BUYAddress *)address
{ {
BUYAddress *address = [[BUYAddress alloc] init]; BUYAddress *address = [[BUYAddress alloc] init];
...@@ -376,7 +401,11 @@ ...@@ -376,7 +401,11 @@
-(void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit -(void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit
{ {
if (self.presentViewController) {
[self presentViewController:viewControllerToCommit animated:YES completion:NULL]; [self presentViewController:viewControllerToCommit animated:YES completion:NULL];
} else {
[self.navigationController pushViewController:viewControllerToCommit animated:YES];
}
} }
@end @end
# Mobile Buy SDK Advanced Sample App
The Advanced Sample App demonstrates how to perform several tasks related to creating a checkout.
- Fetch collections
- Fetch products
- Optionally present using the `BUYProductViewController`
- Create a checkout
- Apply shipping rate
- Apply gift cards and discounts
- Complete checkout via web view, native checkout implementation, and Apple Pay
### Getting started
First, add your shop domain, API key and Channel ID to the `CollectionListViewController.m` macros.
```objc
#define SHOP_DOMAIN @"<shop_domain>"
#define API_KEY @"<api_key>"
#define CHANNEL_ID @"<channel_id>"
```
### Overview
The Advanced Sample App demonstrates several tasks that can be performed using the Mobile Buy SDK. Each task is broken up into seperate view controllers. Polling endpoints are represented as NSOperations which can easily be utilized in your own apps.
### Classes
#### View Controllers
###### `CollectionListViewController`
* Initializes the `BUYClient`
* Fetches collections and displays them in a list
* Optionally allows for fetch of the first product page
###### `ProductListViewController`
* Fetches the products and displays them in a list
* Can present a product using the `BUYProductViewController` and demo the theme settings on the controller, or
* Creates a checkout with the selected product and pushes to the `ShippingRatesTableViewController`
###### `ShippingRatesTableViewController`
* Fetches the shipping rates for the checkout using `GetShippingRatesOperation`
* Updates the checkout with the selected shipping rate and pushes to the `PreCheckoutViewController`
###### `PreCheckoutViewController`
* Displays a summary of the checkout
* Allows for discounts and gift cards to be added to the checkout
###### `CheckoutViewController`
* Displays a summary of the checkout
* Checkout using a credit card
* Web checkout using Safari
* Checkout using Apple Pay
#### `NSOperation`s
###### `GetShopOperation`
* `NSOperation` based class to fetch the shop object
###### `GetShippingRatesOperation`
* `NSOperation` based class to poll for shipping rates
###### `GetCompletionStatusOperation`
* `NSOperation` based class to poll for the checkout completion status
### Apple Pay
Apple Pay is implemented in the CheckoutViewController. It utilizes the `BUYApplePayHelpers` class which acts as the delegate for the `PKPaymentAuthorizationViewController`. Setting the `MerchantId` is required to use Apple Pay. For more information about supporting Apple Pay in your app, please consult [https://docs.shopify.com/mobile-buy-sdk/ios/enable-apple-pay](https://docs.shopify.com/mobile-buy-sdk/ios/enable-apple-pay).
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.2</string> <string>1.2.1</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
// //
import UIKit import UIKit
import Buy
class ViewController: UIViewController { class ViewController: UIViewController {
......
# Mobile Buy SDK Sample Swift App
The Swift sample app demonstrates how to use the SDK within a Swift app. The app includes an Objective-C bridging header.
### Getting started
First, add your shop domain, API key and Channel ID to the `ViewController.swift`.
```swift
let shopDomain = ""
let apiKey = ""
let channelId = ""
let productId = ""
```
### Overview
The sample app also demonstrates how to use the `BUYClient` to obtain a product by calling `getProductById()`.
```swift
client.getProductById(productId) { (product, error) -> Void in
}
```
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.2</string> <string>1.2.1</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
......
# Mobile Buy SDK Sample Web App
The web sample app demonstrates how you can load your shop's website in a webview, and support Apple Pay.
### Getting started
First, add your shop domain, API key and Channel ID to the `AppDelegate.h` macros.
```objc
#define SHOP_DOMAIN @"<shop_domain>"
#define API_KEY @"<api_key>"
#define CHANNEL_ID @"<channel_id>"
```
To support Apple Pay, add your Merchant ID as well.
```objc
#define MERCHANT_ID @"<merchant_id>"
```
### Overview
The sample app instantiates a view controller which is a subclass of `BUYStoreViewController`. This displays a webview with your shop, but intercepts the checkout to support Apple Pay.
The sample app also demonstrates how to use the `BUYClient` to obtain shop details by calling `getShop:`
```objc
[self.provider getShop:^(BUYShop *shop, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error == nil && shop) {
self.title = shop.name;
}
else {
NSLog(@"Error fetching shop: %@", error.localizedDescription);
}
});
}];
```
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Mobile Buy SDK/Mobile Buy SDK.xcodeproj">
</FileRef>
<FileRef
location = "group:Mobile Buy SDK Sample Apps/Sample App Web/Mobile Buy SDK Web Sample.xcodeproj">
</FileRef>
<FileRef
location = "group:Mobile Buy SDK Sample Apps/Sample App Swift/Mobile Buy SDK Swift Sample.xcodeproj">
</FileRef>
<FileRef
location = "group:Mobile Buy SDK Sample Apps/Sample App Advanced/Mobile Buy SDK Advanced Sample.xcodeproj">
</FileRef>
</Workspace>
{
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "B8AB7D59AD74F224C9D65CE20D7D3C30D5100598",
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
},
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
"27386CDE6C45B5519FB1AD62B45ACA8C18A2EFF0" : 0,
"B8AB7D59AD74F224C9D65CE20D7D3C30D5100598" : 0
},
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "F65CB188-9FFA-4AD7-8982-12C88FB79C9D",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"27386CDE6C45B5519FB1AD62B45ACA8C18A2EFF0" : "mobile-buy-sdk-private\/Submodules",
"B8AB7D59AD74F224C9D65CE20D7D3C30D5100598" : "mobile-buy-sdk-private"
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "Mobile Buy SDK",
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Mobile Buy SDK.xcworkspace",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:Shopify\/BUYPaymentButton.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "27386CDE6C45B5519FB1AD62B45ACA8C18A2EFF0"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:Shopify\/mobile-buy-sdk-private.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "B8AB7D59AD74F224C9D65CE20D7D3C30D5100598"
}
]
}
\ No newline at end of file
...@@ -245,4 +245,37 @@ ...@@ -245,4 +245,37 @@
}]; }];
} }
- (void)testValidTags
{
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) {
return [self shouldUseMocks];
} withStubResponse:^OHHTTPStubsResponse * _Nonnull(NSURLRequest * _Nonnull request) {
return [OHHTTPStubsResponse responseWithKey:@"testGetValidTag_0"];
}];
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
[self.client getProductsPage:1 completion:^(NSArray *products, NSUInteger page, BOOL reachedEnd, NSError *error) {
XCTAssertNil(error);
XCTAssertNotNil(products);
if (products.count > 0) {
BUYProduct *product = products[0];
if (product.tags) {
XCTAssertTrue([product.tags isKindOfClass:[NSSet class]]);
for (NSString *tag in [product.tags allObjects]) {
XCTAssert([tag isKindOfClass:[NSString class]]);
}
}
}
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:10 handler:^(NSError *error) {
XCTAssertNil(error);
}];
}
@end @end
...@@ -248,7 +248,7 @@ ...@@ -248,7 +248,7 @@
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) { [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) {
return [self shouldUseMocks]; return [self shouldUseMocks];
} withStubResponse:^OHHTTPStubsResponse * _Nonnull(NSURLRequest * _Nonnull request) { } withStubResponse:^OHHTTPStubsResponse * _Nonnull(NSURLRequest * _Nonnull request) {
return [OHHTTPStubsResponse responseWithKey:@"testCheckoutFlowUsingCreditCard_17"]; return [OHHTTPStubsResponse responseWithKey:@"testCheckoutFlowUsingCreditCard_14"];
}]; }];
__block BUYStatus checkoutStatus = BUYStatusUnknown; __block BUYStatus checkoutStatus = BUYStatusUnknown;
...@@ -285,7 +285,7 @@ ...@@ -285,7 +285,7 @@
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) { [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) {
return [self shouldUseMocks]; return [self shouldUseMocks];
} withStubResponse:^OHHTTPStubsResponse * _Nonnull(NSURLRequest * _Nonnull request) { } withStubResponse:^OHHTTPStubsResponse * _Nonnull(NSURLRequest * _Nonnull request) {
return [OHHTTPStubsResponse responseWithKey:@"testCheckoutFlowUsingCreditCard_18"]; return [OHHTTPStubsResponse responseWithKey:@"testCheckoutFlowUsingCreditCard_15"];
}]; }];
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
buildForAnalyzing = "YES"> buildForAnalyzing = "YES">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "BE9A64271B503C2F0033E558" BlueprintIdentifier = "901930E11BC5B9BC00D1134E"
BuildableName = "Buy.framework" BuildableName = "Buy.framework"
BlueprintName = "Buy" BlueprintName = "Buy"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj"> ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
<MacroExpansion> <MacroExpansion>
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "BE9A64271B503C2F0033E558" BlueprintIdentifier = "901930E11BC5B9BC00D1134E"
BuildableName = "Buy.framework" BuildableName = "Buy.framework"
BlueprintName = "Buy" BlueprintName = "Buy"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj"> ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
<MacroExpansion> <MacroExpansion>
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "BE9A64271B503C2F0033E558" BlueprintIdentifier = "901930E11BC5B9BC00D1134E"
BuildableName = "Buy.framework" BuildableName = "Buy.framework"
BlueprintName = "Buy" BlueprintName = "Buy"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj"> ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
</MacroExpansion> </MacroExpansion>
</ProfileAction> </ProfileAction>
<AnalyzeAction <AnalyzeAction
buildConfiguration = "Release"> buildConfiguration = "Debug">
</AnalyzeAction> </AnalyzeAction>
<ArchiveAction <ArchiveAction
buildConfiguration = "Release" buildConfiguration = "Release"
......
...@@ -15,8 +15,8 @@ ...@@ -15,8 +15,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "904FB61A1AE03DC500EA1758" BlueprintIdentifier = "904FB61A1AE03DC500EA1758"
BuildableName = "Universal Framework" BuildableName = "Static Universal Framework"
BlueprintName = "Universal Framework" BlueprintName = "Static Universal Framework"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj"> ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
...@@ -46,8 +46,8 @@ ...@@ -46,8 +46,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "904FB61A1AE03DC500EA1758" BlueprintIdentifier = "904FB61A1AE03DC500EA1758"
BuildableName = "Universal Framework" BuildableName = "Static Universal Framework"
BlueprintName = "Universal Framework" BlueprintName = "Static Universal Framework"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj"> ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
...@@ -64,8 +64,8 @@ ...@@ -64,8 +64,8 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "904FB61A1AE03DC500EA1758" BlueprintIdentifier = "904FB61A1AE03DC500EA1758"
BuildableName = "Universal Framework" BuildableName = "Static Universal Framework"
BlueprintName = "Universal Framework" BlueprintName = "Static Universal Framework"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj"> ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
......
...@@ -24,33 +24,36 @@ ...@@ -24,33 +24,36 @@
// THE SOFTWARE. // THE SOFTWARE.
// //
#import <Buy/BUYAddress.h> /**
#import <Buy/BUYCart.h> * Umbrella header used for Cocoapods
#import <Buy/BUYCheckout.h> */
#import <Buy/BUYCreditCard.h>
#import <Buy/BUYDiscount.h> #import "BUYApplePayAdditions.h"
#import <Buy/BUYGiftCard.h> #import "BUYApplePayHelpers.h"
#import <Buy/BUYLineItem.h> #import "BUYAddress.h"
#import <Buy/BUYClient.h> #import "BUYCart.h"
#import <Buy/BUYClient+Test.h> #import "BUYCartLineItem.h"
#import <Buy/BUYImage.h> #import "BUYCheckout.h"
#import <Buy/BUYOption.h> #import "BUYClient+Test.h"
#import <Buy/BUYOptionValue.h> #import "BUYClient.h"
#import <Buy/BUYOrder.h> #import "BUYCollection.h"
#import <Buy/BUYProduct.h> #import "BUYCreditCard.h"
#import <Buy/BUYProductVariant.h> #import "BUYDiscount.h"
#import <Buy/BUYShippingRate.h> #import "BUYError.h"
#import <Buy/BUYShop.h> #import "BUYGiftCard.h"
#import <Buy/BUYStoreViewController.h> #import "BUYImage.h"
#import <Buy/BUYTaxLine.h> #import "BUYLineItem.h"
#import <Buy/BUYViewController.h> #import "BUYMaskedCreditCard.h"
#import <Buy/BUYApplePayAdditions.h> #import "BUYOption.h"
#import <Buy/BUYApplePayHelpers.h> #import "BUYOptionValue.h"
#import <Buy/BUYPaymentButton.h> #import "BUYOrder.h"
#import <Buy/BUYProductViewController.h> #import "BUYPaymentButton.h"
#import <Buy/BUYTheme.h> #import "BUYProduct.h"
#import <Buy/BUYCartLineItem.h> #import "BUYProductVariant.h"
#import <Buy/BUYCollection.h> #import "BUYProductViewController.h"
#import <Buy/BUYMaskedCreditCard.h> #import "BUYShippingRate.h"
#import <Buy/BuyError.h> #import "BUYShop.h"
#import <Buy/Buy-Bridging-Header.h> #import "BUYStoreViewController.h"
#import "BUYTaxLine.h"
#import "BUYTheme.h"
#import "BUYViewController.h"
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.2</string> <string>1.2.1</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
* Note: These are different from BUYLineItem objects in that * Note: These are different from BUYLineItem objects in that
* the line item objects do include the BUYProductVariant. * the line item objects do include the BUYProductVariant.
*/ */
@property (nonatomic, strong, readonly) NSArray *lineItems; @property (nonatomic, strong, readonly, nonnull) NSArray<BUYCartLineItem *> *lineItems;
/** /**
* Returns true if the cart is acceptable to send to Shopify. * Returns true if the cart is acceptable to send to Shopify.
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
* *
* @param variant The BUYProductVariant to add to the BUYCart or increase by one quantity * @param variant The BUYProductVariant to add to the BUYCart or increase by one quantity
*/ */
- (void)addVariant:(BUYProductVariant *)variant; - (void)addVariant:(nonnull BUYProductVariant *)variant;
/** /**
* Removes the BUYCartLineItem from the BUYCart associated with the given BUYProductVariant object. * Removes the BUYCartLineItem from the BUYCart associated with the given BUYProductVariant object.
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
* *
* @param variant The BUYProductVariant to remove from the BUYCart or decrease by one quantity * @param variant The BUYProductVariant to remove from the BUYCart or decrease by one quantity
*/ */
- (void)removeVariant:(BUYProductVariant *)variant; - (void)removeVariant:(nonnull BUYProductVariant *)variant;
/** /**
* Adds a BUYCartLineItem with a set quantity to the BUYCart with the given BUYProductVariant object on it. * Adds a BUYCartLineItem with a set quantity to the BUYCart with the given BUYProductVariant object on it.
...@@ -80,6 +80,6 @@ ...@@ -80,6 +80,6 @@
* @param variant The BUYProductVariant to add to the BUYCart with a quantity * @param variant The BUYProductVariant to add to the BUYCart with a quantity
* @param quantity The quantity for the BUYCartLineItem associated with the BUYProductVariant * @param quantity The quantity for the BUYCartLineItem associated with the BUYProductVariant
*/ */
- (void)setVariant:(BUYProductVariant *)variant withTotalQuantity:(NSInteger)quantity; - (void)setVariant:(nonnull BUYProductVariant *)variant withTotalQuantity:(NSInteger)quantity;
@end @end
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
@interface BUYCart () @interface BUYCart ()
@property (nonatomic, strong) NSMutableSet *lineItemsSet; @property (nonatomic, strong, nonnull) NSMutableSet<BUYCartLineItem *> *lineItemsSet;
@end @end
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
return self; return self;
} }
- (NSArray *)lineItems - (nonnull NSArray<BUYCartLineItem *> *)lineItems
{ {
return [self.lineItemsSet allObjects]; return [self.lineItemsSet allObjects];
} }
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
#pragma mark - Simple Cart Editing #pragma mark - Simple Cart Editing
- (void)addVariant:(BUYProductVariant *)variant - (void)addVariant:(nonnull BUYProductVariant *)variant
{ {
BUYCartLineItem *lineItem = [[BUYCartLineItem alloc] initWithVariant:variant]; BUYCartLineItem *lineItem = [[BUYCartLineItem alloc] initWithVariant:variant];
BUYCartLineItem *existingLineItem = [self.lineItemsSet member:lineItem]; BUYCartLineItem *existingLineItem = [self.lineItemsSet member:lineItem];
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
} }
} }
- (void)removeVariant:(BUYProductVariant *)variant - (void)removeVariant:(nonnull BUYProductVariant *)variant
{ {
BUYCartLineItem *lineItem = [[BUYCartLineItem alloc] initWithVariant:variant]; BUYCartLineItem *lineItem = [[BUYCartLineItem alloc] initWithVariant:variant];
BUYCartLineItem *existingLineItem = [self.lineItemsSet member:lineItem]; BUYCartLineItem *existingLineItem = [self.lineItemsSet member:lineItem];
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
} }
} }
- (void)setVariant:(BUYProductVariant *)variant withTotalQuantity:(NSInteger)quantity - (void)setVariant:(nonnull BUYProductVariant *)variant withTotalQuantity:(NSInteger)quantity
{ {
BUYCartLineItem *lineItem = [[BUYCartLineItem alloc] initWithVariant:variant]; BUYCartLineItem *lineItem = [[BUYCartLineItem alloc] initWithVariant:variant];
BUYCartLineItem *existingLineItem = [self.lineItemsSet member:lineItem]; BUYCartLineItem *existingLineItem = [self.lineItemsSet member:lineItem];
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
@class BUYOrder; @class BUYOrder;
@class BUYShippingRate; @class BUYShippingRate;
@class BUYTaxLine; @class BUYTaxLine;
@class BUYLineItem;
@class BUYGiftCard;
/** /**
* The checkout object. This is the main object that you will interact with when creating orders on Shopify. * The checkout object. This is the main object that you will interact with when creating orders on Shopify.
...@@ -125,13 +127,12 @@ ...@@ -125,13 +127,12 @@
* Note: These are different from BUYCartLineItems in that the line item * Note: These are different from BUYCartLineItems in that the line item
* objects do not include the BUYProductVariant * objects do not include the BUYProductVariant
*/ */
@property (nonatomic, readonly, copy) NSArray *lineItems; @property (nonatomic, readonly, copy) NSArray<__kindof BUYLineItem *> *lineItems;
/** /**
* Array of tax line objects on the checkout * Array of tax line objects on the checkout
*/ */
@property (nonatomic, readonly, copy) NSArray *taxLines; @property (nonatomic, readonly, copy) NSArray<BUYTaxLine *> *taxLines;
/** /**
* The mailing address associated with the payment method * The mailing address associated with the payment method
*/ */
...@@ -162,7 +163,7 @@ ...@@ -162,7 +163,7 @@
/** /**
* An array of BUYGiftCard objects applied to the checkout * An array of BUYGiftCard objects applied to the checkout
*/ */
@property (nonatomic, strong, readonly) NSArray *giftCards; @property (nonatomic, strong, readonly) NSArray<BUYGiftCard *> *giftCards;
/** /**
* Channel ID where the checkout was created * Channel ID where the checkout was created
...@@ -238,6 +239,11 @@ ...@@ -238,6 +239,11 @@
@property (nonatomic, copy, readonly) NSString *customerId; @property (nonatomic, copy, readonly) NSString *customerId;
/** /**
* An optional note attached to the order
*/
@property (nonatomic, copy) NSString *note;
/**
* The BUYOrder for a completed checkout * The BUYOrder for a completed checkout
*/ */
@property (nonatomic, strong, readonly) BUYOrder *order; @property (nonatomic, strong, readonly) BUYOrder *order;
......
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
- (instancetype)initWithCart:(BUYCart *)cart - (instancetype)initWithCart:(BUYCart *)cart
{ {
self = [super initWithDictionary:@{}]; self = [super init];
if (self) { if (self) {
_lineItems = [cart.lineItems copy]; _lineItems = [cart.lineItems copy];
[self markPropertyAsDirty:@"lineItems"]; [self markPropertyAsDirty:@"lineItems"];
...@@ -160,6 +160,7 @@ ...@@ -160,6 +160,7 @@
self.updatedAtDate = [dateFormatter dateFromString:dictionary[@"updated_at"]]; self.updatedAtDate = [dateFormatter dateFromString:dictionary[@"updated_at"]];
self.creditCard = [BUYMaskedCreditCard convertObject:dictionary[@"credit_card"]]; self.creditCard = [BUYMaskedCreditCard convertObject:dictionary[@"credit_card"]];
self.customerId = [dictionary[@"customer_id"] copy]; self.customerId = [dictionary[@"customer_id"] copy];
self.note = dictionary[@"note"];
self.privacyPolicyURL = [NSURL buy_urlWithString:dictionary[@"privacy_policy_url"]]; self.privacyPolicyURL = [NSURL buy_urlWithString:dictionary[@"privacy_policy_url"]];
self.refundPolicyURL = [NSURL buy_urlWithString:dictionary[@"refund_policy_url"]]; self.refundPolicyURL = [NSURL buy_urlWithString:dictionary[@"refund_policy_url"]];
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
/** /**
* An array of variant ids associated with the image. * An array of variant ids associated with the image.
*/ */
@property (nonatomic, readonly, copy) NSArray *variantIds; @property (nonatomic, readonly, copy) NSArray<NSNumber *> *variantIds;
/** /**
* Creation date of the image * Creation date of the image
......
...@@ -64,19 +64,19 @@ ...@@ -64,19 +64,19 @@
/** /**
* A list of BUYProductVariant objects, each one representing a slightly different version of the product. * A list of BUYProductVariant objects, each one representing a slightly different version of the product.
*/ */
@property (nonatomic, readonly, copy) NSArray *variants; @property (nonatomic, readonly, copy) NSArray<BUYProductVariant *> *variants;
/** /**
* A list of BUYImage objects, each one representing an image associated with the product. * A list of BUYImage objects, each one representing an image associated with the product.
*/ */
@property (nonatomic, readonly, copy) NSArray *images; @property (nonatomic, readonly, copy) NSArray<BUYImage *> *images;
/** /**
* Custom product property names like "Size", "Color", and "Material". * Custom product property names like "Size", "Color", and "Material".
* Products are based on permutations of these options. * Products are based on permutations of these options.
* A product may have a maximum of 3 options. 255 characters limit each. * A product may have a maximum of 3 options. 255 characters limit each.
*/ */
@property (nonatomic, readonly, copy) NSArray *options; @property (nonatomic, readonly, copy) NSArray<BUYOption *> *options;
/** /**
* The description of the product, complete with HTML formatting. * The description of the product, complete with HTML formatting.
...@@ -89,6 +89,12 @@ ...@@ -89,6 +89,12 @@
@property (nonatomic, readonly, assign) BOOL available; @property (nonatomic, readonly, assign) BOOL available;
/** /**
* A categorization that a product can be tagged with, commonly used for filtering and searching.
* Each tag has a character limit of 255.
*/
@property (nonatomic, readonly, copy) NSSet<NSString *> *tags;
/**
* The product is published on the current sales channel * The product is published on the current sales channel
*/ */
@property (nonatomic, readonly, assign) BOOL published; @property (nonatomic, readonly, assign) BOOL published;
......
...@@ -53,6 +53,9 @@ ...@@ -53,6 +53,9 @@
_createdAtDate = [dateFormatter dateFromString:dictionary[@"created_at"]]; _createdAtDate = [dateFormatter dateFromString:dictionary[@"created_at"]];
_updatedAtDate = [dateFormatter dateFromString:dictionary[@"updated_at"]]; _updatedAtDate = [dateFormatter dateFromString:dictionary[@"updated_at"]];
_publishedAtDate = [dateFormatter dateFromString:dictionary[@"published_at"]]; _publishedAtDate = [dateFormatter dateFromString:dictionary[@"published_at"]];
NSArray *tagsArray = [dictionary[@"tags"] componentsSeparatedByString:@", "];
NSSet *tagsSet = [NSSet setWithArray:tagsArray];
_tags = [tagsSet copy];
} }
@end @end
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#import "BUYObject.h" #import "BUYObject.h"
@class BUYProduct; @class BUYProduct;
@class BUYOptionValue;
/** /**
* A BUYProductVariant is a different version of a product, such as differing sizes or differing colours. * A BUYProductVariant is a different version of a product, such as differing sizes or differing colours.
...@@ -46,7 +47,7 @@ ...@@ -46,7 +47,7 @@
/** /**
* Custom properties that a shop owner can use to define BUYProductVariants. * Custom properties that a shop owner can use to define BUYProductVariants.
*/ */
@property (nonatomic, readonly, copy) NSArray *options; @property (nonatomic, readonly, copy) NSArray<BUYOptionValue *> *options;
/** /**
* The price of the BUYProductVariant. * The price of the BUYProductVariant.
......
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
/** /**
* A list of two-letter country codes identifying the countries that the shop ships to. * A list of two-letter country codes identifying the countries that the shop ships to.
*/ */
@property (nonatomic, readonly, copy) NSArray *shipsToCountries; @property (nonatomic, readonly, copy) NSArray<NSString *> *shipsToCountries;
/** /**
* The URL for the web storefront * The URL for the web storefront
......
...@@ -44,7 +44,11 @@ ...@@ -44,7 +44,11 @@
closeButton.frame = CGRectMake(0, 0, 22, 22); closeButton.frame = CGRectMake(0, 0, 22, 22);
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:closeButton]; UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:closeButton];
self.topViewController.navigationItem.leftBarButtonItem = barButtonItem; self.topViewController.navigationItem.leftBarButtonItem = barButtonItem;
if ([[UINavigationBar class] respondsToSelector:@selector(appearanceWhenContainedInInstancesOfClasses:)]) {
[[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[BUYNavigationController class]]] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
} else {
[[UINavigationBar appearanceWhenContainedIn:[BUYNavigationController class], nil] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault]; [[UINavigationBar appearanceWhenContainedIn:[BUYNavigationController class], nil] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
}
return self; return self;
} }
...@@ -87,7 +91,11 @@ ...@@ -87,7 +91,11 @@
_theme = theme; _theme = theme;
self.navigationBar.barStyle = [theme navigationBarStyle]; self.navigationBar.barStyle = [theme navigationBarStyle];
[self updateCloseButtonImageWithTintColor:NO duration:0]; [self updateCloseButtonImageWithTintColor:NO duration:0];
if ([[UINavigationBar class] respondsToSelector:@selector(appearanceWhenContainedInInstancesOfClasses:)]) {
[[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[BUYNavigationController class]]] setTitleTextAttributes:@{ NSForegroundColorAttributeName: [theme navigationBarTitleColor] }];
} else {
[[UINavigationBar appearanceWhenContainedIn:[BUYNavigationController class], nil] setTitleTextAttributes:@{ NSForegroundColorAttributeName: [theme navigationBarTitleColor] }]; [[UINavigationBar appearanceWhenContainedIn:[BUYNavigationController class], nil] setTitleTextAttributes:@{ NSForegroundColorAttributeName: [theme navigationBarTitleColor] }];
}
} }
-(UIViewController *)childViewControllerForStatusBarStyle -(UIViewController *)childViewControllerForStatusBarStyle
......
...@@ -125,9 +125,17 @@ ...@@ -125,9 +125,17 @@
/** /**
* The inset for the table view and scroll indicator, allowing for custom insets. * The inset for the table view and scroll indicator, allowing for custom insets.
* *
* @param edgeInsets The edge inset to set for the table view * @param edgeInsets The edge inset to set for the table view.
* @param appendToCurrentInset A flag that allows for adding the edge insets to the current edgeinsets of the table view. * @param appendToCurrentInset A flag that allows for adding the edge insets to the current edgeinsets of the table view.
*/ */
- (void)setInsets:(UIEdgeInsets)edgeInsets appendToCurrentInset:(BOOL)appendToCurrentInset; - (void)setInsets:(UIEdgeInsets)edgeInsets appendToCurrentInset:(BOOL)appendToCurrentInset;
/**
* Sets the top inset specifically for when the product view is pushed into a navigation controller stack
* instead of presented modally.
*
* @param topInset The inset to use for insetting the product view inside the container.
*/
- (void)setTopInset:(CGFloat)topInset;
@end @end
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
@property (nonatomic, strong) UILabel *poweredByShopifyLabel; @property (nonatomic, strong) UILabel *poweredByShopifyLabel;
@property (nonatomic, strong) NSLayoutConstraint *poweredByShopifyLabelConstraint; @property (nonatomic, strong) NSLayoutConstraint *poweredByShopifyLabelConstraint;
@property (nonatomic, strong) BUYProductViewErrorView *errorView; @property (nonatomic, strong) BUYProductViewErrorView *errorView;
@property (nonatomic, strong) NSLayoutConstraint *topInsetConstraint;
@end @end
...@@ -121,11 +122,20 @@ ...@@ -121,11 +122,20 @@
options:0 options:0
metrics:nil metrics:nil
views:NSDictionaryOfVariableBindings(_tableView)]]; views:NSDictionaryOfVariableBindings(_tableView)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_tableView]|" [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_tableView]|"
options:0 options:0
metrics:nil metrics:nil
views:NSDictionaryOfVariableBindings(_tableView)]]; views:NSDictionaryOfVariableBindings(_tableView)]];
_topInsetConstraint = [NSLayoutConstraint constraintWithItem:self.tableView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0];
[self addConstraint:_topInsetConstraint];
CGFloat size = MIN(CGRectGetWidth(rect), CGRectGetHeight(rect)); CGFloat size = MIN(CGRectGetWidth(rect), CGRectGetHeight(rect));
if ([product.images count] > 0) { if ([product.images count] > 0) {
_productViewHeader = [[BUYProductViewHeader alloc] initWithFrame:CGRectMake(0, 0, size, size) theme:theme]; _productViewHeader = [[BUYProductViewHeader alloc] initWithFrame:CGRectMake(0, 0, size, size) theme:theme];
...@@ -163,7 +173,7 @@ ...@@ -163,7 +173,7 @@
options:0 options:0
metrics:nil metrics:nil
views:NSDictionaryOfVariableBindings(_productViewFooter)]]; views:NSDictionaryOfVariableBindings(_productViewFooter)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_productViewFooter]|" [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_productViewFooter]-|"
options:0 options:0
metrics:nil metrics:nil
views:NSDictionaryOfVariableBindings(_productViewFooter)]]; views:NSDictionaryOfVariableBindings(_productViewFooter)]];
...@@ -193,7 +203,7 @@ ...@@ -193,7 +203,7 @@
- (void)layoutSubviews - (void)layoutSubviews
{ {
[super layoutSubviews]; [super layoutSubviews];
[self setInsets:UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, CGRectGetHeight(self.productViewFooter.frame), self.tableView.contentInset.right) appendToCurrentInset:NO]; [self setInsets:UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, CGRectGetHeight(self.bounds) - CGRectGetMinY(self.productViewFooter.frame), self.tableView.contentInset.right) appendToCurrentInset:NO];
} }
- (void)setTheme:(BUYTheme *)theme - (void)setTheme:(BUYTheme *)theme
...@@ -233,6 +243,10 @@ ...@@ -233,6 +243,10 @@
if (footerViewHeight <= 0) { if (footerViewHeight <= 0) {
footerViewHeight = 0; footerViewHeight = 0;
} }
// Add the top inset for the navigation bar (when pushed in a navigation controller stack, not presented)
footerViewHeight += -self.topInsetConstraint.constant;
self.footerHeightLayoutConstraint.constant = footerViewHeight; self.footerHeightLayoutConstraint.constant = footerViewHeight;
self.footerOffsetLayoutConstraint.constant = -footerViewHeight; self.footerOffsetLayoutConstraint.constant = -footerViewHeight;
...@@ -325,4 +339,9 @@ ...@@ -325,4 +339,9 @@
self.tableView.contentInset = self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(top, left, bottom, right); self.tableView.contentInset = self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(top, left, bottom, right);
} }
- (void)setTopInset:(CGFloat)topInset
{
self.topInsetConstraint.constant = topInset;
}
@end @end
...@@ -90,6 +90,7 @@ CGFloat const BUYMaxProductViewHeight = 640.0; ...@@ -90,6 +90,7 @@ CGFloat const BUYMaxProductViewHeight = 640.0;
{ {
self = [super initWithClient:client]; self = [super initWithClient:client];
if (self) { if (self) {
self.theme = theme? : [[BUYTheme alloc] init]; self.theme = theme? : [[BUYTheme alloc] init];
self.modalPresentationStyle = UIModalPresentationCustom; self.modalPresentationStyle = UIModalPresentationCustom;
...@@ -118,6 +119,8 @@ CGFloat const BUYMaxProductViewHeight = 640.0; ...@@ -118,6 +119,8 @@ CGFloat const BUYMaxProductViewHeight = 640.0;
attribute:NSLayoutAttributeCenterX attribute:NSLayoutAttributeCenterX
multiplier:1.0 multiplier:1.0
constant:0.0]]; constant:0.0]];
} }
return self; return self;
} }
...@@ -175,6 +178,10 @@ CGFloat const BUYMaxProductViewHeight = 640.0; ...@@ -175,6 +178,10 @@ CGFloat const BUYMaxProductViewHeight = 640.0;
[super viewWillAppear:animated]; [super viewWillAppear:animated];
[self setupNavigationBarAppearance]; [self setupNavigationBarAppearance];
[self.navigationController setNavigationBarHidden:self.isLoading]; [self.navigationController setNavigationBarHidden:self.isLoading];
CGFloat bottomMargin = 0;
bottomMargin += self.tabBarController ? CGRectGetHeight(self.tabBarController.tabBar.bounds) : 0;
bottomMargin += self.navigationController.isToolbarHidden ? 0 : CGRectGetHeight(self.navigationController.toolbar.bounds);
_productView.layoutMargins = UIEdgeInsetsMake(self.productView.layoutMargins.top, self.productView.layoutMargins.left, bottomMargin, self.productView.layoutMargins.right);
} }
- (void)viewDidLayoutSubviews - (void)viewDidLayoutSubviews
...@@ -195,7 +202,7 @@ CGFloat const BUYMaxProductViewHeight = 640.0; ...@@ -195,7 +202,7 @@ CGFloat const BUYMaxProductViewHeight = 640.0;
- (void)setupNavigationBarAppearance - (void)setupNavigationBarAppearance
{ {
if (self.navigationBar == nil && _productView) { if (self.navigationBar == nil && _productView && self.presentingViewController != nil) {
for (UIView *view in [self.navigationController.navigationBar subviews]) { for (UIView *view in [self.navigationController.navigationBar subviews]) {
if (CGRectGetHeight(view.bounds) >= 44) { if (CGRectGetHeight(view.bounds) >= 44) {
// Get a reference to the UINavigationBar // Get a reference to the UINavigationBar
...@@ -211,6 +218,8 @@ CGFloat const BUYMaxProductViewHeight = 640.0; ...@@ -211,6 +218,8 @@ CGFloat const BUYMaxProductViewHeight = 640.0;
} }
// Hide the navigation bar // Hide the navigation bar
[self scrollViewDidScroll:self.productView.tableView]; [self scrollViewDidScroll:self.productView.tableView];
} else if (self.navigationController && _productView && self.presentingViewController == nil) {
[self.productView setTopInset:CGRectGetHeight(self.navigationController.navigationBar.bounds) + self.navigationController.topLayoutGuide.length];
} }
} }
...@@ -460,9 +469,11 @@ CGFloat const BUYMaxProductViewHeight = 640.0; ...@@ -460,9 +469,11 @@ CGFloat const BUYMaxProductViewHeight = 640.0;
[(BUYNavigationController*)self.navigationController updateCloseButtonImageWithTintColor:YES duration:0]; [(BUYNavigationController*)self.navigationController updateCloseButtonImageWithTintColor:YES duration:0];
self.navigationBar.alpha = 1; self.navigationBar.alpha = 1;
self.navigationBarTitle.alpha = 1; self.navigationBarTitle.alpha = 1;
// When using 3D Touch, the initial height of the navigation bar (without UIStatusBar) doesn't match the final height (with UIStatusBar) CGFloat topInset = 0;
// so we're forced to set it manually in case it's not tall enough. Of course, this is only valid for products with no product images. if (self.presentingViewController) {
[self.productView setInsets:UIEdgeInsetsMake(MAX(CGRectGetHeight(self.navigationBar.bounds), 64), 0, 0, 0) appendToCurrentInset:YES]; topInset = CGRectGetHeight([[(UINavigationController*)self.presentingViewController navigationBar] bounds]) + self.presentingViewController.topLayoutGuide.length;
}
[self.productView setInsets:UIEdgeInsetsMake(topInset, 0, 0, 0) appendToCurrentInset:YES];
} }
} }
} }
......
...@@ -47,9 +47,15 @@ ...@@ -47,9 +47,15 @@
// Add custom back button // Add custom back button
UIImage *buttonImage = [[BUYImageKit imageOfVariantBackImageWithFrame:CGRectMake(0, 0, 12, 18)] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; UIImage *buttonImage = [[BUYImageKit imageOfVariantBackImageWithFrame:CGRectMake(0, 0, 12, 18)] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
if ([[UIBarButtonItem class] respondsToSelector:@selector(appearanceWhenContainedInInstancesOfClasses:)]) {
[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[BUYNavigationController class]]] setBackButtonBackgroundImage:[buttonImage resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 0)]
forState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
} else {
[[UIBarButtonItem appearanceWhenContainedIn:[BUYNavigationController class], nil] setBackButtonBackgroundImage:[buttonImage resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 0)] [[UIBarButtonItem appearanceWhenContainedIn:[BUYNavigationController class], nil] setBackButtonBackgroundImage:[buttonImage resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 0)]
forState:UIControlStateNormal forState:UIControlStateNormal
barMetrics:UIBarMetricsDefault]; barMetrics:UIBarMetricsDefault];
}
_breadsCrumbsView = [BUYVariantOptionBreadCrumbsView new]; _breadsCrumbsView = [BUYVariantOptionBreadCrumbsView new];
_breadsCrumbsView.translatesAutoresizingMaskIntoConstraints = NO; _breadsCrumbsView.translatesAutoresizingMaskIntoConstraints = NO;
......
//
// Buy.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/UIKit.h>
//! 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>
...@@ -57,5 +57,4 @@ NSString * const BUYPartialAddressPlaceholder = @"---"; ...@@ -57,5 +57,4 @@ NSString * const BUYPartialAddressPlaceholder = @"---";
return valid; return valid;
} }
@end @end
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Returns an array of summary items for all Apple Pay requests. Will use 'PAY TOTAL' as the summary label. Apple recommends * Returns an array of summary items for all Apple Pay requests. Will use 'PAY TOTAL' as the summary label. Apple recommends
* including the business name in the summary label, so it is recommended to use `buy_summaryItemsWithShopName` instead. * including the business name in the summary label, so it is recommended to use `buy_summaryItemsWithShopName` instead.
*/ */
- (NSArray *)buy_summaryItems; - (nonnull NSArray<PKPaymentSummaryItem *> *)buy_summaryItems;
/** /**
* Returns an array of summary items for all Apple Pay requests using the shop name in the "PAY" section * Returns an array of summary items for all Apple Pay requests using the shop name in the "PAY" section
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
* *
* @return An array of PKPaymentSummaryItems * @return An array of PKPaymentSummaryItems
*/ */
- (NSArray *)buy_summaryItemsWithShopName:(NSString *)shopName; - (nonnull NSArray<PKPaymentSummaryItem *> *)buy_summaryItemsWithShopName:(nullable NSString *)shopName;
@end @end
...@@ -59,13 +59,13 @@ ...@@ -59,13 +59,13 @@
* *
* @return An array of PKShippingMethods * @return An array of PKShippingMethods
*/ */
+ (NSArray *)buy_convertShippingRatesToShippingMethods:(NSArray *)rates; + (nonnull NSArray<PKShippingMethod *> *)buy_convertShippingRatesToShippingMethods:(nonnull NSArray<BUYShippingRate *> *)rates;
@end @end
@interface BUYAddress (ApplePay) @interface BUYAddress (ApplePay)
+ (NSString *)buy_emailFromRecord:(ABRecordRef)record; + (nullable NSString *)buy_emailFromRecord:(nullable ABRecordRef)record;
/** /**
* Creates a BUYAddress from an ABRecordRef * Creates a BUYAddress from an ABRecordRef
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
* *
* @return The BUYAddress created from an ABRecordRef * @return The BUYAddress created from an ABRecordRef
*/ */
+ (BUYAddress *)buy_addressFromRecord:(ABRecordRef)record NS_DEPRECATED_IOS(8_0, 9_0, "Use the CNContact backed `buy_addressFromContact:` instead"); + (nonnull BUYAddress *)buy_addressFromRecord:(nullable ABRecordRef)record NS_DEPRECATED_IOS(8_0, 9_0, "Use the CNContact backed `buy_addressFromContact:` instead");
/** /**
* Creates a BUYAddress from a PKContact * Creates a BUYAddress from a PKContact
...@@ -83,6 +83,6 @@ ...@@ -83,6 +83,6 @@
* *
* @return The BUYAddress created from a PKContact * @return The BUYAddress created from a PKContact
*/ */
+ (BUYAddress *)buy_addressFromContact:(PKContact*)contact NS_AVAILABLE_IOS(9_0); + (nonnull BUYAddress *)buy_addressFromContact:(nullable PKContact*)contact NS_AVAILABLE_IOS(9_0);
@end @end
...@@ -38,11 +38,11 @@ ...@@ -38,11 +38,11 @@
@implementation BUYCheckout (ApplePay) @implementation BUYCheckout (ApplePay)
- (NSArray *)buy_summaryItemsWithShopName:(NSString *)shopName { - (nonnull NSArray<PKPaymentSummaryItem *> *)buy_summaryItemsWithShopName:(nullable NSString *)shopName {
BOOL hasDiscount = [self.discount.amount compare:[NSDecimalNumber zero]] == NSOrderedDescending; BOOL hasDiscount = [self.discount.amount compare:[NSDecimalNumber zero]] == NSOrderedDescending;
NSMutableArray *summaryItems = [[NSMutableArray alloc] init]; NSMutableArray<PKPaymentSummaryItem *> *summaryItems = [[NSMutableArray alloc] init];
if (hasDiscount || [self.lineItems count] > 1) { if (hasDiscount || [self.lineItems count] > 1) {
NSDecimalNumber *lineItemSubtotal = [NSDecimalNumber zero]; NSDecimalNumber *lineItemSubtotal = [NSDecimalNumber zero];
...@@ -76,10 +76,11 @@ ...@@ -76,10 +76,11 @@
NSString *itemLabel = shopName ?: @"TOTAL"; NSString *itemLabel = shopName ?: @"TOTAL";
[summaryItems addObject:[PKPaymentSummaryItem summaryItemWithLabel:itemLabel amount:self.paymentDue ?: [NSDecimalNumber zero]]]; [summaryItems addObject:[PKPaymentSummaryItem summaryItemWithLabel:itemLabel amount:self.paymentDue ?: [NSDecimalNumber zero]]];
return summaryItems; return summaryItems;
} }
- (NSArray *)buy_summaryItems - (nonnull NSArray<PKPaymentSummaryItem *> *)buy_summaryItems
{ {
return [self buy_summaryItemsWithShopName:nil]; return [self buy_summaryItemsWithShopName:nil];
} }
...@@ -88,9 +89,9 @@ ...@@ -88,9 +89,9 @@
@implementation BUYShippingRate (ApplePay) @implementation BUYShippingRate (ApplePay)
+ (NSArray *)buy_convertShippingRatesToShippingMethods:(NSArray *)rates + (nonnull NSArray<PKShippingMethod *> *)buy_convertShippingRatesToShippingMethods:(nonnull NSArray<BUYShippingRate *> *)rates
{ {
NSMutableArray *shippingMethods = [[NSMutableArray alloc] init]; NSMutableArray<PKShippingMethod *> *shippingMethods = [[NSMutableArray alloc] init];
for (BUYShippingRate *shippingRate in rates) { for (BUYShippingRate *shippingRate in rates) {
PKShippingMethod *shippingMethod = [[PKShippingMethod alloc] init]; PKShippingMethod *shippingMethod = [[PKShippingMethod alloc] init];
shippingMethod.label = shippingRate.title; shippingMethod.label = shippingRate.title;
...@@ -121,7 +122,7 @@ ...@@ -121,7 +122,7 @@
@implementation BUYAddress (ApplePay) @implementation BUYAddress (ApplePay)
+ (NSString *)buy_emailFromRecord:(ABRecordRef)record + (nullable NSString *)buy_emailFromRecord:(nullable ABRecordRef)record
{ {
ABMultiValueRef emailMultiValue = ABRecordCopyValue(record, kABPersonEmailProperty); ABMultiValueRef emailMultiValue = ABRecordCopyValue(record, kABPersonEmailProperty);
CFArrayRef allEmails = ABMultiValueCopyArrayOfAllValues(emailMultiValue); CFArrayRef allEmails = ABMultiValueCopyArrayOfAllValues(emailMultiValue);
...@@ -136,7 +137,7 @@ ...@@ -136,7 +137,7 @@
return email; return email;
} }
+ (BUYAddress *)buy_addressFromRecord:(ABRecordRef)record + (nonnull BUYAddress *)buy_addressFromRecord:(nullable ABRecordRef)record
{ {
BUYAddress *address = [[BUYAddress alloc] init]; BUYAddress *address = [[BUYAddress alloc] init];
...@@ -193,7 +194,7 @@ ...@@ -193,7 +194,7 @@
return address; return address;
} }
+ (BUYAddress *)buy_addressFromContact:(PKContact*)contact + (nonnull BUYAddress *)buy_addressFromContact:(nullable PKContact*)contact
{ {
BUYAddress *address = [[BUYAddress alloc] init]; BUYAddress *address = [[BUYAddress alloc] init];
......
...@@ -264,8 +264,7 @@ const NSTimeInterval PollDelay = 0.5; ...@@ -264,8 +264,7 @@ const NSTimeInterval PollDelay = 0.5;
self.shippingRates = shippingRates; self.shippingRates = shippingRates;
if ([self.shippingRates count] == 0) { if ([self.shippingRates count] == 0) {
// Shipping address not supported // Shipping address is not supported and no shipping rates were returned
self.checkout.shippingRate = nil;
if (completion) { if (completion) {
completion(PKPaymentAuthorizationStatusInvalidShippingPostalAddress, nil, [self.checkout buy_summaryItemsWithShopName:self.shop.name]); completion(PKPaymentAuthorizationStatusInvalidShippingPostalAddress, nil, [self.checkout buy_summaryItemsWithShopName:self.shop.name]);
} }
......
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'Mobile-Buy-SDK' s.name = 'Mobile-Buy-SDK'
s.version = '1.2.0' s.version = '1.2.1'
s.summary = 'Sell with Shopify in iOS apps' 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.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' s.homepage = 'https://developers.shopify.com/mobile-buy-sdk'
...@@ -9,9 +9,9 @@ Pod::Spec.new do |s| ...@@ -9,9 +9,9 @@ Pod::Spec.new do |s|
s.platform = :ios, '8.0' s.platform = :ios, '8.0'
s.source = { :git => 'https://github.com/Shopify/mobile-buy-sdk-ios.git', :tag => s.version } 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.source_files = 'Mobile Buy SDK/Mobile Buy SDK/**/*.{h,m,mm}'
s.exclude_files = 'Mobile Buy SDK/Mobile Buy SDK/Buy.h' s.public_header_files = 'Mobile Buy SDK/Mobile Buy SDK/**/*.h'
s.public_header_files = 'Mobile Buy SDK/Mobile Buy SDK/**/*.{h}' s.exclude_files = 'Mobile Buy SDK/Mobile Buy SDK/Static Framework/*'
s.module_map = 'Mobile Buy SDK/Mobile Buy SDK/Buy.modulemap' s.module_name = 'Buy'
s.frameworks = 'PassKit' s.frameworks = 'PassKit'
s.libraries = 'c++' s.libraries = 'c++'
s.requires_arc = true s.requires_arc = true
......
![Mobile Buy SDK](http://s3.amazonaws.com/shopify-marketing_assets/static/mbsdk-github.png) ![Mobile Buy SDK](http://s3.amazonaws.com/shopify-marketing_assets/static/mbsdk-github.png)
[![Build status](https://badge.buildkite.com/d8fe8aa44d801c6238ab767867e4fb09abe516bb2933b577cc.svg?branch=develop)](https://buildkite.com/shopify/mobile-buy-sdk-ios) [![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) [![GitHub license](https://img.shields.io/badge/license-MIT-lightgrey.svg)](https://github.com/Shopify/mobile-buy-sdk-ios/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/shopify/mobile-buy-sdk-ios.svg)](https://github.com/Shopify/mobile-buy-sdk-ios/releases) [![GitHub release](https://img.shields.io/github/release/shopify/mobile-buy-sdk-ios.svg)](https://github.com/Shopify/mobile-buy-sdk-ios/releases)
[![Cocoapods](https://img.shields.io/cocoapods/v/mobile-buy-sdk.svg)](https://cocoapods.org/pods/mobile-buy-sdk) [![Cocoapods](https://img.shields.io/cocoapods/v/Mobile-Buy-SDK.svg)](https://cocoapods.org/pods/Mobile-Buy-SDK)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
# Mobile Buy SDK for iOS # Mobile Buy SDK for iOS
...@@ -16,21 +16,23 @@ Please find all documentation on the [Mobile Buy SDK for iOS page](https://docs. ...@@ -16,21 +16,23 @@ Please find all documentation on the [Mobile Buy SDK for iOS page](https://docs.
### Installation ### Installation
#### Manual Installation (Project)
<a href="../../releases/latest">Download the latest version</a> <a href="../../releases/latest">Download the latest version</a>
#### Dynamic Framework Installation
1. Drag the `Mobile Buy SDK.xcodeproj` into your existing project 1. Drag the `Mobile Buy SDK.xcodeproj` into your existing project
2. Add the `Buy` target as a `Target Dependancy` in the `Build Phases` of your project's target 2. Add the `Buy` target as a `Target Dependancy` in the `Build Phases` of your project's target
3. Add the `Buy` target in the `Link Binary with Libraries` section in `Build Phases` 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.
#### Manual Installation (Framework) #### Static Framework Installation
If you would like to not include the Mobile Buy SDK Project within your existing project, you can link directly to the `Buy.framework`. If you would like to not include the Mobile Buy SDK Project within your existing project, you can link directly to the `Buy.framework`.
1. Open the `Mobile Buy SDK.xcodeproj` and build the `Universal Framework` Target 1. Open the `Mobile Buy SDK.xcodeproj` and build the `Static Universal Framework` scheme
2. Drag the `Buy.framework` that was just created from `Mobile Buy SDK Sample Apps` onto the `Linked Frameworks and Libraries` section for the target you want to add the framework to. Check Copy items if needed so the framework is copied to your project 2. Drag the `Buy.framework` that was just created from `Mobile Buy SDK Sample Apps` into the `Linked Frameworks and Libraries` section for the target you want to add the framework to. Check Copy items if needed so the framework is copied to your project
3. In the `Build Settings` tab, add `-all_load` to `Other Linker Flags`. 3. In the `Build Settings` tab, add `-all_load` to `Other Linker Flags`
#### CocoaPods #### CocoaPods
...@@ -42,6 +44,10 @@ pod "Mobile-Buy-SDK" ...@@ -42,6 +44,10 @@ pod "Mobile-Buy-SDK"
Then run `pod install` Then run `pod install`
```objc
#import "Buy.h"
```
#### Carthage #### Carthage
Add the following line to your Cartfile Add the following line to your Cartfile
...@@ -84,23 +90,35 @@ Consult the [Usage Section](https://docs.shopify.com/mobile-buy-sdk/ios/integrat ...@@ -84,23 +90,35 @@ Consult the [Usage Section](https://docs.shopify.com/mobile-buy-sdk/ios/integrat
### Building the SDK ### Building the SDK
Clone this repo or download as .zip and open `Mobile Buy SDK.xcworkspace`. Clone this repo or download as .zip and open `Mobile Buy SDK.xcodeproj`.
The workspace includes the Mobile Buy SDK project and the sample app projects. The sample apps can also be opened outside the workspace with the `.xcodeproj` files found in the sample app folders. However, if you need to use breakpoints or inspect methods in the SDK, run the sample apps from the workspace. The workspace includes the Mobile Buy SDK project.
### Mobile Buy SDK Targets and schemes ### Mobile Buy SDK Targets and schemes
The Mobile Buy SDK includes a number of targets and schemes: The Mobile Buy SDK includes a number of targets and schemes:
* **Buy**: This is the Mobile Buy SDK framework. This build is based on the current build configuration. To build a universal framework that can run on a device and on the Simulator and to be included in your app, please refer to the `Universal Framework` target below * **Buy**: This is the Mobile Buy SDK dynamic framework. Please refer to the installation section above
* **Universal Framework**: This builds the framework using `build_universal.sh` script in the `Universal Framework` target and copies the built framework in the `/Mobile Buy SDK Sample Apps` folder. Build this target if you have made any changes to the framework that you want to test with the sample apps as the sample apps do not build the framework directly but embed the already built framework * **Buy Static** (target only): This is the Mobile Buy SDK static framework. This build is based on the current build configuration. To build a universal framework that can run on a device and on the Simulator and to be included in your app, please refer to the `Static Universal Framework` target below
* **Static Universal Framework**: This builds a **static** framework from the `Buy Static` target using the `build_universal.sh` script in the `Static Universal Framework` target and copies the built framework in the `/Mobile Buy SDK Sample Apps` folder. This is a fat binary that includes arm and i386 slices. Build this target if you have made any changes to the framework that you want to test with the sample apps as the sample apps do not build the framework directly but embed the already built framework
* **Mobile Buy SDK Tests**: Tests for the Mobile Buy SDK framework. See instructions below * **Mobile Buy SDK Tests**: Tests for the Mobile Buy SDK framework. See instructions below
* **Documentation**: This generates appledoc documentation for the framework * **Documentation**: This generates appledoc documentation for the framework
* **Playground**: This target is a basic app that depends directly on the `Buy` framework target and builds the framework every time using the `Playground` app's build configuration. 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 * **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)
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.
### Unit Tests ### Unit Tests
......
# Mobile Buy SDK Release Notes prior to 1.2.0 (Open Source)
Here is a reverse-chronologically ordered list of patch notes for the Mobile Buy SDK for iOS prior to the SDK becoming open source at 1.2.0.
For release notes following the 1.2.0 (open source) release, please see [Github releases](https://github.com/Shopify/mobile-buy-sdk-ios/releases).
### Version 1.1.6
###### Released September 28, 2015
* Add "PAY [SHOP NAME]" to `PKPaymentAuthorizationViewController` when using `BUYApplePayHelpers`. This is also available through `buy_summaryItemsWithShopName:` in `BUYApplePayAdditions`. Apple's HIG specifies that the store's name is required in the summary items for the total amount.
* Set `DWARF` to suppress compiler warnings for all sample apps.
### Version 1.1.5
###### Released September 17, 2015
* [Advanced Sample App](https://docs.shopify.com/mobile-buy-sdk/ios/advanced-sample-app) which takes the developer through all the steps from downloading products to building a cart and completing a checkout.
* Fix for additional country code validation for Apple Pay, where addresses from the `PKPaymentAuthorizationViewControllerDelegate` sometimes don't return country codes correctly.
### Version 1.1.4
###### Released September 10, 2015
* Add support for the SafariViewController on iOS 9.
* Add support for Discover credit cards.
* Use new Contact API for Apple Pay on iOS 9.
* Option breadcrumbs for variant selection in `BUYProductViewController`.
### Version 1.1.3
###### Released September 2, 2015
* Use of HTTPs for all network calls.
* Improvements to shipping address validation including client-side pre-condition check for address when user selects an address in the `PKPaymentViewController`.
* BUYProduct objects with no images will no longer show the header placeholder in `BUYProductViewController`.
* `setVariant:withQuantity:` available on `BUYCart` to easily add or remove `BUYCartLineItem` objects for an associated `BUYProductVariant`.
* Updated documentation.
* `sourceUrl` has been removed from `BUYCheckout`.
### Version 1.1.2
###### Released August 20, 2015
`BUYProductViewController`:
* Products with one variant will now correctly show the variant but variant selection flow is disabled.
* Prices and "Sold Out" are now displayed for the last variant option in the variant selection flow.
* Variant selection controller size tied to device width and height for better UI on larger device screens.
* An error alert is shown if an error occurs creating a new checkout.
* Improved iPad presentation.
* Fixed an issue where dark theme wasn't properly applied to all views.
* Added `initWithClient:theme:` to more easily set the theme.
* Navigation bar title colour fix.
Other changes:
* `source` and `source_name` are now correctly set to `mobile_app` for checkouts, which propagates to orders in the shop admin. An *order.json* will include both and the orders CSV file will include the `source`.
* `sourceId` on `BUYCheckout` has been changed to `sourceIdentifer`. This is a `readonly` property, which automatically gets the channel ID for the Mobile App channel. This gets shows in *orders.json* as `source_identifier` on the shop admin.
* Clearer documentation for `reservationTime`.
* Fixed an issue with summary items for Apple Pay.
* Fix crash on `getCollections:` when a collection does not include an image.
### Version 1.1.1
###### Released August 12, 2015
* `BUYLineItem` now uses `lineItemIdentifier` as its identifier.
* Fix an issue where image would reset while scrolling.
* Added "Powered by Shopify" footer in `BUYProductViewController`.
* Hiding image page control on scrolling in `BUYProductViewController`.
* `webReturnToLabel` on `BUYCheckout` can now correctly be used for the web checkout return-to-app-name button.
* Unavailable variants now appear as "Sold Out" and the customer is unable to checkout via the web and Apple Pay using the `BUYProductViewController`.
* Improved support for portrait orientation for the `BUYProductViewController` when presented in landscape apps.
### Version 1.1
###### Released August 6, 2015
* Product View: Easily display and sell products from your shop using the new `BUYProductViewController`, which can be presented from any view controller in your app.
* Support for Product Collections.
* Support for custom properties on `BUYLineItem`.
* Added better support for responsive web checkout.
* Added `BUYApplePayHelpers` to help easily support Apple Pay if `BUYViewController` isn't used.
* `getCompletionStatusOfCheckout:completion:` no longer returns the `BUYCheckout` object that was passed in - use `getCheckout:completion:` to retrieve the updated `BUYCheckout` object.
* Added `isApplePayAvailable` flag on `BUYViewController` that returns YES if the customer can pay with Apple Pay.
* Applying or removing gift cards now applies/removes the gift card(s) on the BUYCheckout and updates the `paymentDue` amount on the `BUYCheckout` object.
* `BUYProduct` and `BUYProductVariant` objects now include an `inventory` flag.
* Add support for Storyboard usage for `BUYViewController`.
* Added `BUYCartLineItem` which contains the original `BUYProductVariant` objects added to the cart.
* `BUYLineItem` objects on a `BUYCheckout` object now reference variant IDs, not a BUYProductVariant.
* `sku` property has been added to `BUYProductVariant` objects.
* Added `paymentSessionId` on `BUYCheckout`.
* Better error messaging.
### Version 1.0.3
###### Released July 2, 2015
* Fixed an issue retrieving a cart when using Apple Pay and WKWebView checkout
### Version 1.0.2
###### Released June 25, 2015
* Changed SDK to a static framework (see updated [Getting Started guide](https://docs.shopify.com/mobile-buy-sdk/integration-guide))
* Fixed `BUYTaxLine` parsing
* Fixed channel attribution
* Removed `app.js`
* Updated docs
### Version 1.0.1
###### Released May 26, 2015
* Supports Apple Pay purchases without shipping requirement
* Fixes missing symbols for `getProductId:completion:`
### Version 1.0
###### Released May 19, 2015
* Initial public release
#!/bin/sh #!/bin/sh
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
TARGET_NAME="Buy Static"
FRAMEWORK_NAME="Buy" FRAMEWORK_NAME="Buy"
# make sure the output directory exists # make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Build Device and Simulator versions # Build Device and Simulator versions
xcodebuild -target "${FRAMEWORK_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -OBJROOT="${OBJROOT}" -sdk iphoneos BUILD_DIR="${BUILD_DIR}" SYMROOT="${SYMROOT}" BUILD_ROOT="${BUILD_ROOT}" clean build xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -OBJROOT="${OBJROOT}" -sdk iphoneos BUILD_DIR="${BUILD_DIR}" SYMROOT="${SYMROOT}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${FRAMEWORK_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -OBJROOT="${OBJROOT}" -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" SYMROOT="${SYMROOT}" BUILD_ROOT="${BUILD_ROOT}" clean build xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -OBJROOT="${OBJROOT}" -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" SYMROOT="${SYMROOT}" BUILD_ROOT="${BUILD_ROOT}" clean build
# Copy the framework structure (from iphoneos build) to the universal folder # Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/" cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
...@@ -17,6 +18,6 @@ cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework" "${UN ...@@ -17,6 +18,6 @@ cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework" "${UN
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}"
# Copy the framework to the sample apps folder # Copy the framework to the sample apps folder
rm -rf "${SRCROOT}/../Mobile Buy SDK Sample Apps/${FRAMEWORK_NAME}.framework" rm -rf "${SRCROOT}/../Mobile Buy SDK Sample Apps/${TARGET_NAME}.framework"
cp -r "${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework" "${SRCROOT}/../Mobile Buy SDK Sample Apps" cp -r "${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework" "${SRCROOT}/../Mobile Buy SDK Sample Apps"
xcodebuild test -workspace "Mobile Buy SDK.xcworkspace" \ xcodebuild test -project "Mobile Buy SDK/Mobile Buy SDK.xcodeproj" \
-scheme "Mobile Buy SDK Tests" \ -scheme "Mobile Buy SDK Tests" \
-sdk iphonesimulator \ -sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 6,OS=9.0' -destination 'platform=iOS Simulator,name=iPhone 6,OS=9.0'
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