Skip to content

Android SDK

SDK (Software Development Kit) для Android — это набор инструментов, библиотек и документации, предназначенных для разработки приложений под операционную систему Android. SDK Android может использоваться для интеграции с API платежных систем. Он предоставляет инструменты и библиотеки, которые помогают разработчикам создавать приложения, способные взаимодействовать с платежными API.

V2 - новая версия

1 Подключение sdk

2 Настройки PROGUARD

3 Flutter - дополнительные шаги интеграции

4 Подключение нативного GooglePay

5 API создания платежа

6 API формы стандартного флоу

7 API GooglePay

8 API сохраненных карт

1 Подключение sdk

В build.gradle модуля добавь implementation 'kz.airbapay:apay_android:~'

Для инициализации sdk нужно выполнить AirbaPaySdk.initSdk()

ПараметрТипОписание
context*ContextКонтекст приложения
lang*AirbaPaySdk.LangКод языка для UI
isProd*BooleanПрод или тест среда Airbapay
phone*StringНомер телефона клиента
userEmail*StringEmail клиента
colorBrandMainandroidx.compose.ui.graphics.ColorБрендовый цвет кнопок, переключателей и текста
colorBrandInversionandroidx.compose.ui.graphics.ColorЦвет текста у кнопок с брендовым цветом
enabledLogsForProdBooleanФлаг для включения логов
actionOnCloseProcessing*(Activity, Boolean) -> UnitЛямбда, вызываемая при клике на кнопку "Вернуться в магазин" и при отмене процесса. Разработчику в ней нужно прописать код для возврата в приложение. Обязательно добавить в конце activity.finish()
needDisableScreenShotBooleanФлаг включения/отключения защиты от скриншота страниц. По дефолту выключен
openCustomPageSuccess((Activity) -> Unit)?Лямбда кастомной страницы успеха
openCustomPageFinalError((Activity) -> Unit)?Лямбда кастомной страницы финальной ошибки
kotlin
AirbaPaySdk.initSdk(
    context = this.application,
    lang = AirbaPaySdk.Lang.RU,
    isProd = false, 
    phone = "77051000000",
    userEmail = "test@test.com", 
    colorBrandMain = Color.Red,
    actionOnCloseProcessing = { activity, isSuccess ->

         if (isSuccess) { 
                  startActivity(Intent(activity, SuccessActivity::class.java)) 
         } else {
                  startActivity(Intent(activity, ErrorActivity::class.java)) 
         }
         activity.finish()
    }
)

При смене значения isProd, требуется выгрузить приложение из памяти.

Для проекта без Jetpack Compose потребуются дополнительные настройки проекта.

Добавить в build.gradle app и, в случае модульной архитектуры, в модуль, где будет использоваться:

kotlin
android {
 
    buildFeatures {
       compose true
       viewBinding true
    }
    
    composeOptions {
       kotlinCompilerExtensionVersion '1.5.9'
    }
    
    kotlinOptions {
      jvmTarget = 17
    }
}

В зависимости от версии котлина, потребуется подобрать версию kotlinCompilerExtensionVersion https://developer.android.com/jetpack/androidx/releases/compose-kotlin

kotlin
dependencies {

    implementation "kz.airbapay:apay_android:$apay_version"
    implementation platform("androidx.compose:compose-bom:2024.01.00")
    implementation 'androidx.compose.ui:ui-graphics'
    implementation 'androidx.compose.ui:ui'

}

2 Настройки PROGUARD

В случае, если используется Proguard, нужно добавить настройки

# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
# EnclosingMethod is required to use InnerClasses.
-keepattributes Signature, InnerClasses, EnclosingMethod

# Retrofit does reflection on method and parameter annotations.
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations

# Keep annotation default values (e.g., retrofit2.http.Field.encoded).
-keepattributes AnnotationDefault

# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
    @retrofit2.http.* <methods>;
}

# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement

# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**

# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
-dontwarn kotlin.Unit

# Top-level functions that can only be used by Kotlin.
-dontwarn retrofit2.KotlinExtensions
-dontwarn retrofit2.KotlinExtensions$*

# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>

# Keep inherited services.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface * extends <1>

# With R8 full mode generic signatures are stripped for classes that are not
# kept. Suspend functions are wrapped in continuations where the type argument
# is used.
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation

# R8 full mode strips generic signatures from return types if not kept.
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>

# With R8 full mode generic signatures are stripped for classes that are not kept.
-keep,allowobfuscation,allowshrinking class retrofit2.Response

3 Flutter - дополнительные шаги интеграции

В dart добавьте:

kotlin
final MethodChannel channel = MethodChannel("com.example.testFlutter/AirbaPayChannel");
   
Future<void> callNativeMethod() async {
    try {
      await channel.invokeMethod('pay');
    } catch (e) {
      print('Error calling native method: $e');
    }
}

И нужно вызвать callNativeMethod для перехода на страницы сдк.

Нужно создать дополнительный промежуточный активити FlutterAirbaPayActivity,

в котором будет производиться инициализация и переход на страницу сдк. Это нужно, чтоб при нажатии назад из сдк, не закрывалось приложение.

Добавить в манифест описание этого активити

kotlin
<activity android:name=".pay.airba.FlutterAirbaPayActivity"
    android:theme="@style/AppTheme.AppCompat"
    android:exported="false" />

В MainActivity нужно добавить

kotlin
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
     MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "com.example.testFlutter/AirbaPayChannel")
         .setMethodCallHandler { call: MethodCall, result: Result ->
             if (call.method == "pay") {
                 result.success(null)
                 FlutterAirbaPayActivity.start(this, call, result)
             } else {
                 result.notImplemented()
             }
         }
}

В FlutterAirbaPayActivity

kotlin
class FlutterAirbaPayActivity : AppCompatActivity() {
    /**
     * Два состояния для activity:
     *
     * 1. started airba pay flow
     * 2. finished airba pay flow
     */
    private var isFlowStarted = false

    companion object {
        fun start(context: Activity, call: MethodCall, result: MethodChannel.Result) {
            val intent = Intent(context, FlutterAirbaPayActivity::class.java)
            context.startActivityForResult(intent, 123)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        AirbaPaySdk.initSdk(
            ~~~,
            actionOnCloseProcessing = { activity, paymentSubmittingResult ->
               close(paymentSubmittingResult, activity)
            }
        )

        AirbaPaySdk.standardFlow(this)
    }

    /**
     * Finishes this activity with setting result
     *
     * @see handleAirbaActivityResult
     */
    private fun close(result: Boolean, childActivity: Activity? = null) {
        setResult(
            Activity.RESULT_OK,
            Intent().putExtra("result", result)
        )
        finish()
        childActivity?.finish()
    }

    override fun onStart() {
        super.onStart()
        if(!isFlowStarted) {
            // 1. started airba pay flow (invoked after onCreate)
            isFlowStarted = true
        } else {
            // 2. finished airba pay flow (invoked after backButton pressed or etc)
            close(false)
        }
    }
}

4 Подключение нативного GooglePay

  1. Добавить в standardFlow параметр isGooglePayNative: true
  2. Перейти в консоль GooglePay https://pay.google.com/business/console/ и перейти в пункт меню Google Pay API
  3. Найти в списке “Integrate with your Android app” ваше приложение и кликнуть “Управление”
  4. Выберите тип интеграции “Через шлюз”.
  5. Загрузите скриншоты по списку указанному ниже и нажмите “Сохранить”
  6. Кликните “Submit for approval”
  7. В случае отказа по каким-либо причинам (к примеру, дизайн кнопки не соответствует их требованиям), нужно будет ответить на письмо гугла, что вы используете стороннее решение компании Airba Pay

5 API создания платежа

Запрос на авторизацию в системе AirbaPay через передачу логина, пароля и айди терминала. Возвращает токен. authPassword()

ПараметрТипОписание
terminalId*StringID терминала под которым создаётся платеж
shopId*StringID магазина в системе AirbaPay
password*StringПароль в системе AirbaPay
paymentIdString?ID платежа. В абсолютном большинстве случаев в этом запросе будет null. Нужен для обновления токена с новым paymentId
onSuccess*(String) -> UnitЛямбда на успех. Возвращает токен
onError*() -> UnitЛямбда на ошибку
kotlin
AirbaPaySdk.authPassword(
     onSuccess = { token -> ~  },
     onError = { ~ },
     shopId = "test", 
     password = "test123!", 
     terminalId = "123qdfssdf"
)

Запрос на авторизацию в системе AirbaPay через передачу JWT. authJwt()

ПараметрТипОписание
jwt*StringJWT токен
onSuccess*() -> UnitЛямбда на успех.
onError*() -> UnitЛямбда на ошибку
kotlin
AirbaPaySdk.authJwt(
     onSuccess = { ~  },
     onError = { ~ },
     jwt = "~"
)

Запрос на инициализацию платежа в системе AirbaPay. Возвращает AirbaPaySdk.CreatePaymentResult.

createPayment()

ПараметрТипОписание
authToken*StringТокен, полученный из auth или другой реализацией получения токена
failureCallback*StringURL вебхука при ошибке
successCallback*StringURL вебхука при успехе
purchaseAmount*DoubleСумма платежа
accountId*StringID аккаунта пользователя
invoiceId*StringID платежа в системе магазина
orderNumber*StringНомер заказа в системе магазина
onSuccess*(AirbaPaySdk.CreatePaymentResult) -> UnitЛямбда на успех. Возвращает AirbaPaySdk.CreatePaymentResult
onError*() -> UnitЛямбда на ошибку
renderGooglePayBoolean?Флаг настройки показа функционала GooglePay в стандартном флоу. NULL - параметры с сервера
renderSavedCardsBoolean?Флаг настройки показа функционала сохраненных карт в стандартном флоу. NULL - параметры с сервера
renderSecurityBiometryBoolean?Флаг глобальной настройки в SDK для биометрии при оплате сохраненной картой или GooglePay. NULL - параметры с сервера
renderSecurityCvvBoolean?Флаг глобальной настройки в SDK для показа боттомщита с CVV при оплате сохраненной картой. NULL - параметры с сервера
autoChargeIntАвтоматическое подтверждение при 2х-стадийном режиме 0 - нет, 1 - да
goodsList<AirbaPaySdk.Goods>Список продуктов для оплаты. Если есть необходимость передачи списка товаров в систему
settlementPaymentsList<AirbaPaySdk.SettlementPayment>Распределение платежа по компаниям. В случае одной компании, может быть null
kotlin
AirbaPaySdk.createPayment(
    authToken = token,
    accountId = "77061111112",
    onSuccess = { result -> ~ },
    onError = { ~ },
    failureCallback = "https://site.kz/failure-clb",
    successCallback = "https://site.kz/success-clb",
    purchaseAmount = 1500.45,
    invoiceId = "1111111111",
    orderNumber = "ab1111111111"
)

AirbaPaySdk.CreatePaymentResult

ПараметрТипОписание
tokenString?Обновленный токен
paymentIdString?ID созданного платежа

6 API формы стандартного флоу

Предварительно выполнить AirbaPaySdk.authPassword() вместе с AirbaPaySdk.createPayment() Или выполнить только AirbaPaySdk.authJwt()

Есть два варианта реализации стандартного флоу:

standardFlow().

ПараметрТипОписание
context*ContextКонтекст приложения
isGooglePayNativeBooleanФлаг, определяющий показ нативной кнопки GooglePay вместо вебвьюшки
kotlin
AirbaPaySdk.standardFlow(
  context = context,
  isGooglePayNative = true
)

standardFlowWebView()

ПараметрТипОписание
isLoadingComplete*() -> UnitЛямбда на завершение загрузки данных о платеже
onError*() -> UnitЛямбда на ошибку
shouldOverrideUrlLoading*(obj: AirbaPaySdk.ShouldOverrideUrlLoading) -> BooleanЛямбда, в которой описаны действия на коллбэки с вебвьюшки

AirbaPaySdk.ShouldOverrideUrlLoading

ПараметрТипОписание
isCallbackSuccess*BooleanФлаг, что можно вызвать переход на страницу успеха
isCallbackBackToApp*BooleanФлаг, что можно вызвать переход в приложение. true - если была нажата стрелака "назад" или кнопка "Вернуться в магазин" на страницах ошибки
url*String?Проброс урла из коллбэка вебвьюшки
webView*WebView?Проброс webview из коллбэка вебвьюшки
kotlin
AirbaPaySdk.standardFlowWebView(
   isLoadingComplete: { isLoading = false },
   onError: { ~ },
   shouldOverrideUrlLoading = { obj ->
     when {
         obj.isCallbackSuccess -> {
             // открыть страницу успеха
             return@standardFlowWebView true
         }
         obj.isCallbackBackToApp -> {
             // клик на кнопку "Вернуться в магазин" или на стрелку "назад"
             return@standardFlowWebView true
         }
   
         else -> obj.webView?.loadUrl(obj.url ?: "")
     }
   
     return@standardFlowWebView false
   }
)

7 API GooglePay

Для работы с GooglePay за пределами стандартного флоу:

  1. Полностью реализовать на стороне приложения механизм вызова GooglePay боттомщита и получения GooglePay токена. Как получить gatewayMerchantId и merchantId, необходимые для GooglePay, будет указано ниже

  2. Выполнить пункт "4 Подключение нативного GooglePay"

  3. Предварительно выполнить AirbaPaySdk.authPassword() вместе с AirbaPaySdk.createPayment() Или выполнить только AirbaPaySdk.authJwt()

  4. Вызвать AirbaPaySdk.getGooglePayMerchantIdAndGateway() для получения объекта GooglePayMerchantResponse

    ПараметрТипОписание
    onSuccess*(GooglePayMerchantResponse) -> UnitЛямбда на успех
    onError*() -> UnitЛямбда на ошибку

    GooglePayMerchantResponse

    ПараметрТипОписание
    gatewayMerchantIdString?gatewayMerchantId для GooglePay
    merchantId?StringmerchanId для GooglePay
  5. Вызвать после получения токена GooglePay функцию processExternalGooglePay()

ПараметрТипОписание
googlePayToken*StringТокен GooglePay
activity*ActivityАктивити
kotlin
AirbaPaySdk.processExternalGooglePay(
   activity = activity,
   googlePayToken = googlePayToken
)

8 API сохраненных карт

Запрос списка сохраненных карт пользователя getCards() Предварительно выполнить AirbaPaySdk.authPassword() или AirbaPaySdk.authJwt()

ПараметрТипОписание
onSuccess*(List<BankCard>) -> UnitЛямбда на успех со списком сохраненных карт
onNoCards*() -> UnitЛямбда на отсутствие сохраненных карт

Запрос удаления сохраненной карты пользователя deleteCard() Предварительно выполнить AirbaPaySdk.authPassword() или AirbaPaySdk.authJwt()

ПараметрТипОписание
cardId*Stringid сохраненной карты из запроса getCards
onSuccess*() -> UnitЛямбда на успех
onError*() -> UnitЛямбда на ошибку

Запрос проведения оплаты по сохраненной карте пользователя paySavedCard() Предварительно выполнить AirbaPaySdk.authPassword() или AirbaPaySdk.authJwt()

ПараметрТипОписание
activity*ActivityActivity
bankCard*BankCardЭкземпляр карты, получаемый из запроса getCards
isLoading*(Bool) -> UnitЛямбда для показа прогрессбара
onError*() -> UnitЛямбда на ошибку

V1 - первая версия SDK до обновления, для новых партнеров использовать V2.

1 Подключение sdk

2 Настройки PROGUARD

3 Вызов стартовой формы

4 Подключение нативного GooglePay

5 Подключение API внешнего взаимодействия с GooglePay

6 Рекомендация в случае интеграции в flutter

1 Подключение sdk

В модуль build.gradle нужно добавить  implementation 'kz.airbapay:apay_android:~'

Для инициализации sdk перед вызовом AirbaPaySdk.startAirbaPay()нужно выполнить AirbaPaySdk.initSdk()

При смене значения isProd, требуется выгрузить приложение из памяти.

ПараметрТипОписание
shopId*stringID магазина в системе AirbaPay
context*contextКонтекст приложения
accountId*stringID аккаунта пользователя
password*stringПароль в системе AirbaPay
terminalId*stringID терминала под которым создали платеж
lang*AirbaPaySdk.LangКод языка для UI
isProd*boolПродовская или тестовая среда airbapay
phone*stringТелефон пользователя
failureCallback*stringURL вебхука при ошибке
successCallback*stringURL вебхука при успехе
userEmail*stringЕмейл пользователя, куда будет отправлена квитанция. В случае отсутствия емейла
colorBrandMainandroidx.compose.ui.graphics.ColorБрендовый цвет кнопок, переключателей и текста
colorBrandInversionandroidx.compose.ui.graphics.ColorЦвет текста у кнопок с брендовым цветом
autoChargeIntАвтоматическое подтверждение при 2х-стадийном режиме 0 - нет, 1 - да
enabledLogsForProdBoolФлаг для включения логов
purchaseAmount*DoubleСумма платежа
invoiceId*stringID платежа в системе магазина
orderNumber*stringНомер заказа в системе магазина
goods*List<AirbaPaySdk.Goods>Список продуктов для оплаты
settlementPaymentsList<AirbaPaySdk.SettlementPayment>Распределение платежа по компаниям. В случае одной компании, может быть null
onProcessingResult*(Activity, Boolean) -> UnitЛямбда, вызываемая при клике на кнопку "Вернуться в магазин" и при отмене процесса. Разработчику в ней нужно прописать код для возврата в приложение. Обязательно добавить в конце activity.finish()
hideInternalGooglePayButtonBooleanФлаг, определяющий, нужно ли скрывать кнопку GooglePay на страницах SDK
isGooglePayNativeBooleanФлаг, определяющий показ нативной кнопки GooglePay вместо вебвьюшки
needDisableScreenShotBooleanФлаг включения/отключения защиты от скриншота страниц. По дефолту выключен
kotlin
val goods = listOf(
           AirbaPaySdk.Goods(
               model = "Чай Tess Banana Split черный 20 пирамидок",
               brand = "Tess",
               category = "Черный чай",
               quantity = 1,
               price = 1000
           )
       )

       val settlementPayment = listOf(
           AirbaPaySdk.SettlementPayment(
               amount = 1000,
               companyId = "test_id"
           )
       )
       
AirbaPaySdk.initSdk(
    context = this.application,
    shopId = "test-merchant",
    password = "123456",
    accountId = "12345979869666",
    terminalId = "64216e7ccc4a48db060dd689",
    lang = AirbaPaySdk.Lang.RU,
    isProd = false, 
    phone = "77051000000",
    failureCallback = "https://site.kz/failure-clb", 
    successCallback = "https://site.kz/success-clb",                
    userEmail = "test@test.com", 
    colorBrandMain = Color.Red,
    purchaseAmount = 1000,
    invoiceId = invoiceId,
    orderNumber = orderNumber,
    goods = goods,
    settlementPayments = settlementPayment,
    onProcessingReult = { activity, isSuccess ->

         if (isSuccess) { 
                  startActivity(Intent(activity, SuccessActivity::class.java)) 
         } else {
                  startActivity(Intent(activity, ErrorActivity::class.java)) 
         }
         activity.finish()
    } 
)

2 Настройки PROGUARD

В случае, если используется Proguard, нужно добавить настройки

jsx
# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
# EnclosingMethod is required to use InnerClasses.
-keepattributes Signature, InnerClasses, EnclosingMethod

# Retrofit does reflection on method and parameter annotations.
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations

# Keep annotation default values (e.g., retrofit2.http.Field.encoded).
-keepattributes AnnotationDefault

# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
    @retrofit2.http.* <methods>;
}

# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement

# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**

# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
-dontwarn kotlin.Unit

# Top-level functions that can only be used by Kotlin.
-dontwarn retrofit2.KotlinExtensions
-dontwarn retrofit2.KotlinExtensions$*

# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>

# Keep inherited services.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface * extends <1>

# With R8 full mode generic signatures are stripped for classes that are not
# kept. Suspend functions are wrapped in continuations where the type argument
# is used.
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation

# R8 full mode strips generic signatures from return types if not kept.
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>

# With R8 full mode generic signatures are stripped for classes that are not kept.
-keep,allowobfuscation,allowshrinking class retrofit2.Response

3 Вызов стартовой формы

Открытие формы AirbaPay выполняется через функцию

AirbaPaySdk.startAirbaPay()

ПараметрТипОписание
activity*ActivityActivity
redirectToCustomSuccessPage(Activity) -> UnitЛямбда, вызываемая для перехода на кастомную страницу успешного завершения. Разработчику в ней нужно прописать код для перехода на кастомную страницу
redirectToCustomFinalErrorPage(Activity) -> UnitЛямбда, вызываемая для перехода на кастомную страницу Финальной ошибки (остальные ошибки показываются в дефолтной странице ошибки). Разработчику в ней нужно прописать код для перехода на кастомную страницу

Пример без кастомной страницы:

kotlin
startAirbaPay(activity = this@MainActivity)

Пример с кастомной станицей:

kotlin
startAirbaPay(
    activity = this@MainActivity,
    redirectToCustomSuccessPage = {
        val intent = Intent(activity, CustomSuccessActivity::java.class)
        activity.startActivity()
        activity.finish()
    }
)

Для проекта без Jetpack Compose  потребуются дополнительные настройки проекта.

Добавить конфигурации в build.gradle. Модуль app и в модули где будет использоваться.

В зависимости от версии котлина, потребуется подобрать версию kotlinCompilerExtensionVersion Compose to Kotlin Compatibility Map  |  Android Developers

Конфигурации:

kotlin
android {
  buildFeatures {
    compose true
    viewBinding true
  }

  composeOptions {
    kotlinCompilerExtensionVersion '1.5.9'
  }

  kotlinOptions {
    jvmTarget = 17
  }
kotlin
dependencies {
  implementation "kz.airbapay:apay_android:$apay_version"
  implementation platform("androidx.compose:compose-bom:2024.01.00")
  implementation 'androidx.compose.ui:ui-graphics'
  implementation 'androidx.compose.ui:ui'
}

4 Подключение нативного GooglePay

  1. Изменить параметр isGooglePayNative в initSdk на true

  2. Перейти в консоль GooglePay https://pay.google.com/business/console/ и перейти в пункт меню

    Google Pay API

  3. Найти в списке “Integrate with your Android app” ваше приложение и кликнуть “Управление”

  4. Выберите тип интеграции “Через шлюз”.

  5. Загрузите скриншоты по списку указанному ниже и нажмите “Сохранить”

  6. Кликните “Submit for approval”

  7. В случае отказа по каким-либо причинам (к примеру, дизайн кнопки не соответствует их

    требованиям), нужно будет ответить на письмо гугла, что вы используете стороннее решение компании Airba Pay

5 Подключение API внешнего взаимодействия с GooglePay

  1. Добавить val googlePayViewModel = GooglePayViewModel() и повесить на клик последовательный вызов функций:

auth(~)

ПараметрТипОписание
onSuccess*(GooglePayMerchantResponse) -> UnitКоллбэк возврата данных для gateway и gatewayMerchantId
onError*() -> UnitКоллбэк ошибки
googlePayToken*StringТокен, полученный из гугл пэй
kotlin
AirbaPaySdk.initSdk(
   ~
   isGooglePayNative = true
)

googlePayViewModel.auth(
activity = activity,
onSuccess = { response ->
        isLoading.value = false

        val gatewayMerchantId: String? = response.gatewayMerchantId
        val gateway: String? = response.gateway
        
        // Здесь вызвать получение токена гугл пэя через шаг №2
    },
    onError = {
        isLoading.value = false
        // вывод сообщения об ошибке
    }
)
  1. Пройти шаги интеграции из

https://developers.google.com/pay/api/android/guides/setup?hl=ru

и

https://developers.google.com/pay/api/android/guides/tutorial?hl=ru

В запросе на получение токена обязательно указать информацию как указано ниже

.put("merchantInfo", JSONObject().put("merchantName", "AirbaPay"))

.put("parameters", JSONObject(mapOf("gateway" to gateway,"gatewayMerchantId" to gatewayMerchantId)))

  1. Далее вызвать processingWalletExternal(~)
ПараметрТипОписание
googlePayTokenStringТокен, полученный из гугл пэй
activityActivityАктивити
coroutineScopeCoroutineScopeCoroutineScope
kotlin
googlePayViewModel.processingWalletExternal(
    activity = activity,
    coroutineScope = coroutineScope!!,
    googlePayToken = googlePayToken
)

6 Рекомендация в случае интеграции в flutter

В dart добавьте:

И нужно вызвать callNativeMethod для перехода на страницы сдк.

Нужно создать дополнительный промежуточный активити FlutterAirbaPayActivity, в котором будет производиться инициализация и переход на страницу сдк. Это нужно, чтоб при нажатии назад из сдк, не закрывалось приложение.

dart
  final MethodChannel channel = MethodChannel("com.example.testFlutter/AirbaPayChannel");

  Future<void> callNativeMethod() async {
    try {
      await channel.invokeMethod('pay');
    } catch (e) {
      print('Error calling native method: $e');
    }
  }

Добавить в манифест описание этого активити

xml
<activity android:name=".pay.airba.FlutterAirbaPayActivity"
    android:taskAffinity="kz.airbapay.apay_android"
    android:exported="false" />

В MainActivity нужно добавить

dart
 override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "com.example.testFlutter/AirbaPayChannel")
            .setMethodCallHandler { call: MethodCall, result: Result ->
                if (call.method == "pay") {
                    result.success(null)
                   FlutterAirbaPayActivity.start(this, call, result)
                } else {
                    result.notImplemented()
                }
            }
    }

В FlutterAirbaPayActivity

dart

class FlutterAirbaPayActivity : AppCompatActivity() {
    /**
     * Два состояния для активити :
     *
     * 1. started airba pay flow
     * 2. finished airba pay flow
     */
    private var isFlowStarted = false

    companion object {
        fun start(context: Activity, call: MethodCall, result: MethodChannel.Result) {
            val intent = Intent(context, AirbaPayActivity::class.java)
            context.startActivityForResult(intent, 123)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val someInvoiceId = ...
        val someOrderNumber = ...

        val goods = listOf(
            AirbaPaySdk.Goods(
                model = "description",
                brand = "Название вашей компании",
                category = "Название категории",
                quantity = 1,
                price = 1500L,
            ),
        )
        AirbaPaySdk.initSdk(
            context = this,
            isProd = true,
            phone = "+77051234567",
            shopId = "test-baykanat",
lang = AirbaPaySdk.Lang.RU,
password = "baykanat123!",
terminalId = "65c5df69e8037f1b451a0594",
            failureCallback = "https://site.kz/failure-clb",
            successCallback = "https://site.kz/success-clb",
            userEmail = "test@test.com",
            accountId = "1000000000",
            purchaseAmount = 1500L,
            invoiceId = someInvoiceId.toString(),
            orderNumber = someInvoiceId.toString(),
            goods = goods,
        ) { activity, paymentSubmittingResult ->
            close(paymentSubmittingResult, activity)
        }

        AirbaPaySdk.startAirbaPay(
            this,
            redirectToCustomSuccessPage = { activity ->
                close(true, activity)
            },
        )
    }

    /**
     * Finishes this activity with setting result
     *
     * @see handleAirbaActivityResult
     */
    private fun close(result: Boolean, childActivity: Activity? = null) {
        setResult(
            Activity.RESULT_OK,
            Intent().putExtra("result", result)
        )
        finish()
        childActivity?.finish()
    }

    override fun onStart() {
        super.onStart()
        if(!isFlowStarted) {
            // 1. started airba pay flow (invoked after onCreate)
            isFlowStarted = true
        } else {
            // 2. finished airba pay flow (invoked after backButton pressed or etc)
            close(false)
        }
    }
}