Menyediakan informasi pengiriman dan kontak dari aplikasi pembayaran Android

Cara mengupdate aplikasi pembayaran Android agar memberikan alamat pengiriman dan informasi kontak pembayar dengan Web Payments API.

Sahel Sharify
Sahel Sharify

Memasukkan alamat pengiriman dan informasi kontak melalui formulir web dapat menjadi dan pengalaman yang rumit bagi pelanggan. Dapat menyebabkan error dan menurunkan konversi besar.

Itulah mengapa Payment Request API mendukung fitur untuk meminta pengiriman alamat dan informasi kontak Anda. Hal ini memberikan beberapa manfaat:

  • Pengguna dapat memilih alamat yang tepat hanya dengan beberapa ketukan.
  • Alamat akan selalu ditampilkan dalam nilai format.
  • Sebaiknya Anda mengirimkan alamat yang salah.

Browser dapat menunda pengumpulan alamat pengiriman dan informasi kontak ke aplikasi pembayaran untuk memberikan pengalaman pembayaran terpadu. Fungsi ini adalah yang disebut delegasi.

Jika memungkinkan, Chrome akan mendelegasikan pengumpulan data pengiriman pelanggan dan informasi kontak ke aplikasi pembayaran Android yang dipanggil. Tujuan delegasi mengurangi friksi selama {i>checkout<i}.

Situs penjual dapat memperbarui opsi pengiriman dan harga total secara dinamis bergantung pada pilihan pelanggan untuk alamat pengiriman dan metode pengiriman sebelumnya.

Perubahan penerapan opsi pengiriman dan alamat pengiriman. Lihat pengaruhnya terhadap opsi pengiriman dan harga total secara dinamis.

Untuk menambahkan dukungan delegasi ke aplikasi pembayaran Android yang sudah ada, terapkan langkah-langkah berikut:

  1. Deklarasikan delegasi yang didukung.
  2. Mengurai tambahan intent PAY untuk pembayaran yang diperlukan opsi.
  3. Berikan informasi yang diperlukan terkait pembayaran respons.
  4. [Opsional] Mendukung alur dinamis:
    1. Beri tahu penjual tentang perubahan pada metode pembayaran yang dipilih pengguna, alamat pengiriman, atau pengiriman .
    2. Terima detail pembayaran yang diperbarui dari penjual (misalnya, jumlah total yang disesuaikan berdasarkan opsi pengiriman yang dipilih biaya).

Mendeklarasikan delegasi yang didukung

Browser perlu mengetahui daftar informasi tambahan yang digunakan yang disediakan oleh aplikasi Anda sehingga dapat mendelegasikan pengumpulan informasi tersebut kepada . Deklarasikan delegasi yang didukung sebagai <meta-data> di metode AndroidManifest.xml aplikasi Anda.

<activity
  android:name=".PaymentActivity"
    <meta-data
    android:name="org.chromium.payment_supported_delegations"
    android:resource="@array/supported_delegations" />
</activity>

<resource> harus berupa daftar string yang dipilih dari nilai valid berikut:

[ "payerName", "payerEmail", "payerPhone", "shippingAddress" ]

Contoh berikut hanya dapat mencantumkan alamat pengiriman dan email pembayar alamat IPv6

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string-array name="supported_delegations">
    <item>payerEmail</item>
    <item>shippingAddress</item>
  </string-array>
</resources>

Mengurai tambahan intent PAY untuk opsi pembayaran yang diperlukan

Penjual dapat menentukan informasi tambahan yang diperlukan menggunakan paymentOptions kata kunci. Chrome akan memberikan daftar opsi yang diperlukan yang dapat digunakan aplikasi Anda sediakan dengan meneruskan parameter berikut ke aktivitas PAY sebagai Intent tambahan.

paymentOptions

paymentOptions adalah subkumpulan opsi pembayaran yang ditentukan penjual yang aplikasi Anda telah mendeklarasikan dukungan delegasi.

val paymentOptions: Bundle? = extras.getBundle("paymentOptions")
val requestPayerName: Boolean? = paymentOptions?.getBoolean("requestPayerName")
val requestPayerPhone: Boolean? = paymentOptions?.getBoolean("requestPayerPhone")
val requestPayerEmail: Boolean? = paymentOptions?.getBoolean("requestPayerEmail")
val requestShipping: Boolean? = paymentOptions?.getBoolean("requestShipping")
val shippingType: String? = paymentOptions?.getString("shippingType")

Hal ini dapat mencakup parameter berikut:

  • requestPayerName - Boolean yang menunjukkan apakah nama pembayar atau bukan tidak diperlukan.
  • requestPayerPhone - Boolean yang menunjukkan apakah ponsel pembayar atau tidak tidak diperlukan.
  • requestPayerEmail - Boolean yang menunjukkan apakah email pembayar atau tidak tidak diperlukan.
  • requestShipping - Boolean yang menunjukkan apakah informasi pengiriman atau tidak tidak diperlukan.
  • shippingType - String yang menunjukkan jenis pengiriman. Jenis pengiriman dapat berupa "shipping", "delivery", atau "pickup". Aplikasi Anda dapat menggunakan petunjuk ini di UI saat meminta alamat pengguna atau pilihan opsi pengiriman.

shippingOptions

shippingOptions adalah array yang dapat dibagi-bagi dari pengiriman yang ditentukan penjual lainnya. Parameter ini hanya akan ada saat paymentOptions.requestShipping == true.

val shippingOptions: List<ShippingOption>? =
    extras.getParcelableArray("shippingOptions")?.mapNotNull {
        p -> from(p as Bundle)
    }

Setiap opsi pengiriman adalah Bundle dengan kunci berikut.

  • id - ID opsi pengiriman.
  • label - Label opsi pengiriman yang ditampilkan kepada pengguna.
  • amount - Paket biaya pengiriman yang berisi kunci currency dan value dengan nilai-nilai {i>string<i}.
    • currency menunjukkan mata uang biaya pengiriman, sebagai ISO4217 tersusun dengan baik Kode alfabet 3 huruf
    • value menampilkan nilai biaya pengiriman, dalam bentuk uang desimal yang valid nilai
  • selected - Apakah opsi pengiriman harus dipilih atau tidak saat aplikasi pembayaran akan menampilkan opsi pengiriman.

Semua kunci selain selected memiliki nilai string. selected memiliki boolean dengan sejumlah nilai.

val id: String = bundle.getString("id")
val label: String = bundle.getString("label")
val amount: Bundle = bundle.getBundle("amount")
val selected: Boolean = bundle.getBoolean("selected", false)

Memberikan informasi yang diperlukan dalam respons pembayaran

Aplikasi Anda harus menyertakan informasi tambahan yang diperlukan dalam responsnya terhadap aktivitas PAY.

Untuk melakukannya, parameter berikut harus ditetapkan sebagai tambahan Intent:

  • payerName - Nama lengkap pembayar. Seharusnya string ini tidak kosong saat paymentOptions.requestPayerName benar.
  • payerPhone - Nomor telepon pembayar. Seharusnya string ini tidak kosong saat paymentOptions.requestPayerPhone benar.
  • payerEmail - Alamat email pembayar. Kolom ini harus berupa string yang tidak kosong jika paymentOptions.requestPayerEmail benar.
  • shippingAddress - Alamat pengiriman yang diberikan pengguna. Ini harus berupa paket yang tidak kosong jika paymentOptions.requestShipping benar. Paket harus memiliki kunci berikut yang mewakili bagian berbeda dalam data alamat email.
    • city
    • countryCode
    • dependentLocality
    • organization
    • phone
    • postalCode
    • recipient
    • region
    • sortingCode
    • addressLine Semua kunci selain addressLine memiliki nilai string. addressLine adalah array string.
  • shippingOptionId - ID opsi pengiriman yang dipilih pengguna. Ini harus berupa string yang tidak kosong jika paymentOptions.requestShipping benar.

Memvalidasi respons pembayaran

Jika hasil aktivitas dari respons pembayaran diterima dari pembayaran yang dipanggil aplikasi disetel ke RESULT_OK, lalu Chrome akan memeriksa informasi dalam bagian tambahannya. Jika validasi gagal, Chrome akan menampilkan penolakan promise dari request.show() dengan salah satu error yang dihadapi developer berikut pesan:

'Payment app returned invalid response. Missing field "payerEmail".'
'Payment app returned invalid response. Missing field "payerName".'
'Payment app returned invalid response. Missing field "payerPhone".'
'Payment app returned invalid shipping address in response.'
'... is not a valid CLDR country code, should be 2 upper case letters [A-Z]'
'Payment app returned invalid response. Missing field "shipping option".'

Contoh kode berikut adalah contoh respons yang valid:

fun Intent.populateRequestedPaymentOptions() {
    if (requestPayerName) {
        putExtra("payerName", "John Smith")
    }
    if (requestPayerPhone) {
        putExtra("payerPhone", "4169158200")
    }
    if (requestPayerEmail) {
        putExtra("payerEmail", "john.smith@gmail.com")
    }
    if(requestShipping) {
        val address: Bundle = Bundle()
        address.putString("countryCode", "CA")
        val addressLines: Array<String> =
                arrayOf<String>("111 Richmond st. West")
        address.putStringArray("addressLines", addressLines)
        address.putString("region", "Ontario")
        address.putString("city", "Toronto")
        address.putString("postalCode", "M5H2G4")
        address.putString("recipient", "John Smith")
        address.putString("phone", "4169158200")
        putExtra("shippingAddress", address)
        putExtra("shippingOptionId", "standard")
    }
}

Opsional: Mendukung alur dinamis

Terkadang total biaya transaksi meningkat, seperti ketika pengguna memilih opsi pengiriman ekspres, atau jika daftar pengiriman yang tersedia opsi pengiriman atau harganya berubah jika pengguna memilih pengiriman internasional alamat IPv6 Jika aplikasi Anda memberikan alamat atau opsi pengiriman yang dipilih pengguna, aplikasi harus dapat memberi tahu penjual tentang alamat atau opsi pengiriman apa pun perubahan, dan menunjukkan kepada pengguna detail pembayaran yang diperbarui (disediakan oleh penjual).

AIDL

Untuk memberi tahu penjual tentang perubahan baru, gunakan PaymentDetailsUpdateService yang dideklarasikan di AndroidManifest.xml di Chrome. Untuk menggunakan layanan ini, buat dua File AIDL dengan konten berikut:

app/src/main/aidl/org/chromium/components/payments/IPaymentDetailsUpdateService

package org.chromium.components.payments;
import android.os.Bundle;

interface IPaymentDetailsUpdateServiceCallback {
    oneway void updateWith(in Bundle updatedPaymentDetails);

    oneway void paymentDetailsNotUpdated();
}

app/src/main/aidl/org/chromium/components/payments/IPaymentDetailsUpdateServiceCallback

package org.chromium.components.payments;
import android.os.Bundle;
import org.chromium.components.payments.IPaymentDetailsUpdateServiceCallback;

interface IPaymentDetailsUpdateService {
    oneway void changePaymentMethod(in Bundle paymentHandlerMethodData,
            IPaymentDetailsUpdateServiceCallback callback);

    oneway void changeShippingOption(in String shippingOptionId,
            IPaymentDetailsUpdateServiceCallback callback);

    oneway void changeShippingAddress(in Bundle shippingAddress,
            IPaymentDetailsUpdateServiceCallback callback);
}

Beri tahu penjual tentang perubahan pada metode pembayaran, alamat pengiriman, atau opsi pengiriman yang dipilih pengguna

private fun bind() {
    // The action is introduced in Chrome version 92, which supports the service in Chrome
    // and other browsers (e.g., WebLayer).
    val newIntent = Intent("org.chromium.intent.action.UPDATE_PAYMENT_DETAILS")
        .setPackage(callingBrowserPackage)
    if (packageManager.resolveService(newIntent, PackageManager.GET_RESOLVED_FILTER) == null) {
        // Fallback to Chrome-only approach.
        newIntent.setClassName(
            callingBrowserPackage,
            "org.chromium.components.payments.PaymentDetailsUpdateService")
        newIntent.action = IPaymentDetailsUpdateService::class.java.name
    }
    isBound = bindService(newIntent, connection, Context.BIND_AUTO_CREATE)
}

private val connection = object : ServiceConnection {
    override fun onServiceConnected(className: ComponentName, service: IBinder) {
        val service = IPaymentDetailsUpdateService.Stub.asInterface(service)
        try {
            if (isOptionChange) {
                service?.changeShippingOption(selectedOptionId, callback)
            } else (isAddressChange) {
                service?.changeShippingAddress(selectedAddress, callback)
            } else {
                service?.changePaymentMethod(methodData, callback)
            }
        } catch (e: RemoteException) {
            // Handle the remote exception
        }
    }
}

callingPackageName yang digunakan untuk intent awal layanan dapat memiliki salah satu nilai berikut, bergantung pada browser yang telah melakukan pembayaran permintaan.

Saluran Chrome Nama Paket
Stabil "com.android.chrome"
Beta "com.chrome.beta"
Pengembang "com.chrome.dev"
Canary "com.chrome.canary"
Kromium "org.chromium.chrome"
Kotak Penelusuran Cepat Google (penyemat Lapisan Web) "com.google.android.googlequicksearchbox"

changePaymentMethod

Memberi tahu penjual tentang perubahan pada metode pembayaran yang dipilih pengguna. Tujuan Paket paymentHandlerMethodData berisi methodName dan details opsional kunci dengan nilai string. Chrome akan memeriksa paket yang tidak kosong dengan methodName yang tidak kosong dan mengirim updatePaymentDetails dengan salah satu pesan error berikut melalui callback.updateWith jika validasi gagal.

'Method data required.'
'Method name required.'

changeShippingOption

Memberi tahu penjual tentang perubahan pada opsi pengiriman yang dipilih pengguna. shippingOptionId harus berupa ID salah satu dari yang ditentukan penjual opsi pengiriman. Chrome akan memeriksa shippingOptionId yang tidak kosong dan mengirim updatePaymentDetails dengan pesan error berikut melalui callback.updateWith jika validasi gagal.

'Shipping option identifier required.'

changeShippingAddress

Memberi tahu penjual tentang perubahan alamat pengiriman yang diberikan pengguna. Krom akan memeriksa paket shippingAddress yang tidak kosong dengan countryCode yang valid dan kirim updatePaymentDetails dengan pesan error berikut melalui callback.updateWith jika validasi gagal.

'Payment app returned invalid shipping address in response.'

Pesan error status tidak valid

Jika Chrome mendapatkan status yang tidak valid setelah menerima salah satu permintaan perubahan fungsi ini akan memanggil callback.updateWith dengan updatePaymentDetails yang disamarkan paket. Paket hanya akan berisi kunci error dengan "Invalid state". Contoh status yang tidak valid adalah:

  • Saat Chrome masih menunggu respons penjual terhadap perubahan sebelumnya (seperti peristiwa perubahan yang sedang berlangsung).
  • ID opsi pengiriman yang disediakan aplikasi pembayaran bukan milik siapa pun opsi pengiriman yang ditentukan penjual.

Menerima detail pembayaran terbaru dari penjual

private fun unbind() {
    if (isBound) {
        unbindService(connection)
        isBound = false
    }
}

private val callback: IPaymentDetailsUpdateServiceCallback =
    object : IPaymentDetailsUpdateServiceCallback.Stub() {
        override fun paymentDetailsNotUpdated() {
            // Payment request details have not changed.
            unbind()
        }

        override fun updateWith(updatedPaymentDetails: Bundle) {
            newPaymentDetails = updatedPaymentDetails
            unbind()
        }
    }

updatePaymentDetails setara dengan paket PaymentRequestDetailsUpdate Kamus WebIDL (setelah menyamarkan modifiers) dan berisi kunci opsional berikut:

  • total - Paket yang berisi kunci currency dan value, kedua kunci memiliki nilai string
  • shippingOptions - Array yang dapat dibagi dari pengiriman opsi
  • error - String yang berisi pesan error generik (misalnya, saat changeShippingOption tidak memberikan ID opsi pengiriman yang valid)
  • stringifiedPaymentMethodErrors - String JSON yang mewakili validasi error untuk metode pembayaran
  • addressErrors - Paket dengan kunci opsional yang sama dengan pengiriman alamat dan string masing-masing. Setiap kunci mewakili error validasi yang terkait dengan kunci bagian dari alamat pengiriman.

Kunci yang tidak ada berarti nilainya tidak berubah.