-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* catch connectivity exceptions (#157) * webview crash handler (#158) * webview crash handler * pr updates * Feature/inapppurchase (#159) * Dev/purchase (#118) * Dev/volatile data (#114) * wip * tests * Dev/visitor fix (#115) * visitor profile fix * vs version * Dev/bug fixes (#116) * WebView Consent Sync sample * Fixes for visitor Id, app data, consent logging profile * Collect consent logging with batching enabled * Update per code review feedback Co-authored-by: Karen Tamayo <[email protected]> * ConsentManager cleanup + test fixes * In app purchase tracking * Latest WIP * Cleanup * WIP - code cleanup * In App Purchase module * Purchase updates + sample app (#119) Co-authored-by: Karen Tamayo <[email protected]> Co-authored-by: James Keith <[email protected]> Co-authored-by: Karen Tamayo <[email protected]> * Cleanup module * Tracker startConnection Co-authored-by: James Keith <[email protected]> Co-authored-by: Karen Tamayo <[email protected]> * remove error count config * inapppurchase proguard * test timeouts Co-authored-by: Karen Tamayo <[email protected]> Co-authored-by: Karen Tamayo <[email protected]>
- Loading branch information
1 parent
82c5382
commit b9f313e
Showing
33 changed files
with
892 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
plugins { | ||
id 'com.android.library' | ||
id 'kotlin-android' | ||
id 'maven-publish' | ||
} | ||
|
||
version = '1.0.0' | ||
|
||
android { | ||
compileSdkVersion 30 | ||
buildToolsVersion "30.0.3" | ||
|
||
defaultConfig { | ||
minSdkVersion 21 | ||
targetSdkVersion 30 | ||
versionCode 1 | ||
versionName "1.0" | ||
buildConfigField 'String', 'TAG', "\"Tealium-InAppPurchaseTracker-$version\"" | ||
buildConfigField 'String', 'LIBRARY_VERSION', "\"$version\"" | ||
|
||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" | ||
consumerProguardFiles "consumer-rules.pro" | ||
} | ||
|
||
buildTypes { | ||
release { | ||
minifyEnabled true | ||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | ||
} | ||
|
||
debug { | ||
minifyEnabled false | ||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | ||
testCoverageEnabled true | ||
} | ||
} | ||
|
||
compileOptions { | ||
sourceCompatibility JavaVersion.VERSION_11 | ||
targetCompatibility JavaVersion.VERSION_11 | ||
} | ||
|
||
kotlinOptions { | ||
jvmTarget = JavaVersion.VERSION_11 | ||
} | ||
|
||
testOptions { | ||
unitTests.returnDefaultValues = true | ||
} | ||
} | ||
|
||
dependencies { | ||
implementation fileTree(dir: 'libs', include: ['*.jar']) | ||
api project(":tealiumlibrary") | ||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" | ||
implementation 'androidx.core:core-ktx:1.3.0' | ||
implementation 'androidx.appcompat:appcompat:1.3.0' | ||
implementation 'com.google.android.material:material:1.4.0' | ||
implementation 'com.android.billingclient:billing:4.0.0' | ||
|
||
testImplementation 'androidx.test:core:1.2.0' | ||
testImplementation 'androidx.arch.core:core-testing:2.1.0' | ||
testImplementation "io.mockk:mockk:$mockk_version" | ||
testImplementation "org.robolectric:robolectric:4.3.1" | ||
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.5' | ||
testImplementation 'junit:junit:4.+' | ||
|
||
androidTestImplementation 'androidx.test.ext:junit:1.1.3' | ||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' | ||
} | ||
|
||
afterEvaluate { | ||
publishing { | ||
publications { | ||
release(MavenPublication) { | ||
from components.release | ||
groupId = 'com.tealium' | ||
artifactId = 'kotlin-inapp-purchase' | ||
} | ||
} | ||
repositories { | ||
// maven { | ||
// url "s3://maven.tealiumiq.com/android/releases/" | ||
// credentials(AwsCredentials) { | ||
// accessKey AWS_ACCESS_KEY | ||
// secretKey AWS_SECRET_KEY | ||
// sessionToken AWS_SESSION_TOKEN | ||
// } | ||
// } | ||
} | ||
} | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Add project specific ProGuard rules here. | ||
# You can control the set of applied configuration files using the | ||
# proguardFiles setting in build.gradle. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
-keepparameternames | ||
-keeppackagenames | ||
-renamesourcefileattribute SourceFile | ||
-keepattributes Exceptions,InnerClasses,Signature,Deprecated, | ||
SourceFile,LineNumberTable,*Annotation*,EnclosingMethod | ||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile | ||
|
||
-keep class kotlin.Metadata { *; } | ||
|
||
# Keep all public interfaces | ||
-keep public interface com.tealium.** { *; } | ||
-keep class com.tealium.inapppurchase.InAppPurchaseManager, | ||
com.tealium.inapppurchase.InAppPurchaseManager$Companion, | ||
com.tealium.inapppurchase.InAppPurchaseManagerKt{ | ||
*; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
package="com.tealium.inapppurchase"> | ||
|
||
</manifest> |
93 changes: 93 additions & 0 deletions
93
inapppurchase/src/main/java/com/tealium/inapppurchase/InAppPurchaseAutoTracker.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package com.tealium.inapppurchase | ||
|
||
import android.app.Activity | ||
import com.android.billingclient.api.* | ||
import com.tealium.core.Logger | ||
import com.tealium.core.TealiumContext | ||
import com.tealium.dispatcher.TealiumEvent | ||
|
||
class InAppPurchaseAutoTracker( | ||
private val context: TealiumContext, | ||
private val purchaseListener: PurchasesUpdatedListener = PurchaseListener(), | ||
private var billingClient: BillingClient? = null | ||
) : InAppPurchaseTracker { | ||
|
||
private fun startConnection() { | ||
if (billingClient == null) { | ||
billingClient = BillingClient.newBuilder(context.config.application) | ||
.setListener(purchaseListener) | ||
.enablePendingPurchases() | ||
.build() | ||
} | ||
|
||
if (billingClient?.isReady == true) { | ||
billingClient?.startConnection(this) | ||
} | ||
} | ||
|
||
private fun endConnection() { | ||
billingClient?.endConnection() | ||
billingClient = null | ||
} | ||
|
||
override fun onBillingSetupFinished(billingResult: BillingResult) { | ||
when (billingResult.responseCode) { | ||
BillingClient.BillingResponseCode.OK -> { | ||
Logger.dev(BuildConfig.TAG, "Connection established to BillingClient") | ||
} | ||
else -> { | ||
Logger.dev(BuildConfig.TAG, "Unable to connect: BillingClient is not available") | ||
} | ||
} | ||
} | ||
|
||
override fun onBillingServiceDisconnected() { | ||
startConnection() | ||
} | ||
|
||
override fun trackInAppPurchase(purchaseItem: Purchase, data: Map<String, Any>?) { | ||
val purchaseData = mutableMapOf<String, Any>( | ||
"autotracked" to true, | ||
PURCHASE_ORDER_ID to purchaseItem.orderId, | ||
PURCHASE_TIMESTAMP to purchaseItem.purchaseTime, | ||
PURCHASE_QUANTITY to purchaseItem.quantity, | ||
PURCHASE_SKUS to purchaseItem.skus, | ||
PURCHASE_AUTORENEWING to purchaseItem.isAutoRenewing, | ||
PURCHASE_STATE to purchaseItem.purchaseState | ||
) | ||
|
||
data?.let { | ||
purchaseData.putAll(it) | ||
} | ||
|
||
context.track(TealiumEvent(IN_APP_PURCHASE_EVENT, purchaseData)) | ||
} | ||
|
||
override fun onActivityPaused(activity: Activity?) { | ||
// do nothing | ||
} | ||
|
||
override fun onActivityResumed(activity: Activity?) { | ||
if (billingClient == null) { | ||
startConnection() | ||
} | ||
} | ||
|
||
override fun onActivityStopped(activity: Activity?, isChangingConfiguration: Boolean) { | ||
billingClient?.let { | ||
if (it.connectionState == BillingClient.ConnectionState.CLOSED) { | ||
endConnection() | ||
} | ||
} | ||
} | ||
|
||
private companion object { | ||
private const val IN_APP_PURCHASE_EVENT = "in_app_purchase" | ||
const val PURCHASE_ORDER_ID = "purchase_order_id" | ||
const val PURCHASE_TIMESTAMP = "purchase_timestamp" | ||
const val PURCHASE_QUANTITY = "purchase_quantity" | ||
const val PURCHASE_SKUS = "purchase_skus" | ||
const val PURCHASE_AUTORENEWING = "purchase_is_auto_renewing" | ||
const val PURCHASE_STATE = "purchase_state" | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
inapppurchase/src/main/java/com/tealium/inapppurchase/InAppPurchaseManager.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package com.tealium.inapppurchase | ||
|
||
import com.android.billingclient.api.* | ||
import com.tealium.core.* | ||
|
||
class InAppPurchaseManager( | ||
private val context: TealiumContext, | ||
private val purchaseListener: PurchasesUpdatedListener = PurchaseListener(), | ||
private val purchaseTracker: InAppPurchaseTracker = InAppPurchaseAutoTracker(context, purchaseListener) | ||
) : Module { | ||
|
||
override val name: String = MODULE_NAME | ||
override var enabled: Boolean = true | ||
|
||
// Manually track purchase | ||
fun trackInAppPurchase(purchaseItem: Purchase, data: Map<String, Any>? = null) { | ||
purchaseTracker.trackInAppPurchase(purchaseItem, data) | ||
} | ||
|
||
companion object : ModuleFactory { | ||
const val MODULE_NAME = "InAppPurchaseManager" | ||
const val MODULE_VERSION = BuildConfig.LIBRARY_VERSION | ||
|
||
@Volatile private var instance: InAppPurchaseManager? = null | ||
private val contexts = mutableListOf<TealiumContext>() | ||
|
||
override fun create(context: TealiumContext): Module { | ||
contexts.add(context) | ||
return instance ?: synchronized(this) { | ||
instance ?: InAppPurchaseManager(context).also { | ||
instance = it | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
val Modules.InAppPurchaseManager: ModuleFactory | ||
get() = com.tealium.inapppurchase.InAppPurchaseManager | ||
|
||
val Tealium.inAppPurchaseManager: InAppPurchaseManager? | ||
get() = modules.getModule(InAppPurchaseManager::class.java) |
9 changes: 9 additions & 0 deletions
9
inapppurchase/src/main/java/com/tealium/inapppurchase/InAppPurchaseTracker.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.tealium.inapppurchase | ||
|
||
import com.android.billingclient.api.BillingClientStateListener | ||
import com.android.billingclient.api.Purchase | ||
import com.tealium.core.messaging.ActivityObserverListener | ||
|
||
interface InAppPurchaseTracker: BillingClientStateListener, ActivityObserverListener { | ||
fun trackInAppPurchase(purchaseItem: Purchase, data: Map<String, Any>? = null) | ||
} |
46 changes: 46 additions & 0 deletions
46
inapppurchase/src/main/java/com/tealium/inapppurchase/PurchaseListener.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package com.tealium.inapppurchase | ||
|
||
import com.android.billingclient.api.BillingClient | ||
import com.android.billingclient.api.BillingResult | ||
import com.android.billingclient.api.Purchase | ||
import com.android.billingclient.api.PurchasesUpdatedListener | ||
import com.tealium.core.Logger | ||
import com.tealium.core.Tealium | ||
|
||
class PurchaseListener: PurchasesUpdatedListener { | ||
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList<Purchase>?) { | ||
Tealium.names().forEach { instanceName -> | ||
when (billingResult.responseCode) { | ||
BillingClient.BillingResponseCode.OK -> { | ||
purchases?.forEach { purchaseItem -> | ||
when(purchaseItem.purchaseState) { | ||
Purchase.PurchaseState.PURCHASED -> { | ||
Logger.dev(BuildConfig.TAG, "Tracking purchase with order id: ${purchaseItem.orderId}") | ||
|
||
Tealium[instanceName]?.inAppPurchaseManager?.trackInAppPurchase(purchaseItem) | ||
} | ||
Purchase.PurchaseState.PENDING -> { | ||
Logger.dev(BuildConfig.TAG, "Purchase pending for order id: ${purchaseItem.orderId}") | ||
Tealium[instanceName]?.inAppPurchaseManager?.trackInAppPurchase(purchaseItem) | ||
} | ||
else -> { | ||
Logger.dev(BuildConfig.TAG, "Unable to track purchase: ${purchaseItem.orderId}") | ||
} | ||
} | ||
} | ||
} | ||
|
||
BillingClient.BillingResponseCode.USER_CANCELED -> { | ||
Logger.dev(BuildConfig.TAG, "Unable to track purchase. User cancelled.") | ||
} | ||
|
||
BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED -> { | ||
Logger.dev(BuildConfig.TAG, "Unable to track purchase. Item is already owned.") | ||
} | ||
else -> { | ||
Logger.dev(BuildConfig.TAG, "Unable to track purchases") | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.