This is a sample application to demonstrate how to integrate with the Fujifilm Smart Publishing iOS SDK.
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
Fujifilm_SPA_SDK_iOS_DemoApp.xcodeproj
Fujifilm_SPA_SDK_iOS_DemoApp
SwiftSupport
.DS_Store
.gitignore
Fujifilm-SPA-SDK.podspec
LICENSE.md
README.md

README.md

Fujifilm SPA iOS SDK Tutorial

Introduction

This project is a sample application to demonstrate how to integrate with the Fujifilm SPA iOS SDK.

This document provides a tutorial to use the Fujifilm SPA iOS SDK library in your iOS application.

What is it?

The Fujifilm Smart Publishing API SDK is a native library that you can include in your existing iOS application to enable photo product output through Fujifilm. This provides you with a new revenue stream while providing a new valuable service to your application users.

The Fujifilm SPA SDK gives you access to over 100 popular photo gift products and allows you to control the availability and pricing of each product through our web portal.

Please visit the Fujifilm Developer Network portal to sign-up and obtain an API key, set product pricing, and configure your application. The portal is available at http://www.fujifilmapi.com/.

What’s new?

There are many new items in this release:

  • Completely re-designed GUI
  • Product categorization to help organize the available product set
  • Over 30 new products including items within popular categories such as Home Décor, Photobooks, Greeting Cards and Mobile Device Cases
  • A native Android SDK in addition to our iOS SDK so that you can provide your users with a common experience in either operating system (Android versions 4.4 and above)
  • Updated support for iOS versions 8 and above

Requirements

  • iOS version 8.0 or later
  • Developers using the Fujifilm SPA iOS SDK need to sign up for an account on Fujifilm Developer Network (http://fujifilmapi.com), create an application, obtain an Api Key, and setup catalog products and pricing.

Integration Instructions

Step 1: Get API Key

Sign up for an account on Fujifilm Developer Network (http://fujifilmapi.com), create an application, obtain an API Key, and setup catalog products and pricing.

Step 2: Include Fujifilm SPA SDK

Include the Fujifilm SPA SDK in your Xcode project. To add Fujifilm SPA SDK to your Xcode project, you may install via Cocoapods or add it manually.

Using CocoaPods

For more information on Cocoapods, including instructions on adding a pod to your Xcode project, visit https://guides.cocoapods.org/using/the-podfile.html.

This section assumes you have CocoaPods installed on your system.

In your Podfile, include the SPA SDK pod like so:

pod 'Fujifilm-SPA-SDK', '~> 1.7.28'

Install the pod by running navigating to the project directory in a terminal and running $ pod install. If you have already installed the SDK and would like to update to the latest version, run $ pod update instead.

Upon successful installation, close your Xcode project if it is open, and open the workspace that was generated by Cocoapods.

Manual Installation

Skip this section if you are using CocoaPods!
  1. Download files
  1. Add files to project
  • Open your project in Xcode. Select File > Add Files To “MyApp” and select the files you just downloaded. Check “Copy items if needed” under Destination and select “Create groups” under Added Folders. Make sure your target is checked in the “Add to targets” section. Click Add.
  1. Link with frameworks
  • Add the following frameworks to your project:
  • Accelerate
  • AddressBook
  • AddressBookUI
  • AVFoundation
  • AudioToolBox
  • CoreMedia
  • MobileCoreServices
  • SystemConfiguration
  • AssetsLibrary
  • ImageIO
  • Photos
  • To add frameworks, select your project in the Xcode file explorer. In the main window, the top left corner has a dropdown menu with a list of your projects and targets. Make sure your target is selected (not your project) and switch to the Build Phases tab. Expand the Link Binary With Libraries section and add the frameworks listed above.
  1. In your TARGETS Build settings, add -lc++ to the Other Linker Flags section
  2. In your TARGETS Build settings, add -ObjC to the Other Linker Flags section

Step 3: Updating info.plist file

In order to use the SDK you will need to add keys to your project's info.plist file.

You can enter all of the keys manually using the Xcode UI, or you can open the info.plist file in a text editor and copy/paste the following in the inside the <plist> <dict> tag.

<key>NSLocationWhenInUseUsageDescription</key>
<string>Please enable this feature to search for stores near you when creating personalized prints and gifts.</string>
<key>NSContactsUsageDescription</key>
<string>Please enable this feature to access your contacts when creating personalized prints and gifts.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Please enable this feature to be able to upload your photos and create personalized prints and gifts.</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>fujifilmesys.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>paypal.com</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>

Step 4: PayPal Payment Option

We offer 2 payment options to users, Credit Card and PayPal. Please follow the steps below to enable PayPal as you'll typically see a higher conversion rate with it.

Setup for app switch using the CFBundleURLTypes key in info.plist

To accept payments from PayPal, you must register a URL type and configure your app to return from app switches.

Register a URL type
  1. In Xcode, click on your project in the Project Navigator and navigate to App Target > Info > URL Types
  2. Click [+] to add a new URL type
  3. Under Identifier, enter your app's Bundle ID
  4. Under URL Schemes, enter your app switch return URL scheme. This scheme must start with your app's Bundle ID and be dedicated to Fujifilm' SDK app switch returns. For example, if the app bundle ID is com.your-company.Your-App, then your URL scheme could be com.your-company.Your-App.FujifilmSDK.Payments.
  5. If your app is built using iOS 9 as its Base SDK, then you must add URLs to a whitelist in your app's info.plist:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>com.paypal.ppclient.touch.v1</string>
<string>com.paypal.ppclient.touch.v2</string>
</array>
  1. Test your URL type set in step 4 above: Open up Mobile Safari on your iOS Device or Simulator and enter in the URL that you set in step 4 (e.g. com.your-company.Your-App.FujifilmSDK.Payments://test). This should launch your app.

Important: If you have multiple app targets, be sure to add the URL type for all of the targets.

Step 5: Integrate with SDK - Objective-C

If your app is Swift, you can following the instructions found here: Swift Integration.

In your view controller header file, import the SDK:

#import "Fujifilm.SPA.SDK.h"

In your view controller header file, ensure it implements the FujifilmSPASDKDelegate protocol:

@interface ViewController : UIViewController <FujifilmSPASDKDelegate>{}

In your view controller, create a Fujifilm_SPA_SDK_iOS object. Initialize it using the initWithApiKey:environment:images:userID:retainUserInfo:promoCode:launchPage:extraOptions method:

Fujifilm_SPA_SDK_iOS *fujifilmOrderController = [[Fujifilm_SPA_SDK_iOS alloc]
initWithApiKey: @"YOUR_API_KEY" //REPLACE with YOUR ApiKey
environment:  @"Preview"
images: NS_ARRAY_OF_IMAGES
userID: @"" //optional
retainUserInfo: YES
promoCode: @"" //optional
launchPage: kHome
extraOptions: nil];

Parameters

Name Type Description
apiKey NSString* Fujifilm SPA apiKey you receive when you create your app at http://fujifilmapi.com. This apiKey is environment specific
environment NSString* Sets the environment to use. The apiKey must match your app’s environment set on http://fujifilmapi.com. Possible values are “preview” or "production".
images id An NSArray* of PHAsset* or NSString* (for public image urls. Must use https://). Array can contain combination of types. Images must be jpeg, png, or heic format and smaller than 20MB. A maximum of 100 images can be sent in a given Checkout process. If more than 100 images are sent, only the first 100 will be processed.
userID NSString* Optional parameter. Send in an empty string @"" if you don't use it. This can be used to link a user with an order. Maximum length is 50 alphanumeric characters.
retainUserInfo BOOL Save user information (address, phone number, email) for when the app is used a second time.
promoCode NSString* Optional parameter to add a promo code to the order. Contact us through http://fujifilmapi.com for usage and support.
launchPage enum The page that the SDK should launch when initialized. Valid values are kHome and kCart. Defaults to kHome
extraOptions NSDictionary<NSString*, id>* A dictionary with key/value pairs. All key/value pairs are optional; extraOptions may be empty or nil if no options are desired. See section "Extra Initialization Options" for more information.

Next, set the Fujifilm_SPA_SDK_iOS object’s delegate to the view controller:

fujifilmOrderController.delegate = self;

Finally, present the Fujifilm_SPA_SDK_iOS object:

[self presentViewController:fujifilmOrderController animated:YES completion:nil];

Extra Initialization Options (Optional)

Key Value Description
kSiteDeepLink NSString* Specifies which page the user is first presented with when launching the SDK. You can send the user to the cart, a category, or to a product details screen. To send the user to the cart, set the value to Cart. To send the user to a category use the follow pattern: mailorder/CATEGORY_NAME. Make sure to change the CATEGORY_NAME to the name of the category, for example, mailorder/WallArt. To send the user to a product details screen use the following pattern: mailorder/CATEGORY_NAME/PRODUCT_NAME. Make sure to change CATEGORY_NAME to the name of the category and the PRODUCT_NAME to the name of the product, for example, mailorder/canvas/11x14gallerywrappedcanvas.
kEnableAddMorePhotos BOOL* By default this is set to YES. To disable the "Add More Photos" feature set this to value No. If YES (or omitted), the user will be able to add more photos from his or her local Photos gallery on the Compose screen and the Prints screen.
kPreRenderedOrder FFOrder* See section "Providing Pre-rendered Products" for more information.

Providing Pre-rendered Products (Optional)

In order to include pre-rendered products with your order, you may pass an instance of the FFOrder class into the extraOptions parameter. This class contains a list of products (instances of FFLine class) to be added to the order. Each FFLine contains a product code field which corresponds to the product code found on http://fujifilmapi.com, as well as a list of FFPage objects. Each FFPage object contains a list of FFAsset objects, each of which contains a url to the Hi-Res image to be printed. The following is an example function showing how to create an order with a pre-rendered Stationery Card:

-(FFOrder *)createPrerenderedOrderWithStationeryCard {
//create a FFAsset for the front of the card
FFAsset *assetFront = [FFAsset assetWithHiResImageURL:@"http://test.com/prerenderedCardFront.jpg"];

//create a FFAsset for the back of the card
FFAsset *assetBack = [FFAsset assetWithHiResImageURL:@"http://test.com/prerenderedCardBack.jpg"];

//create a FFPage for the front of the card. Add the front asset
FFPage *pageFront = [FFPage page];
[pageFront addAsset:assetFront];

//create a FFPage for the back of the card. Add the back asset
FFPage *pageBack = [FFPage page];
[pageBack addAsset:assetBack];

//create a FFLine with product code which represents the desired product
FFLine *line = [FFLine lineWithProductCode:@"PRGift;4121"];

//add the front and back pages to the Line
[line addPage:pageFront];
[line addPage:pageBack];

//Create a new order containing the Line
FFOrder *order = [FFOrder order];
[order addLine:line];

//return the FFOrder to be added to extraOptions
return order;
}

Finishing SPA SDK

The FujifilmSPASDKDelegate requires your view controller to implement the method fujifilmSPASDKFinishedWithStatus:(int) statusCode andMessage: (NSString*) message.

When the Fujifilm SPA SDK is finished, it will return to the parent app, calling fujifilmSPASDKFinishedWithStatus:andMessage. You must implement like so:

#pragma mark -
#pragma mark Fujifilm SPA SDK delegate

-(void) fujifilmSPASDKFinishedWithStatus: (int) statusCode andMessage: (NSString*) message{
    NSString *msg;
    /**
     Status codes that may be sent from Fujifilm SPA SDK. This may require updates if any new codes are added. See documentation for list of status codes.
     */
    switch (statusCode){
        case kFujifilmSDKStatusCodeFatal:
            msg = @"Fatal Error";
            break;
        case kFujifilmSDKStatusCodeNoImagesUploaded:
            msg = @"No Images Uploaded";
            break;
        case kFujifilmSDKStatusCodeNoInternet:
            msg = @"No Internet";
            break;
        case kFujifilmSDKStatusCodeInvalidAPIKey:
            msg = @"Invalid APIKey";
            break;
        case kFujifilmSDKStatusCodeUserCanceled:
            msg = @"User Canceled";
            break;
        case kFujifilmSDKStatusCodeNoValidImages:
            msg = @"No Valid Images";
            break;
        case kFujifilmSDKStatusCodeTimeout:
            msg = @"Timeout Error";
            break;
        case kFujifilmSDKStatusCodeOrderComplete:
            msg = message;
            break;
        case kFujifilmSDKStatusCodeUploadFailed:
            msg = @"Upload Failed";
            break;
        case kFujifilmSDKStatusCodeInvalidUserIDFormat:
            msg = @"Invalid User ID Format";
            break;
        case kFujifilmSDKStatusCodeInvalidPromoCodeFormat:
            msg = @"Invalid Promo Code Format";
            break;
        case kFujifilmSDKStatusCodeRequiresPhotoPermission:
            msg = @"Photo Permission Required";
            break;
        default:
            msg = @"Unknown Error";
    }
    
    NSLog(@"fujifilmSPASDKFinishedWithStatus: statusCode: %u message: %@", statusCode, msg);
}

The status code will be one of the following values:

statusCode meaning
0 Fatal Error
1 No Images Uploaded
2 No Internet
3 Invalid API Key
4 User Cancelled
5 No Valid Images
6 Time Out
7 Order Complete
8 Upload Failed
9 User ID Invalid Format
10 Promo Code Invalid Format

It is up to your view controller to handle any/all of these cases in fujifilmSPASDKFinishedWithStatus:andMessage as seen above. The status codes and messages are for internal use only; please do not present these to the user.

In addition, the FujifilmSPASDKDelegate has an optional method promoCodeDidFailValidationWithError: (int) error

This method is called when a promotion code that is passed in fails validation in the SDK. The error parameter is an int corresponding to the cause of the failure. Possible error values are provided as an enum (FFPromotionError). Though not required, it is recommended that this method is implemented in order to log issues and/or inform users that their promotion is invalid. An example implementation is given below:

-(void) promoCodeDidFailValidationWithError:(int)error {
    NSString *errorReason;
    switch(error) {
        case 0:
            errorReason = @"Promotion Expired";
            break;
        case 1:
            errorReason = @"Promotion Not Activated";
            break;
        case 2:
            errorReason = @"Invalid Discount";
            break;
        case 3:
            errorReason = @"Promotion Disabled";
            break;
        case 4:
            errorReason = @"Promotion Does Not Exist";
            break;
        case 5:
        default:
            errorReason = @"Fatal Error";
            break;
    }
    NSLog(@"Promotion is invalid. Cause: %@",errorReason);
}

PayPal Payment Option

In addition to updating your info.plist in Step 4 above, you must also update your application delegate.

Update your application delegate

In your AppDelegate's application:didFinishLaunchingWithOptions implementation, use setReturnURLScheme: with the value you set above in Step 4:PayPal Payment Option. It's important that the url you pass in here matches the url that you set in your info.plist for Step 4 above.

For example:

#import "AppDelegate.h"
#import "Fujifilm_SPA_SDK_iOS_AppSwitch.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [Fujifilm_SPA_SDK_iOS_AppSwitch setReturnURLScheme:@"com.your-company.Your-App.FujifilmSDK.Payments"];
    return YES;
}

Then in your application delegate, pass the payment URL that you set above in Step 4:PayPal Payment Option. Make sure that you change the "com.your-company.Your-App.FujifilmSDK.Payments" from the example below to the url that you set in your info.plist for Step 4 above.

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
  if ([url.scheme localizedCaseInsensitiveCompare:@"com.your-company.Your-App.FujifilmSDK.Payments"] == NSOrderedSame) {
    return [Fujifilm_SPA_SDK_iOS_AppSwitch handleOpenURL:url options:options];
  }
  return NO;
}
#endif

// If you support iOS 7 or 8, add the following method.
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
  if ([url.scheme localizedCaseInsensitiveCompare:@"com.your-company.Your-App.FujifilmSDK.Payments"] == NSOrderedSame) {
    return [Fujifilm_SPA_SDK_iOS_AppSwitch handleOpenURL:url sourceApplication:sourceApplication];
  }
  return NO;
}

Receiving analytic events (Optional)

If you're interested in seeing what behavior your users are taking in our SDK, we provide a way for you to listen to events from us when users take certain actions. To receive these events, implement the receivedAnalyticsEvent:withAttributes: delegate method.

The attributes are a NSArray of NSDictionary. In each NSDictionary, the keys (defined below) will correspond to either an NSString value for strings, or NSNumber value for booleans and numbers. Below is an example of how data is passed to this method.

Example Code
-(void) receivedAnalyticsEvent:(NSString *)event withAttributes:(NSArray *)attributes{
    if (!event) {
        return;
    }
    if ([event isEqualToString:kAnalyticsEventItemPurchased]) {
        [self processItemPurchasedEventWithAttributes:attributes];
    }
    // Handle any other desired events here
}

-(void) processItemPurchasedEventWithAttributes:(NSArray *)attributes {
    NSString *productName = nil;
    NSString *productCode = nil;
    NSNumber *quantity = @0;
    NSNumber *unitPrice = @0.0;
    
    for (NSDictionary *attribute in attributes) {
        NSObject *eventValue = [attribute valueForKey:valueKey];
        if (eventValue == nil || [eventValue isKindOfClass:[NSNull class]]) {
            continue;
        }
        
        NSString *attributeName = [attribute valueForKey:attributeKey];
        if ([attributeName isEqualToString:kAnalyticsAttributePurchasedProduct]) {
            productName = [attribute valueForKey:valueKey];
        }
        else if ([attributeName isEqualToString:kAnalyticsAttributeProductCodePurchased]) {
            productCode = [attribute valueForKey:valueKey];
        }
        else if ([attributeName isEqualToString:kAnalyticsAttributePurchasedQuantity]) {
            quantity = [attribute valueForKey:valueKey];
        }
        else if ([attributeName isEqualToString:kAnalyticsAttributePurchasedUnitPrice]) {
            unitPrice = [attribute valueForKey:valueKey];
        }
    }
    
    NSLog(@"Received purchased event for product %@ (%@) with quantity %@ and unit price %@", productName, productCode, quantity, unitPrice);
}
Events
Event Name Event Value Description
Exit kAnalyticsEventExit Sent when the user exits the SDK
Print Edited kAnalyticsEventPhotoEdited Sent when the user edits a print product
Product Edited kAnalyticsEventProductEdited Sent when the user edits any non-print product
Continue Shopping kAnalyticsEventContinueShopping Sent when the user tapps "Continue Shopping" from the cart page and the thank you page
Item Added to Cart kAnalyticsEventItemAddedToCart Sent when a product is added to cart from either the compose page or the prints page
Item Composed kAnalyticsEventitemComposed Sent when the user goes to the compose page to edit a product
Item Details Viewed kAnalyticsEventDetailsViewed Sent when the user taps navigates to the product details page
Item Purchased kAnalyticsEventItemPurchased Sent for every item when the user successfully checks out
Order Complete kAnalyticsEventOrderComplete Sent when the user successfully checks out
Checkout Started kAnalyticsEventCheckoutStarted Sent when the user taps "Continue to Checkout" from the cart page
Store Searched kAnalyticsEventStoreSearched Sent when the user searches for a store on the store list page
Item Removed from Cart kAnalyticsEventRemovedFromCart Sent when a product is removed from the cart, either due to an error or when the user deletes the product themselves
Store Favorited kAnalyticsEventStoreFavorited Sent when the user favorites a store on the store search page or on the first step of checkout
Exit Event Attributes
Event Attribute Data Type Description
kAnalyticsAttributeItemsPurchased NSNumber (integer) Number of items purchased
kAnalyticsAttributeExitPoint NSString Page the user left on
kAnalyticsAttributePromoCode NSString Comma separated list of promo codes applied
kAnalyticsAttributeExitMethod NSString Done Button/Back Button/Cancel Button
kAnalyticsAttributeDeliveryType NSString Retail Pickup/Mail Order
kAnalyticsAttributePickupLocation NSString If this is a Mail Order order, N/A. Otherwise, it is the name of the retailer the user selected (Walmart, Sam's Club, etc.)
kAnalyticsAttributeAddressValidationErrors NSNumber (integer) Number of address validation errors that have occurred during the session
Print Edited Event Attributes

No event attributes

Product Edited Event Attributes

Not event attributes

Continue Shopping Event Attributes
Event Attribute Data Type Description
kAnalyticsAttributeScreen NSString the page in which the user tapped Continue Shopping
Item Added to Cart Event Attributes
Event Attribute Data Type Description
kAnalyticsAttributeStatus NSNumber (BOOL) Whether add to cart succeeded or failed
kAnalyticsAttributeDuration NSNumber (integer) The amount of time it took to add to cart
kAnalyticsAttributeItemAdded NSString Name of the product added to cart
kAnalyticsAttributeAddToCartDelivery NSString Retail Pickup/Mail Order
kAnalyticsAttributeAddToCartPickup NSString If this is a Mail Order order, N/A. Otherwise, it is the name of the retailer the user selected (Walmart, Sam's Club, etc.)
kAnalyticsAttributeAddedProductCode NSString The product code of the item added to cart
Item Composed Event Attributes
Event Attribute Data Type Description
kAnalyticsAttributeComposedProduct NSString Name of the product composed
kAnalyticsAttributeComposedSource NSString Where the user came from. One of: Cart Page, Order Prints Page, Product List
kAnalyticsAttributeComposedDelivery NSString Retail Pickup/Mail Order
kAnalyticsAttributeComposedPickup NSString If this is a Mail Order order, N/A. Otherwise, it is the name of the retailer the user selected (Walmart, Sam's Club, etc.)
Item Details Viewed Event Attributes
Event Attribute Data Type Description
kAnalyticsAttributeDetailsProduct NSString Name of the product the user viewed
kAnalyticsAttributeDetailsSource NSString Where the user viewed the product from. Currently only "Product List"
kAnalyticsAttributeDetailsDelivery NSString Retail Pickup/Mail Order
kAnalyticsAttributeDetailsPickup NSString If this is a Mail Order order, N/A. Otherwise, it is the name of the retailer the user selected (Walmart, Sam's Club, etc.)
Item Purchased Event Attributes
Event Attribute Data Type Description
kAnalyticsAttributePurchasedProduct NSString Name of the product the user purchased
kAnalyticsAttributePurchasedQuantity NSNumber (integer) Quantity of the line in the order
kAnalyticsAttributePurchasedDelivery NSString Retail Pickup/Mail Order
kAnalyticsAttributePurchasedPickup NSString this is a Mail Order order, N/A. Otherwise, it is the name of the retailer the user selected (Walmart, Sam's Club, etc.)
kAnalyticsAttributeProductCodePurchased NSString Product code of the item purchased
kAnalyticsAttributePurchasedUnitPrice NSNumber (float) Unit price of the product
Order Complete Event Attributes
Event Attribute Data Type Description
kAnalyticsAttributeNumberOfItems NSNumber (integer) Number of lines in the order
kAnalyticsAttributeNumberOfDistinctItems NSNumber (integer) Number of distinct products in the order
kAnalyticsAttributeOrderPaymentType NSString Name of the payment method used by the user
kAnalyticsAttributeOrderCurrencyType NSString ISO 4217 currency code for the type of currency used. Currently only USD.
kAnalyticsAttributeOrderSubtotal NSNumber (float) Sub total of the order
kAnalyticsAttributeOrderTax NSNumber (float) Tax the user was charged for
kAnalyticsAttributeOrderShipping NSNumber (float) Total cost of shipping for the user
kAnalyticsAttributeOrderDiscount NSNumber (float) Amount taken off the order due to discounts
kAnalyticsAttributeOrderTotal NSNumber (float) Total amount of the order
kAnalyticsAttributeOrderRetailer NSString If this is Mail Order, N/A. Otherwise, it is the name of the retailer the user selected (Walmart, Sam's Club, etc.)
kAnalyticsAttributeOrderServiceType NSString Mail Order/Retail Pickup
kAnalyticsAttributeOrderDeliveryMethod NSString The delivery level the user selected: Standard/Expidited/Rush. If this is a store pickup order, this is "Pay in Store".
kAnalyticsAttributeStoreNumber NSString The store number of the store the user selected, if the order is store pickup.
Checkout Started Event Attributes
Event Attribute Data Type Description
kAnalyticsAttributeStoreNumber NSString The store number of the store the user selected, if the order is store pickup.
kAnalyticsAttributeNumberOfItems NSNumber (integer) Number of lines in the order
kAnalyticsAttributeNumberOfDistinctItems NSNumber (integer) Number of distinct products in the order
kAnalyticsAttributeOrderCurrencyType NSString ISO 4217 currency code for the type of currency used. Currently only USD.
kAnalyticsAttributeOrderSubtotal NSNumber (float) Sub total of the order
kAnalyticsAttributeIsPreservedCart NSNumber (BOOL) If this is a new order or a preserved cart
kAnalyticsAttributeOrderRetailer NSString If is is Mail Order, N/A. Otherwise, it is the name of the retailer the user selected (Walmart, Sam's Club, etc.)
kAnalyticsAttributeOrderServiceType NSString Mail Order/Retail Pickup
Store Searched Event Attributes
Event Attribute Data Type Description
kAnalyticsAttributeSearchLatitude NSNumber (float) The latitude of the user when they tap "Find near me" on the store search page
kAnalyticsAttributeSearchLongitude NSNumber (float) The longitude of the user when they tap "Find near me" on the store search page
kAnalyticsAttributeSearchZip NSString The zip code the user entered on the store search page
kAnalyticsAttributeSearchRadius NSNumber (integer) The radius the user had selected
kAnalyticsAttributeSearchResultsCount NSNumber (integer) The number of stores found based on the users search criteria
Item Removed from Cart Event Attributes
Event Attribute Data Type Description
kAnalyticsAttributeProductRemoved NSString The name of the product removed from the users cart
kAnalyticsAttributeProductCodeRemoved NSString The product code of the product removed from the users cart
Store Favorited Event Attributes
Event Attribute Data Type Description
kAnalyticsAttributeFavoritedStoreNumber NSString The store number of the store that the user favorited

Full Example Code

Podfile
pod 'Fujifilm-SPA-SDK', '~> 1.7.28'
ViewController.h
#import "Fujifilm.SPA.SDK.h"

@interface ViewController : UIViewController <FujifilmSPASDKDelegate>{}

/**
 Enum of status codes that may be sent from Fujifilm SPA SDK. This may require updates if any new codes are added. See documentation for list of status codes.
 */
typedef enum FujifilmSDKStatusCode {
    kFujifilmSDKStatusCodeFatal= 0,
    kFujifilmSDKStatusCodeNoImagesUploaded= 1,
    kFujifilmSDKStatusCodeNoInternet= 2,
    kFujifilmSDKStatusCodeInvalidAPIKey= 3,
    kFujifilmSDKStatusCodeUserCanceled= 4,
    kFujifilmSDKStatusCodeNoValidImages= 5,
    kFujifilmSDKStatusCodeTimeout= 6,
    kFujifilmSDKStatusCodeOrderComplete= 7,
    kFujifilmSDKStatusCodeUploadFailed= 8,
    kFujifilmSDKStatusCodeInvalidUserIDFormat = 9,
    kFujifilmSDKStatusCodeInvalidPromoCodeFormat = 10,
    kFujifilmSDKStatusCodeRequiresPhotoPermission= 11
} FujifilmSDKStatusCode;
@end
ViewController.m
- (IBAction)launchFujifilmSDK:(id)sender {
    NSArray *images = [[NSArray alloc] initWithObjects:@"https://webservices.fujifilmesys.com/venus/imagebank/fujifilmCamera.jpg",@"https://webservices.fujifilmesys.com/venus/imagebank/mustang.jpg", nil];

    /*
    -------------------------------------------------------------------------------
    Create a Fujifilm_SPA_SDK_iOS instance and present the Fujifilm SDK controller.
    -------------------------------------------------------------------------------

    - Go to http://www.fujifilmapi.com to register for an apiKey.
    - Ensure you have the right apiKey for the right environment.
    //MAKE SURE TO CHANGE YOUR_API_KEY TO YOUR APIKEY!
    */
    Fujifilm_SPA_SDK_iOS *fujifilmOrderController = [[Fujifilm_SPA_SDK_iOS alloc]
    initWithApiKey: @"5cb79d2191874aca879e2c9ed7d5747c"
    environment:  @"Preview"
    images: images
    userID: @"" //optional
    retainUserInfo: YES
    promoCode: @"" //optional
    launchPage: kHome
    extraOptions: nil];

    fujifilmOrderController.delegate = self;
    //Create a new FujifilmSPASDKNavigation Controller with the orderController as its root
    FujifilmSPASDKNavigationController *navController = [[FujifilmSPASDKNavigationController alloc] initWithRootViewController:fujifilmOrderController];
    /*
    ---------------------------------------------------------------------------------------
    Present the Fujifilm SPA SDK Navigation Controller
    ---------------------------------------------------------------------------------------
    */
    [self presentViewController:navController animated:YES completion:nil];
}
-(void) fujifilmSPASDKFinishedWithStatus: (int) statusCode andMessage: (NSString*) message{
    NSString *msg;
    /**
     Status codes that may be sent from Fujifilm SPA SDK. This may require updates if any new codes are added. See documentation for list of status codes.
     */
    switch (statusCode){
        case kFujifilmSDKStatusCodeFatal:
            msg = @"Fatal Error";
            break;
        case kFujifilmSDKStatusCodeNoImagesUploaded:
            msg = @"No Images Uploaded";
            break;
        case kFujifilmSDKStatusCodeNoInternet:
            msg = @"No Internet";
            break;
        case kFujifilmSDKStatusCodeInvalidAPIKey:
            msg = @"Invalid APIKey";
            break;
        case kFujifilmSDKStatusCodeUserCanceled:
            msg = @"User Canceled";
            break;
        case kFujifilmSDKStatusCodeNoValidImages:
            msg = @"No Valid Images";
            break;
        case kFujifilmSDKStatusCodeTimeout:
            msg = @"Timeout Error";
            break;
        case kFujifilmSDKStatusCodeOrderComplete:
            msg = message;
            break;
        case kFujifilmSDKStatusCodeUploadFailed:
            msg = @"Upload Failed";
            break;
        case kFujifilmSDKStatusCodeInvalidUserIDFormat:
            msg = @"Invalid User ID Format";
            break;
        case kFujifilmSDKStatusCodeInvalidPromoCodeFormat:
            msg = @"Invalid Promo Code Format";
            break;
        case kFujifilmSDKStatusCodeRequiresPhotoPermission:
            msg = @"Photo Permission Required";
            break;
        default:
            msg = @"Unknown Error";
    }
    //NSLog(@"fujifilmSPASDKFinishedWithStatus: statusCode: %u message: %@", statusCode, msg);
}
AppDelegate.m

Make sure to change the "com.your-company.Your-App.FujifilmSDK.Payments" to match the URL that you set above in Step 4:PayPal Payment Option. Make sure that you change the "com.your-company.Your-App.FujifilmSDK.Payments" from the example below to the url that you set in your info.plist for Step 4 above.

#import "AppDelegate.h"
#import "Fujifilm_SPA_SDK_iOS_AppSwitch.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [Fujifilm_SPA_SDK_iOS_AppSwitch setReturnURLScheme:@"com.your-company.Your-App.FujifilmSDK.Payments"];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
}

- (void)applicationWillTerminate:(UIApplication *)application {
}

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    if ([url.scheme localizedCaseInsensitiveCompare:@"com.your-company.Your-App.FujifilmSDK.Payments"] == NSOrderedSame) {
      return [Fujifilm_SPA_SDK_iOS_AppSwitch handleOpenURL:url options:options];
    }
      return NO;
    }
#endif

// If you support iOS 8, add the following method.
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
    if ([url.scheme localizedCaseInsensitiveCompare:@"com.your-company.Your-App.FujifilmSDK.Payments"] == NSOrderedSame) {
      return [Fujifilm_SPA_SDK_iOS_AppSwitch handleOpenURL:url sourceApplication:sourceApplication];
    }
    return NO;
    }
@end

Additional notes and debugging help

The following are some notes to help with integrating with Fujifilm SPA iOS SDK.

Use Requirements:

  • The phone must have internet access to begin the SDK, and must retain access throughout the checkout process. If the connection is lost during the checkout process, an alert will be shown notifying the user that an internet connection is required
  • A maximum of 100 images can be sent to the SDK in a given checkout process. If more than 100 images are sent, only the first 100 will be processed
  • Only jpeg, png, and heic files are supported
  • The maximum size of a single file is 20MB

General Errors

  • Ensure that you updated your info.plist with required data listed above (NSAppTransportSecurity, NSLocationWhenInUseUsageDescription, NSContactsUsageDescription, and NSPhotoLibraryUsageDescription)

Errors that prevent the SDK from Starting

  • 0 valid images
  • No internet access
  • Invalid APIKey. Ensure the APIKey you are using matches the environment string you are passing in (“stage’, “preview”, "production")
  • Missing required frameworks: AddressBook, AddressBookUI, MobileCoreServices, SystemConfiguration, AssetsLibrary, ImageIO, and Photos

Errors that will cancel the SDK

  • Loss of network or internet access before all images have finished uploading
  • All images fail to upload / no remaining images to checkout with

These errors will return control back to the parent app and call fujifilmSPASDKFinishedWithStatus:andMessage with status code and message corresponding to the cause of the error.

Errors that will prevent a specific picture from uploading or being processed

  • An image is over 20MB
  • An image is of an unsupported file format Image file is corrupt or is uploaded unsuccessfully, making it corrupt

These Errors will not cancel the SDK, and as such, they will not directly return an error code to fujifilmSPASDKFinishedWithStatus:andMessage. However, if enough images are removed such that 0 images are remaining then the SDK will be terminated.

Feedback

We’re very interested in your feedback! If you run into any trouble, have a suggestion, or want to let us know what worked well send us an email to contact@fujifilmapi.com or use the web form at https://www.fujifilmapi.com/contact-us.

License

IMPORTANT - PLEASE READ THE FOLLOWING TERMS AND CONDITIONS CAREFULLY BEFORE USING THE FOLLOWING COMPUTER CODE (THE “CODE”). USE OF THE CODE IS AT YOUR OWN RISK. THE CODE IS PROVIDED “AS IS”, WITH ANY AND ALL FAULTS, DEFECTS AND ERRORS, AND WITHOUT ANY WARRANTY OF ANY KIND. FUJIFILM DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT, WITH RESPECT TO THE CODE OR DEFECTS IN OPERATION OR ANY PARTICULAR APPLICATION OR USE OF THE CODE. FUJIFILM DOES NOT WARRANT THAT THE CODE WILL MEET YOUR REQUIREMENTS OR EXPECTATIONS, THAT THE CODE WILL WORK ON ANY HARDWARE, OPERATING SYSTEM OR WITH ANY SOFTWARE, THAT THE OPERATION OF THE CODE WILL BE UNINTERRUPTED, FREE OF HARMFUL COMPONENTS OR ERROR-FREE, OR THAT ANY KNOWN OR DISCOVERED ERRORS WILL BE CORRECTED. FUJIFILM SHALL NOT BE LIABLE TO YOU OR ANY THIRD PARTY FOR ANY LOSS OF PROFIT, LOSS OF DATA, COMPUTER FAILURE OR MALFUNCTION, INTERRUPTION OF BUSINESS, OR OTHER DAMAGE ARISING OUT OF OR RELATING TO THE CODE, INCLUDING, WITHOUT LIMITATION, EXEMPLARY, PUNITIVE, SPECIAL, STATUTORY, DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, TORT OR COVER DAMAGES, WHETHER IN CONTRACT, TORT OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, DAMAGES RESULTING FROM THE USE OR INABILITY TO USE THE CODE, EVEN IF FUJIFILM HAS BEEN ADVISED OR AWARE OF THE POSSIBILITY OF SUCH DAMAGES.