آشنایی با «پولکی»

«پولکی» کتابخانه‌ای نو برای پیاده‌سازی پرداخت درون برنامه بازار است که با زبان برنامه نویسی Kotlin توسعه داده شده است و از چارچوب ReactiveX پشتیبانی می‌کند. هدف از پیاده‌سازی این کتابخانه، بهبود فرآیند پیاده‌سازی پرداخت درون برنامه‌ای بازار برای توسعه‌دهنده است و به ما اجازه می‌دهد در طولانی مدت، قابلیت‌های تازه‌ای به این کتابخانه اضافه کنیم.


 استفاده از پولکی

۱: افزودن کتابخانه به پروژه

برای شروع، کتابخانه پولکی را به پروژه خود در فایل build.gradle اضافه کنید:

dependencies {
  implementation "com.phelat:poolakey:1.0.0-alpha01"
}

  مطمئن شوید که از آخرین نسخه پولکی استفاده می‌کنید:

https://github.com/PHELAT/Poolakey/releases

۲: ساخت و ساز

ساختار پرداخت درون برنامه‌ای به شکلی هست که برنامه شما باید مستقیما با برنامه بازار صحبت کند تا بتواند عملیات خرید و... را انجام دهد. برای صحبت کردن با بازار، ابتدا باید به بازار متصل شوید. برای انجام این کار ، وارد فایل Activity یا  Fragment خود شوید و در متد onCreate یک نمونه از کلاس SecurityCheck درست کنید:

val localSecurityCheck = SecurityCheck.Enable(
  rsaPublicKey = "KEY"
)

به جای مقدار KEY باید از کلید برنامه خود استفاده کنید، برای دریافت کلید برنامه به پنل پیشخان مراجعه کنید و در صفحه اطلاعات برنامه، وارد تب «پرداخت درون برنامه‌ای» شوید و کلید را از آنجا کپی کنید و به جای مقدار KEY در نمونه کد بالا قرار دهید.

در مرحله بعد باید یک نمونه از کلاس PaymentConfiguration درست کنید و localSecurityCheck را به آن تزریق کنید:

val paymentConfiguration = PaymentConfiguration(
  localSecurityCheck = localSecurityCheck
)

و در آخرین مرحله باید یک نمونه از کلاس Payment درست کنید:

val payment = Payment(context = this, config = paymentConfiguration)

کلاس Payment پل ارتباطی بین برنامه شما و بازار است و از این کلاس برای اتصال به بازار، خرید یک محصول و... می‌توانید استفاده کنید.

۳. اتصال به بازار

برای اتصال به بازار، باید از فانکشن connect موجود در کلاس Payment استفاده کنید:

val paymentConnection = payment.connect {
  connectionSucceed {
        ...
  }
  connectionFailed { throwable ->
        ...
  }
  disconnected {
        ...
  }
}

در بدنه فانکشن connect به سه callback دسترسی دارید:

  • وقتی صدا زده می‌شود که اتصال به بازار برقرار شود.
  • وقتی صدا زده می‌شود که اتصال به بازار برقرار نشود.
  • وقتی صدا زده می‌شود که طبق رویدادی ارتباط برنامه شما با بازار قطع شود.

همان‌طور که می‌بینید، در connectionFailed به یک نمونه از throwable دسترسی دارید که به کمک آن می‌توانید متوجه مشکلی که باعث عدم اتصال برنامه شما به بازار شده است شوید.

۴: قطع اتصال با بازار

برای جلوگیری از مشکلاتی همچون Memory Leak باید در متد onDestroy از Activity یا Fragment خود، اقدام به قطع اتصال با بازار کنید:

override fun onDestroy() {
  paymentConnection.disconnect()
  super.onDestroy()
}

۵. شروع روند خرید یک محصول

برای شروع روند خرید یک محصول، باید ابتدا یک نمونه از کلاس PurchaseRequest بسازید:

val purchaseRequest = PurchaseRequest(
   productId = "PRODUCT_ID",
   requestCode = 1000,
   payload = ""
)

به جای مقدار PRODUCT_ID باید مقدار شناسه محصولی که قصد خرید آن را دارید را جایگزین کنید. برای دریافت مقدار شناسه محصول مورد نظر، به پیشخان توسعه‌دهندگان مراجعه کنید و در صفحه اطلاعات برنامه، در تب «پرداخت درون برنامه‌ای» یک محصول جدید بسازید و شناسه‌ای برای آن در نظر بگیرید یا این که می‌توانید، شناسه محصول‌های پیشین که ساخته‌اید را جایگزین مقدار PRODUCT_ID کنید.

سپس با استفاده از فانکشن purchaseProduct از کلاس Payment روند خرید محصول مورد نظر را شروع کنید:

payment.purchaseProduct(
  activity = this,
  request = purchaseRequest
) {
  purchaseFlowBegan {
        ...    
  }
  failedToBeginFlow { throwable ->
        ...    
  }
}

در بدنه فانکشن purchaseProduct به دو callback دسترسی دارید:

  • وقتی صدا زده می‌شود که فرایند هدایت کاربر به صفحه خرید بازار به درستی انجام شود.
  • وقتی صدا زده می‌شود که فرایند هدایت کاربر به صفحه خرید بازار به درستی انجام نشود.

همانطور که می‌بینید، در failedToBeginFlow به یک نمونه از throwable دسترسی دارید که به کمک آن می‌توانید متوجه مشکلی که در شروع فرایند خرید شده است شوید.

۶: شروع روند اشتراک یک محصول

برای اشتراک یک محصول، دقیقا مثل شروع خرید یک محصول عمل کنید و به جای استفاده از فانکشن purchaseProduct از فانکشن subscribeProduct موجود در کلاس Payment استفاده کنید.

۷: دریافت نتیجه خرید اشتراک و محصول

بعد از این‌که از یکی از فانکشن‌های purchaseProduct  یا  subscribeProduct استفاده کردید، باید از نتیجه خرید کاربر خود مطلع شوید و برای این کار لازم است،  از فانکشن onActivityResult موجود در کلاس Payment در متد  onActivityResult از  Activity  یا  Fragment خود استفاده کنید:

 

override fun onActivityResult(
  requestCode: Int, 
  resultCode: Int, 
  data: Intent?
) {
  super.onActivityResult(requestCode, resultCode, data)
  payment.onActivityResult(requestCode, resultCode, data) {
     purchaseSucceed { purchaseEntity ->
            ...
     }
     purchaseCanceled {
            ...        
     }
     purchaseFailed { throwable ->
            ...        
     }
  }
}

همان‌طور که می‌بینید در بدنه onActivityResult به سه callback دسترسی دارید:

  • وقتی صدا زده می‌شود که خرید با موفقیت انجام شود، که در این صورت، از طریق purchaseEntity می‌توانید به اطلاعات خرید دست پیدا کنید. توجه کنید که در صورت موفقیت‌آمیز بودن خرید، بسیار پیشنهاد می‌شود که از طریق API پرداخت بازار، خودتان صحت پرداخت را نیز بررسی کنید.
  • وقتی صدا زده می‌شود که کاربر از خرید منصرف شود.
  • وقتی صدا زده می‌شود که مشکلی در خرید وجود داشته باشد، این مشکل می‌تواند از جنس صحت نداشتن اطلاعات خرید و... باشد که در این‌صورت به کمک نمونه throwable موجود در این callback می‌توانید از مشکل به‌وجود آمده مطلع شوید.

۸: مصرف کردن خرید کاربر

وقتی کاربر یکی از محصولات دیجیتالی برنامه شما را خریداری می‌کند، مالک یک نسخه محصول مورد نظر می‌شود و در صورتی که شما کاربر را مجددا به صفحه پرداخت هدایت کنید، کاربر نمی‌تواند دوباره خرید خود را انجام دهد و با اطلاعات خرید قبلی به برنامه شما باز می‌گردد (purchaseSucceed). اما شما می‌توانید برای محصول مورد نظر خود تاریخ مصرف و یا شرایط خاصی را در نظر بگیرید که خرید مصرف شود که در این صورت کاربر می‌تواند مجددا خرید خود را انجام دهد. برای مصرف کردن یک خرید از فانکشن consumeProduct موجود در کلاس Payment استفاده کنید:

payment.consumeProduct("PURCHASE_TOKEN") {
  consumeSucceed {
      ...
  }
  consumeFailed { throwable ->
      ...
  }
}

همان‌طور که می‌بینید، در بدنه consumeProduct به دو callback دسترسی دارید:

  • وقتی صدا زده می‌شود که عملیات مصرف کردن خرید با موفقیت انجام شود.
  • وقتی صدا زده می‌شود که عملیات مصرف کردن خرید انجام نشود،  که در این صورت شما می‌توانید شما می‌توانید با استفاده از نمونه throwable موجود در این callback متوجه مشکل شوید.

توجه کنید که به‌جای مقدار PURCHASE_TOKEN در نمونه کد بالا، باید مقدار واقعی توکن خریدی که می‌خواهید مصرف شود را قرار دهید. دسترسی به توکن خرید، از طریق کلاس PurchaseEntity امکان‌پذیر است. وقتی کاربر خرید انجام می‌دهد، پولکی به شما یک PurchaseEntity در purchaseSucceed می‌دهد. همچنین می‌توانید تمام خریدهای کاربر که در برنامه شما انجام داده است را از طریق فانکشن getPurchasedProducts بدست بیاورید که در این صورت، پولکی به شما لیستی از  PurchaseEntity می‌دهد که از این طریق نیز می‌توانید به توکن خرید دسترسی پیدا کنید.

توجه: محصولات اشتراکی را نمی‌توانید مصرف کنید.
توجه: به این نکته توجه داشته باشید که قبل از کار با consumeProduct باید مطمئن شوید که کاربر وارد حساب بازار خود شده است، در غیر این‌صورت consumeFailed صدا زده می‌شود.

۹: دریافت خریدهای کاربر در برنامه شما

شما می‌توانید با استفاده از فانکشن getPurchasedProducts موجود در کلاس Payment از خریدهای کاربر که در برنامه شما انجام داده است، مطلع شود:

payment.getPurchasedProducts {
  querySucceed { purchasedProducts ->
      ...
  }
  queryFailed { throwable ->
      ...
  }
}

همانطور که می‌بینید، در بدنه getPurchasedProducts به دو callback دسترسی دارید:

  • وقتی صدا زده می‌شود که ارتباط با بازار به خوبی برقرار شود و مشکلی در دریافت لیست خریدها وجود نداشته باشد که در این صورت، با استفاده از purchasedProducts که لیستی از PurchaseInfo است می‌توانید به خریدهای کاربر دسترسی پیدا کنید.
  • وقتی صدا زده می‌شود که ارتباط با بازار برقرار نشود یا مشکلی در دریافت لیست خریدها وجود داشته باشد، که در این صورت، می‌توانید با استفاده از نمونه throwable موجود در این callback متوجه مشکل به‌وجود آمده شوید.
توجه: به این نکته توجه داشته باشید قبل از کار با getPurchasedProducts باید مطمئن شوید که کاربر وارد حساب بازار خود شده است، در غیر این‌صورت queryFailed صدا زده می‌شود.

۱۰: دریافت اشتراک‌های کاربر در برنامه شما

برای دریافت لیست محصولاتی که کاربر اشتراک آنها را در برنامه شما خریداری کرده، دقیقا مانند دریافت خریدهای کاربر عمل کنید و به‌ جای استفاده از فانکشن getPurchasedProducts، از فانکشن getSubscribedProducts استفاده کنید.

توجه: به این نکته توجه داشته باشید که قبل از کار با getSubscribedProducts باید مطمئن شوید که کاربر وارد حساب بازار خود شده است، در غیر این‌صورت queryFailed صدا زده می‌شود.