Подключение QR‑код от Яндекс Пэй iOS SDK
Шаг 1. Добавьте зависимость
Через Xcode (рекомендуется):
- File → Add Package Dependencies
- URL:
https://github.com/yandexmobile/yandex-quickpay-sdk-ios - Выберите актуальную версию и добавьте к таргету.
Через Package.swift:
.package(
url: "https://github.com/yandexmobile/yandex-quickpay-sdk-ios",
from: "LATEST_VERSION"
)
Актуальную версию смотрите в releases.
Шаг 2. Настройте Info.plist и Entitlements
Info.plist
Добавьте OAuth Client ID (инструкция):
<key>YandexClientID</key>
<string>YOUR_CLIENT_ID</string>
URL Scheme для OAuth-редиректа (замените YOUR_CLIENT_ID на ваш Client ID):
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>yx.YOUR_CLIENT_ID</string>
</array>
</dict>
</array>
Список приложений для проверки SDK:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>yandexauth</string>
<string>yandexauth2</string>
</array>
Entitlements
Настройте Associated Domains и Keychain Sharing. Подробная инструкция.
Шаг 3. Инициализируйте SDK
Вызовите YandexQuickPay.initialize() один раз при запуске. SDK использует синглтон — доступ через YandexQuickPay.instance.
Важно
Инициализацию выполняйте только один раз. Повторный вызов initialize() заменяет предыдущий экземпляр.
AppDelegate
import YandexQuickPaySDK
class AppDelegate: UIResponder, UIApplicationDelegate {
lazy var quickPayListener = MyQuickPayListener()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let config = QuickPayConfig(
merchantId: "YOUR_MERCHANT_ID",
environment: .sandbox, // Используйте .production перед релизом
locale: .system,
theme: .system
)
YandexQuickPay.initialize(
configuration: config,
presenterViewController: nil,
quickPaymentStateListener: quickPayListener
)
return true
}
func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
return YandexQuickPay.instance.handleOpenURL(url)
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
return YandexQuickPay.instance.handleUserActivity(userActivity)
}
}
Важно
handleOpenURL(_ url: URL) и handleUserActivity(_:) необходимы для OAuth-авторизации в процессе enableQuickPayment(). Без них авторизация через Яндекс ID не завершится.
SceneDelegate
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let url = URLContexts.first?.url else { return }
_ = YandexQuickPay.instance.handleOpenURL(url)
}
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
_ = YandexQuickPay.instance.handleUserActivity(userActivity)
}
SwiftUI App
@main
struct MyApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
_ = YandexQuickPay.instance.handleOpenURL(url)
}
}
}
}
Шаг 4. Жизненный цикл листенера
QuickPaymentStateListener — протокол с AnyObject. SDK хранит листенер как weak-ссылку.
Если у листенера нет другого владельца, ARC освободит объект и колбэки не будут приходить.
// Неправильно — объект немедленно освобождается
YandexQuickPay.initialize(
configuration: config,
presenterViewController: nil,
quickPaymentStateListener: MyListener() // ← временный объект
)
// Правильно — сохраняем сильную ссылку
class AppDelegate: UIApplicationDelegate {
lazy var quickPayListener = MyQuickPayListener()
func application(...) -> Bool {
YandexQuickPay.initialize(
configuration: config,
presenterViewController: nil,
quickPaymentStateListener: quickPayListener
)
return true
}
}
Реализация листенера
Колбэки могут вызываться не на Main thread. Обновления UI — через DispatchQueue.main.async или await MainActor.run.
final class QuickPayListener: QuickPaymentStateListener {
weak var delegate: QuickPayListenerDelegate?
func onPaymentEnabledStateChanged(isEnabled: Bool) {
DispatchQueue.main.async {
self.delegate?.quickPayEnabledStateChanged(isEnabled: isEnabled)
}
}
func onSessionExpired() {
DispatchQueue.main.async { self.delegate?.quickPaySessionExpired() }
}
func onPaymentResult(quickpayResult: QuickPayResult) {
DispatchQueue.main.async {
self.delegate?.quickPayPaymentResult(quickpayResult)
}
}
}
initialize() можно вызывать повторно — для смены конфигурации или обновления листенера.
Шаг 5. Добавьте виджет методов оплаты
createPaymentMethodsWidget() не бросает исключений. Два варианта — UIKit и SwiftUI.
UIKit
let widget: UIView = YandexQuickPay.instance.createPaymentMethodsWidget()
widget.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(widget)
// Настройте constraints
SwiftUI
AnyView(YandexQuickPay.instance.createPaymentMethodsWidget())
.frame(maxWidth: .infinity)
Шаг 6. Управляйте состоянием быстрой оплаты
- Включение:
try await YandexQuickPay.instance.enableQuickPayment()— может показать OAuth или биометрию. - Отключение:
try await YandexQuickPay.instance.disableQuickPayment() - Выход:
try await YandexQuickPay.instance.logout()— очищает данные, требуется повторная авторизация.
Шаг 7. Работайте с платёжной сессией и QR-кодом
do {
let sessionId = try await YandexQuickPay.instance.getPaymentSessionId()
let qrImage = generateQrImage(from: sessionId)
await MainActor.run { qrImageView.image = qrImage }
} catch FintechQuickPaymentError.noAuth {
showEnablePaymentButton()
} catch FintechQuickPaymentError.noPresentationContext {
// Вызов до отображения ViewController — переместите в viewDidAppear
} catch FintechQuickPaymentError.cannotCreateNewSession {
// Ошибка сети/сервера — повторить запрос
} catch {
showError(error)
}
Когда обновлять QR: первое отображение экрана, onSessionExpired(), onPaymentResult(), onPaymentEnabledStateChanged(true).
Обработка ошибок
| Ошибка | Когда | Действие |
|---|---|---|
.noAuth |
Пользователь не авторизован | enableQuickPayment() |
.cannotAuth |
Ошибка авторизации | Проверить Info.plist, Entitlements, URL Scheme |
.cannotCreateNewSession(underlying:) |
Ошибка сети/сервера | Повторить запрос |
.noPresentationContext |
Нет активного ViewController | Вызов после viewDidAppear / .onAppear |
Безопасность
merchantId— публичный, не секрет.sessionId— не логировать в production, не передавать третьим.- SDK не хранит данные карт.
- Биометрия — системные средства iOS.
Тестирование
Используйте .sandbox для разработки. Перед релизом — .production.
| Сценарий | Ожидаемое поведение |
|---|---|
| Первая авторизация | Показ экрана авторизации Яндекс ID |
| Успешный платёж | onPaymentResult(.success) |
| Истечение сессии | onSessionExpired(), затем новый QR |
| Выход | logout() — очистка данных |