Руководство по iOS SDK

Важно

Этот способ интеграции требует настройки API.

Подробнее о способах интеграции см. Интеграция

Требования к подключению

Поддерживаемая версия iOS SDK: 13.0 и выше.

Подключение

Перед началом интеграции нужно получить и добавить в проект несколько идентификаторов:

  1. MerchantId,
  2. ClientId,
  3. AppId

Подробнее про идентификаторы для пунктов 2-3 см. далее в инструкции.

Шаг 1. Настройка авторизации

1.1 Получите Client Id

  1. Зарегистрируйте приложение в сервисе Яндекс OAuth.

  2. В разделе Платформы выберите iOS-приложение и укажите параметры вашего сервиса:

    • iOS Appid — точный идентификатор iOS-приложения, например A1B2C3D4E5.com.domain.application. Состоит из Prefix и Bundle ID. Подробнее про идентификаторы iOS-приложений читайте в документации Apple.
    • iOS AppStore URL — ссылка на приложение в AppStore.
  3. Убедитесь, что на Яндекс.OAuth у вашего приложения добавлен доступ к Яндекс Пэй. Для этого перейдите к редактированию приложения и в блоке Какие данные вам нужны? выберите Яндекс ПэйОплата через Яндекс Пэй.

  4. Нажмите кнопку Создать приложение, скопируйте значение поля Client ID.

  5. Укажите полученный Client ID в блоке Client ID на странице Настройки личного кабинета.

  6. Передайте значение хеша AppId в службу поддержки при помощи формы обратной связи для настройки нужных редиректов на стороне сервиса.

Пример сообщения

Здравствуйте! Направляем значение AppId для подключения iOS SDK: "AppId:..."

1.2 Настройте Info.plist

Добавьте в файл Info.plist строки:

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>yandexauth</string>
    <string>yandexauth2</string>
    <string>yandexauth4</string>
</array>
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLName</key>
        <string>YandexLoginSDK</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>$(YANDEX_CLIENT_ID)</string>
        </array>
    </dict>
</array>

1.3 Настройте Entitlements

Сервис авторизации обменивается информацией с приложениями Яндекса через Universal Links. Для их работы добавьте строки в Capability: Associated Domains или файл *.entitlements.

DEBUG-конфигурация

  <key>com.apple.developer.associated-domains</key>
  <array>
    <string>applinks:yx$(YANDEX_CLIENT_ID).oauth.yandex.ru</string>
    <string>applinks:$(YANDEX_CLIENT_ID).merchant.applink.pay.yandex.ru</string>
    <string>applinks:$(YANDEX_CLIENT_ID).merchant.applink.sandbox.pay.yandex.ru</string>
  </array>

RELEASE-конфигурация

  <key>com.apple.developer.associated-domains</key>
  <array>
    <string>applinks:yx$(YANDEX_CLIENT_ID).oauth.yandex.ru</string>
    <string>applinks:$(YANDEX_CLIENT_ID).merchant.applink.sandbox.pay.yandex.ru</string>
    <string>applinks:$(YANDEX_CLIENT_ID).merchant.applink.pay.yandex.ru</string>
  </array>

Шаг 2. Установка Yandex Pay SDK

Текущая версия YandexPaySDK - 1.6.0

Добавьте зависимость в Podfile:

...
pod 'YandexPaySDK/Static'
...

В окне Xcode навигатора проектов (Project Navigator) выберите свой проект (если у вас используется Workspace). Затем в верхнем меню нажмите File и выберите Add Package Dependencies...

Добавьте пакет по ссылке:

https://github.com/yandexmobile/yandex-pay-ios

На текущий момент есть поддержка только динамической библиотеки, которая включает все необходимые зависимости. Распространение исходным кодом недоступно из-за ограничений, связанных с PCI DSS.

Добавьте package зависимость в Package.swift:

let package = Package(
    ...
    dependencies: [
        .package(
            name: "YandexPaySDK",
            url: " https://github.com/yandexmobile/yandex-pay-ios"
        ),
    ],
    ...
)

На текущий момент есть поддержка только динамической библиотеки, которая включает все необходимые зависимости. Распространение исходным кодом недоступно из-за ограничений, связанных с PCI DSS.

Шаг 3. Инициализация Yandex Pay SDK

Инициализируйте SDK в AppDelegate.swift вашего проекта в методе application(_:didFinishLaunchingWithOptions:):

import YandexPaySDK

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
      do {
          // Укажите конфигурацию
          let merchant = YandexPaySDKMerchant(
              // ID продавца в системе Яндекс Пэй
              id: "MERCHANT_ID",
              // Имя продавца
              name: "MERCHANT_NAME",
              // URL продавца
              url: "https://example.org/"
          )
          let configuration = YandexPaySDKConfiguration(
              // Необходимое окружение
              environment: .sandbox,
              // Информация о мерчанте
              merchant: merchant,
              // Локализация
              locale: .ru
          )
          // Инициализируйте SDK
          try YandexPaySDKApi.initialize(configuration: configuration)
      } catch {
          // Отреагируйте на ошибку должным образом
          assertionFailure("Unable to initialize YandexPaySDKApi.")
      }

      // Инициализируйте UIWindow и ViewController
      let controller = PaymentURLViewController()
      let window = UIWindow(frame: UIScreen.main.bounds)
      window.rootViewController = controller
      window.makeKeyAndVisible()
      self.window = window
      return true
  }

Также в AppDelegate.swift вашего проекта добавьте нотификацию YandexPaySDK о событиях жизненного цикла приложения:

import YandexPaySDK

  func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
      // Проверьте, что SDK проинициализирован
      guard YandexPaySDKApi.isInitialized else {
        assertionFailure("YandexPaySDK is not initialized.")
        return false
      }

      return YandexPaySDKApi.instance.applicationDidReceiveUserActivity(userActivity)
  }

  func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
      // Проверьте, что SDK проинициализирован
      guard YandexPaySDKApi.isInitialized else {
        assertionFailure("YandexPaySDK is not initialized.")
        return false
      }

      return YandexPaySDKApi.instance.applicationDidReceiveOpen(url, options: options)
  }

Примеры использования

Для ознакомления доступен демо-проект. В нем есть пример настройки проекта, а также два вида интеграции:

Добавление кнопки Яндекс Пэй с созданием заказа по ссылке на экран в Swift проекте

В демо-проекте есть пример для использования кнопки с созданием заказа по ссылке, но рассмотрим подробнее реализацию ниже.

Если вы хотите создать кнопку с новым методом создания заказа, используйте сигнатуру createButton(dataSource:delegate:) класса YandexPaySDKApi. Пример использования кнопки во ViewController:

import YandexPaySDK

final class PaymentURLViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .systemBackground

        // Проверьте, что SDK проинициализирован
        guard YandexPaySDKApi.isInitialized else {
          assertionFailure("YandexPaySDK is not initialized.")
          return
        }

        // Создайте кнопку
        let button = YandexPaySDKApi.instance.createButton(dataSource: self, delegate: self)
      
        // Есть возможность настроить отображение кнопки
        button.preferredPaymentMethods = [.card, .split]
        button.appearance = .system
        button.order = (100, .rub)
        button.cornerRadius = 16
        button.isBordered = false
        button.isLoading = false

        // Добавьте кнопку в иерархию
        view.addSubview(button)

        // Установите layout для кнопки
        button.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            button.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            button.widthAnchor.constraint(equalToConstant: 250)
        ])
    }
}

Кнопка для взаимодействия с клиентским приложением использует делегат YandexPayButtonDelegate. Реализуйте данный делегат, чтобы передать его кнопке при ее создании:

extension PaymentURLViewController: YandexPayButtonDelegate {
    func yandexPayButton(
        _ button: YandexPayButtonProtocol,
        didCompletePaymentWithResult result: YPYandexPayPaymentResult,
        data: YandexPaySDK.YPYandexPayPaymentData
    ) {
        let title: String
        let message: String
        switch result {
        case .succeeded:
            title = "Success!"
            message = "Payment successfuly proceeded."
        case .cancelled:
            title = "Cancelled!"
            message = "Payment has been cancelled by user."
        case .failed:
            fallthrough
        @unknown default:
            title = "Error!"
            message = "An error occured while payment processing."
        }

        let controller = UIAlertController(title: title, message: message, preferredStyle: .alert)
        controller.addAction(UIAlertAction(title: "OK", style: .default))
        present(controller, animated: true)
    }
}

В этом примере мы показываем пользователю сообщение с текущим статусом оплаты через YandexPay.

Также данная кнопка использует datasource YandexPayButtonDataSource. Реализуйте данный datasource, чтобы передать его кнопке при ее создании вместе с делегатом:

extension PaymentURLViewController: YandexPayButtonDataSource {
  func paymentUrl(for yandexPayButton: YandexPayButtonProtocol) async throws -> String {
    // Запросите paymentUrl (создайте заказ) асинхронно с вашего бекенда
    await withCheckedContinuation { continuation in
      // Это пример реализации async кода, скорее всего здесь будет сетевой запрос
      DispatchQueue.main.async {
        continuation.resume(returning: "payment-url.ru")
      }
    }
  }

  func viewControllerForPresentation(for yandexPayButton: YandexPayButtonProtocol) -> UIViewController {
    // Предоставьте UIViewController, с которого необходимо показать форму YandexPay по нажатию на кнопку
    self
  }
}

Все методы запроса данных являются асинхронными. Это значит, что они должны работать с подходом Swift Concurrency. Если есть необходимость, можно вернуть значение сразу. Есть отличный пример от Apple с WWDC 2021, как перевевести элементы вашего кода c подхода GCD на подход Concurrency: Swift concurrency: Update a sample app.