Skip to content
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
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
## 2.6.0

- **BREAKING** [Android] `ApphudListener.apphudDidReceivePurchase` method was introduced
- **BREAKING** [iOS], [Android] `paywalls` method was removed
- **BREAKING** [iOS] `rawPaywalls` method was removed
- [Android] `ApphudNonRenewingPurchase.purchaseToken` property was introduced
- [Android] `ApphudSubscription.purchaseToken` property was introduced
- [Android], [iOS] `deferPlacements` method was introduced
- [Android] `refreshUserData` method was introduced
- [Android], [iOS] `forceFlushUserProperties` method was introduced
- [Android] `refreshUserData` now returns `ApphudUser?`
- [Android] `updateUserID` now returns `ApphudUser?`
- [Android], [iOS] `attributeFromWeb` method was introduced

- Dependencies of Native SDK's were updated to:
- [Android] 2.8.3
- [iOS] 3.5.6

## 2.5.4

- [iOS],[Android] `ApphudAttributionProvider.facebook` was added.
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ android {

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "com.apphud:ApphudSDK-Android:2.7.0"
implementation 'com.apphud:ApphudSDK-Android:2.8.3'
implementation 'com.android.billingclient:billing:6.1.0'
implementation 'com.google.code.gson:gson:2.8.8'
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ class ApphudPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {

private fun setHeaders() {
HeadersInterceptor.X_SDK = "Flutter"
HeadersInterceptor.X_SDK_VERSION = "2.5.4"
HeadersInterceptor.X_SDK_VERSION = "2.6.0"
}

override fun onDetachedFromActivityForConfigChanges() {
Expand Down
8 changes: 5 additions & 3 deletions android/src/main/kotlin/com/apphud/fluttersdk/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ fun ApphudNonRenewingPurchase.toMap(): HashMap<String, Any?> {
"productId" to productId,
"purchasedAt" to purchasedAt,
"canceledAt" to canceledAt,
"isActive" to isActive()
"isActive" to isActive(),
"purchaseToken" to purchaseToken
)
}

Expand All @@ -111,14 +112,15 @@ fun ApphudSubscription.toMap(): HashMap<String, Any?> {
"isAutorenewEnabled" to isAutoRenewEnabled,
"isIntroductoryActivated" to isIntroductoryActivated,
"isActive" to isActive(),
"status" to status.name.lowercase(Locale.ROOT)
"status" to status.name.lowercase(Locale.ROOT),
"purchaseToken" to purchaseToken
)
}

fun ApphudGroup.toMap(): HashMap<String, Any?> {
return hashMapOf(
"name" to name,
"productIds" to ((products?.map { it.productId }) ?: listOf()),
"productIds" to productIds(),
"hasAccess" to hasAccess()
)
}
Expand Down
15 changes: 10 additions & 5 deletions android/src/main/kotlin/com/apphud/fluttersdk/FlutterSdkCommon.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,25 @@ package com.apphud.fluttersdk

import com.apphud.sdk.Apphud
import com.apphud.sdk.domain.ApphudPaywall

import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

object FlutterSdkCommon {
public suspend fun getPaywall(
paywallIdentifier: String?,
placementIdentifier: String?
): ApphudPaywall? {
val foundPaywall: ApphudPaywall? = if (placementIdentifier != null) {
return if (placementIdentifier != null) {
val placements = Apphud.placements()
placements.firstOrNull { it.identifier == placementIdentifier }?.paywall
} else if (paywallIdentifier != null) {
val paywalls = Apphud.paywalls()
paywalls.firstOrNull { it.identifier == paywallIdentifier }
suspendCancellableCoroutine { cont ->
Apphud.paywallsDidLoadCallback { paywalls, _ ->
val paywall = paywalls.firstOrNull { it.identifier == paywallIdentifier }
cont.resume(paywall)
}
}
} else null
return foundPaywall
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.apphud.fluttersdk.handlers

import com.android.billingclient.api.ProductDetails
import com.android.billingclient.api.Purchase
import com.apphud.fluttersdk.toMap
import com.apphud.sdk.Apphud
import com.apphud.sdk.ApphudListener
Expand All @@ -25,6 +26,7 @@ class ApphudListenerHandler(handleOnMainThreadP: HandleOnMainThread) :
private var subscriptionsCached: List<ApphudSubscription>? = null
private var purchasesCached: List<ApphudNonRenewingPurchase>? = null
private var placementsCached: List<ApphudPlacement>? = null
private var purchaseCached: Purchase? = null
private var handleOnMainThread = handleOnMainThreadP

init {
Expand Down Expand Up @@ -65,6 +67,7 @@ class ApphudListenerHandler(handleOnMainThreadP: HandleOnMainThread) :
subscriptionsCached?.let { v -> apphudSubscriptionsUpdated(v) }
purchasesCached?.let { v -> apphudNonRenewingPurchasesUpdated(v) }
placementsCached?.let { v -> placementsDidFullyLoad(v) }
purchaseCached?.let { v -> apphudDidReceivePurchase(v) }
}

private fun stop() {
Expand All @@ -80,6 +83,15 @@ class ApphudListenerHandler(handleOnMainThreadP: HandleOnMainThread) :
}
}

override fun apphudDidReceivePurchase(purchase: Purchase) {
purchaseCached = purchase
if(isListeningStarted) {
handleOnMainThread {
channel?.invokeMethod("apphudDidReceivePurchase", purchase.toMap())
}
}
}


override fun apphudFetchProductDetails(details: List<ProductDetails>) {
detailsCached = details
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.apphud.fluttersdk.handlers

import com.apphud.fluttersdk.toMap
import com.apphud.sdk.Apphud
import com.apphud.sdk.ApphudAttributionProvider
import io.flutter.plugin.common.MethodChannel
Expand All @@ -19,7 +20,24 @@ class AttributionHandler(
AttributionRoutes.addAttribution.name -> AttributionParser(result).parse(args) { provider, data, identifier ->
addAttribution(provider, data, identifier, result)
}

AttributionRoutes.collectSearchAdsAttribution.name -> result.notImplemented()
AttributionRoutes.attributeFromWeb.name -> AttributeFromWebParser(result).parse(args) { data ->
attributeFromWeb(data, result)
}
}
}

private fun attributeFromWeb(data: Map<String, Any>?, result: MethodChannel.Result) {
if (data == null) {
result.success({ "wasSuccessful" to false })
return
}
Apphud.attributeFromWeb(data) { wasSuccessful, user ->
val resultMap = hashMapOf<String, Any?>()
resultMap["wasSuccessful"] = wasSuccessful
resultMap["user"] = user?.toMap()
handleOnMainThread { result.success(resultMap) }
}
}

Expand Down Expand Up @@ -69,12 +87,33 @@ class AttributionHandler(
}
}
}

class AttributeFromWebParser(val result: MethodChannel.Result) {
fun parse(
args: Map<String, Any>?, callback: (
data: Map<String, Any>?,
) -> Unit
) {
try {
if (args == null) {
callback(null)
} else {
val data = args as? Map<String, Any>?
callback(data)
}
} catch (e: IllegalArgumentException) {
result.error("400", e.message, "")
}
}
}
}


enum class AttributionRoutes {

addAttribution,
collectSearchAdsAttribution;
collectSearchAdsAttribution,
attributeFromWeb;

companion object Mapper {
fun stringValues(): List<String> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ class HandlePurchasesHandler(

HandlePurchasesRoutes.restorePurchases.name -> restorePurchases(result)
HandlePurchasesRoutes.hasPremiumAccess.name -> hasPremiumAccess(result)
HandlePurchasesRoutes.refreshUserData.name -> refreshUserData(result)
}
}

private fun refreshUserData(result: MethodChannel.Result) {
Apphud.refreshUserData { user ->
handleOnMainThread { result.success(user?.toMap()) }
}
}

Expand Down Expand Up @@ -118,7 +125,8 @@ enum class HandlePurchasesRoutes {
nonRenewingPurchases,
isNonRenewingPurchaseActive,
restorePurchases,
hasPremiumAccess;
hasPremiumAccess,
refreshUserData;

companion object Mapper {
fun stringValues(): List<String> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ class InitializationHandler(
}

private fun updateUserID(userId: String, result: MethodChannel.Result) {
Apphud.updateUserId(userId = userId)
handleOnMainThread { result.success(null) }
Apphud.updateUserId(userId = userId) { user ->
handleOnMainThread { result.success(user?.toMap()) }
}
}

private fun userID(result: MethodChannel.Result) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import com.apphud.fluttersdk.FlutterSdkCommon
import com.apphud.fluttersdk.toApphudProduct
import com.apphud.fluttersdk.toMap
import com.apphud.sdk.Apphud
import com.apphud.sdk.ApphudError
import com.apphud.sdk.ApphudPurchaseResult
import com.apphud.sdk.domain.ApphudPaywall
import com.apphud.sdk.domain.ApphudProduct
import com.apphud.sdk.flutter.ApphudFlutter
import io.flutter.plugin.common.MethodChannel
Expand Down Expand Up @@ -51,8 +49,6 @@ class MakePurchaseHandler(

MakePurchaseRoutes.getPaywalls.name -> result.notImplemented()

MakePurchaseRoutes.paywalls.name -> paywalls(result)

MakePurchaseRoutes.paywallsDidLoadCallback.name -> paywallsDidLoadCallback(result)

MakePurchaseRoutes.purchaseProduct.name -> PurchaseProductParser(result).parse(args)
Expand All @@ -66,7 +62,7 @@ class MakePurchaseHandler(
)
}

MakePurchaseRoutes.permissionGroups.name -> getPermissionGroups(result)
MakePurchaseRoutes.permissionGroups.name -> permissionGroups(result)

MakePurchaseRoutes.rawPaywalls.name -> rawPaywalls(result)

Expand All @@ -84,20 +80,20 @@ class MakePurchaseHandler(
result
)
}

MakePurchaseRoutes.deferPlacements.name -> deferPlacements(result)
}
}

private fun getPermissionGroups(result: MethodChannel.Result) {
val groups = Apphud.permissionGroups()
handleOnMainThread { result.success(groups.map { it.toMap() }) }
private fun deferPlacements(result: MethodChannel.Result) {
Apphud.deferPlacements()
handleOnMainThread { result.success(null) }
}

private fun paywalls(result: MethodChannel.Result) {
private fun permissionGroups(result: MethodChannel.Result) {
GlobalScope.launch {
val paywalls: List<ApphudPaywall> = Apphud.paywalls()
val resultMap = hashMapOf<String, Any?>()
resultMap["paywalls"] = paywalls.map { paywall -> paywall.toMap() }
handleOnMainThread { result.success(resultMap) }
val groups = Apphud.fetchPermissionGroups()
handleOnMainThread { result.success(groups.map { it.toMap() }) }
}
}

Expand Down Expand Up @@ -346,14 +342,14 @@ enum class MakePurchaseRoutes {
syncPurchasesInObserverMode,
presentOfferCodeRedemptionSheet,
getPaywalls,
paywalls,
purchaseProduct,
permissionGroups,
paywallsDidLoadCallback,
rawPaywalls,
refreshUserData,
loadFallbackPaywalls,
trackPurchase;
trackPurchase,
deferPlacements;

companion object Mapper {
fun stringValues(): List<String> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ package com.apphud.fluttersdk.handlers
import com.apphud.sdk.Apphud
import com.apphud.sdk.domain.ApphudGroup
import io.flutter.plugin.common.MethodChannel
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch


@OptIn(DelicateCoroutinesApi::class)
class PromotionalsHandler(
override val routes: List<String>,
handleOnMainThreadP: HandleOnMainThread
Expand All @@ -17,9 +21,18 @@ class PromotionalsHandler(
) {
when (method) {
PromotionalsRoutes.grantPromotional.name ->
PromotionalsParser(result).parse(args) { daysCount, productId, permissionGroup ->
Apphud.grantPromotional(daysCount, productId, permissionGroup) { isGranted ->
handleOnMainThread { result.success(isGranted) }
PromotionalsParser(result).parse(args) { daysCount, productId, groupName ->
GlobalScope.launch {
val permissionGroup =
Apphud.fetchPermissionGroups().firstOrNull { it.name == groupName }

Apphud.grantPromotional(
daysCount,
productId,
permissionGroup
) { isGranted ->
handleOnMainThread { result.success(isGranted) }
}
}
}
}
Expand All @@ -29,16 +42,15 @@ class PromotionalsHandler(
class PromotionalsParser(private val result: MethodChannel.Result) {
fun parse(
args: Map<String, Any>?,
callback: (daysCount: Int, productId: String?, permissionGroup: ApphudGroup?) -> Unit
callback: (daysCount: Int, productId: String?, groupName: String?) -> Unit
) {
try {
args ?: throw IllegalArgumentException("arguments are required")
val daysCount = args["daysCount"] as? Int
?: throw IllegalArgumentException("daysCount is required argument")
val productId = args["productId"] as? String
val groupName = args["permissionGroupName"] as? String
val permissionGroup = Apphud.permissionGroups().firstOrNull { it.name == groupName }
callback(daysCount, productId, permissionGroup)
callback(daysCount, productId, groupName)
} catch (e: IllegalArgumentException) {
result.error("400", e.message, "")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,15 @@ class UserPropertiesHandler(
) { key, by ->
incrementUserProperty(key, by, result)
}

UserPropertiesRoutes.forceFlushUserProperties.name -> forceFlushUserProperties(result)
}
}

private fun forceFlushUserProperties(result: MethodChannel.Result) {
Apphud.forceFlushUserProperties { v -> handleOnMainThread { result.success(v) } }
}

private fun setUserProperty(
key: ApphudUserPropertyKey,
value: Any?,
Expand Down Expand Up @@ -112,7 +118,8 @@ class UserPropertiesHandler(

enum class UserPropertiesRoutes {
setUserProperty,
incrementUserProperty;
incrementUserProperty,
forceFlushUserProperties;

companion object Mapper {
fun stringValues(): List<String> {
Expand Down
Loading