1 android huawei-mobile-services
我想知道华为在应用程序中购买的编码方式与从安卓购买的普通应用程序中的编码方式不同吗?
如果是的话,我们是否需要重新编码从android购买到华为版本的正常应用程序?
是的,对于 appGallery(华为)来说,这是一种不同的方式。我已经在我的应用程序的应用程序购买中实现了 Playstore 和 appgallery。我只是使用风味和存储库模式分离了实现,如下所示。
productFlavors {
googlePlay {
versionCode 72
versionName "1.6.2"
}
appGallery {
versionCode 70
versionName "1.5.9"
}
}
Run Code Online (Sandbox Code Playgroud)
然后在我的 gradle 文件中,我为 appGallery 和 Play 商店添加了自定义实现,如下所示。
对于应用程序库
appGalleryImplementation 'com.huawei.agconnect:agconnect-core:1.2.0.300'
appGalleryImplementation 'com.huawei.hms:iap:4.0.2.300'
Run Code Online (Sandbox Code Playgroud)
用于游戏商店
googlePlayImplementation 'com.android.billingclient:billing:3.0.0'
Run Code Online (Sandbox Code Playgroud)
然后我创建了一个接口,这个接口需要两种风格都实现。
interface PurchaseRepository : LifecycleObserver {
fun provideActivity(activity: Activity)
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onCreate()
fun loadInventorySkus()
fun purchaseItem(sku: String)
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onDestroy()
interface OwnedSkusPurchaseListener {
fun onOwnedSkuLoaded(sku: Sku?)
}
interface PurchaseResultListener {
fun onLoadingInventory()
fun onCancelPurchase()
fun onFailedPurchase(exception: Exception? = null)
fun onOrderNotLogin()
fun onSuccessPurchase()
fun onInventoryLoaded(skus: List<Sku?>)
fun onSkuAlreadyOwned()
}
}
Run Code Online (Sandbox Code Playgroud)
应用程序库的实现如下所示
class PurchaseRepositoryImpl(userEndpoints: UserEndpoints,
private val userRepositoryConfig: UserRepositoryConfig,
private val skus: List<String>) : BasePurchaseRepository(userEndpoints, userRepositoryConfig) {
override fun onCreate() {
updateOwnedProducts()
if (BuildConfig.DEBUG)
isSandBoxActivated()
}
override fun loadInventorySkus() {
getSkuDetails(activity, skus, PRODUCT_TYPE_RENEWABLE_SUBSCRIPTION)
}
private fun updateOwnedProducts() {
val task = Iap.getIapClient(activity).obtainOwnedPurchases(OwnedPurchasesReq().apply {
priceType = PRODUCT_TYPE_RENEWABLE_SUBSCRIPTION
})
task.addOnSuccessListener { result ->
if (result != null && result.inAppPurchaseDataList != null) {
(0 until result.inAppPurchaseDataList.size).forEach { i ->
val inAppPurchaseData = result.inAppPurchaseDataList[i]
val inAppSignature = result.inAppSignature[i]
val inAppPurchaseDataBean = InAppPurchaseData(inAppPurchaseData)
val purchaseState = inAppPurchaseDataBean.purchaseState
if (checkDeliverTransactionState(inAppPurchaseData, inAppSignature)
&& purchaseState == InAppPurchaseData.PurchaseState.PURCHASED) {
listenerProductSku?.onOwnedSkuLoaded(inAppPurchaseDataBean.toSku())
} else
listenerProductSku?.onOwnedSkuLoaded(null)
sendUpdatePurchase(inAppPurchaseData)
}
}
}.addOnFailureListener {
listenerProductSku?.onOwnedSkuLoaded(null)
}
}
private fun isSandBoxActivated() {
val client = Iap.getIapClient(activity)
val task = client.isSandboxActivated(IsSandboxActivatedReq())
task.addOnSuccessListener {
if (it != null)
Timber.d("Sandbox is activated")
}.addOnFailureListener {
if (it != null)
Timber.e(it)
}
}
override fun purchaseItem(sku: String) {
val client: IapClient = Iap.getIapClient(activity)
val task = client.createPurchaseIntent(createGetBuyIntentReq(PRODUCT_TYPE_RENEWABLE_SUBSCRIPTION, sku))
task.apply {
addOnSuccessListener { it ->
it.status?.let {
// you should pull up the page to complete the payment process
startResolutionForResult(activity, it, REQ_CODE_BUY)
}
}
addOnFailureListener {
when (it) {
is IapApiException -> {
val apiException = it
val returnCode = apiException.statusCode
listenerPurchaseResult?.onFailedPurchase(exception)
Timber.d("getBuyIntent, returnCode: $returnCode")
}
else -> Timber.e(it)
}
}
}
}
private fun startResolutionForResult(activity: Activity, status: Status?, reqCode: Int) {
if (status == null) {
Timber.e("status is null")
return
}
if (status.hasResolution()) {
try {
status.startResolutionForResult(activity, reqCode)
} catch (exp: IntentSender.SendIntentException) {
listenerPurchaseResult?.onFailedPurchase(exp)
Timber.e(exp)
}
} else {
Timber.e("intent is null")
}
}
private fun getSkuDetails(context: Context, skuList: List<String>, type: Int) {
val client = Iap.getIapClient(context)
val task = client.obtainProductInfo(createGetSkuDetailReq(type, ArrayList(skuList)))
task.addOnSuccessListener { result ->
if (result.productInfoList != null) {
listenerPurchaseResult?.onInventoryLoaded(result.productInfoList.map { it.transform() })
}
}.addOnFailureListener { exception ->
if (exception is IapApiException) {
val returnCode = exception.statusCode
if (returnCode == OrderStatusCode.ORDER_HWID_NOT_LOGIN)
listenerPurchaseResult?.onOrderNotLogin()
else
listenerPurchaseResult?.onFailedPurchase(exception)
} else
listenerPurchaseResult?.onFailedPurchase(exception)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQ_CODE_BUY) {
data?.let {
val buyResultInfo = Iap.getIapClient(activity).parsePurchaseResultInfoFromIntent(data)
when (buyResultInfo.returnCode) {
OrderStatusCode.ORDER_STATE_CANCEL -> listenerPurchaseResult?.onCancelPurchase()
OrderStatusCode.ORDER_PRODUCT_OWNED -> {
listenerPurchaseResult?.onSkuAlreadyOwned()
sendUpdatePurchase(buyResultInfo.inAppPurchaseData)
}
OrderStatusCode.ORDER_STATE_SUCCESS -> {
if (checkDeliverTransactionState(buyResultInfo.inAppPurchaseData, buyResultInfo.inAppDataSignature)) {
sendUpdatePurchase(buyResultInfo.inAppPurchaseData)
listenerPurchaseResult?.onSuccessPurchase()
} else
listenerPurchaseResult?.onFailedPurchase()
}
else -> listenerPurchaseResult?.onFailedPurchase()
}
}
}
}
private fun checkDeliverTransactionState(appData: String, appSignature: String): Boolean {
return CipherUtil.doCheck(appData, appSignature, API_KEY_HMS_IN_PURCHASE)
}
private fun sendUpdatePurchase(jsonAppPurchaseData: String?) {
jsonAppPurchaseData?.let {
val inAppPurchaseDataBean = InAppPurchaseData(jsonAppPurchaseData)
userUpgradeRepository(inAppPurchaseDataBean.transform(userRepositoryConfig.uuid))
}
}
private fun createGetSkuDetailReq(type: Int, skuList: ArrayList<String>): ProductInfoReq = ProductInfoReq().apply {
productIds = skuList
priceType = type
}
private fun createGetBuyIntentReq(type: Int, skuId: String?) = PurchaseIntentReq().apply {
productId = skuId
priceType = type
}
Run Code Online (Sandbox Code Playgroud)
}
以及 Play 商店的实现
class PurchaseRepositoryImpl(userEndpoints: UserEndpoints,
private val userRepositoryConfig: UserRepositoryConfig,
private val skus: List<String>) : BasePurchaseRepository(userEndpoints, userRepositoryConfig) {
private lateinit var checkout: ActivityCheckout
private lateinit var inventory: Inventory
private lateinit var selectedSku: String
override fun onCreate() {
checkout = Checkout.forActivity(activity, BaseApplication[activity].billing)
checkout.start()
checkout.createPurchaseFlow(PurchaseListener())
loadInventorySkus()
}
override fun loadInventorySkus() {
inventory = checkout.makeInventory()
inventory.load(Inventory.Request.create()
.loadAllPurchases()
.loadSkus(ProductTypes.SUBSCRIPTION, skus), InventoryCallback())
}
override fun purchaseItem(sku: String) {
checkout.whenReady(object : Checkout.EmptyListener() {
override fun onReady(requests: BillingRequests) {
selectedSku = sku
requests.purchase(ProductTypes.SUBSCRIPTION, selectedSku, null, checkout.purchaseFlow)
}
})
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
checkout.onActivityResult(requestCode, resultCode, data)
}
private inner class PurchaseListener : EmptyRequestListener<Purchase>() {
override fun onSuccess(purchase: Purchase) {
if (purchase.state == Purchase.State.PURCHASED) {
userUpgradeRepository(purchase.transform(userRepositoryConfig.getFirebaseId(), true))
listenerPurchaseResult?.onSuccessPurchase()
} else
userUpgradeRepository(purchase.transform(userRepositoryConfig.getFirebaseId(), false))
}
override fun onError(response: Int, e: Exception) {
if (e is BillingException) {
when (e.response) {
ResponseCodes.ITEM_ALREADY_OWNED -> {
listenerPurchaseResult?.onSkuAlreadyOwned()
userUpgradeRepository(PurchaseInfo(
sku = selectedSku,
isPurchase = true
))
}
ResponseCodes.USER_CANCELED -> listenerPurchaseResult?.onCancelPurchase()
else -> listenerPurchaseResult?.onFailedPurchase(e)
}
}
}
}
private inner class InventoryCallback : Inventory.Callback {
override fun onLoaded(products: Inventory.Products) {
try {
val skuProducts = products[ProductTypes.SUBSCRIPTION].skus.toList()
.map { it.transform() }
.sortedBy { it.detailedPrice?.amount }
listenerPurchaseResult?.onInventoryLoaded(skuProducts)
skuProducts.forEach { sku ->
val isPurchased = products[ProductTypes.SUBSCRIPTION].hasPurchaseInState(sku.id?.code
?: "", Purchase.State.PURCHASED)
if (isPurchased) listenerProductSku?.onOwnedSkuLoaded(sku)
if (!isPurchased && userRepositoryConfig.getTypeSubscription() == sku.id?.code)
userUpgradeRepository(sku.toPurchaseInfo(userRepositoryConfig.getFirebaseId(), isPurchased))
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}}
Run Code Online (Sandbox Code Playgroud)
每个存储库实现必须在其各自的风味目录中,如下所示
这些购买存储库包含来自我的应用程序的一些业务逻辑,但我希望这个答案可以帮助您了解如何让您的应用程序在应用程序库和 Play 商店中运行。
| 归档时间: |
|
| 查看次数: |
513 次 |
| 最近记录: |