commit b7c7e3fd69bfd0d6bd72b92333abc34a6206664c Author: Искандар Р. Шабаев Date: Sun Jul 3 20:52:22 2022 +0300 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d381c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +.DS_Store +.dart_tool/ + +.packages +.pub/ +/.idea/vcs.xml + +build/ +*.iml +Flutter/Generated.xcconfig +Flutter/flutter_export_environment.sh + +.idea/* +!.idea/codeStyles/ +!.idea/copyright/ + +#Mac OS X +.DS_Store \ No newline at end of file diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..5bed526 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 18116933e77adc82f80866c928266a5b4f1ed645 + channel: stable + +project_type: plugin diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..aa11258 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "demo", + "cwd": "demo", + "request": "launch", + "type": "dart" + }, + { + "name": "demo-debug-dev", + "cwd": "demo", + "request": "launch", + "type": "dart", + "flutterMode": "debug", + "args": [ + "-t", + "lib/main-dev.dart", + "--flavor", + "dev" + ] + } + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..025e1f3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# 1.0.1 + +* Formatted code. Added homepage and repo urls. + +# 1.0.0 + +* Initial development release. \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e5495d4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,18 @@ +The MIT License (MIT) +Copyright © 2022 NBCO YooMoney LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the “Software”), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a7e70b5 --- /dev/null +++ b/README.md @@ -0,0 +1,517 @@ +# YooKassa Payments SDK + +Библиотека позволяет встроить прием платежей в мобильные приложения на Flutter и работает как дополнение к API ЮKassa.\ +В мобильный SDK входят готовые платежные интерфейсы (форма оплаты и всё, что с ней связано).\ +С помощью SDK можно получать токены для проведения оплаты с банковской карты, через Сбербанк Онлайн или из кошелька в ЮMoney. + +## Подключение зависимостей + +1. В файл `pubspec.yami` добавьте зависимость и запустите `pub get`: + +```dart +dependencies: + flutter: + sdk: flutter + yookassa_payments_flutter: ^version +``` + +2. Для iOS в файле your_project_name.podspec, лежащий в корне проекта в папке ios добавьте зависимость: +```ruby +s.dependency 'YooKassaPayments', '6.8.0' +``` + +3. Запустите `pod install` в директории рядом с Runner.xcworkspace + +4. В Info.plist своего приложения добавьте поддержку url-схем для корректной работы mSDK с оплатой через Сбер и ЮMoney: +``` +CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + yookassapaymentsflutter + + + + +LSApplicationQueriesSchemes + + yoomoneyauth + sberpay + +``` + +Решение проблем подключения: + +А. В случае когда `pod install` завершается с ошибкой – попробуйте команду `pod update YooKassaPayments` + +B. В некоторых сложных случаях рекомендуем сбросить кэш cocoapods. Это можно сделать несколькими способам. + + Вариант 1: выполнить набор команд для сброса кэша для пода YooKassaPayments и его зависимостей: + ``` + pod cache clean FunctionalSwift --all + pod cache clean MoneyAuth --all + pod cache clean ThreatMetrixAdapter --all + pod cache clean YooKassaPayments --all + pod cache clean YooKassaPaymentsApi --all + pod cache clean YooKassaWalletApi --all + pod cache clean YooMoneyCoreApi --all + pod cache clean TMXProfiling --all + pod cache clean TMXProfilingConnections --all + ``` + Вариант 2: Удалить полностью кэш cocoapods командой `rm -rf ~/.cocoapods/repos`. Обращаем ваше внимание что после этого + cocoapods будет восстанавливать свой локальный каталог некоторое время. + + Далее рекомендуем выполнить `flutter clean`, `pod clean` и `pod deintegrate YOUR_PROJECT_NAME.xcodeproj` + для последущей чистой установки командой `pod install` + +## Быстрая интеграция + +1. Создайте `TokenizationModuleInputData` (понадобится [ключ для клиентских приложений](https://yookassa.ru/my/tunes) из личного кабинета ЮKassa). В этой модели передаются параметры платежа (валюта и сумма) и параметры платежной формы, которые увидит пользователь при оплате (способы оплаты, название магазина и описание заказа). + +Пример создания `TokenizationModuleInputData`: + +```dart +var clientApplicationKey = "<Ключ для клиентских приложений>"; +var amount = Amount(value: 999.9, currency: Currency.rub); +var applePayID = "<Идентификатор продавца Apple Pay>"; +var shopId = "<Идентификатор магазина в ЮKassa)>"; +var tokenizationModuleInputData = + TokenizationModuleInputData(clientApplicationKey: clientApplicationKey, + title: "Космические объекты", + subtitle: "Комета повышенной яркости, период обращения — 112 лет", + amount: amount, + shopId: shopId, + savePaymentMethod: SavePaymentMethod.on); +``` + +2. Запустите процесс токенизации с кейсом `.tokenization` и передайте `TokenizationModuleInputData`. + +3. Получите token в `TokenizationResult` + +Пример: + +```dart +var result = await YookassaPaymentsFlutter.tokenization(tokenizationModuleInputData); +var token = result.token; +var paymentMethodType = result.paymentMethodType; +``` + +Закройте модуль SDK и отправьте токен в вашу систему. Затем [создайте платеж](https://yookassa.ru/developers/api#create_payment) по API ЮKassa, в параметре `payment_token` передайте токен, полученный в SDK. Способ подтверждения при создании платежа зависит от способа оплаты, который выбрал пользователь. Он приходит вместе с токеном в `paymentMethodType`. + +## Доступные способы оплаты + +Сейчас в SDK доступны следующие способы оплаты: + +`.yooMoney` — ЮMoney (платежи из кошелька или привязанной картой)\ +`.bankCard` — банковская карта (карты можно сканировать)\ +`.sberbank` — SberPay (с подтверждением через приложение Сбербанк Онлайн, если оно установленно, иначе с подтверждением по смс)\ + +## Настройка способов оплаты + +У вас есть возможность сконфигурировать способы оплаты.\ +Для этого необходимо при создании `TokenizationModuleInputData` в параметре `tokenizationSettings` передать модель типа `TokenizationSettings`. + +> Для некоторых способов оплаты нужна дополнительная настройка (см. ниже).\ +> По умолчанию используются все доступные способы оплаты. + +```dart +// Создайте пустой List +List paymentMethodTypes = []; + +if (<Условие для банковской карты>) { + // Добавляем в paymentMethodTypes элемент `PaymentMethod.bankCard` + paymentMethodTypes.add(PaymentMethod.bankCard); +} + +if (<Условие для Сбербанка Онлайн>) { + // Добавляем в paymentMethodTypes элемент `PaymentMethod.sberbank` + paymentMethodTypes.add(PaymentMethod.sberbank); +} + +if (<Условие для ЮMoney>) { + // Добавляем в paymentMethodTypes элемент `PaymentMethod.yooMoney` + paymentMethodTypes.add(PaymentMethod.yooMoney); +} + +var settings = TokenizationSettings(PaymentMethodTypes(paymentMethodTypes)); +``` + +Теперь используйте `tokenizationSettings` при инициализации `TokenizationModuleInputData`. + +### ЮMoney + +Для подключения способа оплаты `ЮMoney` необходимо: + +1. Получить `client id` центра авторизации системы `ЮMoney`. +2. При создании `TokenizationModuleInputData` передать `client id` в параметре `moneyAuthClientId` +3. В `TokenizationSettings` передайте значение `PaymentMethodTypes.yooMoney`. +4. Получите токен. +5. [Создайте платеж](https://yookassa.ru/developers/api#create_payment) с токеном по API ЮKassa. + +#### Как получить `client id` центра авторизации системы `ЮMoney` + +1. Авторизуйтесь на [yookassa.ru](https://yookassa.ru) +2. Перейти на страницу регистрации клиентов СЦА - [yookassa.ru/oauth/v2/client](https://yookassa.ru/oauth/v2/client) +3. Нажать [Зарегистрировать](https://yookassa.ru/oauth/v2/client/create) +4. Заполнить поля:\ + 4.1. "Название" - `required` поле, отображается при выдаче прав и в списке приложений.\ + 4.2. "Описание" - `optional` поле, отображается у пользователя в списке приложений.\ + 4.3. "Ссылка на сайт приложения" - `optional` поле, отображается у пользователя в списке приложений.\ + 4.4. "Код подтверждения" - выбрать `Передавать в Callback URL`, можно указывать любое значение, например ссылку на сайт. +5. Выбрать доступы:\ + 5.1. `Кошелёк ЮMoney` -> `Просмотр`\ + 5.2. `Профиль ЮMoney` -> `Просмотр` +6. Нажать `Зарегистрировать` + +#### Передать `client id` в параметре `moneyAuthClientId` + +При создании `TokenizationModuleInputData` передать `client id` в параметре `moneyAuthClientId` + +```swift +let moduleData = TokenizationModuleInputData( + ... + moneyAuthClientId: "client_id") +``` + +Чтобы провести платеж: + +1. При создании `TokenizationModuleInputData` передайте значение `.yooMoney` в `paymentMethodTypes.` +2. Получите токен. +3. [Создайте платеж](https://yookassa.ru/developers/api#create_payment) с токеном по API ЮKassa. + +#### Поддержка авторизации через мобильное приложение + +1. В `TokenizationModuleInputData` необходимо передавать `applicationScheme` – схема для возврата в приложение после успешной авторизации в `ЮMoney` через мобильное приложение. + +Пример `applicationScheme`: + +```swift +let moduleData = TokenizationModuleInputData( + ... + applicationScheme: "examplescheme://" +``` + +2. В `AppDelegate` импортировать зависимость `YooKassaPayments`: + + ```swift + import YooKassaPayments + ``` + +3. Добавить обработку ссылок через `YKSdk` в `AppDelegate`: + +```swift +func application( + _ application: UIApplication, + open url: URL, + sourceApplication: String?, + annotation: Any +) -> Bool { + return YKSdk.shared.handleOpen( + url: url, + sourceApplication: sourceApplication + ) +} + +@available(iOS 9.0, *) +func application( + _ app: UIApplication, + open url: URL, + options: [UIApplication.OpenURLOptionsKey: Any] = [:] +) -> Bool { + return YKSdk.shared.handleOpen( + url: url, + sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String + ) +} +``` + +4. В `Info.plist` добавьте следующие строки: + +```plistbase +LSApplicationQueriesSchemes + + yoomoneyauth + +CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + ${BUNDLE_ID} + CFBundleURLSchemes + + examplescheme + + + +``` + +где `examplescheme` - схема для открытия вашего приложения, которую вы указали в `applicationScheme` при создании `TokenizationModuleInputData`. Через эту схему будет открываться ваше приложение после успешной авторизации в `ЮMoney` через мобильное приложение. + +### Банковская карта + +1. При создании `TokenizationModuleInputData` в `TokenizationSettings` передайте значение `PaymentMethodTypes.bankCard`. +2. Получите токен. +3. [Создайте платеж](https://yookassa.ru/developers/api#create_payment) с токеном по API ЮKassa. + +### SberPay + +Чтобы провести платёж: + +1. При создании `TokenizationModuleInputData` в `TokenizationSettings` передайте значение `PaymentMethodTypes.sberbank`. +2. Получите токен. +3. [Создайте платеж](https://yookassa.ru/developers/api#create_payment) с токеном по API ЮKassa. + +Для подтверждения платежа через приложение СберБанк Онлайн: + +1. В `AppDelegate` импортируйте зависимость `YooKassaPayments`: + + ```swift + import YooKassaPayments + ``` + +2. Добавьте обработку ссылок через `YKSdk` в `AppDelegate`: + +```swift +func application( + _ application: UIApplication, + open url: URL, + sourceApplication: String?, + annotation: Any +) -> Bool { + return YKSdk.shared.handleOpen( + url: url, + sourceApplication: sourceApplication + ) +} + +@available(iOS 9.0, *) +func application( + _ app: UIApplication, + open url: URL, + options: [UIApplication.OpenURLOptionsKey: Any] = [:] +) -> Bool { + return YKSdk.shared.handleOpen( + url: url, + sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String + ) +} +``` + +3. В `Info.plist` добавьте следующие строки: + +```plistbase +LSApplicationQueriesSchemes + + sberpay + +CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + ${BUNDLE_ID} + CFBundleURLSchemes + + examplescheme + + + +``` + +где `examplescheme` - схема для открытия вашего приложения, которую вы указали в `applicationScheme` при создании `TokenizationModuleInputData`. Через эту схему будет открываться ваше приложение после успешной оплаты с помощью `SberPay`. + +4. Обработка успешного подтверждения уже реализована в плагине. Плагин отобразит алерт с информацией об успешном подтверждении. + +## Описание публичных параметров + +### TokenizationModuleInputData + +>Обязательные: + +| Параметр | Тип | Описание | +| -------------------- | ------ | -------- | +| clientApplicationKey | String | Ключ для клиентских приложений из личного кабинета ЮKassa | +| title | String | Название магазина в форме оплаты | +| subtitle | String | Описание заказа в форме оплаты | +| purchaseDescription | String | Описание заказа в форме оплаты | +| amount | Amount | Объект, содержащий сумму заказа и валюту | +| shopId | String | Идентификатор магазина в ЮKassa ([раздел Организации](https://yookassa.ru/my/company/organization) - скопировать shopId у нужного магазина) | +| savePaymentMethod | SavePaymentMethod | Объект, описывающий логику того, будет ли платеж рекуррентным | + +>Необязательные: + +| Параметр | Тип | Описание | +| -------------------------- | --------------------- | ------------------------------------------------------------ | +| gatewayId | String | По умолчанию `null`. Используется, если у вас несколько платежных шлюзов с разными идентификаторами. | +| tokenizationSettings | TokenizationSettings | По умолчанию используется стандартный инициализатор со всеми способами оплаты. Параметр отвечает за настройку токенизации (способы оплаты и логотип ЮKassa). | +| testModeSettings | TestModeSettings | По умолчанию `null`. Настройки тестового режима. | +| cardScanning | CardScanning | По умолчанию `null`. Возможность сканировать банковские карты. | +| applePayMerchantIdentifier | String | По умолчанию `null`. Apple Pay merchant ID (обязательно для платежей через Apple Pay). | +| returnUrl | String | По умолчанию `null`. URL страницы (поддерживается только `https`), на которую надо вернуться после прохождения 3-D Secure. Необходим только при кастомной реализации 3-D Secure. Если вы используете `startConfirmationProcess(confirmationUrl:paymentMethodType:)`, не задавайте этот параметр. | +| isLoggingEnabled | Bool | По умолчанию `false`. Включает логирование сетевых запросов. | +| userPhoneNumber | String | По умолчанию `null`. Телефонный номер пользователя. | +| customizationSettings | CustomizationSettings | По умолчанию используется цвет blueRibbon. Цвет основных элементов, кнопки, переключатели, поля ввода. | +| moneyAuthClientId | String | По умолчанию `null`. Идентификатор для центра авторизации в системе YooMoney. | +| applicationScheme | String | По умолчанию `null`. Схема для возврата в приложение после успешной оплаты с помощью `Sberpay` в приложении СберБанк Онлайн или после успешной авторизации в `YooMoney` через мобильное приложение. | +| customerId | String | По умолчанию `null`. Уникальный идентификатор покупателя в вашей системе, например электронная почта или номер телефона. Не более 200 символов. Используется, если вы хотите запомнить банковскую карту и отобразить ее при повторном платеже в mSdk. Убедитесь, что customerId относится к пользователю, который хочет совершить покупку. Например, используйте двухфакторную аутентификацию. Если передать неверный идентификатор, пользователь сможет выбрать для оплаты чужие банковские карты.| +| googlePayParameters | GooglePayParameters | По умолчанию поддерживает mastercard и visa. Настройки для платежей через Google Pay. | + +### SavedBankCardModuleInputData + +>Обязательные: + +| Параметр | Тип | Описание | +| -------------------- | ------ | -------- | +| clientApplicationKey | String | Ключ для клиентских приложений из личного кабинета ЮKassa | +| title | String | Название магазина в форме оплаты | +| purchaseDescription | String | Описание заказа в форме оплаты | +| subtitle | String | Описание заказа в форме оплаты | +| paymentMethodId | String | Идентификатор сохраненного способа оплаты | +| amount | Amount | Объект, содержащий сумму заказа и валюту | +| shopId | String | Идентификатор магазина в ЮKassa ([раздел Организации](https://yookassa.ru/my/company/organization) - скопировать shopId у нужного магазина) | +| savePaymentMethod | SavePaymentMethod | Объект, описывающий логику того, будет ли платеж рекуррентным | + +>Необязательные: + +| Параметр | Тип | Описание | +| --------------------- | --------------------- | ------------------------------------------------------------ | +| gatewayId | String | По умолчанию `null`. Используется, если у вас несколько платежных шлюзов с разными идентификаторами. | +| testModeSettings | TestModeSettings | По умолчанию `null`. Настройки тестового режима. | +| returnUrl | String | По умолчанию `null`. URL страницы (поддерживается только `https`), на которую надо вернуться после прохождения 3-D Secure. Необходим только при кастомной реализации 3-D Secure. Если вы используете `startConfirmationProcess(confirmationUrl:paymentMethodType:)`, не задавайте этот параметр. | +| isLoggingEnabled | Bool | По умолчанию `false`. Включает логирование сетевых запросов. | +| customizationSettings | CustomizationSettings | По умолчанию используется цвет Color.fromARGB(255, 0, 112, 240). Цвет основных элементов, кнопки, переключатели, поля ввода. | + +### TokenizationSettings + +Можно настроить список способов оплаты и отображение логотипа ЮKassa в приложении. + +| Параметр | Тип | Описание | +| ---------------------- | ------------------ | -------- | +| paymentMethodTypes | PaymentMethodTypes | По умолчанию `PaymentMethodTypes.all`. [Способы оплаты](#настройка-способов-оплаты), доступные пользователю в приложении. | +| showYooKassaLogo | Bool | По умолчанию `true`. Отвечает за отображение логотипа ЮKassa. По умолчанию логотип отображается. | + +### TestModeSettings + +| Параметр | Тип | Описание | +| -------------------------- | ------ | -------- | +| paymentAuthorizationPassed | Bool | Определяет, пройдена ли платежная авторизация при оплате ЮMoney. | +| cardsCount | Int | Количество привязанные карт к кошельку в ЮMoney. | +| charge | Amount | Сумма и валюта платежа. | +| enablePaymentError | Bool | Определяет, будет ли платеж завершен с ошибкой. | + +### Amount + +| Параметр | Тип | Описание | +| -------- | -------- | -------- | +| value | Double | Сумма платежа | +| currency | Currency | Валюта платежа | + +### Currency + +| Параметр | Тип | Описание | +| -------- | -------- | -------- | +| Currency.rub | String | ₽ - Российский рубль | +| Currency.usd | String | $ - Американский доллар | +| Currency.eur | String | € - Евро | +| Currency(“custom”) | String | Будет отображаться значение, которое передали | + +### CustomizationSettings + +| Параметр | Тип | Описание | +| ---------- | ------- | -------- | +| mainScheme | Color | По умолчанию используется цвет Color.fromARGB(255, 0, 112, 240). Цвет основных элементов, кнопки, переключатели, поля ввода. | + +### SavePaymentMethod + +| Параметр | Тип | Описание | +| ----------- | ----------------- | -------- | +| SavePaymentMethod.on | SavePaymentMethod | Сохранить платёжный метод для проведения рекуррентных платежей. Пользователю будут доступны только способы оплаты, поддерживающие сохранение. На экране контракта будет отображено сообщение о том, что платёжный метод будет сохранён. | +| SavePaymentMethod.off | SavePaymentMethod | Не дает пользователю выбрать, сохранять способ оплаты или нет. | +| SavePaymentMethod.userSelects | SavePaymentMethod | Пользователь выбирает, сохранять платёжный метод или нет. Если метод можно сохранить, на экране контракта появится переключатель. | + +## Настройка подтверждения платежа + +Если вы хотите использовать нашу реализацию подтверждения платежа, не закрывайте модуль SDK после получения токена.\ +Отправьте токен на ваш сервер и после успешной оплаты закройте модуль.\ +Если ваш сервер сообщил о необходимости подтверждения платежа (т.е. платёж пришёл со статусом `pending`), вызовите метод `confirmation(confirmationUrl, paymentMethodType)`. + +Примеры кода: + +```dart +await YookassaPaymentsFlutter.confirmation(controller.text, result.paymentMethodType); +) +``` + +## Логирование + +У вас есть возможность включить логирование всех сетевых запросов.\ +Для этого необходимо при создании `TokenizationModuleInputData` передать `isLoggingEnabled: true` + +## Тестовый режим + +У вас есть возможность запустить мобильный SDK в тестовом режиме.\ +Тестовый режим не выполняет никаких сетевых запросов и имитирует ответ от сервера. + +Если вы хотите запустить SDK в тестовом режиме, необходимо: + +1. Сконфигурировать объект с типом `TestModeSettings(paymentAuthorizationPassed, cardsCount, charge, enablePaymentError)`. + +```dart +var testModeSettings = TestModeSettings(true, 5, Amount(value: 999, currency: .rub), false); +``` + +2. Передать его в `TokenizationModuleInputData` в параметре `testModeSettings:` + +```dart +var tokenizationModuleInputData = TokenizationModuleInputData( + ... + testModeSettings: testModeSettings); +``` + +## Кастомизация интерфейса + +По умолчанию используется цвет Color.fromARGB(255, 0, 112, 240). Цвет основных элементов, кнопки, переключатели, поля ввода. + +1. Сконфигурировать объект `CustomizationSettings` и передать его в параметр `customizationSettings` объекта `TokenizationModuleInputData`. + +```dart +var tokenizationModuleInputData = TokenizationModuleInputData( + ... + customizationSettings: const CustomizationSettings(Colors.black)); +``` + +## Платёж привязанной к магазину картой с дозапросом CVC/CVV + +1. Создайте `SavedBankCardModuleInputData`. + +```dart +var savedBankCardModuleInputData = SavedBankCardModuleInputData( + clientApplicationKey: clientApplicationKey, + title: "Космические объекты", + subtitle: "Комета повышенной яркости, период обращения — 112 лет", + purchaseDescription: "root.description", + amount: amount, + savePaymentMethod: SavePaymentMethod.on, + applePayID: applePayID, + shopId: shopId, + paymentMethodId: paymentMethodId +); +``` + +2. Запустите процесс с кейсом `.bankCardRepeat` и передайте `SavedBankCardModuleInputData`. + +```dart +var result = await YookassaPaymentsFlutter.bankCardRepeat(savedBankCardModuleInputData); +``` + +3. Получите token в `TokenizationResult` + +## Лицензия + +YooKassa Payments SDK доступна под лицензией MIT. Смотрите [LICENSE](https://git.yoomoney.ru/projects/SDK/repos/yookassa-payments-swift/browse/LICENSE) файл для получения дополнительной информации. diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..a5744c1 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..c6cbe56 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..843a471 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,56 @@ +group 'ru.yoomoney.sdk.kassa.payments.flutter' + +buildscript { + ext.kotlin_version = '1.5.0' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.0.3' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + compileSdkVersion 31 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + minSdkVersion 21 + } + + buildTypes { + release { + signingConfig signingConfigs.debug + } + } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'ru.yoomoney.sdk.kassa.payments:yookassa-android-sdk:6.5.2' +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..4d3226a --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..c17bc40 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a5657a --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'yookassa_payments_flutter' diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..b2726e8 --- /dev/null +++ b/android/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/android/src/main/kotlin/ru/yoomoney/sdk/kassa/payments/flutter/TokenizationResultExtensions.kt b/android/src/main/kotlin/ru/yoomoney/sdk/kassa/payments/flutter/TokenizationResultExtensions.kt new file mode 100644 index 0000000..9c34b94 --- /dev/null +++ b/android/src/main/kotlin/ru/yoomoney/sdk/kassa/payments/flutter/TokenizationResultExtensions.kt @@ -0,0 +1,17 @@ +package ru.yoomoney.sdk.kassa.payments.flutter + +import ru.yoomoney.sdk.kassa.payments.TokenizationResult +import org.json.JSONObject +import ru.yoomoney.sdk.kassa.payments.checkoutParameters.PaymentMethodType + +fun TokenizationResult.toJson(): String { + val json = JSONObject() + json.put("paymentToken", paymentToken) + json.put("paymentMethodType", when(paymentMethodType) { + PaymentMethodType.YOO_MONEY -> "yoo_money" + PaymentMethodType.BANK_CARD -> "bank_card" + PaymentMethodType.SBERBANK -> "sberbank" + PaymentMethodType.GOOGLE_PAY -> "google_pay" + }) + return json.toString() +} \ No newline at end of file diff --git a/android/src/main/kotlin/ru/yoomoney/sdk/kassa/payments/flutter/YookassaPaymentsFlutterPlugin.kt b/android/src/main/kotlin/ru/yoomoney/sdk/kassa/payments/flutter/YookassaPaymentsFlutterPlugin.kt new file mode 100644 index 0000000..9269e70 --- /dev/null +++ b/android/src/main/kotlin/ru/yoomoney/sdk/kassa/payments/flutter/YookassaPaymentsFlutterPlugin.kt @@ -0,0 +1,301 @@ +package ru.yoomoney.sdk.kassa.payments.flutter + +import android.graphics.Color; +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.widget.Toast +import androidx.annotation.NonNull +import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.common.MethodChannel.MethodCallHandler +import io.flutter.plugin.common.MethodChannel.Result +import io.flutter.plugin.common.PluginRegistry +import io.flutter.plugin.common.PluginRegistry.Registrar +import io.flutter.embedding.engine.plugins.activity.ActivityAware +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding +import java.io.StringReader +import java.math.BigDecimal +import java.util.Currency +import ru.yoomoney.sdk.kassa.payments.checkoutParameters.Amount +import ru.yoomoney.sdk.kassa.payments.Checkout +import ru.yoomoney.sdk.kassa.payments.ui.color.ColorScheme +import ru.yoomoney.sdk.kassa.payments.checkoutParameters.HostParameters; +import ru.yoomoney.sdk.kassa.payments.checkoutParameters.GooglePayParameters +import ru.yoomoney.sdk.kassa.payments.checkoutParameters.GooglePayCardNetwork +import ru.yoomoney.sdk.kassa.payments.checkoutParameters.MockConfiguration +import ru.yoomoney.sdk.kassa.payments.checkoutParameters.PaymentMethodType +import ru.yoomoney.sdk.kassa.payments.checkoutParameters.SavePaymentMethod +import ru.yoomoney.sdk.kassa.payments.checkoutParameters.PaymentParameters +import ru.yoomoney.sdk.kassa.payments.checkoutParameters.SavedBankCardPaymentParameters +import ru.yoomoney.sdk.kassa.payments.checkoutParameters.TestParameters +import ru.yoomoney.sdk.kassa.payments.TokenizationResult +import ru.yoomoney.sdk.kassa.payments.checkoutParameters.UiParameters + +class YookassaPaymentsFlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, PluginRegistry.ActivityResultListener { + + private lateinit var flutterResult: Result + private lateinit var channel : MethodChannel + private lateinit var context: Context + private lateinit var activity: Activity + private var binding: ActivityPluginBinding? = null + + private val REQUEST_CODE_TOKENIZE = 33 + private val REQUEST_CODE_CONFIRMATION = 44 + + override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + channel = MethodChannel(flutterPluginBinding.binaryMessenger, "ru.yoomoney.yookassa_payments_flutter/yoomoney") + channel.setMethodCallHandler(this) + context = flutterPluginBinding.applicationContext + } + + override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { + flutterResult = result + + val data: HashMap = call.arguments as HashMap + + when (call.method) { + "tokenization" -> tokenization(data) + "confirmation" -> confirmation(data) + "repeat" -> repeat(data) + } + } + + fun confirmation(data: HashMap) { + val paymentMethod = when (data["paymentMethod"] as String) { + "bankCard" -> PaymentMethodType.BANK_CARD + "yooMoney" -> PaymentMethodType.YOO_MONEY + "sberbank" -> PaymentMethodType.SBERBANK + "googlePay" -> PaymentMethodType.GOOGLE_PAY + else -> PaymentMethodType.BANK_CARD + } + + val url = data["url"] as String + + val intent: Intent = Checkout.createConfirmationIntent( + context = context, + confirmationUrl = url, + paymentMethodType = paymentMethod + ) + + activity.startActivityForResult(intent, REQUEST_CODE_CONFIRMATION) + } + + fun repeat(data: HashMap) { + val showLogs = data["isLoggingEnabled"] as Boolean + val mockConfiguration: MockConfiguration? = MockConfiguration(data) + val uiParameters = UiParameters(data) + var hostParameters = HostParameters(data) + val testParameters = TestParameters( + showLogs = showLogs, + mockConfiguration = mockConfiguration, + hostParameters = hostParameters + ) + + val parameters = SavedBankCardPaymentParameters(data) + + val intent = Checkout.createSavedCardTokenizeIntent(context, parameters, testParameters) + activity.startActivityForResult(intent, REQUEST_CODE_TOKENIZE) + } + + fun tokenization(data: HashMap) { + val showLogs = data["isLoggingEnabled"] as Boolean + val mockConfiguration: MockConfiguration? = MockConfiguration(data) + val uiParameters = UiParameters(data) + var hostParameters = HostParameters(data) + val googlePayTestEnvironment = data["googlePayTestEnvironment"] as Boolean + val testParameters = TestParameters( + showLogs = showLogs, + googlePayTestEnvironment = googlePayTestEnvironment, + mockConfiguration = mockConfiguration, + hostParameters = hostParameters + ) + + val paymentParameters = PaymentParameters(data) + + val intent = Checkout.createTokenizeIntent(context, paymentParameters, testParameters, uiParameters) + activity.startActivityForResult(intent, REQUEST_CODE_TOKENIZE) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { + if (requestCode == REQUEST_CODE_TOKENIZE) { + if (resultCode == Activity.RESULT_OK && data != null) { + val result: TokenizationResult = Checkout.createTokenizationResult(data); + flutterResult.success(result.toJson()) + } + } else if (requestCode == REQUEST_CODE_CONFIRMATION) { + flutterResult.success(resultCode) + } + + return false + } + + override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { + channel.setMethodCallHandler(null) + } + + override fun onAttachedToActivity(binding: ActivityPluginBinding) { + activity = binding.activity + binding.addActivityResultListener(this) + this.binding = binding + } + + override fun onDetachedFromActivity() { + binding?.removeActivityResultListener(this) + binding = null + } + + override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { + this.binding?.removeActivityResultListener(this) + this.binding = binding + binding.addActivityResultListener(this) + } + + override fun onDetachedFromActivityForConfigChanges() { + binding?.removeActivityResultListener(this) + binding = null + } +} + +private fun PaymentParameters(data: Map): PaymentParameters { + val amountMap: HashMap = data["amount"] as HashMap + val amount = Amount(BigDecimal(amountMap["value"] as Double), Currency.getInstance(amountMap["currency"] as String)) + + val clientApplicationKey = data["clientApplicationKey"] as String + val title = data["title"] as String + val subtitle = data["subtitle"] as String + val shopId = data["shopId"] as String + val authCenterClientId = data["moneyAuthClientId"] as String + val gatewayId = data["gatewayId"] as? String + val userPhoneNumber = data["userPhoneNumber"] as? String + val customReturnUrl = data["returnUrl"] as? String + val applicationScheme = data["applicationScheme"] as? String + val customerId = data["customerId"] as? String + val savePaymentMethod: SavePaymentMethod = SavePaymentMethod(data) + val paymentMethodTypes = PaymentMethodType(data) + val googlePayParameters = GooglePayParameters(data) + + return PaymentParameters( + amount = amount, + title = title, + subtitle = subtitle, + clientApplicationKey = clientApplicationKey, + shopId = shopId, + customerId = customerId, + savePaymentMethod = savePaymentMethod, + authCenterClientId = authCenterClientId, + gatewayId = gatewayId, + userPhoneNumber = userPhoneNumber, + customReturnUrl = customReturnUrl, + paymentMethodTypes = paymentMethodTypes, + googlePayParameters = googlePayParameters + ) +} + +private fun PaymentMethodType(data: Map): Set { + val flutterPaymentMethodTypes = (data["tokenizationSettings"] as HashMap)["paymentMethodTypes"] as ArrayList + val paymentMethodTypes: MutableSet = mutableSetOf() + + for(type in flutterPaymentMethodTypes){ + when (type) { + "PaymentMethod.bankCard" -> paymentMethodTypes.add(PaymentMethodType.BANK_CARD) + "PaymentMethod.yooMoney" -> paymentMethodTypes.add(PaymentMethodType.YOO_MONEY) + "PaymentMethod.sberbank" -> paymentMethodTypes.add(PaymentMethodType.SBERBANK) + "PaymentMethod.googlePay" -> paymentMethodTypes.add(PaymentMethodType.GOOGLE_PAY) + } + } + return paymentMethodTypes +} + +private fun GooglePayParameters(data: Map): GooglePayParameters { + val flutterGooglePayParameters = data["googlePayParameters"] as ArrayList + val googlePayParameters: MutableSet = mutableSetOf() + + for(type in flutterGooglePayParameters){ + when (type) { + "GooglePayCardNetwork.AMEX" -> googlePayParameters.add(GooglePayCardNetwork.AMEX) + "GooglePayCardNetwork.DISCOVER" -> googlePayParameters.add(GooglePayCardNetwork.DISCOVER) + "GooglePayCardNetwork.JCB" -> googlePayParameters.add(GooglePayCardNetwork.JCB) + "GooglePayCardNetwork.MASTERCARD" -> googlePayParameters.add(GooglePayCardNetwork.MASTERCARD) + "GooglePayCardNetwork.VISA" -> googlePayParameters.add(GooglePayCardNetwork.VISA) + "GooglePayCardNetwork.INTERAC" -> googlePayParameters.add(GooglePayCardNetwork.INTERAC) + "GooglePayCardNetwork.OTHER" -> googlePayParameters.add(GooglePayCardNetwork.OTHER) + } + } + return GooglePayParameters(googlePayParameters) +} + +private fun SavedBankCardPaymentParameters(data: Map): SavedBankCardPaymentParameters { + val amountMap: HashMap = data["amount"] as HashMap + val amount = Amount(BigDecimal(amountMap["value"] as Double), Currency.getInstance(amountMap["currency"] as String)) + val title = data["title"] as String + val subtitle = data["subtitle"] as String + val clientApplicationKey = data["clientApplicationKey"] as String + val shopId = data["shopId"] as String + val paymentId = data["paymentMethodId"] as String + val savePaymentMethod: SavePaymentMethod = SavePaymentMethod(data) + + return SavedBankCardPaymentParameters( + amount = amount, + title = title, + subtitle = subtitle, + clientApplicationKey = clientApplicationKey, + shopId = shopId, + paymentMethodId = paymentId, + savePaymentMethod = savePaymentMethod + ) +} + +private fun SavePaymentMethod(data: Map): SavePaymentMethod { + return when (data["savePaymentMethod"] as String) { + "SavePaymentMethod.on" -> SavePaymentMethod.ON + "SavePaymentMethod.off" -> SavePaymentMethod.OFF + else -> { + SavePaymentMethod.USER_SELECTS + } + } +} + +private fun HostParameters(data: Map): HostParameters { + val hostParametersData = data["hostParameters"] as? HashMap + return if (hostParametersData != null) { + HostParameters( + hostParametersData["apiHost"] as String, + hostParametersData["paymentAuthApiHost"] as String, + hostParametersData["authApiHost"] as String, + hostParametersData["configHost"] as String, + ) + } else { + HostParameters() + } +} + +private fun UiParameters(data: Map): UiParameters { + val customizationSettings = data["customizationSettings"] as HashMap + val showLogo = customizationSettings["showYooKassaLogo"] as Boolean + val dataColor = customizationSettings["mainScheme"] as HashMap + + val alpha = dataColor["alpha"] as Int + val red = dataColor["red"] as Int + val blue = dataColor["blue"] as Int + val green = dataColor["green"] as Int + + return UiParameters(showLogo, ColorScheme(Color.argb(alpha, red, green, blue))) +} + +private fun MockConfiguration(data: Map): MockConfiguration? { + val testModeSettings = data["testModeSettings"] as? HashMap + if (testModeSettings == null) return null + + val paymentAuthPassed = testModeSettings["paymentAuthorizationPassed"] as Boolean + val completeWithError = testModeSettings["enablePaymentError"] as Boolean + val linkedCardsCount = testModeSettings["cardsCount"] as Int + val serviceFeeMap: HashMap = testModeSettings["charge"] as HashMap + val serviceFee = Amount(BigDecimal(serviceFeeMap["value"] as Double), Currency.getInstance(serviceFeeMap["currency"] as String)) + + return MockConfiguration(completeWithError, paymentAuthPassed, linkedCardsCount, serviceFee) +} \ No newline at end of file diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 0000000..0fa6b67 --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/example/.metadata b/example/.metadata new file mode 100644 index 0000000..a5584fc --- /dev/null +++ b/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 18116933e77adc82f80866c928266a5b4f1ed645 + channel: stable + +project_type: app diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..4fd4f99 --- /dev/null +++ b/example/README.md @@ -0,0 +1,3 @@ +# yookassa_payments_flutter_example + +Demonstrates how to use the yookassa_payments_flutter plugin. \ No newline at end of file diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml new file mode 100644 index 0000000..61b6c4d --- /dev/null +++ b/example/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/example/android/.gitignore b/example/android/.gitignore new file mode 100644 index 0000000..6f56801 --- /dev/null +++ b/example/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle new file mode 100644 index 0000000..4daae36 --- /dev/null +++ b/example/android/app/build.gradle @@ -0,0 +1,70 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 31 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "ru.yoomoney.yookassa_payments_flutter_example" + minSdkVersion 21 + targetSdkVersion 31 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + + resValue "string", "ym_app_scheme", "yookassapaymentsexample" + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..4348684 --- /dev/null +++ b/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/android/app/src/main/kotlin/ru/yoomoney/yookassa_payments_flutter_example/MainActivity.kt b/example/android/app/src/main/kotlin/ru/yoomoney/yookassa_payments_flutter_example/MainActivity.kt new file mode 100644 index 0000000..1deae04 --- /dev/null +++ b/example/android/app/src/main/kotlin/ru/yoomoney/yookassa_payments_flutter_example/MainActivity.kt @@ -0,0 +1,6 @@ +package ru.yoomoney.yookassa_payments_flutter_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/drawable/launch_background.xml b/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..449a9f9 --- /dev/null +++ b/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..d74aa35 --- /dev/null +++ b/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/android/build.gradle b/example/android/build.gradle new file mode 100644 index 0000000..9d58a21 --- /dev/null +++ b/example/android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + ext.kotlin_version = '1.5.0' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.0.3' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/example/android/gradle.properties b/example/android/gradle.properties new file mode 100644 index 0000000..4d3226a --- /dev/null +++ b/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true \ No newline at end of file diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..ed1a787 --- /dev/null +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle new file mode 100644 index 0000000..44e62bc --- /dev/null +++ b/example/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/example/ios/.gitignore b/example/ios/.gitignore new file mode 100644 index 0000000..addd0e7 --- /dev/null +++ b/example/ios/.gitignore @@ -0,0 +1,35 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Pods/** +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..8d4492f --- /dev/null +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 9.0 + + diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..ec97fc6 --- /dev/null +++ b/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..c4855bf --- /dev/null +++ b/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 0000000..ca04734 --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,47 @@ +platform :ios, '10.0' + +source 'https://github.com/CocoaPods/Specs.git' +source 'https://git.yoomoney.ru/scm/sdk/cocoa-pod-specs.git' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + + target.build_configurations.each do |config| + config.build_settings["ONLY_ACTIVE_ARCH"] = "YES" + end + end +end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock new file mode 100644 index 0000000..df1fba5 --- /dev/null +++ b/example/ios/Podfile.lock @@ -0,0 +1,78 @@ +PODS: + - Flutter (3.0.0) + - FunctionalSwift (1.8.0) + - MoneyAuth (3.4.0): + - FunctionalSwift + - ThreatMetrixAdapter + - YooMoneyCoreApi + - ThreatMetrixAdapter (3.3.3) + - TMXProfiling (1.0.1) + - TMXProfilingConnections (1.0.1) + - YandexMobileMetrica/Dynamic (4.2.0): + - YandexMobileMetrica/Dynamic/Core (= 4.2.0) + - YandexMobileMetrica/Dynamic/Crashes (= 4.2.0) + - YandexMobileMetrica/Dynamic/Core (4.2.0) + - YandexMobileMetrica/Dynamic/Crashes (4.2.0): + - YandexMobileMetrica/Dynamic/Core + - yookassa_payments_flutter (0.0.1): + - Flutter + - YooKassaPayments (= 6.8.0) + - YooKassaPayments (6.8.0): + - MoneyAuth (~> 3.4.0) + - ThreatMetrixAdapter (~> 3.3.3) + - TMXProfiling (= 1.0.1) + - TMXProfilingConnections (= 1.0.1) + - YandexMobileMetrica/Dynamic (>= 3.0) + - YooKassaPaymentsApi (~> 2.11.0) + - YooKassaWalletApi (~> 2.3.1) + - YooMoneyCoreApi (~> 2.1.0) + - YooKassaPaymentsApi (2.11.0): + - FunctionalSwift + - YooMoneyCoreApi + - YooKassaWalletApi (2.3.1): + - FunctionalSwift + - YooMoneyCoreApi + - YooMoneyCoreApi (2.1.0): + - FunctionalSwift (~> 1.8.0) + +DEPENDENCIES: + - Flutter (from `Flutter`) + - yookassa_payments_flutter (from `.symlinks/plugins/yookassa_payments_flutter/ios`) + +SPEC REPOS: + https://git.yoomoney.ru/scm/sdk/cocoa-pod-specs.git: + - FunctionalSwift + - MoneyAuth + - ThreatMetrixAdapter + - TMXProfiling + - TMXProfilingConnections + - YooKassaPayments + - YooKassaPaymentsApi + - YooKassaWalletApi + - YooMoneyCoreApi + https://github.com/CocoaPods/Specs.git: + - YandexMobileMetrica + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + yookassa_payments_flutter: + :path: ".symlinks/plugins/yookassa_payments_flutter/ios" + +SPEC CHECKSUMS: + Flutter: 6f378e544fdb3c2db75671011442c5eaf902d3c4 + FunctionalSwift: b65b0a7ddde7f11a11e794f79a1e8009724ed0bd + MoneyAuth: 8f2e4968132e0d187c1f33b6a99f998220c22135 + ThreatMetrixAdapter: 683cc07cd1faee65c14292f7d748d56b92ff34c9 + TMXProfiling: a3b9808d62abf72227a366f2cbdca414ee38a023 + TMXProfilingConnections: e3984a86c3c338f13af682bb77a6d18474289b79 + YandexMobileMetrica: f5f9c605eaaba33ff6ab2b6bc3259035ca60ed87 + yookassa_payments_flutter: d3cefc2d375b816278cb1f22a85a74adfda274b8 + YooKassaPayments: 6e725f147d2dc30b1427518e72d6115e227c48a2 + YooKassaPaymentsApi: 1b2ea9cadc898717f6216dd0e84dbabd5294dfb4 + YooKassaWalletApi: ea6fd080bd4663c66fe5db0f37aafb999282048c + YooMoneyCoreApi: ddf9ea035b9a3f8d0563b4da8e55652fa07040d3 + +PODFILE CHECKSUM: b2e848e40e05488c9273432fb90c6c5918bb082f + +COCOAPODS: 1.11.3 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..7814c42 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,471 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + BAEDD6C9220D1ABA0429DC05 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08BAA017D1C1DD8F2E26E61B /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 08BAA017D1C1DD8F2E26E61B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 0F432271E158C4356E30E297 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 6AF9C6944A49F0D9AC28EF18 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + A95B0811275AB8E600BAE8AB /* TMXProfilingConnections.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = TMXProfilingConnections.xcframework; path = Frameworks/TMXProfilingConnections.xcframework; sourceTree = ""; }; + A95B0815275AB8F400BAE8AB /* TMXProfiling.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = TMXProfiling.xcframework; path = Frameworks/TMXProfiling.xcframework; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BAEDD6C9220D1ABA0429DC05 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0A9E0AECE28BA26A565C74FA /* Pods */ = { + isa = PBXGroup; + children = ( + 6AF9C6944A49F0D9AC28EF18 /* Pods-Runner.debug.xcconfig */, + 0F432271E158C4356E30E297 /* Pods-Runner.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + 2B777917365CBF507928ADBB /* Frameworks */ = { + isa = PBXGroup; + children = ( + A95B0815275AB8F400BAE8AB /* TMXProfiling.xcframework */, + A95B0811275AB8E600BAE8AB /* TMXProfilingConnections.xcframework */, + 08BAA017D1C1DD8F2E26E61B /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 0A9E0AECE28BA26A565C74FA /* Pods */, + 2B777917365CBF507928ADBB /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 73C3CA7DD996445733801D0C /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 5A51D23740C73B8FBFF86A21 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 5A51D23740C73B8FBFF86A21 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 73C3CA7DD996445733801D0C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + BUILD_LIBRARY_FOR_DISTRIBUTION = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = ru.yoomoney.yookassa_payments_flutter_example; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + BUILD_LIBRARY_FOR_DISTRIBUTION = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = ru.yoomoney.yookassa_payments_flutter_example; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + BUILD_LIBRARY_FOR_DISTRIBUTION = NO; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "ru.yoomoney.yookassa-payments-flutter-exampe"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + BUILD_LIBRARY_FOR_DISTRIBUTION = NO; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "ru.yoomoney.yookassa-payments-flutter-exampe"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..c87d15a --- /dev/null +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..5203365 --- /dev/null +++ b/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,40 @@ +import UIKit +import Flutter +import YooKassaPayments + +var result: FlutterResult? + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + override func application( + _ application: UIApplication, + open url: URL, + sourceApplication: String?, + annotation: Any + ) -> Bool { + return YKSdk.shared.handleOpen( + url: url, + sourceApplication: sourceApplication + ) + } + + @available(iOS 9.0, *) + override func application( + _ app: UIApplication, + open url: URL, + options: [UIApplication.OpenURLOptionsKey: Any] = [:] + ) -> Bool { + return YKSdk.shared.handleOpen( + url: url, + sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String + ) + } +} diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..dc9ada4 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..28c6bf0 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..f091b6b Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cde121 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..d0ef06e Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..dcdc230 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..c8f9ed8 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..a6d6b86 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..a6d6b86 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..75b2d16 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..c4df70d Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..6a84f41 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..d0e1f58 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Contents.json b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..dc9ada4 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-20x20@1x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..28c6bf0 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-20x20@2x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..f091b6b Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-29x29@1x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cde121 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-29x29@2x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..d0ef06e Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-29x29@3x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..dcdc230 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-40x40@1x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..c8f9ed8 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-40x40@3x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..a6d6b86 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..a6d6b86 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..75b2d16 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..c4df70d Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-76x76@2x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..6a84f41 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..d0e1f58 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devAppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/Contents.json b/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/LaunchImage.png b/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/LaunchImage.png differ diff --git a/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/LaunchImage@2x.png b/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/LaunchImage@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/LaunchImage@3x.png b/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/LaunchImage@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/README.md b/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/devLaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Contents.json b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..dc9ada4 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-20x20@1x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..28c6bf0 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-20x20@2x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..f091b6b Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-29x29@1x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cde121 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-29x29@2x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..d0ef06e Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-29x29@3x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..dcdc230 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-40x40@1x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..c8f9ed8 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-40x40@3x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..a6d6b86 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..a6d6b86 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..75b2d16 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..c4df70d Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-76x76@2x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..6a84f41 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..d0e1f58 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodAppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/Contents.json b/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/LaunchImage.png b/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/LaunchImage.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/LaunchImage@2x.png b/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/LaunchImage@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/LaunchImage@3x.png b/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/LaunchImage@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/README.md b/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/prodLaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner/Base.lproj/Main.storyboard b/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist new file mode 100644 index 0000000..90605ac --- /dev/null +++ b/example/ios/Runner/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(BUNDLE_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + NSCameraUsageDescription + Разрешить доступ к камере + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/example/ios/Runner/Runner-Bridging-Header.h b/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/example/lib/app.dart b/example/lib/app.dart new file mode 100644 index 0000000..1e5de40 --- /dev/null +++ b/example/lib/app.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; +import 'tokenization_screen.dart'; + +class App extends StatelessWidget { + const App({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Example app", + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: const TokenizationScreen(), + ); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart new file mode 100644 index 0000000..99da45a --- /dev/null +++ b/example/lib/main.dart @@ -0,0 +1,6 @@ +import 'package:flutter/material.dart'; +import 'app.dart'; + +void main() { + runApp(const App()); +} diff --git a/example/lib/success_tokenization_screen.dart b/example/lib/success_tokenization_screen.dart new file mode 100644 index 0000000..c08b63a --- /dev/null +++ b/example/lib/success_tokenization_screen.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:yookassa_payments_flutter/input_data/saved_card_module_input_data.dart'; +import 'package:yookassa_payments_flutter/models/tokenization_result.dart'; +import 'package:yookassa_payments_flutter/yookassa_payments_flutter.dart'; + +class SuccessTokenizationScreen extends StatefulWidget { + const SuccessTokenizationScreen({Key? key, required this.result, this.tokenizationData, this.repeatData}) : super(key: key); + + final TokenizationResult result; + final TokenizationModuleInputData? tokenizationData; + final SavedBankCardModuleInputData? repeatData; + + @override + State createState() => SuccessTokenizationScreenState(result, tokenizationData, repeatData); +} + +class SuccessTokenizationScreenState extends State { + final TokenizationResult result; + final TokenizationModuleInputData? tokenizationData; + final SavedBankCardModuleInputData? repeatData; + + SuccessTokenizationScreenState(this.result, this.tokenizationData, this.repeatData); + + late TextEditingController controller; + + @override + void initState() { + controller = TextEditingController(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Flutter Example App"), + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const ListTile( + leading: Icon(Icons.done, color: Colors.green), + title: Text("Токен готов"), + ), + Container( + padding: const EdgeInsets.all(20.0), + child: TextField( + controller: controller, + decoration: const InputDecoration( + hintText: "3ds / App2App ссылка" + ), + ), + ), + ElevatedButton( + onPressed: () async { + await YookassaPaymentsFlutter.confirmation(controller.text, result.paymentMethodType); + showDialog(context: context, builder: (context) => const AlertDialog( + content: Text("Confirmation process is done"), + )); + }, + child: const Text("Подтвердить") + ), + TextButton( + onPressed: () async { + showDialog(context: context, builder: (context) => AlertDialog( + content: Text(result.token), + actions: [ + TextButton( + onPressed: () { + Clipboard.setData(ClipboardData(text: result.token)); + Navigator.of(context).pop(); + }, + child: const Text('Скопировать'), + ), + ] + )); + }, + child: const Text("Показать токен") + ) + ], + ), + ); + } +} \ No newline at end of file diff --git a/example/lib/tokenization_screen.dart b/example/lib/tokenization_screen.dart new file mode 100644 index 0000000..6444651 --- /dev/null +++ b/example/lib/tokenization_screen.dart @@ -0,0 +1,78 @@ +import 'package:flutter/material.dart'; +import 'package:yookassa_payments_flutter/yookassa_payments_flutter.dart'; +import 'package:yookassa_payments_flutter_example/success_tokenization_screen.dart'; + +class TokenizationScreen extends StatefulWidget{ + const TokenizationScreen({Key? key}) : super(key: key); + + @override + State createState() => TokenizationScreenState(); +} + +class TokenizationScreenState extends State { + late TextEditingController controller; + + @override + void initState() { + controller = TextEditingController(text: "10.0"); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Flutter Example App"), + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + padding: const EdgeInsets.all(20.0), + child: TextField( + controller: controller, + ), + ), + ElevatedButton( + onPressed: () async { + startTokenization(); + }, + child: const Text("Оплатить") + ) + ], + ), + ); + } + + void startTokenization() async { + var clientApplicationKey = "<Ключ для клиентских приложений>"; + var amount = Amount(value: double.parse(controller.text), currency: Currency.rub); + var moneyAuthClientId = ""; + var applePayID = "<Идентификатор продавца Apple Pay>"; + var shopId = "<Идентификатор магазина в ЮKassa>"; + var applicationScheme = "<Схема вашего приложения для deeplink>" "://"; + var tokenizationModuleInputData = TokenizationModuleInputData( + clientApplicationKey: clientApplicationKey, + title: "Космические объекты", + subtitle: "Комета повышенной яркости, период обращения — 112 лет", + amount: amount, + savePaymentMethod: SavePaymentMethod.userSelects, + isLoggingEnabled: true, + moneyAuthClientId: moneyAuthClientId, + applePayID: applePayID, + shopId: shopId, + customerId: "<Уникальный идентификатор покупателя>", + applicationScheme: applicationScheme, + tokenizationSettings: const TokenizationSettings( + PaymentMethodTypes([ + PaymentMethod.bankCard, + PaymentMethod.yooMoney, + PaymentMethod.sberbank + ]) + ), + testModeSettings: null + ); + var result = await YookassaPaymentsFlutter.tokenization(tokenizationModuleInputData); + Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SuccessTokenizationScreen(result: result, tokenizationData: tokenizationModuleInputData))); + } +} \ No newline at end of file diff --git a/example/pubspec.lock b/example/pubspec.lock new file mode 100644 index 0000000..09397f3 --- /dev/null +++ b/example/pubspec.lock @@ -0,0 +1,175 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.2" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.16.0" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.4" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.2" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.9" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + yookassa_payments_flutter: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "1.0.0" +sdks: + dart: ">=2.17.0-0 <3.0.0" + flutter: ">=2.10.5" diff --git a/example/pubspec.yaml b/example/pubspec.yaml new file mode 100644 index 0000000..833f018 --- /dev/null +++ b/example/pubspec.yaml @@ -0,0 +1,85 @@ +name: yookassa_payments_flutter_example +description: Demonstrates how to use the yookassa_payments_flutter plugin. + +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +environment: + sdk: ">=2.12.0 <3.0.0" + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + + yookassa_payments_flutter: + # When depending on this package from a real application you should use: + # yookassa_payments_flutter: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. + path: ../ + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^1.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..0c88507 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,38 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ +GeneratedPluginRegistrant.h +GeneratedPluginRegistrant.m + +.generated/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +/Flutter/Generated.xcconfig +/Flutter/ephemeral/ +/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/ios/Assets/.gitkeep b/ios/Assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ios/Classes/SwiftYookassaPaymentsFlutterPlugin.swift b/ios/Classes/SwiftYookassaPaymentsFlutterPlugin.swift new file mode 100644 index 0000000..6886356 --- /dev/null +++ b/ios/Classes/SwiftYookassaPaymentsFlutterPlugin.swift @@ -0,0 +1,480 @@ +import Flutter +import UIKit +import YooKassaPayments +import Foundation + +var flutterResult: FlutterResult? +var tokenizationModuleInput: TokenizationModuleInput? +var flutterController: FlutterViewController? +var yoomoneyController: UIViewController? + +public class SwiftYookassaPaymentsFlutterPlugin: NSObject, FlutterPlugin { + public static func register(with registrar: FlutterPluginRegistrar) { + let channel = FlutterMethodChannel(name: "ru.yoomoney.yookassa_payments_flutter/yoomoney", binaryMessenger: registrar.messenger()) + let instance = SwiftYookassaPaymentsFlutterPlugin() + registrar.addMethodCallDelegate(instance, channel: channel) + } + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + flutterResult = result + + if (call.method == YooMoneyService.tokenization.rawValue) { + guard let data = call.arguments as? [String:AnyObject], + let jsonData = try? JSONSerialization.data(withJSONObject: data, options: .prettyPrinted), + let tokenizationModuleInputData = try? JSONDecoder().decode(TokenizationModuleInputData.self, from: jsonData) + else { + result(YooMoneyErrors.tokenizationData.rawValue) + return + } + + let inputData: TokenizationFlow = .tokenization(tokenizationModuleInputData) + + let controller = UIApplication.shared.delegate?.window??.rootViewController as! FlutterViewController + + let vc = TokenizationAssembly.makeModule(inputData: inputData, moduleOutput: controller) + controller.present(vc, animated: true, completion: nil) + + flutterController = controller + yoomoneyController = vc + } + + if (call.method == YooMoneyService.confirmation.rawValue) { + guard let data = call.arguments as? [String:AnyObject], + let jsonData = try? JSONSerialization.data(withJSONObject: data, options: .prettyPrinted), + let conformationData = try? JSONDecoder().decode(ConformationData.self, from: jsonData) + else { + result(YooMoneyErrors.conformationData.rawValue) + return + } + + var paymentMethod: PaymentMethodType? + switch conformationData.paymentMethod { + case "bankCard": + paymentMethod = .bankCard + case "yooMoney": + paymentMethod = .yooMoney + case "sberbank": + paymentMethod = .sberbank + case "applePay": + paymentMethod = .applePay + default: break + } + + guard + let module = tokenizationModuleInput, + let method = paymentMethod, + let url = conformationData.url, + let sheetController = yoomoneyController + else { + result(YooMoneyErrors.navigation.rawValue) + return + } + + let controller = UIApplication.shared.delegate?.window??.rootViewController as! FlutterViewController + controller.present(sheetController, animated: true, completion: nil) + + module.startConfirmationProcess( + confirmationUrl: url, + paymentMethodType: method + ) + } + + if (call.method == YooMoneyService.repeatPayment.rawValue) { + guard let data = call.arguments as? [String:AnyObject], + let jsonData = try? JSONSerialization.data(withJSONObject: data, options: .prettyPrinted), + let bankCardRepeatModuleInputData = try? JSONDecoder().decode(BankCardRepeatModuleInputData.self, from: jsonData) + else { + result(YooMoneyErrors.repeatPaymentData.rawValue) + return + } + + let inputData: TokenizationFlow = .bankCardRepeat(bankCardRepeatModuleInputData) + + flutterController = UIApplication.shared.delegate?.window??.rootViewController as? FlutterViewController + + if let controller = flutterController { + let vc = TokenizationAssembly.makeModule(inputData: inputData, moduleOutput: controller) + tokenizationModuleInput = vc + controller.present(vc, animated: true, completion: nil) + } + } + } +} + +extension FlutterViewController: TokenizationModuleOutput { + public func didSuccessfullyPassedCardSec(on module: TokenizationModuleInput) { + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } + let alertController = UIAlertController( + title: "3D-Sec", + message: "Successfully passed 3d-sec", + preferredStyle: .alert + ) + + let action = UIAlertAction(title: "OK", style: .default) + alertController.addAction(action) + self.dismiss(animated: true) + self.present(alertController, animated: true) + } + } + + public func tokenizationModule( + _ module: TokenizationModuleInput, + didTokenize token: Tokens, + paymentMethodType: PaymentMethodType + ) { + tokenizationModuleInput = module + + if let result = flutterResult { + result("{\"paymentToken\": \"\(token.paymentToken)\", \"paymentMethodType\": \"\(paymentMethodType.rawValue)\"}") + DispatchQueue.main.async { + if let controller = yoomoneyController { + controller.dismiss(animated: true) + } + } + } + } + + public func didFinish( + on module: TokenizationModuleInput, + with error: YooKassaPaymentsError? + ) { + DispatchQueue.main.async { [weak self] in + if let controller = yoomoneyController { + controller.dismiss(animated: true) + } + } + } + + public func didSuccessfullyConfirmation( + paymentMethodType: PaymentMethodType + ) { + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } + let alertController = UIAlertController( + title: "Confirmation", + message: "Successfully confirmation", + preferredStyle: .alert + ) + + let action = UIAlertAction(title: "OK", style: .default) + alertController.addAction(action) + self.dismiss(animated: true) + self.present(alertController, animated: true) + } + } +} + +struct HostParameters: Codable, Equatable { + let host: String? + let paymentAuthorizationHost: String? + let authHost: String? + let configHost: String? + + enum CodingKeys: String, CodingKey { + case host = "host" + case paymentAuthorizationHost = "paymentAuthorizationHost" + case authHost = "authHost" + case configHost = "configHost" + } +} + +struct ConformationData: Codable, Equatable { + let url: String? + let paymentMethod: String? + + enum CodingKeys: String, CodingKey { + case url = "url" + case paymentMethod = "paymentMethod" + } +} + +enum YooMoneyService: String { + case tokenization = "tokenization" + case confirmation = "confirmation" + case repeatPayment = "repeat" +} + +enum YooMoneyErrors: String { + case navigation = "ErrorNavigation" + case tokenizationData = "ErrorTokenizationData" + case conformationData = "ErrorConfirmationData" + case repeatPaymentData = "ErrorRepeatPaymentData" + case tokenizationResult = "ErrorTokenizationResult" +} + +extension TokenizationModuleInputData: Decodable { + enum CodingKeys: String, CodingKey { + case clientApplicationKey = "clientApplicationKey" + case shopName = "title" + case purchaseDescription = "subtitle" + case amount = "amount" + case savePaymentMethod = "savePaymentMethod" + case gatewayId = "gatewayId" + case tokenizationSettings = "tokenizationSettings" + case testModeSettings = "testModeSettings" + case applePayMerchantIdentifier = "applePayMerchantIdentifier" + case returnUrl = "returnUrl" + case isLoggingEnabled = "isLoggingEnabled" + case userPhoneNumber = "userPhoneNumber" + case customizationSettings = "customizationSettings" + case moneyAuthClientId = "moneyAuthClientId" + case applicationScheme = "applicationScheme" + case customerId = "customerId" + case hostParameters = "hostParameters" + + enum CustomizationKeys: String, CodingKey { + case mainScheme = "mainScheme" + case showYooKassaLogo = "showYooKassaLogo" + } + } + + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + + let clientApplicationKey = try values.decode(String.self, forKey: .clientApplicationKey) + let shopName = try values.decode(String.self, forKey: .shopName) + let purchaseDescription = try values.decode(String.self, forKey: .purchaseDescription) + let amount = try values.decode(Amount.self, forKey: .amount) + let gatewayId = try? values.decode(String.self, forKey: .gatewayId) + + let settings = try values.decode(TokenizationSettings.self, forKey: .tokenizationSettings) + let customizationContainer = try values.nestedContainer(keyedBy: CodingKeys.CustomizationKeys.self, forKey: .customizationSettings) + let showYooKassaLogo = try customizationContainer.decode(Bool.self, forKey: .showYooKassaLogo) + let tokenizationSettings = TokenizationSettings(paymentMethodTypes: settings.paymentMethodTypes, showYooKassaLogo: showYooKassaLogo) + + let testModeSettings = try? values.decode(TestModeSettings.self, forKey: .testModeSettings) + let applePayMerchantIdentifier = try? values.decode(String.self, forKey: .applePayMerchantIdentifier) + let returnUrl = try? values.decode(String.self, forKey: .returnUrl) + let isLoggingEnabled = try values.decode(Bool.self, forKey: .isLoggingEnabled) + let userPhoneNumber = try? values.decode(String.self, forKey: .userPhoneNumber) + let customizationSettings = try values.decode(CustomizationSettings.self, forKey: .customizationSettings) + let moneyAuthClientId = try? values.decode(String.self, forKey: .moneyAuthClientId) + let applicationScheme = try? values.decode(String.self, forKey: .applicationScheme) + let customerId = try? values.decode(String.self, forKey: .customerId) + let hostParameters = try? values.decode(HostParameters.self, forKey: .hostParameters) + + var savePaymentMethod: SavePaymentMethod + switch try values.decode(String.self, forKey: .savePaymentMethod) { + case "SavePaymentMethod.on": + savePaymentMethod = .on + case "SavePaymentMethod.off": + savePaymentMethod = .off + default: + savePaymentMethod = .userSelects + } + + let userDefaults = UserDefaults.standard + userDefaults.set(hostParameters != nil, forKey: "dev_host_preference") + userDefaults.synchronize() + + self.init( + clientApplicationKey: clientApplicationKey, + shopName: shopName, + purchaseDescription: purchaseDescription, + amount: amount, + gatewayId: gatewayId, + tokenizationSettings: tokenizationSettings, + testModeSettings: testModeSettings, + applePayMerchantIdentifier: applePayMerchantIdentifier, + returnUrl: returnUrl, + isLoggingEnabled: isLoggingEnabled, + userPhoneNumber: userPhoneNumber, + customizationSettings: customizationSettings, + savePaymentMethod: savePaymentMethod, + moneyAuthClientId: moneyAuthClientId, + applicationScheme: applicationScheme, + customerId: customerId + ) + } +} + +extension BankCardRepeatModuleInputData: Decodable { + enum CodingKeys: String, CodingKey { + case clientApplicationKey = "clientApplicationKey" + case shopName = "shopName" + case purchaseDescription = "purchaseDescription" + case amount = "amount" + case savePaymentMethod = "savePaymentMethod" + case paymentMethodId = "paymentMethodId" + case gatewayId = "gatewayId" + case testModeSettings = "testModeSettings" + case returnUrl = "returnUrl" + case isLoggingEnabled = "isLoggingEnabled" + case customizationSettings = "customizationSettings" + case cardScanning = "cardScanning" + case isSafeDeal = "isSafeDeal" + case customerId = "customerId" + } + + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + + let clientApplicationKey = try values.decode(String.self, forKey: .clientApplicationKey) + let shopName = try values.decode(String.self, forKey: .shopName) + let purchaseDescription = try values.decode(String.self, forKey: .purchaseDescription) + let amount = try values.decode(Amount.self, forKey: .amount) + let paymentMethodId = try values.decode(String.self, forKey: .paymentMethodId) + let gatewayId = try? values.decode(String.self, forKey: .gatewayId) + let testModeSettings = try? values.decode(TestModeSettings.self, forKey: .testModeSettings) + let returnUrl = try? values.decode(String.self, forKey: .returnUrl) + let isLoggingEnabled = try values.decode(Bool.self, forKey: .isLoggingEnabled) + let customizationSettings = try values.decode(CustomizationSettings.self, forKey: .customizationSettings) + + var savePaymentMethod: SavePaymentMethod + switch try values.decode(String.self, forKey: .savePaymentMethod) { + case "SavePaymentMethod.on": + savePaymentMethod = .on + case "SavePaymentMethod.off": + savePaymentMethod = .off + default: + savePaymentMethod = .userSelects + } + + self.init( + clientApplicationKey: clientApplicationKey, + shopName: shopName, + purchaseDescription: purchaseDescription, + paymentMethodId: paymentMethodId, + amount: amount, + testModeSettings: testModeSettings, + returnUrl: returnUrl, + isLoggingEnabled: isLoggingEnabled, + customizationSettings: customizationSettings, + savePaymentMethod: savePaymentMethod, + gatewayId: gatewayId + ) + } +} + +extension Amount: Decodable { + enum CodingKeys: String, CodingKey { + case value = "value" + case currency = "currency" + } + + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + + let value = try values.decode(Double.self, forKey: .value) + let currency = try values.decode(String.self, forKey: .currency) + self.init(value: Decimal(value), currency: .custom(currency)) + } +} + +extension TokenizationSettings: Decodable { + enum CodingKeys: String, CodingKey { + case paymentMethodTypes = "paymentMethodTypes" + case showYooKassaLogo = "showYooKassaLogo" + } + + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + + let paymentFlutterMethodTypes = try values.decode([String].self, forKey: .paymentMethodTypes) + var paymentTypes: PaymentMethodTypes = [] + for type in paymentFlutterMethodTypes { + switch type { + case "PaymentMethod.bankCard": + paymentTypes.insert(.bankCard) + case "PaymentMethod.yooMoney": + paymentTypes.insert(.yooMoney) + case "PaymentMethod.sberbank": + paymentTypes.insert(.sberbank) + case "PaymentMethod.applePay": + paymentTypes.insert(.applePay) + default: break + } + } + + let showYooKassaLogo = try values.decodeIfPresent(Bool.self, forKey: .showYooKassaLogo) + self.init(paymentMethodTypes: paymentTypes, showYooKassaLogo: showYooKassaLogo ?? true) + } +} + +extension TestModeSettings: Decodable { + enum CodingKeys: String, CodingKey { + case paymentAuthorizationPassed = "paymentAuthorizationPassed" + case cardsCount = "cardsCount" + case charge = "charge" + case enablePaymentError = "enablePaymentError" + } + + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + + let paymentAuthorizationPassed = try values.decode(Bool.self, forKey: .paymentAuthorizationPassed) + let cardsCount = try values.decode(Int.self, forKey: .cardsCount) + let charge = try values.decode(Amount.self, forKey: .charge) + let enablePaymentError = try values.decode(Bool.self, forKey: .enablePaymentError) + + self.init( + paymentAuthorizationPassed: paymentAuthorizationPassed, + cardsCount: cardsCount, + charge: charge, + enablePaymentError: enablePaymentError + ) + } +} + +extension CustomizationSettings: Decodable { + enum CodingKeys: String, CodingKey { + case mainScheme = "mainScheme" + } + + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + let schemeColor = try values.decode(Color.self, forKey: .mainScheme) + + self.init(mainScheme: + UIColor( + red: schemeColor.red, + green: schemeColor.green, + blue: schemeColor.blue, + alpha: schemeColor.alpha + ) + ) + } +} + +struct Color: Decodable { + + let red: CGFloat + let green: CGFloat + let blue: CGFloat + let alpha: CGFloat + + init( + red: CGFloat, + green: CGFloat, + blue: CGFloat, + alpha: CGFloat + ) { + self.red = red + self.green = green + self.blue = blue + self.alpha = alpha + } + + enum CodingKeys: String, CodingKey { + case red = "red" + case blue = "blue" + case green = "green" + case alpha = "alpha" + } + + init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + + let red = try values.decode(CGFloat.self, forKey: .red) + let blue = try values.decode(CGFloat.self, forKey: .blue) + let green = try values.decode(CGFloat.self, forKey: .green) + let alpha = try values.decode(CGFloat.self, forKey: .alpha) + + self.init(red: red / 255, + green: green / 255, + blue: blue / 255, + alpha: alpha + ) + } +} diff --git a/ios/Classes/YookassaPaymentsFlutterPlugin.h b/ios/Classes/YookassaPaymentsFlutterPlugin.h new file mode 100644 index 0000000..e8d325f --- /dev/null +++ b/ios/Classes/YookassaPaymentsFlutterPlugin.h @@ -0,0 +1,4 @@ +#import + +@interface YookassaPaymentsFlutterPlugin : NSObject +@end diff --git a/ios/Classes/YookassaPaymentsFlutterPlugin.m b/ios/Classes/YookassaPaymentsFlutterPlugin.m new file mode 100644 index 0000000..8d0c361 --- /dev/null +++ b/ios/Classes/YookassaPaymentsFlutterPlugin.m @@ -0,0 +1,15 @@ +#import "YookassaPaymentsFlutterPlugin.h" +#if __has_include() +#import +#else +// Support project import fallback if the generated compatibility header +// is not copied when this plugin is created as a library. +// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 +#import "yookassa_payments_flutter-Swift.h" +#endif + +@implementation YookassaPaymentsFlutterPlugin ++ (void)registerWithRegistrar:(NSObject*)registrar { + [SwiftYookassaPaymentsFlutterPlugin registerWithRegistrar:registrar]; +} +@end diff --git a/ios/yookassa_payments_flutter.podspec b/ios/yookassa_payments_flutter.podspec new file mode 100644 index 0000000..d6bcc62 --- /dev/null +++ b/ios/yookassa_payments_flutter.podspec @@ -0,0 +1,22 @@ +Pod::Spec.new do |s| + s.name = 'yookassa_payments_flutter' + s.version = '0.0.1' + s.summary = 'Flutter SDK from yoomoney' + s.description = <<-DESC +Flutter SDK from yoomoney + DESC + s.homepage = 'https://yoomoney.ru' + s.license = { :file => '../LICENSE' } + s.author = 'YooMoney Team' + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.dependency 'Flutter' + s.dependency 'YooKassaPayments', '6.8.0' + + s.platform = :ios, '10.0' + + # Flutter.framework does not contain a i386 slice. + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } + s.swift_version = '5.0' + s.static_framework = true +end diff --git a/lib/input_data/saved_card_module_input_data.dart b/lib/input_data/saved_card_module_input_data.dart new file mode 100644 index 0000000..e33398e --- /dev/null +++ b/lib/input_data/saved_card_module_input_data.dart @@ -0,0 +1,61 @@ +import '../models/amount.dart'; +import '../models/customization_settings.dart'; +import '../models/method_save_payment.dart'; +import '../models/test_mode_settings.dart'; +import '../models/host_parameters.dart'; + +class SavedBankCardModuleInputData { + String clientApplicationKey; + String title; + String subtitle; + Amount amount; + SavePaymentMethod savePaymentMethod; + String applePayID; + String shopId; + String paymentMethodId; + String? gatewayId; + TestModeSettings? testModeSettings; + String? returnUrl; + bool isLoggingEnabled; + CustomizationSettings customizationSettings; + String? customerId; + bool isSafeDeal; + HostParameters? hostParameters; + + SavedBankCardModuleInputData( + {required this.clientApplicationKey, + required this.title, + required this.subtitle, + required this.amount, + required this.savePaymentMethod, + required this.applePayID, + required this.shopId, + required this.paymentMethodId, + required this.isSafeDeal, + this.gatewayId, + this.testModeSettings, + this.returnUrl, + this.isLoggingEnabled = false, + this.customizationSettings = const CustomizationSettings(), + this.customerId, + this.hostParameters}); + + Map toJson() => { + 'clientApplicationKey': clientApplicationKey, + 'title': title, + 'subtitle': subtitle, + 'amount': amount.toJson(), + 'savePaymentMethod': savePaymentMethod.toString(), + 'gatewayId': gatewayId, + 'testModeSettings': testModeSettings?.toJson(), + 'applePayMerchantIdentifier': applePayID, + 'shopId': shopId, + 'returnUrl': returnUrl, + 'isLoggingEnabled': isLoggingEnabled, + 'customizationSettings': customizationSettings.toJson(), + 'paymentMethodId': paymentMethodId, + 'customerId': customerId, + 'isSafeDeal': isSafeDeal, + 'hostParameters': hostParameters?.toJson(), + }; +} diff --git a/lib/input_data/tokenization_module_input_data.dart b/lib/input_data/tokenization_module_input_data.dart new file mode 100644 index 0000000..285a5b0 --- /dev/null +++ b/lib/input_data/tokenization_module_input_data.dart @@ -0,0 +1,75 @@ +import 'package:yookassa_payments_flutter/models/amount.dart'; +import 'package:yookassa_payments_flutter/models/customization_settings.dart'; +import 'package:yookassa_payments_flutter/models/google_pay_parameters.dart'; +import 'package:yookassa_payments_flutter/models/method_save_payment.dart'; +import 'package:yookassa_payments_flutter/models/test_mode_settings.dart'; +import 'package:yookassa_payments_flutter/models/tokenization_settings.dart'; +import 'package:yookassa_payments_flutter/models/host_parameters.dart'; + +class TokenizationModuleInputData { + String clientApplicationKey; + String title; + String subtitle; + Amount amount; + SavePaymentMethod savePaymentMethod; + String applePayID; + String shopId; + String moneyAuthClientId; + HostParameters? hostParameters; + String? gatewayId; + TokenizationSettings tokenizationSettings; + TestModeSettings? testModeSettings; + String? returnUrl; + bool isLoggingEnabled; + String? userPhoneNumber; + CustomizationSettings customizationSettings; + String? applicationScheme; + String? customerId; + GooglePayParameters googlePayParameters; + bool googlePayTestEnvironment; + + TokenizationModuleInputData( + {required this.clientApplicationKey, + required this.title, + required this.subtitle, + required this.amount, + required this.savePaymentMethod, + required this.applePayID, + required this.shopId, + required this.moneyAuthClientId, + this.hostParameters, + this.gatewayId, + this.tokenizationSettings = const TokenizationSettings(), + this.testModeSettings, + this.returnUrl, + this.isLoggingEnabled = false, + this.userPhoneNumber, + this.customizationSettings = const CustomizationSettings(), + this.applicationScheme, + this.customerId, + this.googlePayParameters = const GooglePayParameters(), + this.googlePayTestEnvironment = false}); + + Map toJson() => { + 'clientApplicationKey': clientApplicationKey, + 'title': title, + 'subtitle': subtitle, + 'amount': amount.toJson(), + 'savePaymentMethod': savePaymentMethod.toString(), + 'hostParameters': hostParameters?.toJson(), + 'gatewayId': gatewayId, + 'tokenizationSettings': tokenizationSettings.toJson(), + 'testModeSettings': testModeSettings?.toJson(), + 'applePayMerchantIdentifier': applePayID, + 'shopId': shopId, + 'returnUrl': returnUrl, + 'isLoggingEnabled': isLoggingEnabled, + 'userPhoneNumber': userPhoneNumber, + 'customizationSettings': customizationSettings.toJson(), + 'moneyAuthClientId': moneyAuthClientId, + 'applicationScheme': applicationScheme, + 'customerId': customerId, + 'googlePayParameters': googlePayParameters.jsonList(), + 'googlePayTestEnvironment': googlePayTestEnvironment + }; +} diff --git a/lib/models/amount.dart b/lib/models/amount.dart new file mode 100644 index 0000000..03f6822 --- /dev/null +++ b/lib/models/amount.dart @@ -0,0 +1,14 @@ +import 'currency.dart'; + +class Amount { + double value; + Currency currency; + + Amount({required this.value, required this.currency}); + + Map toJson() => + { + 'value': value, + 'currency': currency.value + }; +} \ No newline at end of file diff --git a/lib/models/currency.dart b/lib/models/currency.dart new file mode 100644 index 0000000..3ea7c4a --- /dev/null +++ b/lib/models/currency.dart @@ -0,0 +1,8 @@ +class Currency { + final String value; + const Currency(this.value); + + static const Currency rub = Currency('RUB'); + static const Currency usd = Currency('USD'); + static const Currency eur = Currency('EUR'); +} \ No newline at end of file diff --git a/lib/models/customization_settings.dart b/lib/models/customization_settings.dart new file mode 100644 index 0000000..59da49b --- /dev/null +++ b/lib/models/customization_settings.dart @@ -0,0 +1,19 @@ +import 'package:flutter/cupertino.dart'; + +class CustomizationSettings { + final Color mainScheme; + final bool showYooKassaLogo; + + const CustomizationSettings([this.mainScheme = const Color.fromARGB(255, 0, 112, 240), this.showYooKassaLogo = true]); + + Map toJson() => + { + 'mainScheme' : { + 'red': mainScheme.red, + 'blue': mainScheme.blue, + 'green': mainScheme.green, + 'alpha': mainScheme.alpha + }, + 'showYooKassaLogo': showYooKassaLogo + }; +} \ No newline at end of file diff --git a/lib/models/google_pay_parameters.dart b/lib/models/google_pay_parameters.dart new file mode 100644 index 0000000..20a8990 --- /dev/null +++ b/lib/models/google_pay_parameters.dart @@ -0,0 +1,18 @@ +class GooglePayParameters { + final List paymentSystems; + const GooglePayParameters([this.paymentSystems = const [GooglePayCardNetwork.mastercard, GooglePayCardNetwork.visa]]); + + List jsonList() { + return paymentSystems.map((e) => e.toString()).toList(); + } +} + +enum GooglePayCardNetwork { + amex, + discover, + jcb, + mastercard, + visa, + interac, + other +} \ No newline at end of file diff --git a/lib/models/host_parameters.dart b/lib/models/host_parameters.dart new file mode 100644 index 0000000..fd43b71 --- /dev/null +++ b/lib/models/host_parameters.dart @@ -0,0 +1,31 @@ +class HostParameters { + + String host; + String paymentAuthorizationHost; + String authHost; + String configHost; + + HostParameters( + this.host, + this.paymentAuthorizationHost, + this.authHost, + this.configHost, + ); + + Map toJson() => + { + 'apiHost': host, + 'paymentAuthApiHost': paymentAuthorizationHost, + 'authApiHost': authHost, + 'configHost': configHost + }; + + factory HostParameters.fromJson(Map json) { + return HostParameters( + json['apiHost'] as String, + json['paymentAuthApiHost'] as String, + json['authApiHost'] as String, + json['configHost'] as String, + ); + } +} \ No newline at end of file diff --git a/lib/models/method_save_payment.dart b/lib/models/method_save_payment.dart new file mode 100644 index 0000000..04db532 --- /dev/null +++ b/lib/models/method_save_payment.dart @@ -0,0 +1,5 @@ +enum SavePaymentMethod { + off, + on, + userSelects +} \ No newline at end of file diff --git a/lib/models/payment_method_types.dart b/lib/models/payment_method_types.dart new file mode 100644 index 0000000..c7424e6 --- /dev/null +++ b/lib/models/payment_method_types.dart @@ -0,0 +1,29 @@ +class PaymentMethodTypes { + final List paymentMethodTypes; + const PaymentMethodTypes(this.paymentMethodTypes); + + List jsonList() { + return paymentMethodTypes.map((e) => e.toString()).toList(); + } + + static const PaymentMethodTypes bankCard = PaymentMethodTypes([PaymentMethod.bankCard]); + static const PaymentMethodTypes yooMoney = PaymentMethodTypes([PaymentMethod.yooMoney]); + static const PaymentMethodTypes sberbank = PaymentMethodTypes([PaymentMethod.sberbank]); + static const PaymentMethodTypes applePay = PaymentMethodTypes([PaymentMethod.applePay]); + static const PaymentMethodTypes googlePay = PaymentMethodTypes([PaymentMethod.googlePay]); + static const PaymentMethodTypes all = PaymentMethodTypes([ + PaymentMethod.bankCard, + PaymentMethod.yooMoney, + PaymentMethod.sberbank, + PaymentMethod.applePay, + PaymentMethod.googlePay + ]); +} + +enum PaymentMethod { + bankCard, + yooMoney, + applePay, + googlePay, + sberbank +} \ No newline at end of file diff --git a/lib/models/test_mode_settings.dart b/lib/models/test_mode_settings.dart new file mode 100644 index 0000000..d4e4779 --- /dev/null +++ b/lib/models/test_mode_settings.dart @@ -0,0 +1,18 @@ +import 'amount.dart'; + +class TestModeSettings { + bool paymentAuthorizationPassed; + int cardsCount; + Amount charge; + bool enablePaymentError; + + TestModeSettings(this.paymentAuthorizationPassed, this.cardsCount, this.charge, this.enablePaymentError); + + Map toJson() => + { + 'paymentAuthorizationPassed': paymentAuthorizationPassed, + 'cardsCount': cardsCount, + 'charge': charge.toJson(), + 'enablePaymentError': enablePaymentError + }; +} \ No newline at end of file diff --git a/lib/models/tokenization_result.dart b/lib/models/tokenization_result.dart new file mode 100644 index 0000000..7c76f31 --- /dev/null +++ b/lib/models/tokenization_result.dart @@ -0,0 +1,35 @@ +import 'package:yookassa_payments_flutter/models/payment_method_types.dart'; + +class TokenizationResult { + String token; + PaymentMethod? paymentMethodType; + + TokenizationResult(this.token, this.paymentMethodType); + + factory TokenizationResult.fromJson(Map json) { + var token = json['paymentToken']; + + PaymentMethod? paymentMethodType; + switch(json['paymentMethodType']){ + case "sberbank": + paymentMethodType = PaymentMethod.sberbank; + break; + case "bank_card": + paymentMethodType = PaymentMethod.bankCard; + break; + case "yoo_money": + paymentMethodType = PaymentMethod.yooMoney; + break; + case "apple_pay": + paymentMethodType = PaymentMethod.applePay; + break; + case "google_pay": + paymentMethodType = PaymentMethod.googlePay; + break; + default: + break; + } + + return TokenizationResult(token, paymentMethodType); + } +} \ No newline at end of file diff --git a/lib/models/tokenization_settings.dart b/lib/models/tokenization_settings.dart new file mode 100644 index 0000000..bb8b9db --- /dev/null +++ b/lib/models/tokenization_settings.dart @@ -0,0 +1,12 @@ +import 'payment_method_types.dart'; + +class TokenizationSettings { + final PaymentMethodTypes paymentMethodTypes; + + const TokenizationSettings([this.paymentMethodTypes = PaymentMethodTypes.all]); + + Map toJson() => + { + 'paymentMethodTypes': paymentMethodTypes.jsonList(), + }; +} diff --git a/lib/yookassa_payments_flutter.dart b/lib/yookassa_payments_flutter.dart new file mode 100644 index 0000000..82b7ff7 --- /dev/null +++ b/lib/yookassa_payments_flutter.dart @@ -0,0 +1,41 @@ +export 'models/currency.dart'; +export 'models/amount.dart'; +export 'models/method_save_payment.dart'; +export 'models/payment_method_types.dart'; +export 'models/tokenization_settings.dart'; +export 'models/customization_settings.dart'; +export 'models/google_pay_parameters.dart'; +export 'models/test_mode_settings.dart'; +export 'input_data/tokenization_module_input_data.dart'; + +import 'input_data/saved_card_module_input_data.dart'; +import 'dart:convert'; +import 'package:flutter/services.dart'; +import 'package:yookassa_payments_flutter/models/tokenization_result.dart'; +import 'input_data/tokenization_module_input_data.dart'; +import 'models/payment_method_types.dart'; + +class YookassaPaymentsFlutter { + static const MethodChannel _channel = MethodChannel('ru.yoomoney.yookassa_payments_flutter/yoomoney'); + + static Future tokenization(TokenizationModuleInputData data) async { + var inputData = data.toJson(); + + return await _channel + .invokeMethod('tokenization', inputData).then((value) => TokenizationResult.fromJson(json.decode(value))); + } + + static Future confirmation(String url, PaymentMethod? paymentMethod) async { + await _channel + .invokeMethod('confirmation', + { + 'url': url, + 'paymentMethod': paymentMethod?.name + } + ); + } + + static Future bankCardRepeat(SavedBankCardModuleInputData data) async { + return await _channel.invokeMethod('repeat', data.toJson()).then((value) => TokenizationResult.fromJson(json.decode(value))); + } +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..96201dd --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,161 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.2" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.16.0" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.4" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.2" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.9" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" +sdks: + dart: ">=2.17.0-0 <3.0.0" + flutter: ">=2.10.5" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..69b2e15 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,35 @@ +name: yookassa_payments_flutter +description: This Flutter SDK allows processing payments using a payment token. It works as an addition to the YooMoney API. +version: 1.0.1 +homepage: https://git.yoomoney.ru/projects/SDK/repos/yookassa-payments-flutter-sdk/browse +repository: https://git.yoomoney.ru/projects/SDK/repos/yookassa-payments-flutter-sdk/browse + +environment: + sdk: ">=2.12.0 <3.0.0" + flutter: ">=2.10.5" + +dependencies: + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^1.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + # This section identifies this Flutter project as a plugin project. + # The 'pluginClass' and Android 'package' identifiers should not ordinarily + # be modified. They are used by the tooling to maintain consistency when + # adding or updating assets for this project. + plugin: + platforms: + android: + package: ru.yoomoney.sdk.kassa.payments.flutter + pluginClass: YookassaPaymentsFlutterPlugin + ios: + pluginClass: YookassaPaymentsFlutterPlugin \ No newline at end of file diff --git a/test/yookassa_payments_flutter_test.dart b/test/yookassa_payments_flutter_test.dart new file mode 100644 index 0000000..a952cd0 --- /dev/null +++ b/test/yookassa_payments_flutter_test.dart @@ -0,0 +1,18 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + const MethodChannel channel = MethodChannel('yookassa_payments_flutter'); + + TestWidgetsFlutterBinding.ensureInitialized(); + + setUp(() { + channel.setMockMethodCallHandler((MethodCall methodCall) async { + return '42'; + }); + }); + + tearDown(() { + channel.setMockMethodCallHandler(null); + }); +}