Распознавание дебетовых и кредитных карт

API Google для распознавания платежных карт позволяет считывать данные, указанные на платежной карте, с помощью камеры. Считывание номера PAN и даты окончания срока действия кредитной или платежной карты выполняется с помощью функции оптического распознавания символов. Для сканирования карты используются сервисы Google Play. Результаты сканирования передаются в ваше приложение, поэтому ему не требуется доступ к камере. Изображения обрабатываются непосредственно на устройстве. Google не хранит результаты сканирования и не предоставляет доступ к изображениям.

Чтобы функция распознавания карт работала правильно, устройство должно соответствовать следующим требованиям:

  • находиться в регионе AU, BR, CA, CH, CZ, DK, ES, FI, FR, GB, HK, IE, JP, KR, NL, NO, NZ, PL, RU, SE, SG, TW, UA или US;
  • иметь не менее 1 ГБ ОЗУ;
  • иметь заднюю камеру;
  • поддерживать вертикальную ориентацию (PORTRAIT).

Создание запроса

Создайте экземпляр PaymentsClient в методе onCreate объекта Activity. Объект PaymentsClient можно использовать для взаимодействия с Google Pay API.

Kotlin

    fun createPaymentsClient(activity: Activity): PaymentsClient {
        val walletOptions = Wallet.WalletOptions.Builder()
                .setEnvironment(Constants.PAYMENTS_ENVIRONMENT)
                .build()

        return Wallet.getPaymentsClient(activity, walletOptions)
    }

Java

  public static PaymentsClient createPaymentsClient(Activity activity) {
    Wallet.WalletOptions walletOptions =
        new Wallet.WalletOptions.Builder().setEnvironment(Constants.PAYMENTS_ENVIRONMENT).build();
    return Wallet.getPaymentsClient(activity, walletOptions);
  }

После того как ответ будет создан, можно отправить асинхронный запрос, чтобы получить объект PendingIntent, с помощью которого можно запустить операцию распознавания карты.

Обратите внимание, что выполнить запрос удается не всегда. Сбой может произойти, если API отключен. Приложение должно правильно обрабатывать такие ответы. В нашем примере кнопка отображается только после того, как запрос будет успешно выполнен.

Kotlin

    private fun possiblyShowPaymentCardOcrButton() {
        // The request can be used to configure the type of the payment card recognition. Currently
        // the only supported type is card OCR, so it is sufficient to call the getDefaultInstance()
        // method.
        val request = PaymentCardRecognitionIntentRequest.getDefaultInstance()
        paymentsClient
            .getPaymentCardRecognitionIntent(request)
            .addOnSuccessListener { intentResponse ->
                cardRecognitionPendingIntent = intentResponse.paymentCardRecognitionPendingIntent
                paymentCardOcrButton.visibility = View.VISIBLE
            }
            .addOnFailureListener { e ->
                // The API is not available either because the feature is not enabled on the device
                // or because your app is not registered.
                Log.e(TAG, "Payment card ocr not available.", e)
            }
    }

Java

  public void possiblyShowPaymentCardOcrButton() {
    // The request can be used to configure the type of the payment card recognition. Currently the
    // only supported type is card OCR, so it is sufficient to call the getDefaultInstance() method.
    PaymentCardRecognitionIntentRequest request =
        PaymentCardRecognitionIntentRequest.getDefaultInstance();
    paymentsClient
        .getPaymentCardRecognitionIntent(request)
        .addOnSuccessListener(intentResponse -> {
          cardRecognitionPendingIntent = intentResponse.getPaymentCardRecognitionPendingIntent();
          paymentCardOcrButton.setVisibility(View.VISIBLE);
        })
        .addOnFailureListener(e -> {
          // The API is not available either because the feature is not enabled on the device
          // or because your app is not registered.
          Log.e(TAG, "Payment card ocr not available.", e);
        });
  }

В следующем примере кода показано, как запустить операцию распознавания платежной карты:

Kotlin

    private fun startPaymentCardOcr() {
        try {
            ActivityCompat.startIntentSenderForResult(
                this@CheckoutActivity,
                cardRecognitionPendingIntent.intentSender,
                PAYMENT_CARD_RECOGNITION_REQUEST_CODE,
                null, 0, 0, 0, null
            )
        } catch (e: SendIntentException) {
            throw RuntimeException("Failed to start payment card recognition.", e)
        }
    }

Java

  public void startPaymentCardOcr(View view) {
    try {
      ActivityCompat.startIntentSenderForResult(
          CheckoutActivity.this, cardRecognitionPendingIntent.getIntentSender(),
          PAYMENT_CARD_RECOGNITION_REQUEST_CODE,
          null, 0, 0, 0, null);
    } catch (SendIntentException e) {
      throw new RuntimeException("Failed to start payment card recognition.", e);
    }
  }

Интерпретация результатов

Если системе удалось распознать платежную карту, API вернет результат в виде объекта PaymentCardRecognitionResult, который обязательно содержит номер карты. Дата окончания срока действия может отсутствовать, если системе не удалось ее распознать или если срок действия карты истек. Если карта не распознана, например из-за того, что пользователь прервал процесс, результатом будет объект Activity.RESULT_CANCELLED.

Kotlin

    private fun handlePaymentCardRecognitionSuccess(
        cardRecognitionResult: PaymentCardRecognitionResult
    ) {
        val creditCardExpirationDate = cardRecognitionResult.creditCardExpirationDate
        val expirationDate = creditCardExpirationDate?.let { "%02d/%d".format(it.month, it.year) }
        val cardResultText = "PAN: ${cardRecognitionResult.pan}\nExpiration date: $expirationDate"
        Toast.makeText(this, cardResultText, Toast.LENGTH_LONG).show()
    }

Java

  private void handleCardRecognitionSuccess(PaymentCardRecognitionResult cardResult) {

    String expirationDate = null;
    Locale locale = Locale.getDefault();
    CreditCardExpirationDate cardExpirationDate = cardResult.getCreditCardExpirationDate();
    if(cardExpirationDate != null) {
      expirationDate = String.format(locale,
          "%02d/%d", cardExpirationDate.getMonth(), cardExpirationDate.getYear());
    }

    String cardResultString = String.format(locale,
        "PAN: %s\nExpiration date: %s", cardResult.getPan(), expirationDate);
    Toast.makeText(this, cardResultString, Toast.LENGTH_LONG).show();
  }