Skip to main content

iOS Native SDK(v3) - PortOne's Checkout

Please follow steps below to setup iOS Native SDK and start accepting payment via PortOne.

For initial setup, go through v2 documentation Native iOS - Payment SDK: v2.


To open the payment link call the checkOutUI method from SDK as below:

```swift
import PortoneSDK
let token = createJWTToken()
let payload = prepareConfig()
checkout?.checkOutUI(config: payload, jwtToken: token, onCompletionHandler: { (result) in
switch result{
case .success(let data):
print("Data", data)
case .failure(let error):
print("error", error)
}
})
```

JWT token Generation:

  • Generate JWT token by using the payload and portone secretKey

    • Required payload:

      var payload = {
      iss: 'CHAIPAY',
      sub: 'lzrYFPfyMLROallZ',
      iat: new Date().getTime(),
      exp: new Date().getTime() + 100 * 1000,
      };
      var secretKey =
      "0e94b3232e1bf9ec0e378a58bc27067a86459fc8f94d19f146ea8249455bf242";
      ParameterDescriptionValues
      issIssuerDefault Value: "CHAIPAY"
      subSubjectCHAIPay Key
      iatIssued Timestamp in secTimestamp in sec
      expExpiry Timestamp in secTimestamp in sec+100
    • Algorithm to use for generating token - “HS256”

      func createJWTToken() -> String {
      struct Header: Encodable {
      let alg = "HS256"
      let typ = "JWT"
      }
      func generateCurrentTimeStamp (extraTime: Int = 0) -> Int {
      let currentTimeStamp = Date().timeIntervalSince1970 + TimeInterval(extraTime)
      let token = String(currentTimeStamp)
      return Int(currentTimeStamp)
      }
      struct Payload: Encodable {
      let iss = "CHAIPAY"
      let sub = "aiHKafKIbsdUJDOb"
      let iat = generateCurrentTimeStamp()
      let exp = generateCurrentTimeStamp(extraTime: 10000)
      }
      let secret = "2601efeb4409f7027da9cbe856c9b6b8b25f0de2908bc5322b1b352d0b7eb2f5"
      let privateKey = SymmetricKey(data: secret.data(using: .utf8)!)
      let headerJSONData = try! JSONEncoder().encode(Header())
      let headerBase64String = headerJSONData.urlSafeBase64EncodedString()
      let payloadJSONData = try! JSONEncoder().encode(Payload())
      let payloadBase64String = payloadJSONData.urlSafeBase64EncodedString()
      let toSign = (headerBase64String + "." + payloadBase64String).data(using: .utf8)!
      let signature = HMAC<SHA256>.authenticationCode(for: toSign, using: privateKey)
      let signatureBase64String = Data(signature).urlSafeBase64EncodedString()
      let token = [headerBase64String, payloadBase64String, signatureBase64String].joined(separator: ".")
      return token
      }

      Sample Payload:

      func prepareConfig() -> WebTransactionRequest {
      let billingAddress = BillingAddress(city: "VND", countryCode: "VN", locale: "en", line1: "address1", line2: "address2", postalCode: "400202", state: "Mah")
      let merchantDetails = MerchantDetails(name: "Downy", logo: "https://upload.wikimedia.org/wikipedia/commons/a/a6/Logo_NIKE.svg", backUrl: "https://demo.portone.cloud/checkout.html", promoCode: "Downy350", promoDiscount: 0, shippingCharges: 0.0)
      let billingDetails = BillingDetails(billingName: "Test mark", billingEmail: "markweins@gmail.com", billingPhone: UserDefaults.getMobileNumber ?? "", billingAddress: billingAddress)
      let shippingAddress = ShippingAddress(city: "abc", countryCode: "VN", locale: "en", line1: "address_1", line2: "address_2", postalCode: "400202", state: "Mah")
      let shippingDetails = ShippingDetails(shippingName: "xyz", shippingEmail: "xyz@gmail.com", shippingPhone: "1234567890", shippingAddress: shippingAddress)
      var orderDetails: [OrderDetails] = []
      for details in self.selectedProducts {
      let product = OrderDetails(id: details.id ?? "", name: details.title ?? "", price: details.price ?? 0, quantity: 1, imageUrl: details.imageName ?? "")
      orderDetails.append(product)
      }
      let transactionRequest = WebTransactionRequest(chaipayKey: selectedEnvironment?.key ?? "", merchantDetails: merchantDetails, merchantOrderId: "MERCHANT\(Int(Date().timeIntervalSince1970 * 1000))", amount: getTotalAmount(), currency: "VND", signatureHash: "123", billingAddress: billingDetails, shippingAddress: shippingDetails, orderDetails: orderDetails, successURL: "https://test-checkout.portone.cloud/success.html", failureURL: "https://test-checkout.portone.cloud/failure.html", redirectURL: "chaipay://checkout", countryCode: "VN", expiryHours: 2, source: "api", description: "test dec", showShippingDetails: true, showBackButton: false, defaultGuestCheckout: false, isCheckoutEmbed: false )
      print(transactionRequest)
      return transactionRequest
      }

      Should implement the delegate methods as below to get the response of failure and success callbacks from the webView.

      extension AppDelegate: CheckoutDelegate {
      func transactionErrorResponse(_ error: Error?) {
      print("Eror",error)
      }
      var viewController: UIViewController? {
      return AppDelegate.shared.window?.rootViewController
      }
      func transactionResponse(_ webViewResponse: WebViewResponse?) {
      // receives the response of the transaction
      NotificationCenter.default.post(name: NSNotification.Name("webViewResponse"), object: webViewResponse)
      print("webview response", webViewResponse)
      }
      }

      Sample response#

      Success callback :

      {
      "merchant_order_ref" : "MERCHANT1630665361511",
      "message" : "",
      "is_success" : "true",
      "order_ref" : "1xcrkpVPNq5vuqQDe3eqrHD3OcG",
      "deep_link" : "",
      "channel_order_ref" : "1xcrkpVPNq5vuqQDe3eqrHD3OcG",
      "additional_data" : null,
      "redirect_url" : ""
      }

      Failure Callback:

      {
      "chaipay_order_ref": "1wa0choxhAy2QtE9ix8aNt8T3Mf",
      "channel_order_ref": "0",
      "merchant_order_ref": "MERCHANT1628681469666",
      "status": "Initiated",
      "status_code": "4000",
      "status_reason": "INVALID_TRANSACTION_ERROR"
      }

Native iOS - Payment SDK: v2