0

I'm trying to make a bridge to implement apple pay in react native. I've made two classes, one that will be expose to react native and the other one that implement apple pay methods. My issue is that when I try to build my app, the build failed with the error:

Cannot find protocol declaration for 'PKPaymentAuthorizationControllerDelegate'

that popped in the interface in mobile-swift.h:

SWIFT_CLASS("_TtC7Staging23InternalApplePayHandler")
@interface InternalApplePayHandler : NSObject
- (nonnull instancetype)init SWIFT_UNAVAILABLE;
+ (nonnull instancetype)new SWIFT_UNAVAILABLE_MSG("-init is unavailable");
@end

@class PKPaymentAuthorizationController;
@class PKPayment;
@class PKPaymentAuthorizationResult;

@interface InternalApplePayHandler (SWIFT_EXTENSION(Staging)) <PKPaymentAuthorizationControllerDelegate>
- (void)paymentAuthorizationController:(PKPaymentAuthorizationController * _Nonnull)controller didAuthorizePayment:(PKPayment * _Nonnull)payment handler:(void (^ _Nonnull)(PKPaymentAuthorizationResult * _Nonnull))completion;
- (void)paymentAuthorizationControllerDidFinish:(PKPaymentAuthorizationController * _Nonnull)controller;
@end

This is the class that implement it:

//
//  ApplePayHandler.swift
//  Mobile
//
//  Created by me on 06/06/2025.
//

final class InternalApplePayHandler: NSObject {
  private var paymentController: PKPaymentAuthorizationController?
  private var onSuccess: ((String) -> Void)?
  private var onFailure: ((String, String) -> Void)?
  private var amount: NSNumber
  private var currencyCode: String
  private var countryCode: String

  static func canMakePayment() -> Bool {
    return PKPaymentAuthorizationController.canMakePayments(usingNetworks: [.visa, .masterCard, .amex, .cartesBancaires])
  }

  init(
    amount: NSNumber,
    currencyCode: String,
    countryCode: String,
    onSuccess: @escaping (String) -> Void,
    onFailure: @escaping (String, String) -> Void
  ) {
    self.amount = amount
    self.currencyCode = currencyCode
    self.countryCode = countryCode
    self.onSuccess = onSuccess
    self.onFailure = onFailure
  }

  func start() {
    let request = PKPaymentRequest()
    request.merchantIdentifier = getMerchantIdentifier()
    request.countryCode = countryCode
    request.currencyCode = currencyCode
    request.supportedNetworks = [.visa, .masterCard, .amex, .discover]
    request.merchantCapabilities = .threeDSecure
    request.paymentSummaryItems = [
      PKPaymentSummaryItem(label: "Total", amount: NSDecimalNumber(decimal: amount.decimalValue), type: .final)
    ]

    let controller = PKPaymentAuthorizationController(paymentRequest: request)
    controller.delegate = self
    paymentController = controller

    controller.present { success in
      if !success {
        self.onFailure?("NOT_PRESENTED", "Failed to present Apple Pay sheet")
        self.cleanup()
      }
    }
  }

  private func getMerchantIdentifier() -> String {
    let bundleId = Bundle.main.bundleIdentifier ?? ""
    return bundleId == "MERCHANT_ID" ? "MERCHANT_ID" : "MERCHANT_ID_B"
  }

  private func cleanup() {
    paymentController = nil
    onSuccess = nil
    onFailure = nil
  }
}

extension InternalApplePayHandler: PKPaymentAuthorizationControllerDelegate {
  func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, didAuthorizePayment payment: PKPayment, handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) {
    let tokenData = payment.token.paymentData.base64EncodedString()
    onSuccess?(tokenData)
    completion(PKPaymentAuthorizationResult(status: .success, errors: nil))
    cleanup()
  }

  func paymentAuthorizationControllerDidFinish(_ controller: PKPaymentAuthorizationController) {
    controller.dismiss {
      self.onFailure?("CANCELLED", "User cancelled Apple Pay")
      self.cleanup()
    }
  }
}

and this class is used in the other class:

//
//  ApplePayManager.swift
//  Mobile
//
//  Created by me on 03/06/2025.
//

import Foundation
import React
import PassKit

@objc(ApplePayManager)
class ApplePayManager: NSObject {
  private var paymentHandler: InternalApplePayHandler?

  @objc
  func canMakePayment(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
    resolve(InternalApplePayHandler.canMakePayment())
  }

  @objc
  func startPayment(_ amount: NSNumber, currencyCode: String, countryCode: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
    paymentHandler = InternalApplePayHandler(
      amount: amount,
      currencyCode: currencyCode,
      countryCode: countryCode,
      onSuccess: { token in
        resolve(token)
      },
      onFailure: { code, message in
        reject(code, message, nil)
      }
    )
    paymentHandler?.start()
  }

  @objc
  static func requiresMainQueueSetup() -> Bool {
    return true
  }
}

and finally this is my ApplePayManager.m:

#import <React/RCTBridgeModule.h>
#import <React/RCTUtils.h>
#import <PassKit/PassKit.h>
#import <PassKit/PKPaymentAuthorizationController.h>


@interface RCT_EXTERN_MODULE(ApplePayManager, NSObject)

RCT_EXTERN_METHOD(canMakePayment:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)

RCT_EXTERN_METHOD(startPayment:(nonnull NSNumber *)amount
                  currencyCode:(nonnull NSString *)currencyCode
                  countryCode:(nonnull NSString *)countryCode
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)

@end

and I also imported the passKit inside my bridging header #import <PassKit/PassKit.h>

1 Answer 1

0

Looks like you aren't importing PassKit in your Swift code. Add import PassKit to the top and it should compile.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.