Meet Poolakey

Poolakey is a new library for implementing Bazaar’s in-app billing which is developed using the Kotlin programming language and supports ReactiveX framework. The goal for developing Poolakey was to improve the implementation process of Bazaar’s in-app billing for developers and in long-term, it lets us implement new features for Bazaar’s in-app billing.


Using Poolakey

1: Adding the library to your project

To begin, add Poolakey’s dependency to your build.gradle file:

dependencies {
    implementation "com.phelat:poolakey:[latest_version]"
}

Make sure that you’re using the latest version of Poolakey:

 

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

 

2: Construction and Connection

In order to work with Poolakey, you need to construct an instance of Payment class:

val securityCheck = SecurityCheck.Enable(rsaPublicKey = "PUBLIC RSA KEY OF YOUR APP")

val paymentConfig = PaymentConfiguration(localSecurityCheck = securityCheck)

val payment = Payment(context = context, config = paymentConfig)

You can also disable local security checks, only if you're using Bazaar's REST API by passing SecurityCheck.Disable object in PaymentConfiguration class.
And after that, you need to connect to the in-app billing service via connect function in Payment class:

payment.connect {
    connectionSucceed {
        ...
    }
    connectionFailed { throwable ->
        ...
    }
    disconnected {
        ...
    }
}

As you can see, there are three callbacks available for you to get notified whenever the connection state changes. It's worth mentioning that the return type of connect function is a Connection interface which has two functions:

  • getState to get the current state of service connection

  • disconnect to disconnect from the in-app billing service

You have to always keep a global reference to this Connection interface.

private lateinit var paymentConnection: Connection
override fun onCreate(bundle: Bundle) {
   super.onCreate(bundle)
   paymentConnection = payment.connect {
       connectionSucceed {
           ...
       }
       connectionFailed { throwable ->
           ...
       }
        disconnected {
           ...
       }
    }
}

 

Note: You have to disconnect from the in-app billing service when your view (Activity or Fragment) gets destroyed.
override fun onDestroy() {
    paymentConnection.disconnect()
    super.onDestroy()
}

Reactive way of this

payment.connect()
    .subscribe({ connection ->
        when (connection.getState()) {
            is ConnectionState.Connected -> {
                ...
            }
            is ConnectionState.Disconnected -> {
                ...
            }
        }
    }, { throwable ->
        ...
    })

connect returns an Observable<Connection> which you can subscribe to it and get notified about the connection state changes.

3: Purchasing a Product

To purchase a product, you need to construct a PurchaseRequest class:

val purchaseRequest = PurchaseRequest(
    productId = "coinBoxProduct",
    requestCode = 123,
    payload = ""
)

productId -> This is the product ID that you have defined inside of the developers panel.
requestCode -> This is just a random integer but, it's a good practice to make this a constant property.
payload -> This can be an empty string or anything else that you wish, but it's a good practice to actually pass in some data to help you to verify the purchase.

Okay, so now that you have constructed a PurchaseRequest, you can easily call purchaseProduct function in Payment class:
purchaseProduct supports fragments as well.

payment.purchaseProduct(activity = this, request = purchaseRequest) {
    purchaseFlowBegan {
        // Bazaar's billing screen has opened successfully
        ...
    }
    failedToBeginFlow { throwable ->
        // Failed to open Bazaar's billing screen
        ...
    }
}

As you can see, inside of the purchaseProduct function, you have access to two callbacks which you can use to get notified about the purchase flow.

Reactive way of this

payment.purchaseProduct(activity = this, request = purchaseRequest)
  .subscribe({
        // Purchase flow began
        ...
    }, { throwable ->
        // Failed to begin flow
        ...
    })

4: Subscribing a Product

To subscribe a product, you need to construct a PurchaseRequest class:

val purchaseRequest = PurchaseRequest(
    productId = "subscriptionProduct",
    requestCode = 1234,
    payload = ""
)

productId -> This is the product ID that you have defined inside of the developers panel.
requestCode -> This is just a random integer but, it's a good practice to make this a constant property.
payload -> This can be an empty string or anything else that you wish, but it's a good practice to actually pass in some data to help you to verify the purchase.

Okay, so now that you have constructed a PurchaseRequest, you can easily call subscribeProduct function in Payment class:
subscribeProduct supports fragments as well.

payment.subscribeProduct(activity = this, request = purchaseRequest) {
    purchaseFlowBegan {
        // Bazaar's billing screen has opened successfully
        ...
    }
    failedToBeginFlow { throwable ->
        // Failed to open Bazaar's billing screen
        ...
    }
}

As you can see, inside of the subscribeProduct function, you have access to two callbacks which you can use to get notified about the purchase flow.

Reactive way of this

payment.subscribeProduct(activity = this, request = purchaseRequest)  
    .subscribe({
        // Purchase flow began
        ...
    }, { throwable ->
        // Failed to begin flow
        ...
    })

5: Purchase Validation

To get notified when user purchases a product, you have to use onActivityResult function in Payment class:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    payment.onActivityResult(requestCode, resultCode, data) {
        purchaseSucceed { purchaseEntity ->
            // User purchased the product
            ...
        }
        purchaseCanceled {
            // User canceled the purchase
            ...
        }
        purchaseFailed { throwable ->
            ...
        }
    }
}

 

Note: Even if the purchase was successful, you have to double check the purchase via Bazaar's REST API

Reactive way of this

payment.onActivityResult(requestCode, resultCode, data)
    .subscribe({ purchaseEntity ->
        ...
    }, { throwable ->
        ...
    })

6. Consume a Purchased Product

You can consume a product just by calling consumeProduct function in Payment class:

payment.consumeProduct(purchaseToken = "THE ACTUAL PURCHASE TOKEN") {
    consumeSucceed {
        ...
    }
    consumeFailed { throwable ->
        ...
    }
}

purchaseToken -> You get this token in onActivityResult function when user purchases a product. Also you can simple query purchased products by that particular user, using getPurchasedProducts in Payment class, which also gives you purchaseToken to consume. You can read more about querying purchased products from here.

 

Note:consumeProduct runs on a background thread and notifies you about the consumption state in the main thread, this means that you don't have to handle threading by yourself.

Reactive way of this

payment.consumeProduct(purchaseToken = "THE ACTUAL PURCHASE TOKEN")
    .subscribe({
        // Successfully consumed the product
        ...
    }, { throwable ->
        // Failed to consume the product
        ...
    })

7. Query User’s Purchased Products

You can query user's purchased products by using getPurchasedProducts function in Payment class:

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

 

Note:getPurchasedProducts runs on a background thread and notifies you about the query result in the main thread, this means that you don't have to handle threading by yourself.

Reactive way of this

payment.getPurchasedProducts()
    .subscribe({ purchasedProducts ->
        ...
    }, { throwable ->
        ...
    })

8. Query User’s Subscribed Products

You can query user's subscribed products by using getSubscribedProducts function in Payment class:

payment.getSubscribedProducts {
    querySucceed { subscribedProducts ->
        ...
    }
    queryFailed { throwable ->
        ...
    }
}

 

Note: getSubscribedProducts runs on a background thread and notifies you about the query result in the main thread, this means that you don't have to handle threading by yourself.

Reactive way of this

payment.getSubscribedProducts()
    .subscribe({ subscribedProducts ->
        ...
    }, { throwable ->
        ...
    })