Cung cấp thông tin vận chuyển và thông tin liên hệ qua ứng dụng thanh toán của Android

Cách cập nhật ứng dụng thanh toán Android của bạn để cung cấp địa chỉ giao hàng và thông tin liên hệ của người thanh toán với Web Payments API.

Sahel Sharify
Sahel Sharify

Nhập địa chỉ giao hàng và thông tin liên hệ thông qua biểu mẫu web có thể là trải nghiệm rườm rà cho khách hàng. Việc này có thể gây ra lỗi và làm giảm tỷ lệ chuyển đổi .

Đó là lý do API yêu cầu thanh toán hỗ trợ tính năng yêu cầu giao hàng địa chỉ và thông tin liên hệ của họ. Điều này mang lại nhiều lợi ích:

  • Người dùng có thể chọn đúng địa chỉ chỉ bằng vài lần nhấn.
  • Địa chỉ luôn được trả về trong phương thức định dạng.
  • Bạn sẽ ít có khả năng gửi địa chỉ không chính xác hơn.

Trình duyệt có thể trì hoãn việc thu thập địa chỉ giao hàng và thông tin liên hệ để một ứng dụng thanh toán để mang đến trải nghiệm thanh toán hợp nhất. Chức năng này có tên là uỷ quyền.

Bất cứ khi nào có thể, Chrome sẽ uỷ quyền thu phí vận chuyển của khách hàng địa chỉ và thông tin liên hệ của bạn với ứng dụng thanh toán Android được gọi. Chiến lược phát hành đĩa đơn uỷ quyền giúp giảm sự phiền hà trong quá trình thanh toán.

Trang web của người bán có thể tự động cập nhật các lựa chọn vận chuyển và tổng giá tuỳ thuộc vào lựa chọn của khách hàng về địa chỉ giao hàng và việc giao hàng .

Cách thay đổi địa chỉ giao hàng và cách tính phí vận chuyển trong thực tế. Xem mức độ ảnh hưởng linh động đến các lựa chọn vận chuyển và tổng giá.

Để thêm tính năng hỗ trợ uỷ quyền vào một ứng dụng thanh toán hiện có trên Android, hãy triển khai các bước sau:

  1. Khai báo các hình thức uỷ quyền được hỗ trợ.
  2. Phân tích cú pháp ý định bổ sung PAY cho khoản thanh toán bắt buộc .
  3. Cung cấp thông tin bắt buộc khi thanh toán .
  4. [Không bắt buộc] Hỗ trợ luồng động:
    1. Thông báo cho người bán về những thay đổi đối với phương thức thanh toán mà người dùng đã chọn. địa chỉ giao hàng hoặc thông tin giao hàng .
    2. Nhận thông tin thanh toán mới nhất từ người bán (ví dụ: tổng số tiền được điều chỉnh dựa trên ).

Khai báo các hình thức uỷ quyền được hỗ trợ

Trình duyệt cần biết danh sách thông tin bổ sung liên quan đến khoản thanh toán của bạn có thể cung cấp để có thể uỷ quyền thu thập thông tin đó cho . Khai báo các uỷ quyền được hỗ trợ dưới dạng <meta-data> trong AndroidManifest.xml.

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

<resource> phải là một danh sách chuỗi được chọn từ các giá trị hợp lệ sau:

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

Ví dụ sau đây chỉ có thể cung cấp địa chỉ giao hàng và email của người thanh toán của bạn.

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

Phân tích cú pháp ý định bổ sung PAY cho các tuỳ chọn thanh toán bắt buộc

Người bán có thể chỉ định thông tin bắt buộc bổ sung bằng cách sử dụng paymentOptions từ điển. Chrome sẽ cung cấp danh sách các tuỳ chọn bắt buộc mà ứng dụng của bạn có thể cung cấp bằng cách truyền các tham số sau đến hoạt động PAY dưới dạng Ý định dịch vụ khác.

paymentOptions

paymentOptions là một nhóm nhỏ các tuỳ chọn thanh toán do người bán chỉ định ứng dụng của bạn đã khai báo hỗ trợ uỷ quyền.

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")

Hàm này có thể bao gồm các tham số sau:

  • requestPayerName – Giá trị boolean cho biết tên của người thanh toán hay không là trường bắt buộc.
  • requestPayerPhone – Giá trị boolean cho biết điện thoại của người thanh toán có hay không là trường bắt buộc.
  • requestPayerEmail – Giá trị boolean cho biết có email của người thanh toán hay không là trường bắt buộc.
  • requestShipping – Giá trị boolean cho biết thông tin vận chuyển có hay không là trường bắt buộc.
  • shippingType – Chuỗi thể hiện loại hình vận chuyển. Loại hình vận chuyển có thể là "shipping", "delivery" hoặc "pickup". Ứng dụng của bạn có thể sử dụng gợi ý này trong Giao diện người dùng khi yêu cầu người dùng cung cấp địa chỉ hoặc lựa chọn về cách thức giao hàng.

shippingOptions

shippingOptions là mảng có thể đóng gói của thông tin vận chuyển do người bán chỉ định . Thông số này sẽ chỉ tồn tại khi paymentOptions.requestShipping == true.

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

Mỗi cách tính phí vận chuyển là một Bundle với các khoá sau.

  • id – Giá trị nhận dạng cách tính phí vận chuyển.
  • label – Nhãn cách tính phí vận chuyển hiển thị cho người dùng.
  • amount – Gói phí vận chuyển chứa khoá currencyvalue có giá trị chuỗi.
    • currency cho biết đơn vị tiền tệ của phí vận chuyển dưới dạng đơn vị tiền tệ Định dạng phù hợp theo ISO4217 Mã gồm 3 chữ cái
    • value thể hiện giá trị của phí vận chuyển dưới dạng số tiền thập phân hợp lệ giá trị
  • selected – Liệu có nên chọn tùy chọn vận chuyển khi ứng dụng thanh toán hiển thị các tuỳ chọn vận chuyển.

Tất cả khoá khác ngoài selected đều có giá trị chuỗi. selected có một giá trị boolean giá trị.

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)

Cung cấp thông tin bắt buộc trong phản hồi thanh toán

Ứng dụng của bạn phải bao gồm thông tin bổ sung bắt buộc khi phản hồi lại hoạt động PAY.

Để làm vậy, bạn phải chỉ định các tham số sau làm phần bổ sung Ý định:

  • payerName – Tên đầy đủ của người thanh toán. Đây phải là một chuỗi không trống khi paymentOptions.requestPayerName là đúng.
  • payerPhone – Số điện thoại của người thanh toán. Đây phải là một chuỗi không trống khi paymentOptions.requestPayerPhone là đúng.
  • payerEmail – Địa chỉ email của người thanh toán. Đây phải là một chuỗi không trống khi paymentOptions.requestPayerEmail đúng.
  • shippingAddress – Địa chỉ giao hàng do người dùng cung cấp. Đây phải là gói không trống khi paymentOptions.requestShipping đúng. Gói phải có các khoá sau đại diện cho các bộ phận khác nhau trong giao diện .
    • city
    • countryCode
    • dependentLocality
    • organization
    • phone
    • postalCode
    • recipient
    • region
    • sortingCode
    • addressLine Tất cả khoá khác ngoài addressLine đều có giá trị chuỗi. addressLine là một mảng chuỗi.
  • shippingOptionId – Giá trị nhận dạng của hình thức vận chuyển do người dùng chọn. Chiến dịch này phải là một chuỗi không trống khi paymentOptions.requestShipping là true.

Xác thực phản hồi thanh toán

Nếu kết quả hoạt động của một phản hồi thanh toán nhận được từ khoản thanh toán đã gọi ứng dụng được đặt thành RESULT_OK, sau đó Chrome sẽ kiểm tra các ứng dụng bổ sung bắt buộc trong phần bổ sung. Nếu xác thực không thành công, Chrome sẽ trả về một thông báo bị từ chối lời hứa từ request.show() với một trong các lỗi sau dành cho nhà phát triển thư:

'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".'

Mã mẫu sau đây là ví dụ về phản hồi hợp lệ:

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")
    }
}

Không bắt buộc: Hỗ trợ luồng động

Đôi khi, tổng chi phí của một giao dịch sẽ tăng lên, chẳng hạn như khi người dùng chọn phương thức vận chuyển nhanh hoặc khi trong danh sách các dịch vụ vận chuyển có thể sử dụng các lựa chọn hoặc giá của chúng thay đổi khi người dùng chọn phí vận chuyển quốc tế của bạn. Khi ứng dụng của bạn cung cấp lựa chọn hoặc địa chỉ giao hàng do người dùng chọn, có thể thông báo cho người bán về bất kỳ địa chỉ hoặc lựa chọn giao hàng nào thay đổi và cho người dùng thấy thông tin thanh toán đã cập nhật (do người bán).

AIDL

Để thông báo cho người bán về các thay đổi mới, hãy sử dụng PaymentDetailsUpdateService dịch vụ đã khai báo trong tệp AndroidManifest.xml của Chrome. Để sử dụng dịch vụ này, hãy tạo hai Tệp AIDL có nội dung sau:

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);
}

Thông báo cho người bán về những thay đổi trong phương thức thanh toán, địa chỉ giao hàng hoặc cách thức giao hàng mà người dùng đã chọn

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 dùng cho ý định bắt đầu của dịch vụ có thể có một trong các các giá trị sau, tuỳ thuộc vào trình duyệt đã thực hiện thanh toán của bạn.

Kênh Chrome Tên gói
Ổn định "com.android.chrome"
Beta "com.chrome.beta"
Nhà phát triển "com.chrome.dev"
Canary "com.chrome.canary"
Chromium "org.chromium.chrome"
Hộp Tìm kiếm Nhanh của Google (trình nhúng WebLayer) "com.google.android.googlequicksearchbox"

changePaymentMethod

Thông báo cho người bán về những thay đổi đối với phương thức thanh toán do người dùng chọn. Chiến lược phát hành đĩa đơn Gói paymentHandlerMethodData chứa methodNamedetails không bắt buộc cả hai khoá đều có giá trị chuỗi. Chrome sẽ kiểm tra một gói không trống có methodName không trống và gửi updatePaymentDetails bằng một trong các thông báo lỗi sau đây qua callback.updateWith nếu quá trình xác thực không thành công.

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

changeShippingOption

Thông báo cho người bán về những thay đổi đối với phương thức vận chuyển do người dùng chọn. shippingOptionId phải là giá trị nhận dạng của một trong những giá trị nhận dạng do người bán chỉ định cách tính phí vận chuyển. Chrome sẽ kiểm tra để tìm shippingOptionId không trống và gửi updatePaymentDetails với thông báo lỗi sau qua callback.updateWith nếu quá trình xác thực không thành công.

'Shipping option identifier required.'

changeShippingAddress

Thông báo cho người bán khi địa chỉ giao hàng do người dùng cung cấp thay đổi. Chrome sẽ kiểm tra gói shippingAddress không trống có countryCode hợp lệ rồi gửi một updatePaymentDetails kèm theo thông báo lỗi sau qua callback.updateWith nếu quá trình xác thực không thành công.

'Payment app returned invalid shipping address in response.'

Thông báo lỗi trạng thái không hợp lệ

Nếu Chrome gặp phải trạng thái không hợp lệ khi nhận được bất kỳ yêu cầu thay đổi nào thì ứng dụng sẽ gọi callback.updateWith kèm theo một updatePaymentDetails đã loại bỏ dữ liệu gói. Gói sẽ chỉ chứa khoá error với "Invalid state". Ví dụ về trạng thái không hợp lệ:

  • Khi Chrome vẫn đang chờ người bán phản hồi về một thay đổi trước đó (chẳng hạn như một sự kiện thay đổi đang diễn ra).
  • Giá trị nhận dạng lựa chọn vận chuyển do ứng dụng thanh toán cung cấp không thuộc bất kỳ hình thức giao hàng do người bán chỉ định.

Nhận thông tin thanh toán mới nhất từ người bán

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 là gói tương đương với PaymentRequestDetailsUpdate Từ điển WebIDL (sau khi loại bỏ modifiers) và chứa các khoá không bắt buộc sau:

  • total – Một gói chứa các khoá currencyvalue, cả hai khoá đều có giá trị chuỗi
  • shippingOptions – Mảng có thể đóng gói của phí vận chuyển lựa chọn
  • error – Chuỗi chứa thông báo lỗi chung (ví dụ: khi changeShippingOption không cung cấp giá trị nhận dạng hợp lệ về cách tính phí vận chuyển)
  • stringifiedPaymentMethodErrors – Một chuỗi JSON đại diện cho việc xác thực lỗi liên quan đến phương thức thanh toán
  • addressErrors – Một gói có các khoá tuỳ chọn giống với phí vận chuyển địa chỉ và chuỗi giá trị. Mỗi khoá biểu thị một lỗi xác thực liên quan đến khoá tương ứng của địa chỉ giao hàng.

Khoá vắng mặt có nghĩa là giá trị của khoá không thay đổi.