1. مقدمة
ما ستنشئه
عند الانتهاء من هذا الدرس العملي، سيكون لديك تطبيق Jetpack Compose بسيط يعمل ويتضمّن عملية دمج Google Pay على Android. يستردّ هذا المشروع رمزًا مميزًا للدفع يمكن إرساله إلى مقدّم خدمة الدفع لمعالجته.
أهداف الدورة التعليمية
- كيفية تثبيت مكتبة Google Pay Jetpack Compose وضبط إعداداتها
- كيفية عرض زر Google Pay والتعامل مع النقرات
- كيفية طلب رمز مميّز للدفع من Google Pay
المتطلبات
- تثبيت أحدث إصدار ثابت من "استوديو Android"
- حزمة تطوير البرامج (SDK) لنظام التشغيل Android ومحاكي أو جهاز تم إعدادهما في "استوديو Android"
- بالنسبة إلى بيئة الإنتاج، ستحتاج إلى
merchantIdفي Google Pay. لا يستغرق التسجيل في Google Pay & Wallet Console سوى دقيقة واحدة، لذا ننصحك بإكمال هذه الخطوة الآن.
2. إنشاء مشروع Jetpack Compose
إنشاء ملفات المشروع
- أنشئ مشروعًا جديدًا في Jetpack Compose في "استوديو Android" باسم
gpay-compose:- افتح "استوديو Android" وانقر على
New Project. - اختَر نموذج
Empty Activity (Jetpack Compose). - الاسم:
gpay-compose، اسم الحزمة:com.example.gpay - اللغة: Kotlin، الحد الأدنى لإصدار حزمة تطوير البرامج (SDK): المستوى 21 من واجهة برمجة التطبيقات أو أعلى
- انقر على "إنهاء" لإنشاء المشروع.
- افتح "استوديو Android" وانقر على
- أضِف تبعية زر Google Pay Compose.في ملف
app/build.gradle(.kts)، أضِف ما يلي: Groovy DSL:dependencies { implementation("com.google.pay.button:compose-pay-button:1.0.0") }dependencies { implementation 'com.google.pay.button:compose-pay-button:1.0.0' } - أضِف اعتمادية "محفظة Google" في "خدمات Google Play" (لفتح ورقة Google Pay):في ملف
app/build.gradle(.kts)، أضِف الاعتمادية التالية: إذا كان مشروعك يستخدم Groovy DSL، استخدِم:dependencies { implementation("com.google.android.gms:play-services-wallet:19.3.0") }dependencies { implementation 'com.google.android.gms:play-services-wallet:19.3.0' } - افتح
MainActivity.ktفي "استوديو Android" واستبدِل المحتوى بالحد الأدنى التالي من بنية تطبيق Compose (سنربط الزر في الخطوة التالية):package com.example.gpay import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { // Google Pay button added in the next section } } } } }
3- ضبط إعدادات Google Pay
يتطلّب طلب الدفع في Google Pay عنصر طلب. يحتوي العنصر المحدّد هنا باسم baseGooglePayRequest على الحدّ الأدنى من الإعدادات الشائعة لجميع الطلبات. ستتم إضافة إعدادات إضافية حسب الطلب المقدَّم، وسنراجعها في هذا الدرس العملي.
أضِف ثوابت إعداد Google Pay إلى MainActivity.kt (ستعيد استخدامها في الخطوة التالية):
private const val merchantId = "12345678901234567890"
// This is the base configuration for all Google Pay payment data requests.
private val baseGooglePayRequest = """
{
"apiVersion": 2,
"apiVersionMinor": 0,
"allowedPaymentMethods": [
{
"type": "CARD",
"parameters": {
"allowedAuthMethods": [
"PAN_ONLY", "CRYPTOGRAM_3DS"
],
"allowedCardNetworks": [
"AMEX", "DISCOVER", "INTERAC", "JCB", "MASTERCARD", "VISA"
]
},
"tokenizationSpecification": {
"type": "PAYMENT_GATEWAY",
"parameters": {
"gateway": "example",
"gatewayMerchantId": "exampleGatewayMerchantId"
}
}
}
],
"merchantInfo": {
"merchantId": "$merchantId"
}
}
""".trimIndent()
الموارد
- مرجع واجهة برمجة التطبيقات: مستندات عناصر الطلب في Google Pay API
- مرجع واجهة برمجة التطبيقات: يُرجى الرجوع إلى
PaymentMethodللحصول على مزيد من المعلومات حول طرق التفويض المسموح بها وشبكات البطاقات المسموح بها ومواصفات الترميز، بما في ذلك قيمة البوابة الصحيحة.
4. إضافة زر Google Pay
استخدِم زر Compose Pay لعرض زر Google Pay أصلي، واستخدِم Wallet API لفتح ورقة Google Pay.
استبدِل محتوى MainActivity.kt بالكامل بالمثال الكامل التالي (يتضمّن الإعدادات والزر وتدفق الدفع):
package com.example.gpay
import android.os.Bundle
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import com.google.android.gms.common.api.CommonStatusCodes
import com.google.android.gms.tasks.Task
import com.google.android.gms.wallet.contract.TaskResultContracts.GetPaymentDataResult
import com.google.android.gms.wallet.*
import com.google.pay.button.ButtonTheme
import com.google.pay.button.ButtonType
import com.google.pay.button.PayButton
import org.json.JSONObject
private const val merchantId = "12345678901234567890"
// Base Google Pay request used for both the button and the Wallet request
private val baseGooglePayRequest = """
{
"apiVersion": 2,
"apiVersionMinor": 0,
"allowedPaymentMethods": [
{
"type": "CARD",
"parameters": {
"allowedAuthMethods": [
"PAN_ONLY", "CRYPTOGRAM_3DS"
],
"allowedCardNetworks": [
"AMEX", "DISCOVER", "INTERAC", "JCB", "MASTERCARD", "VISA"
]
},
"tokenizationSpecification": {
"type": "PAYMENT_GATEWAY",
"parameters": {
"gateway": "example",
"gatewayMerchantId": "exampleGatewayMerchantId"
}
}
}
],
"merchantInfo": {
"merchantId": "$merchantId"
}
}
""".trimIndent()
class MainActivity : ComponentActivity() {
private val paymentDataLauncher = registerForActivityResult(GetPaymentDataResult()) { taskResult ->
when (taskResult.status.statusCode) {
CommonStatusCodes.SUCCESS -> {
handlePaymentData(taskResult.result!!)
}
//CommonStatusCodes.CANCELED -> The user canceled
//CommonStatusCodes.DEVELOPER_ERROR -> The API returned an error (it.status: Status)
//else -> Handle internal and other unexpected errors
}
}
private lateinit var paymentsClient: PaymentsClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Create the PaymentsClient
paymentsClient = Wallet.getPaymentsClient(
this,
Wallet.WalletOptions.Builder()
.setEnvironment(WalletConstants.ENVIRONMENT_TEST) // Switch to PRODUCTION when ready
.build()
)
// Derive allowedPaymentMethods for the button from baseGooglePayRequest
val allowedPaymentMethods = JSONObject(baseGooglePayRequest)
.getJSONArray("allowedPaymentMethods")
.toString()
setContent {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
PayButton(
onClick = { requestPayment(paymentDataLauncher) },
allowedPaymentMethods = allowedPaymentMethods,
type = ButtonType.Pay,
theme = ButtonTheme.Light
)
}
}
}
private fun requestPayment(launcher: ActivityResultLauncher<Task<PaymentData>>) {
// Build a PaymentDataRequest from the base request by adding transaction info
val requestJson = JSONObject(baseGooglePayRequest).apply {
put("transactionInfo", JSONObject().apply {
put("totalPrice", "14.95")
put("totalPriceStatus", "FINAL")
put("countryCode", "US")
put("currencyCode", "USD")
})
}
val request = PaymentDataRequest.fromJson(requestJson.toString())
val task = paymentsClient.loadPaymentData(request)
task.addOnCompleteListener(paymentDataLauncher::launch)
}
private fun handlePaymentData(paymentData: PaymentData?) {
val json = paymentData?.toJson() ?: return
val paymentMethodData = JSONObject(json).getJSONObject("paymentMethodData")
val tokenizationData = paymentMethodData.getJSONObject("tokenizationData")
val token = tokenizationData.getString("token")
// Send 'token' to your payment service provider (PSP)
println("Payment token: $token")
}
}
5- إرسال طلب دفع
عند الضغط على زر Google Pay، ينشئ requestPayment(...) PaymentDataRequest من خلال إضافة transactionInfo إلى baseGooglePayRequest، ويفتح ورقة Google Pay، ويعرض رمزًا مميزًا للدفع.
النقاط الرئيسية
- الزر: يعرض
PayButtonزر Google Pay الأصلي. - تم ضبط إعدادات العميل:
PaymentsClientعلى TEST أو PRODUCTION. - الإطلاق: استخدِم
loadPaymentDataوحلّ المشكلة باستخدامIntentSenderعند الحاجة. - الرمز المميّز: حلِّل
PaymentData.toJson()لاستخراجpaymentMethodData.tokenizationData.tokenوإرساله إلى مقدّم خدمة الدفع.
6. الخاتمة
تهانينا على إكمال هذا الدرس التطبيقي حول الترميز. لقد تعرّفت على كيفية دمج Google Pay API في تطبيق Jetpack Compose على Android.
تشغيل المشروع
شغِّل المشروع من "استوديو Android" (Run > Run 'app') لبدء تطبيقك.
الخطوة التالية
مراجع إضافية
- الانضمام إلى المحادثة في قناة #payments على Discord
- متابعة @GooglePayDevs على X
- مشاهدة فيديوهات ذات صلة بـ Google Pay على YouTube