2

I can't find resources on the internet on How to achieve the google API integration into an Compose based app.

I need help, especially in the AutoResolveHelper.resolveTask, how to do it in compose.

Thank you for your answers.

(That's mind blowing that there is no more documentation on this API, it's pretty difficult to implement).

Edit :

This is the traditional way to do it ->

private fun requestPayment() {

    // Disables the button to prevent multiple clicks.
    googlePayButton.isClickable = false

    // The price provided to the API should include taxes and shipping.
    // This price is not displayed to the user.
    val garmentPrice = selectedGarment.getDouble("price")
    val priceCents = Math.round(garmentPrice * PaymentsUtil.CENTS.toLong()) + SHIPPING_COST_CENTS

    val paymentDataRequestJson = PaymentsUtil.getPaymentDataRequest(priceCents)
    if (paymentDataRequestJson == null) {
        Log.e("RequestPayment", "Can't fetch payment data request")
        return
    }
    val request = PaymentDataRequest.fromJson(paymentDataRequestJson.toString())

    // Since loadPaymentData may show the UI asking the user to select a payment method, we use
    // AutoResolveHelper to wait for the user interacting with it. Once completed,
    // onActivityResult will be called with the result.
    if (request != null) {
        AutoResolveHelper.resolveTask(
                paymentsClient.loadPaymentData(request), this, LOAD_PAYMENT_DATA_REQUEST_CODE)
    }
}

/**
 * Handle a resolved activity from the Google Pay payment sheet.
 *
 * @param requestCode Request code originally supplied to AutoResolveHelper in requestPayment().
 * @param resultCode Result code returned by the Google Pay API.
 * @param data Intent from the Google Pay API containing payment or error data.
 * @see [Getting a result
 * from an Activity](https://developer.android.com/training/basics/intents/result)
 */
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    when (requestCode) {
        // Value passed in AutoResolveHelper
        LOAD_PAYMENT_DATA_REQUEST_CODE -> {
            when (resultCode) {
                RESULT_OK ->
                    data?.let { intent ->
                        PaymentData.getFromIntent(intent)?.let(::handlePaymentSuccess)
                    }

                RESULT_CANCELED -> {
                    // The user cancelled the payment attempt
                }

                AutoResolveHelper.RESULT_ERROR -> {
                    AutoResolveHelper.getStatusFromIntent(data)?.let {
                        handleError(it.statusCode)
                    }
                }
            }

            // Re-enables the Google Pay payment button.
            googlePayButton.isClickable = true
        }
    }
}
Mehdi.ncb
  • 346
  • 3
  • 13
  • Compose is a UI Framework, so the implementation is the same as that of the traditional Android development. Compose has nothing to do with it – Richard Onslow Roper May 23 '22 at 06:00
  • Yes I know, but there is some part of code you can't implement properly with compose, like for example : activityResult,you need to use rememberForActiviryResult, with contract, launch, and so on. You understand ? – Mehdi.ncb May 23 '22 at 09:25
  • AutoResolveHelper.resolveTask is calling onActivityResult with override and code. But with compose you can't do that, you need to create a composable, remember it, and launch it with intent, you understand? But we have not enough information to do that, so my question is how to do that properly in compose. – Mehdi.ncb May 23 '22 at 09:28
  • 1
    Then please share your traditional implementation. We might be able to help you migrate it to Compose. Good luck with that though. – Richard Onslow Roper May 23 '22 at 10:24
  • It's okay, i've edited the question – Mehdi.ncb May 23 '22 at 10:38
  • So what's the problem?? Just copy-paste this code in your Compose app inside a ViewModel or something. – Richard Onslow Roper May 23 '22 at 16:00
  • Edit : I've pasted the code in my MainActivity but it's not very clean so... i don't know how to do it. I made lambda call from MainActivity to my composable for button clicking.. Do you have any clean tips to do that ? – Mehdi.ncb May 26 '22 at 18:26
  • that's fine, if it works. – Richard Onslow Roper Aug 21 '22 at 20:10

1 Answers1

3

I recently came into this exact same issue. I didn't want to add the code to the activity and make an ugly, unreadable code so I ended up doing this:

In your composable, add this code to the click modifier or whatever:

val task = paymentsClient.loadPaymentData(request)
task.addOnCompleteListener { completedTask ->
   if (completedTask.isSuccessful) {
      completedTask.result.let{
         //Do whatever you want
      }
   } else {
      when (val exception = completedTask.exception) {
         is ResolvableApiException -> {
            resolvePaymentForResult.launch(
                IntentSenderRequest.Builder(exception.resolution).build()
            )
         }
         is ApiException -> {
            Log.e("Google Pay API error", "Error code: ${exception.statusCode}, Message: ${exception.message}")
         }
         else -> {
            Log.e("Unexpected non API exception")
         }
      }
   }
}

With resolvePaymentForResult being:

val resolvePaymentForResult = rememberLauncherForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) {
        result: ActivityResult ->
    when (result.resultCode) {
        RESULT_OK ->
            result.data?.let { intent ->
                PaymentData.getFromIntent(intent)?.let{
                   //Do whatever you want
                }
            }

        RESULT_CANCELED -> {
            // The user cancelled the payment attempt
        }
    }
}

You can always move paymentsClient.loadPaymentData(request) to your ViewModel if that's your architecture too!

Hope that will clean up your code a little bit more :)

Odin
  • 642
  • 1
  • 9
  • 27