Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add amazon module Unit Tests #2104

Merged
merged 2 commits into from
Nov 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions IapExample/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ PODS:
- React-Core
- RNGestureHandler (2.5.0):
- React-Core
- RNIap (11.0.0-alpha.1):
- RNIap (12.4.1):
- React-Core
- RNScreens (3.15.0):
- React-Core
Expand Down Expand Up @@ -575,7 +575,7 @@ SPEC CHECKSUMS:
ReactCommon: e30ec17dfb1d4c4f3419eac254350d6abca6d5a2
RNCMaskedView: cb9670ea9239998340eaab21df13fa12a1f9de15
RNGestureHandler: bad495418bcbd3ab47017a38d93d290ebd406f50
RNIap: ec6593b74c48fa06f4614ff9ec2dc2e4dffcba0c
RNIap: a694c95267d38c882adf68999814edd17fc343ce
RNScreens: 4a1af06327774490d97342c00aee0c2bafb497b7
SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
Yoga: 7ab6e3ee4ce47d7b789d1cb520163833e515f452
Expand Down
2 changes: 1 addition & 1 deletion IapExample/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"android:amazon": "react-native run-android --variant=AmazonDebug",
"ios": "react-native run-ios",
"start": "react-native start",
"pods": "pod-install --quiet",
"pods": "cd ios && pod install",
"test": "jest"
},
"dependencies": {
Expand Down
3 changes: 3 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ android {
}

testOptions {
unitTests.all {
jvmArgs '-noverify'
}
unitTests.returnDefaultValues = true
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.dooboolab.RNIap

import android.content.Context
import com.amazon.device.iap.PurchasingListener
import com.amazon.device.iap.model.FulfillmentResult
import com.amazon.device.iap.model.RequestId

interface PurchasingServiceProxy {
fun registerListener(var0: Context?, var1: PurchasingListener?)

fun getUserData(): RequestId

fun purchase(var0: String?): RequestId

fun getProductData(var0: Set<String?>?): RequestId

fun getPurchaseUpdates(var0: Boolean): RequestId

fun notifyFulfillment(var0: String?, var1: FulfillmentResult?)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.dooboolab.RNIap

import android.content.Context
import com.amazon.device.iap.PurchasingListener
import com.amazon.device.iap.PurchasingService
import com.amazon.device.iap.model.FulfillmentResult
import com.amazon.device.iap.model.RequestId

class PurchasingServiceProxyAmazonImpl : PurchasingServiceProxy {
override fun registerListener(var0: Context?, var1: PurchasingListener?) {
return PurchasingService.registerListener(var0, var1)
}

override fun getUserData(): RequestId {
return PurchasingService.getUserData()
}

override fun purchase(var0: String?): RequestId {
return PurchasingService.purchase(var0)
}

override fun getProductData(var0: Set<String?>?): RequestId {
return PurchasingService.getProductData(var0)
}

override fun getPurchaseUpdates(var0: Boolean): RequestId {
return PurchasingService.getPurchaseUpdates(var0)
}

override fun notifyFulfillment(var0: String?, var1: FulfillmentResult?) {
return PurchasingService.notifyFulfillment(var0, var1)
}
}
53 changes: 19 additions & 34 deletions android/src/amazon/java/com/dooboolab/RNIap/RNIapAmazonListener.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package com.dooboolab.RNIap

import android.util.Log
import com.amazon.device.iap.PurchasingListener
import com.amazon.device.iap.PurchasingService
import com.amazon.device.iap.model.Product
import com.amazon.device.iap.model.ProductDataResponse
import com.amazon.device.iap.model.ProductType
import com.amazon.device.iap.model.PurchaseResponse
Expand All @@ -18,26 +16,21 @@ import com.facebook.react.bridge.WritableNativeArray
import com.facebook.react.bridge.WritableNativeMap
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
import java.lang.NumberFormatException
import java.util.ArrayList

val ProductType.typeString: String
get() = if (this == ProductType.ENTITLED || this == ProductType.CONSUMABLE) "inapp" else "subs"

class RNIapAmazonListener(private val reactContext: ReactContext) : PurchasingListener {
private val skus: MutableList<Product>
class RNIapAmazonListener(
private val reactContext: ReactContext,
private val purchasingService: PurchasingServiceProxy
) : PurchasingListener {

override fun onProductDataResponse(response: ProductDataResponse) {
val requestId = response.requestId.toString()
when (response.requestStatus) {
ProductDataResponse.RequestStatus.SUCCESSFUL -> {
val productData = response.productData
val unavailableSkus = response.unavailableSkus
val items = WritableNativeArray()
for ((_, product) in productData) {
if (!skus.contains(product)) {
skus.add(product)
}

var priceNumber: Number = 0.00
val priceString = product.price
try {
Expand Down Expand Up @@ -107,7 +100,7 @@ class RNIapAmazonListener(private val reactContext: ReactContext) : PurchasingLi
availableItems.pushMap(promiseItem)
}
if (response.hasMore()) {
PurchasingService.getPurchaseUpdates(false)
purchasingService.getPurchaseUpdates(false)
} else {
if (purchases.size > 0 && promiseItem != null) {
PromiseUtils
Expand Down Expand Up @@ -197,13 +190,8 @@ class RNIapAmazonListener(private val reactContext: ReactContext) : PurchasingLi
override fun onPurchaseResponse(response: PurchaseResponse) {
val requestId = response.requestId.toString()
val userId = response.userData.userId
val status = response.requestStatus

// Info for potential error reporting
val debugMessage: String?
var errorCode = PromiseUtils.E_UNKNOWN
val error = Arguments.createMap()
when (status) {
when (response.requestStatus) {
PurchaseResponse.RequestStatus.SUCCESSFUL -> {
val receipt = response.receipt
val userData = response.userData
Expand All @@ -218,8 +206,9 @@ class RNIapAmazonListener(private val reactContext: ReactContext) : PurchasingLi
)
}
PurchaseResponse.RequestStatus.ALREADY_PURCHASED -> {
debugMessage = "You already own this item."
errorCode = PromiseUtils.E_ALREADY_OWNED
val error = Arguments.createMap()
val debugMessage = "You already own this item."
val errorCode = PromiseUtils.E_ALREADY_OWNED
error.putInt("responseCode", 0)
error.putString("debugMessage", debugMessage)
error.putString("code", errorCode)
Expand All @@ -234,9 +223,10 @@ class RNIapAmazonListener(private val reactContext: ReactContext) : PurchasingLi
)
}
PurchaseResponse.RequestStatus.FAILED -> {
debugMessage =
val error = Arguments.createMap()
val debugMessage =
"An unknown or unexpected error has occurred. Please try again later."
errorCode = PromiseUtils.E_UNKNOWN
val errorCode = PromiseUtils.E_UNKNOWN
error.putInt("responseCode", 0)
error.putString("debugMessage", debugMessage)
error.putString("code", errorCode)
Expand All @@ -251,8 +241,9 @@ class RNIapAmazonListener(private val reactContext: ReactContext) : PurchasingLi
)
}
PurchaseResponse.RequestStatus.INVALID_SKU -> {
debugMessage = "That item is unavailable."
errorCode = PromiseUtils.E_ITEM_UNAVAILABLE
val error = Arguments.createMap()
val debugMessage = "That item is unavailable."
val errorCode = PromiseUtils.E_ITEM_UNAVAILABLE
error.putInt("responseCode", 0)
error.putString("debugMessage", debugMessage)
error.putString("code", errorCode)
Expand All @@ -267,8 +258,9 @@ class RNIapAmazonListener(private val reactContext: ReactContext) : PurchasingLi
)
}
PurchaseResponse.RequestStatus.NOT_SUPPORTED -> {
debugMessage = "This feature is not available on your device."
errorCode = PromiseUtils.E_SERVICE_ERROR
val error = Arguments.createMap()
val debugMessage = "This feature is not available on your device."
val errorCode = PromiseUtils.E_SERVICE_ERROR
error.putInt("responseCode", 0)
error.putString("debugMessage", debugMessage)
error.putString("code", errorCode)
Expand Down Expand Up @@ -314,11 +306,8 @@ class RNIapAmazonListener(private val reactContext: ReactContext) : PurchasingLi
)
}
}
fun clear() {
skus.clear()
}

private fun sendEvent(
fun sendEvent(
reactContext: ReactContext,
eventName: String,
params: WritableMap?
Expand All @@ -344,8 +333,4 @@ class RNIapAmazonListener(private val reactContext: ReactContext) : PurchasingLi
private const val E_USER_DATA_RESPONSE_NOT_SUPPORTED = "E_USER_DATA_RESPONSE_NOT_SUPPORTED"
const val TAG = "RNIapAmazonListener"
}

init {
skus = ArrayList()
}
}
45 changes: 24 additions & 21 deletions android/src/amazon/java/com/dooboolab/RNIap/RNIapAmazonModule.kt
Original file line number Diff line number Diff line change
@@ -1,45 +1,49 @@
package com.dooboolab.RNIap

import android.os.Handler
import android.os.Looper
import android.util.Log
import com.amazon.device.drm.LicensingService
import com.amazon.device.drm.model.LicenseResponse
import com.amazon.device.iap.PurchasingService
import com.amazon.device.iap.PurchasingListener
import com.amazon.device.iap.model.FulfillmentResult
import com.facebook.react.bridge.LifecycleEventListener
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.module.annotations.ReactModule

@ReactModule(name = RNIapAmazonModule.TAG)
class RNIapAmazonModule(reactContext: ReactApplicationContext) :
class RNIapAmazonModule(
reactContext: ReactApplicationContext,
private val purchasingService: PurchasingServiceProxy = PurchasingServiceProxyAmazonImpl(),
private val handler: Handler = Handler(Looper.getMainLooper()),
private val amazonListener: PurchasingListener = RNIapAmazonListener(reactContext, purchasingService)
) :
ReactContextBaseJavaModule(reactContext) {
var hasListener = false
private var amazonListener: RNIapAmazonListener? = null
override fun getName(): String {
return TAG
}

@ReactMethod
fun initConnection(promise: Promise) {
val context = reactApplicationContext
val amazonListener = RNIapAmazonListener(context)
this.amazonListener = amazonListener
UiThreadUtil.runOnUiThread {

handler.postDelayed({
try {
PurchasingService.registerListener(context.applicationContext, amazonListener)
purchasingService.registerListener(context.applicationContext, amazonListener)
hasListener = true
// Prefetch user and purchases as per Amazon SDK documentation:
PurchasingService.getUserData()
PurchasingService.getPurchaseUpdates(false)
purchasingService.getUserData()
purchasingService.getPurchaseUpdates(false)
promise.safeResolve(true)
} catch (e: Exception) {
promise.safeReject("Error initializing Amazon appstore sdk", e)
}
}
}, 0L)
}

@ReactMethod
Expand Down Expand Up @@ -84,14 +88,13 @@ class RNIapAmazonModule(reactContext: ReactApplicationContext) :
@ReactMethod
fun endConnection(promise: Promise) {
PromiseUtils.rejectAllPendingPromises()
amazonListener?.clear()
hasListener = false
promise.resolve(true)
}

@ReactMethod
fun getUser(promise: Promise) {
val requestId = PurchasingService.getUserData()
val requestId = purchasingService.getUserData()
PromiseUtils.addPromiseForKey(PROMISE_GET_USER_DATA, promise)
}

Expand All @@ -114,13 +117,13 @@ class RNIapAmazonModule(reactContext: ReactApplicationContext) :
ii++
}
PromiseUtils.addPromiseForKey(PROMISE_GET_PRODUCT_DATA, promise)
val requestId = PurchasingService.getProductData(productSkus)
val requestId = purchasingService.getProductData(productSkus)
}

@ReactMethod
fun getAvailableItems(promise: Promise) {
PromiseUtils.addPromiseForKey(PROMISE_QUERY_AVAILABLE_ITEMS, promise)
PurchasingService.getPurchaseUpdates(true)
purchasingService.getPurchaseUpdates(true)
}

@ReactMethod
Expand All @@ -129,7 +132,7 @@ class RNIapAmazonModule(reactContext: ReactApplicationContext) :
promise: Promise
) {
PromiseUtils.addPromiseForKey(PROMISE_BUY_ITEM, promise)
val requestId = PurchasingService.purchase(sku)
val requestId = purchasingService.purchase(sku)
}

@ReactMethod
Expand All @@ -138,7 +141,7 @@ class RNIapAmazonModule(reactContext: ReactApplicationContext) :
developerPayLoad: String?,
promise: Promise
) {
PurchasingService.notifyFulfillment(token, FulfillmentResult.FULFILLED)
purchasingService.notifyFulfillment(token, FulfillmentResult.FULFILLED)
promise.resolve(true)
}

Expand All @@ -148,13 +151,13 @@ class RNIapAmazonModule(reactContext: ReactApplicationContext) :
developerPayLoad: String?,
promise: Promise
) {
PurchasingService.notifyFulfillment(token, FulfillmentResult.FULFILLED)
purchasingService.notifyFulfillment(token, FulfillmentResult.FULFILLED)
promise.resolve(true)
}

private fun sendUnconsumedPurchases(promise: Promise) {
PromiseUtils.addPromiseForKey(PROMISE_QUERY_PURCHASES, promise)
PurchasingService.getPurchaseUpdates(false)
purchasingService.getPurchaseUpdates(false)
}

@ReactMethod
Expand Down Expand Up @@ -189,8 +192,8 @@ class RNIapAmazonModule(reactContext: ReactApplicationContext) :
*/
override fun onHostResume() {
if (hasListener) {
PurchasingService.getUserData()
PurchasingService.getPurchaseUpdates(false)
purchasingService.getUserData()
purchasingService.getPurchaseUpdates(false)
}
}
override fun onHostPause() {}
Expand Down
Loading