NAV
docs

Create Token

Apple Pay in Apps

如欲了解最新版號 SDK 以及各版號之間的差異性,請參考 Github Release Page : TapPay iOS Github

支援 iOS 10 以上

Environment

請先依照以下步驟設定環境:

1. 下載 TPDirect.framework 並加入您的專案
2. 將 PassKit.framework 加入您的專案
3. 在 Xcode 中將 Apple Pay 打開,並加入 Apple Merchant ID

4. 利用 TPDSetup 設定環境
5. 為提高偽卡交易的準確度,若可以請開啟IDFA功能

TPDSetup

+ (instancetype _Nonnull)setWithAppId:(int)appId
                           withAppKey:(NSString *_Nonnull)appKey
                       withServerType:(TPDServerType)serverType;
class func setWithAppKey(_ appKey: String, withAppId appId: Int32, with serverType: TPDServerType) -> Self



...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    [TPDSetup setWithAppId:"APP_ID" withAppKey:@"APP_KEY" withServerType:TPDServer_SandBox];

    return YES;
}

...

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
  // Override point for customization after application launch.
  TPDSetup.setWithAppId("APP_ID", withAppKey: "APP_KEY", with: TPDServerType.sandBox)

  return true
}
名稱 類別 內容
appID int 驗證識別碼
appKey String 驗證金鑰
serverType TPDServerType 使用的伺服器種類
測試時請使用 Sandbox 環境(TPDServerType.Sandbox)
實體上線後請切換至 Production 環境(TPDServerType.Production)


為提高偽卡交易的準確度,若可以請開啟IDFA功能

Codes

  1. 將 PassKit 跟 TPDirect frameworks 加入您的專案
#import <PassKit/PassKit.h>
#import <TPDirect/TPDirect.h>
import PassKit
import TPDirect

2. 依照順序實作以下類別:

TPDApplePay

@interface ViewController () <TPDApplePayDelegate>

@property (nonatomic, strong) TPDApplePay *applePay;

@end
class ViewController: UIViewController {

    var applePay : TPDApplePay!

}

TPDApplePayDelegate

@protocol TPDApplePayDelegate <NSObject>

@required
// Send To The Delegate After Receive Prime and prime expiry millis.
- (void)tpdApplePay:(TPDApplePay *)applePay didReceivePrime:(NSString *)prime withExpiryMillis:(long)expiryMillis withCardInfo:(TPDCardInfo *)cardInfo withMerchantReferenceInfo:(NSDictionary *)merchantReferenceInfo;

// Send To The Delegate After Apple Pay Payment Processing Succeeds.
- (void)tpdApplePay:(TPDApplePay *)applePay didSuccessPayment: (TPDTransactionResult *)result;

// Send To The Delegate After Apple Pay Payment Processing Fails.
- (void)tpdApplePay:(TPDApplePay *)applePay didFailurePayment: (TPDTransactionResult *)result;

@optional
// Send To The Delegate After Apple Pay Payment's Form Is Shown.
- (void)tpdApplePayDidStartPayment:(TPDApplePay *)applePay;

// Send To The Delegate After User Selects A Payment Method.
// You Can Change The PaymentItem Or Discount Here.
- (TPDCart *)tpdApplePay:(TPDApplePay *)applePay didSelectPaymentMethod: (PKPaymentMethod *)paymentMethod cart:(TPDCart *)cart;

// Send To The Delegate After User Selects A Shipping Method.
// Set shippingMethods ==> TPDMerchant.shippingMethods.
- (void)tpdApplePay:(TPDApplePay *)applePay didSelectShippingMethod: (PKShippingMethod *)shippingMethod;

// Send To The Delegate After User Authorizes The Payment.
// You Can Check Shipping Contact Here, Return YES If Authorized.
- (BOOL)tpdApplePay:(TPDApplePay *)applePay canAuthorizePaymentWithShippingContact:(PKContact *)shippingContact;

// Send To The Delegate After User Cancels The Payment.
- (void)tpdApplePayDidCancelPayment:(TPDApplePay *)applePay;

// Send To The Delegate After Apple Pay Payment's Form Disappeared.
- (void)tpdApplePayDidFinishPayment:(TPDApplePay *)applePay;

@end
public protocol TPDApplePayDelegate : NSObjectProtocol {
  // Send To The Delegate After Receive Prime.
  public func tpdApplePay(_ applePay: TPDApplePay!, didReceivePrime prime: String!, withExpiryMillis expiryMillis: Int, withCardInfo cardInfo: TPDCardInfo, withMerchantReferenceInfo merchantReferenceInfo: [AnyHashable : Any]!)

  // Send To The Delegate After Apple Pay Payment Processing Succeeds.
  public func tpdApplePay(_ applePay: TPDApplePay!, didSuccessPayment result: TPDTransactionResult!)

  // Send To The Delegate After Apple Pay Payment Processing Fails.
  public func tpdApplePay(_ applePay: TPDApplePay!, didFailurePayment result: TPDTransactionResult!)

  // Send To The Delegate After Apple Pay Payment's Form Is Shown.
  optional public func tpdApplePayDidStartPayment(_ applePay: TPDApplePay!)

  // Send To The Delegate After User Selects A Payment Method.
  // You Can Change The PaymentItem Or Discount Here.
  @available(iOS 9.0, *)
  optional public func tpdApplePay(_ applePay: TPDApplePay!, didSelect paymentMethod: PKPaymentMethod!, cart: TPDCart!) -> TPDCart!

  // Send To The Delegate After User Selects A Shipping Method.
  // Set shippingMethods ==> TPDMerchant.shippingMethods.
  @available(iOS 8.0, *)
  optional public func tpdApplePay(_ applePay: TPDApplePay!, didSelect shippingMethod: PKShippingMethod!)

  // Send To The Delegate After User Authorizes The Payment.
  // You Can Check Shipping Contact Here, Return YES If Authorized.
  @available(iOS 9.0, *)
  optional public func tpdApplePay(_ applePay: TPDApplePay!, canAuthorizePaymentWithShippingContact shippingContact: PKContact!) -> Bool

  // Send To The Delegate After User Cancels The Payment.
  optional public func tpdApplePayDidCancelPayment(_ applePay: TPDApplePay!)

  // Send To The Delegate After Apple Pay Payment's Form Disappeared.
  optional public func tpdApplePayDidFinishPayment(_ applePay: TPDApplePay!)
}
名稱 使用時機
didSuccessPayment 付款成功時呼叫此方法
didFailurePayment 付款失敗時呼叫此方法
tpdApplePayDidStartPayment 付款開始時呼叫此方法
didSelectPaymentMethod 選擇付款方式時呼叫此方法
didSelectShippingMethod 選擇運送方式時呼叫此方法
canAuthorizePaymentWithShippingContact 檢查付款資訊是否正確
tpdApplePayDidCancelPayment 付款取消時呼叫此方法
tpdApplePayDidFinishPayment 付款完成,但結果尚未決定時呼叫此方法
didReceivePrime:withExpiryMillis:withCardInfo:withMerchantReferenceInfo 從 TapPay 獲得 Prime 及 prime 的過期時間時將呼叫此方法
將 Prime 回傳給您的伺服器並透過 Pay by Prime API 完成交易,然後呼叫 showPaymentResult 來顯示結果
showPaymentResult Pay by Prime 成功後

TPDTransactionResult

  @interface TPDTransactionResult : NSObject
  // message, Report Message.
  @property (nonatomic, strong) NSString *message;

  // status, Result Code, '0' Means Success.
  @property (nonatomic, assign) NSInteger status;

  // amount
  @property (nonatomic, strong) NSDecimalNumber *amount;

  // paymentMehod
  @property (nonatomic, strong) PKPaymentMethod *paymentMethod;
  @end
class TPDTransactionResult : NSObject {
  // message, Report Message.
  var message: String!

  // status, Result Code, '0' Means Success.
  var status: Int

  // amount
  var amount: NSDecimalNumber!

  // paymentMehod
  var paymentMethod: PKPaymentMethod!
}

在 didSuccessPayment 及 didFailurePayment 中回傳的物件 TPDTransactionResult 將會有以下的值:

名稱 內容
amount 交易金額
status 交易代碼
message 錯誤訊息
paymentMethod 蘋果的 PKPaymentMethod
- (void)tpdApplePayDidStartPayment:(TPDApplePay *)applePay {
  NSLog(@"=====================================================");
  NSLog(@"Apple Pay On Start");
  NSLog(@"===================================================== \n\n");
}

- (void)tpdApplePay:(TPDApplePay *)applePay didSuccessPayment: (TPDTransactionResult *)result {
  NSLog(@"=====================================================");
  NSLog(@"Apple Pay Did Success ==> Amount : %@", [result.amount stringValue]);
  NSLog(@"shippingContact.name : %@ %@", applePay.consumer.shippingContact.name.givenName, applePay.consumer.shippingContact.name.familyName);
  NSLog(@"shippingContact.emailAddress : %@", applePay.consumer.shippingContact.emailAddress);
  NSLog(@"shippingContact.phoneNumber : %@", applePay.consumer.shippingContact.phoneNumber.stringValue);
  NSLog(@"===================================================== \n\n");
}

- (void)tpdApplePay:(TPDApplePay *)applePay didFailurePayment: (TPDTransactionResult *)result {
  NSLog(@"=====================================================");
  NSLog(@"Apple Pay Did Failure ==> Message : %@, ErrorCode : %ld", result.message, (long)result.status);
  NSLog(@"===================================================== \n\n");
}

- (void)tpdApplePayDidCancelPayment:(TPDApplePay *)applePay {
  NSLog(@"=====================================================");
  NSLog(@"Apple Pay Did Cancel");
  NSLog(@"===================================================== \n\n");
}

- (void)tpdApplePayDidFinishPayment:(TPDApplePay *)applePay {
  NSLog(@"=====================================================");
  NSLog(@"Apple Pay Did Finish");
  NSLog(@"===================================================== \n\n");
}

- (void)tpdApplePay:(TPDApplePay *)applePay didSelectShippingMethod: (PKShippingMethod *)shippingMethod {
  NSLog(@"=====================================================");
  NSLog(@"======> didSelectShippingMethod: ");
  NSLog(@"Shipping Method.identifier : %@", shippingMethod.identifier);
  NSLog(@"Shipping Method.detail : %@", shippingMethod.detail);
  NSLog(@"===================================================== \n\n");
}

- (TPDCart *)tpdApplePay:(TPDApplePay *)applePay didSelectPaymentMethod: (PKPaymentMethod *)paymentMethod cart:(TPDCart *)cart {
  NSLog(@"=====================================================");
  NSLog(@"======> didSelectPaymentMethod: ");
  NSLog(@"===================================================== \n\n");
  if (paymentMethod.type == PKPaymentMethodTypeDebit) {
    [self.cart addPaymentItem:[TPDPaymentItem paymentItemWithItemName:@"Discount"
                                                           withAmount:[NSDecimalNumber decimalNumberWithString:@"-1.00"]]];
  }
  return self.cart;
}

- (BOOL)tpdApplePay:(TPDApplePay *)applePay canAuthorizePaymentWithShippingContact:(PKContact *)shippingContact {
  NSLog(@"=====================================================");
  NSLog(@"======> canAuthorizePaymentWithShippingContact ");
  NSLog(@"shippingContact.name : %@ %@", applePay.consumer.shippingContact.name.givenName, applePay.consumer.shippingContact.name.familyName);
  NSLog(@"shippingContact.emailAddress : %@", shippingContact.emailAddress);
  NSLog(@"shippingContact.phoneNumber : %@", shippingContact.phoneNumber.stringValue);
  NSLog(@"===================================================== \n\n");
  return YES;
}

- (void)tpdApplePay:(TPDApplePay *)applePay didReceivePrime:(NSString *)prime withExpiryMillis:(long)expiryMillis withCardInfo:(TPDCardInfo *)cardInfo withMerchantReferenceInfo:(NSDictionary *)merchantReferenceInfo {

    // 1. Send Your 'Prime' To Your Server, And Handle Payment With Result
    // ...
    NSLog(@"=====================================================");
    NSLog(@"======> didReceivePrime ");
    NSLog(@"Prime : %@", prime);
    NSLog(@"apple pay %lu", expiryMillis);
    NSLog(@"totalAmount : %@",applePay.cart.totalAmount);
    NSLog(@"Client  IP : %@",applePay.consumer.clientIP);
    NSLog(@"shippingContact.name : %@ %@", applePay.consumer.shippingContact.name.givenName, applePay.consumer.shippingContact.name.familyName);
    NSLog(@"shippingContact.emailAddress : %@", applePay.consumer.shippingContact.emailAddress);
    NSLog(@"shippingContact.phoneNumber : %@", applePay.consumer.shippingContact.phoneNumber.stringValue);
    PKPaymentMethod * paymentMethod = applePay.consumer.paymentMethod;
    NSLog(@"Type : %ld", (long)paymentMethod.type);
    NSLog(@"Network : %@", paymentMethod.network);
    NSLog(@"Display Name : %@", paymentMethod.displayName);
    NSLog(@"===================================================== \n\n");

    // 2. If Payment Success, applePay.
    BOOL paymentResult = YES;
    [applePay showPaymentResult:paymentResult];

}
extension ViewController :TPDApplePayDelegate {

  func tpdApplePayDidStartPayment(_ applePay: TPDApplePay!) {
    print("=====================================================")
    print("Apple Pay On Start")
    print("=====================================================\n\n")
  }

  func tpdApplePay(_ applePay: TPDApplePay!, didSuccessPayment result: TPDTransactionResult!) {
    print("=====================================================")
    print("Apple Pay Did Success ==> Amount : \(result.amount.stringValue)")
    print("shippingContact.name : \(applePay.consumer.shippingContact?.name?.givenName) \( applePay.consumer.shippingContact?.name?.familyName)")
    print("shippingContact.emailAddress : \(applePay.consumer.shippingContact?.emailAddress)")
    print("shippingContact.phoneNumber : \(applePay.consumer.shippingContact?.phoneNumber?.stringValue)")
    print("Shipping Method.identifier : \(applePay.cart.shippingMethod.identifier)")
    print("Shipping Method.detail : \(applePay.cart.shippingMethod.detail)")
    print("=====================================================\n\n")
  }

  func tpdApplePay(_ applePay: TPDApplePay!, didFailurePayment result: TPDTransactionResult!) {
    print("=====================================================")
    print("Apple Pay Did Failure ==> Message : \(result.message), ErrorCode : \(result.status)")
    print("=====================================================\n\n")
  }

  func tpdApplePayDidCancelPayment(_ applePay: TPDApplePay!) {
    print("=====================================================")
    print("Apple Pay Did Cancel")
    print("=====================================================\n\n")
  }

  func tpdApplePayDidFinishPayment(_ applePay: TPDApplePay!) {
    print("=====================================================")
    print("Apple Pay Did Finish")
    print("=====================================================\n\n")
  }

  func tpdApplePay(_ applePay: TPDApplePay!, didSelect shippingMethod: PKShippingMethod!) {
    print("=====================================================")
    print("======> didSelectShippingMethod: ")
    print("Shipping Method.identifier : \(shippingMethod.identifier)")
    print("Shipping Method.detail : \(shippingMethod.detail)")
    print("=====================================================\n\n")
  }

  func tpdApplePay(_ applePay: TPDApplePay!, didSelect paymentMethod: PKPaymentMethod!, cart: TPDCart!) -> TPDCart! {
    print("=====================================================");
    print("======> didSelectPaymentMethod: ");
    print("=====================================================\n\n");
    if paymentMethod.type == .debit {
      self.cart.add(TPDPaymentItem(itemName: "Discount", withAmount: NSDecimalNumber(string: "-1.00")))
    }
    return self.cart;
  }

  func tpdApplePay(_ applePay: TPDApplePay!, canAuthorizePaymentWithShippingContact shippingContact: PKContact!) -> Bool {
    print("=====================================================")
    print("======> canAuthorizePaymentWithShippingContact ")
    print("shippingContact.name : \(applePay.consumer.shippingContact?.name?.givenName) \( applePay.consumer.shippingContact?.name?.familyName)")
    print("shippingContact.emailAddress : \(shippingContact.emailAddress)")
    print("shippingContact.phoneNumber : \(shippingContact.phoneNumber?.stringValue)")
    print("=====================================================\n\n")
    return true;
  }
  tpdApplePay(_ applePay: TPDApplePay!, didReceivePrime prime: String!, withExpiryMillis expiryMillis: Int, withCardInfo cardInfo: TPDCardInfo, withMerchantReferenceInfo merchantReferenceInfo: [AnyHashable : Any]!) {

    // 1. Send Your Prime To Your Server, And Handle Payment With Result
    // ...
    print("=====================================================");
    print("======> didReceivePrime");
    print("Prime : \(prime!)");
    print("Expiry Millis : \(expiryMillis)");
    print("total Amount :   \(applePay.cart.totalAmount!)")
    print("Client IP : \(applePay.consumer.clientIP!)")
    print("shippingContact.name : \(applePay.consumer.shippingContact?.name?.givenName) \(applePay.consumer.shippingContact?.name?.familyName)");
    print("shippingContact.emailAddress : \(applePay.consumer.shippingContact?.emailAddress)");
    print("shippingContact.phoneNumber : \(applePay.consumer.shippingContact?.phoneNumber?.stringValue)");
    let paymentMethod = self.consumer.paymentMethod!
    print("type : \(paymentMethod.type.rawValue)")
    print("Network : \(paymentMethod.network!.rawValue)")
    print("Display Name : \(paymentMethod.displayName!)")
    print("===================================================== \n\n");

    // 2. If Payment Success, applePay.
    let paymentResult = true;
    applePay.showPaymentResult(paymentResult)
    }
}


名稱 類別 內容
prime String 交易用的加密字串
expiryMillis Int prime 過期的 millis
cardInfo TPDCardInfo 卡片資訊,將會回傳以下幾個值:
名稱類別(長度)內容
bincodeString(6)卡片前六碼
lastFourString(4)卡片後四碼
issuerString發卡銀行
issuerZhTWString發卡銀行中文名稱
bankIdString銀行代碼
fundingint卡片類別
-1 = Unknown
0 = 信用卡 (Credit Card)
1 = 簽帳卡 (Debit Card)
2 = 預付卡 (Prepaid Card)
cardTypeint卡片種類
-1 = Unknown
1 = VISA
2 = MasterCard
3 = JCB
4 = Union Pay
5 = AMEX
levelString卡片等級
countryString發卡行國家
countryCodeString發卡行國家碼
merchantReferenceInfo JSONObject 若商戶在 TapPay 後台使用 Co-brand card management 功能,且交易卡號符合設定時,將會回傳此參數,不支援 JKOPAY

商戶於TapPay後台設定的affiliate code management須限制於20字元內且為半形的英數字
名稱類別內容
affiliateCodesArray商戶在 TapPay 後台的 Co-brand card management 功能專區設定的Affiliated codes

PKPaymentButton

@interface ViewController () <TPDApplePayDelegate>

@property (nonatomic, strong) PKPaymentButton *applePayButton;

@end
class ViewController: UIViewController {

    var applePayButton : PKPaymentButton!

}

您應在設定付款按鈕前檢查卡片跟機台是否支援 Apple Pay

/**
  [TPDApplePay canMakePaymentsUsingNetworks:(NSArray<PKPaymentNetwork> *)]
  檢查是否有支援的發卡組織

  TPDApplePay setupWthMerchant:(TPDMerchant *) withConsumer:(TPDConsumer *) withCart:(TPDCart *) withDelegate:(id)
  將 TPDMerchant, TPDConsumer, TPDCart 帶入初始化 Apple Pay 物件

  startPayment
  呼叫 Apple Pay Payment Sheet
*/

- (void)paymentButtonSetting {

    if ([TPDApplePay canMakePaymentsUsingNetworks:self.merchant.supportedNetworks]) {
        self.applePayButton = [PKPaymentButton buttonWithType:PKPaymentButtonTypeBuy style:PKPaymentButtonStyleBlack];
    }else{
        self.applePayButton = [PKPaymentButton buttonWithType:PKPaymentButtonTypeSetUp style:PKPaymentButtonStyleBlack];
    }

    [self.view addSubview:self.applePayButton];
    self.applePayButton.center = self.view.center;

    [self.applePayButton addTarget:self action:@selector(didClickButton:) forControlEvents:UIControlEventTouchUpInside];
}

- (void)didClickButton:(PKPaymentButton *)sender {

    // Without Handle Payment
    self.applePay = [TPDApplePay setupWthMerchant:self.merchant withConsumer:self.consumer withCart:self.cart withDelegate:self];

    [self.applePay startPayment];
}

/**
  TPDApplePay.canMakePayments(usingNetworks: [PKPaymentNetwork]!)
  檢查是否有支援的發卡組織

  TPDApplePay.setupWthMerchant(TPDMerchant!, with: TPDConsumer!, with: TPDCart!, withDelegate: Any!)
   TPDMerchant, TPDConsumer, TPDCart 帶入初始化 Apple Pay 物件

  startPayment
  呼叫 Apple Pay Payment Sheet
*/

func paymentButtonSetting() {

    if (TPDApplePay.canMakePayments(usingNetworks: self.merchant.supportedNetworks)) {
        applePayButton = PKPaymentButton.init(paymentButtonType: .buy, paymentButtonStyle: .black)
    } else {
        applePayButton = PKPaymentButton.init(paymentButtonType: .setUp, paymentButtonStyle: .black)
    }

    view.addSubview(applePayButton)
    applePayButton.center = view.center

    applePayButton.addTarget(self, action: #selector(ViewController.didClickBuyButton(sender:)), for: .touchUpInside)

}

@objc func didClickBuyButton(sender:PKPaymentButton) {

    applePay = TPDApplePay.setupWthMerchant(merchant, with: consumer, with: cart, withDelegate: self)

    applePay.startPayment()

}

TPDMerchant

@interface ViewController () <TPDApplePayDelegate>

@property (nonatomic, strong) TPDMerchant *merchant;

@end
class ViewController: UIViewController {

    var merchant : TPDMerchant!

}


self.merchant = [TPDMerchant new];
self.merchant.merchantName               = @"TapPay!";
self.merchant.merchantCapability         = PKMerchantCapability3DS;
self.merchant.applePayMerchantIdentifier = @"merchant.apple.pay";       
self.merchant.countryCode                = @"TW";
self.merchant.currencyCode               = @"TWD";
self.merchant.supportedNetworks          = @[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa, PKPaymentNetworkJCB];
merchant = TPDMerchant()
merchant.merchantName               = "TapPay!";
merchant.merchantCapability         = .capability3DS;
merchant.applePayMerchantIdentifier = "merchant.apple.pay";
merchant.countryCode                = "TW";
merchant.currencyCode               = "TWD";
merchant.supportedNetworks          = [.amex, .masterCard, .visa, .JCB]


名稱 內容
merchantName 顯示於 Payment Sheet 欲付給的商家名稱
merchantCapability 欲支援的支付方式,詳細請參考 Apple Pay merchantCapabilities
applePayMerchantIdentifier Apple Merchant ID.
countryCode 國碼
currencyCode 交易貨幣
supportedNetworks 設定欲支援的信用卡組織


supportedNetworks 信用卡組織支援的版本

信用卡組織 版本
American Express iOS 8.0+
watchOS 3.0+
MasterCard iOS 8.0+
watchOS 3.0+
Visa iOS 8.0+
watchOS 3.0+
JCB iOS 10.1+
watchOS 3.1+

TPDConsumer

@interface ViewController () <TPDApplePayDelegate>

@property (nonatomic, strong) TPDConsumer *consumer;

@end
class ViewController: UIViewController {

    var consumer : TPDConsumer!

}


self.consumer = [TPDConsumer new];
self.consumer.requiredShippingAddressFields  = PKAddressFieldEmail | PKAddressFieldName | PKAddressFieldPhone;
self.consumer.requiredBillingAddressFields   = PKAddressFieldPostalAddress;
consumer = TPDConsumer()
consumer.requiredShippingAddressFields  = [.email, .name, .phone]
consumer.requiredBillingAddressFields   = [.postalAddress]


Name Content
requiredShippingAddressFields 設定必填運送資訊欄位
預設為無需要的運送資訊欄位
requiredBillingAddressFields 設定必填帳單資訊欄位
預設為無需要的帳單資訊欄位


Apple Pay 指紋認證成功後,可以在 didReceivePrime delegate 中,TPDConsumer.paymentMethod 中取得卡片資訊
可以參考 apple 文件 PKPaymentMethod

名稱 內容
type 卡片類別
0 : unknown
1 : debit
2 : credit
3 : prepaid
4 : store
network 卡別
displayName 卡別及卡片後四碼

TPDCart

@interface ViewController () <TPDApplePayDelegate>

@property (nonatomic, strong) TPDCart *cart;

@end
class ViewController: UIViewController {
    var cart     : TPDCart!
}


/**
  [cart addPaymentItem:(TPDPaymentItem *)]
  將交易品項加入交易品項列表
*/

self.cart = [TPDCart new];
TPDPaymentItem *book = [TPDPaymentItem paymentItemWithItemName:@"book"
                                                            withAmount:[NSDecimalNumber decimalNumberWithString:@"100.00"]];
[self.cart addPaymentItem:book];
/**
  cart.add(TPDPaymentItem!)
  將交易品項加入交易品項列表
*/
cart = TPDCart()

let book = TPDPaymentItem(itemName: "Initial Charge", withAmount: NSDecimalNumber(string: "100.00"))
cart.add(book)


您可用 TPDPaymentItem 來新增新的物品至您的 TPDCart
使用 paymentItemWithItemName 設定顯示物品的金額
TPDCart 中品項的總金額必須大於 0,否則將回傳 error code: 88016

Deferred Payment

self.cart = [TPDCart new];
self.cart.isAmountPending = YES;
self.cart.isShowTotalAmount = NO;
// 設定顯示金額品項
TPDPaymentItem *initialCharge = [TPDPaymentItem paymentItemWithItemName:@"Initial Charge"
                                                        withAmount:[NSDecimalNumber decimalNumberWithString:@"100.00"]];
[self.cart addPaymentItem:initialCharge];

// 設定待處理品項
TPDPaymentItem *improvementSurcharge  = [TPDPaymentItem pendingPaymentItemWithItemName:@"NT$5 per miles"];
[self.cart addPaymentItem:improvementSurcharge];
cart = TPDCart()
cart.isAmountPending = true
cart.isShowTotalAmount = false
// 設定顯示金額品項
let initialCharge = TPDPaymentItem(itemName: "Initial Charge", withAmount: NSDecimalNumber(string: "100.00"))
cart.add(initialCharge)

// 設定待處理品項
let improvementSurcharge = TPDPaymentItem.pendingPaymentItem(withItemName: "NT$5 per miles")
cart.add(improvementSurcharge)


若要使用 Apple Pay 延後授權 ,請先向 TapPay 客服申請開通此功能(support@cherri.tech)
使用此功能 prime 的時效為取得 prime 後的 30天,實際扣款金額由 pay by prime 設定
TPDCart 中 isAmountPending 屬性決定是否使用延後授權,預設為 false
TPDCart 中 isShowTotalAmount 屬性決定總金額欄位是否顯示總金額或金額待處理,預設為 true

使用 pendingPaymentItemWithItemName 設定品項金額欄位顯示『...』代表為金額待處理

使用延後授權請注意以下規則

TPDCart 中的品項皆為顯示金額

isAmountPending isShowTotalAmount 總金額欄位 Prime 的時效
true true 顯示品項加總金額 30天
true false 顯示金額待處理 30天
false true 顯示品項加總金額 90秒
false false 不支援,請參考 error code:88013 X


TPDCart 中的品項皆為待處理

isAmountPending isShowTotalAmount 總金額欄位 Prime 的時效
true true 不支援,請參考 error code:88014 X
true false 顯示金額待處理 30天
false true 不支援,請參考 error code:88015 X
false false 不支援,請參考 error code:88013 X


TPDCart 中的品項包含待處理、顯示金額

isAmountPending isShowTotalAmount 總金額欄位 Prime 的時效
true true 顯示金額品項加總金額 30天
true false 顯示金額待處理 30天
false true 不支援,請參考 error code:88015 X
false false 不支援,請參考 error code:88013 X

注意事項

因為在 iOS 12 以下的版本 (包含), Apple Pay 延後授權總金額必須大於 0 元
為了達到不同 iOS 版本間相容性, 以下情況 SDK v2.6.0 和以上的版本會把總金額改為 1 並帶入給 Apple 產生交易資料

1.TPDCart 品項皆為『待處理』或品項金額總和為『 0 元』, 且總金額要顯示『金額待處理』(self.cart.isAmountPending = true)

Example

如果您碰到問題,可參考我們的範例程式

Apple Pay on the Web

如欲了解最新版號 SDK 以及各版號之間的差異性,請參考 Github Release Page : TapPay Web Github

Apple Pay JavaScript API 只有在 iOS 10 以後的機台以及 macOS Sierra (10.12) 以上的 Mac 上才能運作

如有使用 Apple Pay on the Web 商家申請服務,請於 Apple Pay 商家識別碼欄位帶入 TapPay 產出給您的 Apple Pay merchant identifier (您能在Portal > 支付管理 > Apple Pay On The Web 找到此資訊)

Requirements

在 Apple Pay on the Web 中,您必須符合以下要求:
1. 所有包含 Apple Pay 的頁面必須要有 HTTPS , 在正式與測試環境都是必要的。在開發環境可以透過 ngrok 的服務滿足 HTTPS 的需求,可以參考我們的 Ngrok 使用教學
2. 您的網域必須要有合法的 SSL 憑證
3. 您的伺服器必須支援 TLS 1.2 以及下列其中一個密碼套件:

密碼套件值 內容
0xC02F TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
0xC027 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
0xC013 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
0x009E TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
0x0067 TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
0x009C TLS_RSA_WITH_AES_128_GCM_SHA256
0x003C TLS_RSA_WITH_AES_128_CBC_SHA256

4. 您的伺服器必須透過 HTTP (TCP over port 443)允許下列的 Apple Pay IP:

IP 名稱 種類
17.171.85.7 apple-pay-gateway-cert.apple.com Sandbox
17.171.78.7 apple-pay-gateway-nc-pod1.apple.com Production
17.171.78.71 apple-pay-gateway-nc-pod2.apple.com Production
17.171.78.135 apple-pay-gateway-nc-pod3.apple.com Production
17.171.78.199 apple-pay-gateway-nc-pod4.apple.com Production
17.171.79.12 apple-pay-gateway-nc-pod5.apple.com Production
17.141.128.7 apple-pay-gateway-pr-pod1.apple.com Production
17.141.128.71 apple-pay-gateway-pr-pod2.apple.com Production
17.141.128.135 apple-pay-gateway-pr-pod3.apple.com Production
17.141.128.199 apple-pay-gateway-pr-pod4.apple.com Production
17.141.129.12 apple-pay-gateway-pr-pod5.apple.com Production
17.171.78.9 apple-pay-gateway-nc-pod1-dr.apple.com Production
17.171.78.73 apple-pay-gateway-nc-pod2-dr.apple.com Production
17.171.78.137 apple-pay-gateway-nc-pod3-dr.apple.com Production
17.171.78.201 apple-pay-gateway-nc-pod4-dr.apple.com Production
17.171.79.13 apple-pay-gateway-nc-pod5-dr.apple.com Production
17.141.128.9 apple-pay-gateway-pr-pod1-dr.apple.com Production
17.141.128.73 apple-pay-gateway-pr-pod2-dr.apple.com Production
17.141.128.137 apple-pay-gateway-pr-pod3-dr.apple.com Production
17.141.128.201 apple-pay-gateway-pr-pod4-dr.apple.com Production
17.141.129.13 apple-pay-gateway-pr-pod5-dr.apple.com Production

SetupSDK

請用以下程式碼在您的 HTML 檔案中設定環境:


請注意版本的差異,避免載入 Web SDK 錯誤
https://js.tappaysdk.com/sdk/tpdirect/v5.14.0
https://js.tappaysdk.com/tpdirect/v5.13.1
使用方式請參考以下範例

<!-- 
    使用 TPDirect.setupSDK("appID" "appKey" 'serverType') 
    設定 App ID, App Key, Server Type 參數
-->

<head>
<script src="https://js.tappaysdk.com/sdk/tpdirect/v5.14.0"></script>
<script>
    TPDirect.setupSDK("appID" "appKey" 'serverType')
</script>
</head>



若使用低於 v5.14.0 之Web SDK版本,請使用以下路徑引用 Web SDK

<script src="https://js.tappaysdk.com/tpdirect/v5.13.1"></script>
<script>
    TPDirect.setupSDK(APP_ID, 'APP_KEY', 'sandbox')
</script>


名稱 類別 內容
appID int 驗證識別碼
appKey String 驗證金鑰
serverType String 使用的伺服器種類
測試時請使用 Sandbox 環境(sandbox)
實體上線後請切換至 Production 環境(production)

如欲知 SDK 兼容性,請參考 SDK compatibility

checkAvailability()

/**
    使用 TPDirect.paymentRequestApi.checkAvailability() 可以檢查使用者的瀏覽器
    是否可以使用 Payment Request API
    若回傳 true: 代表支援
    若回傳 false: 代表不支援
*/

TPDirect.paymentRequestApi.checkAvailability()

Setup Apple Pay

/**
    使用 TPDirect.paymentRequestApi.setupApplePay 設定 Apple Pay 相關參數
*/

TPDirect.paymentRequestApi.setupApplePay({
    merchantIdentifier: 'merchant.tech.cherri',
    countryCode: 'TW',
})


名稱 (*=必填) 類別 內容
merchantIdentifier* String 您於 Apple Developer 註冊的 Merchant Id
若您有使用 Apple Pay on the Web 商家申請服務,請帶入TapPay 產出給您的 Apple Pay merchantIdentifier (您能在Portal > 支付方式 > Apple Pay > Apple Pay on the Web 找到此資訊)
countryCode String 國家代碼 , 預設為 TW

PaymentRequest

建立一個 paymentRequest 的物件設定交易資訊來索取 Prime

var paymentRequest = {
    supportedNetworks: ['AMEX', 'JCB', 'MASTERCARD', 'VISA'],
    supportedMethods: ['apple_pay'],

    displayItems: [{
        label: 'TapPay - iPhone8',
        amount: {
            currency: 'TWD',
            value: '1.00'
        }
    }],
    total: {
        label: '付給 TapPay',
        amount: {
            currency: 'TWD',
            value: '1.00'
        }
    },
    shippingOptions: [{
            id: "standard",
            label: "🚛 Ground Shipping (2 days)",
            detail: 'Estimated delivery time: 2 days',
            amount: {
                currency: "TWD",
                value: "5.00"
            }
        },
        {
            id: "drone",
            label: "🚀 Drone Express (2 hours)",
            detail: 'Estimated delivery time: 2 hours',
            amount: {
                currency: "TWD",
                value: "25.00"
            }
        },
    ],
    options: {
        requestPayerEmail: false,
        requestPayerName: false,
        requestPayerPhone: false,
        requestShipping: false,
        shippingType: 'shipping'
    }
}
名稱 類別 內容
supportedNetworks Array 設定可支援的卡別, 目前支援帶入 “VISA”, “MASTERCARD”, “JCB” 和 “AMEX”
supportedMethods Array 設定支援的付款方式
displayItems Array
名稱類別內容
labelString商品名稱
amountJSONObjectvalue: 金額,不得為 0
currency: 貨幣
isAmountPendingBoolean是否為待處理品項, 預設為 false
與 amount.value 擇一帶入
詳細可以參考 Deferred Payment
total JSONObject
名稱類別內容
labelString交易說明
amountJSONObjectvalue: 總金額
設置 isShowTotalAmount: true 時,value 須大於 0
currency: 貨幣
isAmountPendingBoolean是否進行延後授權, 預設為 false
詳細可以參考 Deferred Payment
isShowTotalAmountBoolean是否顯示總金額或待處理, 預設為 true
與 amount.value 擇一帶入
詳細可以參考 Deferred Payment
shippingOptions JSONObject
名稱類別內容
idString運送名稱
labelString運送方式介紹
detailString運送方式詳細說明 (限定 Apple Pay)
amountJSONObjectvalue: 金額
currency: 貨幣
options JSONObject
名稱類別內容
requestPayerEmailBool是否需要消費者信箱
requestPayerNameBool是否需要消費者名字
requestPayerPhoneBool是否需要消費者號碼
requestShippingBool是否需要消費者運送地址
shippingTypeString運送方式 , 若需設定請參考 shippingType
shipping , delivery , pickup



設定好 payment request 物件後, 透過以下方法設定 Payment Request API

/**
    使用 TPDirect.paymentRequestApi.setupPaymentRequest 設定 payment request 物件
    並在 callback function 回傳物件關於使用者的瀏覽器是否可以使用 Payment Request API 以及是否有卡片進行付款
*/

TPDirect.paymentRequestApi.setupPaymentRequest(paymentRequest, function (result) {
    if (!result.browserSupportPaymentRequest) {
        console.log('瀏覽器不支援 PaymentRequest')
        return
    }
    if (result.canMakePaymentWithActiveCard === true) {
        console.log('該裝置有支援的卡片可以付款')
    } else {
        console.log('該裝置沒有支援的卡片可以付款')
    }
})


setupPaymentRequest 有一個 callback 函式, 裡面會帶有以下物件屬性

名稱 類別 內容
result JSONObject
名稱類別內容
browserSupportPaymentRequestBoolean瀏覽器是否支援 Payment Request API
true: 支援
false: 不支援
canMakePaymentWithActiveCardBoolean檢查使用者是否有符合 supportedNetworks 與 supportedMethods 的卡片
Apple Pay 只會檢查使用者是否有在 Apple Pay 裡面綁卡片
true: 有卡片
false: 無卡片


Deferred Payment

若要使用 Apple Pay 延後授權 ,請先向 TapPay 客服申請開通此功能(support@cherri.tech)
使用此功能 prime 的時效為取得 prime 後的 30天,實際扣款金額由 pay by prime 設定
paymentRequest 中 total.isAmountPending 屬性決定是否使用延後授權,預設為 false
paymentRequest 中 total.isShowTotalAmount 屬性決定總金額欄位是否顯示總金額或金額待處理,預設為 true

使用 paymentRequest displayItems 中的 isAmountPending:true 設定品項金額欄位顯示『...』代表為金額待處理

使用延後授權請注意以下規則

displayItems 中設置的品項皆為顯示金額

total.isAmountPending total.isShowTotalAmount 總金額欄位 Prime 的時效
true true 顯示品項加總金額 30天
true false 顯示金額待處理 30天
false true 顯示品項加總金額 90秒
false false 不支援,TPDirect.paymentRequestApi.setupPaymentRequest 無法初始化 X


displayItems 中設置的品項皆為待處理

total.isAmountPending total.isShowTotalAmount 總金額欄位 Prime 的時效
true true 不支援,TPDirect.paymentRequestApi.setupPaymentRequest 無法初始化 X
true false 顯示金額待處理 30天
false true 不支援,TPDirect.paymentRequestApi.setupPaymentRequest 無法初始化 X
false false 不支援,TPDirect.paymentRequestApi.setupPaymentRequest 無法初始化 X


displayItems 中設置的品項包含待處理、顯示金額

total.isAmountPending total.isShowTotalAmount 總金額欄位 Prime 的時效
true true 顯示金額品項加總金額 30天
true false 顯示金額待處理 30天
false true 不支援,TPDirect.paymentRequestApi.setupPaymentRequest 無法初始化 X
false false 不支援,TPDirect.paymentRequestApi.setupPaymentRequest 無法初始化 X

注意事項

因為在 MacOS 10.14.1 以及 iOS 12.1 以下的版本 (包含), Apple Pay 延後授權 total.amount.value 必須大於 0 元
為了達到不同 MacOS 與 iOS 版本間相容性, 以下情況 SDK 會把 total.amount.value 改為 1 並帶入給 Apple 產生交易資料

1.displayItems 品項皆為『待處理』(isAmountPending:true)或品項金額總和為『 0 元』, 且總金額要顯示『金額待處理』(total.isShowTotalAmount:false)
2.displayItems 沒有任何品項且總金額要顯示『金額待處理』(total.isShowTotalAmount:false)

另外請注意如果在 Mac 上面進行付款, 並使用 iPhone 進行指紋、臉部辨識時, 在以上情況中使用者在 iPhone 上看到的金額會是 1 元

shippingOptions

於 paymentRequest 的 ShippingOption 中未加入 detail

shippingOptions: [{
    id: "standard",
    label: "🚛 Ground Shipping (2 days)",
    amount: {
        currency: "TWD",
        value: "5.00"
    }
}]




於 paymentRequest 的 ShippingOption 中加入 detail

shippingOptions: [{
    id: "standard",
    label: "🚛 Ground Shipping (2 days)",
    detail: "Estimated delivery time: 2 days",
    amount: {
        currency: "TWD",
        value: "5.00"
    }
}]


Get Prime

/**
    使用 TPDirect.paymentRequestApi.getPrime 向 TapPay 取得付款用的 prime
*/

TPDirect.paymentRequestApi.getPrime(function(result) {
    console.log('paymentRequestApi.getPrime result', result)
    if (result.status !== 0) {
        console.error('getPrime failed: ' + result.msg)
        return
    }
    var prime = result.prime
})

Get Prime Result

處理收到的結果,將 Prime 回傳至您的伺服器
再用 Pay by Prime API 來完成付款

{
    "prime": String,
    // 加上運費的價格
    "total_amount": String,
    "status": Int,
    "msg": String,
    "client_ip": String,
    "payer": {
        "name": String,
        "phone": String,
        "email": String
    },
    "shippingAddress": {
        "country": String,
        "addressLine": ArrayString,
        "region": String,
        "city": String,
        "dependentLocality": String,
        "postalCode": String,
        "sortingCode": String,
        "languageCode": String,
        "organization": String,
        "recipient": String,
        "phone": String
    },
    "shippingOption": String,
    "billingAddress": {
        "country": String,
        "addressLine": ArrayString,
        "region": String,
        "city": String,
        "dependentLocality": String,
        "postalCode": String,
        "sortingCode": String,
        "languageCode": String,
        "organization": String,
        "recipient": String,
        "phone": String
    },
    "methodName": String ("apple_pay")
    "requestId": String,
    "card": {
        "lastfour": String,
        "funding": Int,
        "type": Int,
    },
    "card_info": {
        "bincode": String,
        "lastfour": String,
        "issuer": String,
        "issuer_zh_tw": String,
        "bank_id": String,
        "funding": Int,
        "type": Int,
        "level": String,
        "country": String,
        "countrycode": String,
    },
    "merchant_reference_info": {
        "affiliate_codes": ArrayString,
    },
    "prime_expiry_millis": Number
}


名稱 類別 內容
prime Stinrg prime 字串,於 Pay by Prime API 交易時使用
total_amount String 總金額
status Int 交易代碼,成功的話為0
msg String 錯誤訊息
client_ip String 消費者的 IP 位置
payer JSONObject 消費者資料
名稱類別內容
nameString消費者姓名
phoneString消費者電話
emailString消費者email
shippingAddress JSONObject 運送地址
名稱類別內容
countryString國家
addressLineArrayString地址欄
regionString地區
cityString城市
dependentLocalityString地區
postalCodeString郵遞區號
sortingCodeString分類編碼
languageCodeString語言代碼
organizationString機構
recipientString收件人
phoneString電話號碼
billingAddress JSONObject 帳單地址
名稱類別內容
countryString國家
addressLineArrayString地址欄
regionString地區
cityString城市
dependentLocalityString地區
postalCodeString郵遞區號
sortingCodeString分類編碼
languageCodeString語言代碼
organizationString機構
recipientString收件人
phoneString電話號碼
shippingOption String 運送方式
methodName String (“apple_pay”)
requestId String 此交易請求識別碼
card JSONObject
名稱類別內容
lastfourString卡片末四碼
fundingInt卡片類別
0 = 信用卡 (Credit Card)
1 = 簽帳卡 (Debit Card)
2 = 預付卡(Prepaid Card)
typeInt卡片種類
1 = VISA
2 = MasterCard
3 = JCB
4 = Union Pay
5 = AMEX
card_info JSONObject 卡片資訊,將會回傳以下幾個值:
名稱類別(長度)內容
bincodeString(6)卡片前六碼
lastfourString(4)卡片後四碼
issuerString發卡銀行
issuer_zh_twString發卡銀行中文名稱
bank_idString發卡銀行代碼
fundingint卡片類別
-1 = Unknown
0 = 信用卡 (Credit Card)
1 = 簽帳卡 (Debit Card)
2 = 預付卡 (Prepaid Card)
typeint卡片種類
-1 = Unknown
1 = VISA
2 = MasterCard
3 = JCB
4 = Union Pay
5 = AMEX
levelString卡片等級
countryString發卡行國家
countrycodeString發卡行國家碼
merchant_reference_info JSONObject 若商戶在 TapPay 後台使用 Co-brand card management 功能,且交易卡號符合設定時,將會回傳此參數,不支援 JKOPAY

商戶於TapPay後台設定的affiliate code management須限制於20字元內且為半形的英數字
名稱類別內容
affiliate_codesArray商戶在 TapPay 後台的 Co-brand card management 功能專區設定的Affiliated codes
prime_expiry_millis Number Prime 到期時間
Web SDK v5.3 版本之後固定回傳

Example

如果您碰到問題,可參考我們的範例程式 或是蘋果的 範例網站做為參考
請記得 Apple Pay JavaScript API 只有在 iOS 10 以後的機台以及 macOS Sierra (10.12) 以上的 Mac 上才能運作

Reference

如果您碰到問題,可參考我們的若您想整合更多付款方式,請參考 Payment Request API

Q&A

如果您需要設定 Content Security Policy 中的 frame-src, 請設置以下二個網域:

  1. js.tappaysdk.com
  2. fraud.tappaysdk.com