-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Prebid] Implement Prebid integration to keep external IDs configured
- Loading branch information
Ian Bird
committed
Jun 13, 2024
1 parent
87747af
commit 0b57225
Showing
13 changed files
with
402 additions
and
7 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
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
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
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 @@ | ||
plugins { | ||
alias libs.plugins.androidLibrary | ||
alias libs.plugins.kotlinAndroid | ||
alias libs.plugins.dokka | ||
alias libs.plugins.mavenPublish | ||
} | ||
|
||
apply from: rootProject.file("$rootDir/common.gradle") | ||
|
||
android { | ||
namespace 'com.uid2.prebid' | ||
defaultConfig { | ||
minSdk 19 | ||
} | ||
|
||
kotlin { | ||
explicitApi() | ||
} | ||
|
||
kotlinOptions { | ||
freeCompilerArgs += [ "-opt-in=com.uid2.InternalUID2Api" ] | ||
} | ||
} | ||
|
||
dependencies { | ||
implementation project(":sdk") | ||
implementation(libs.prebid) | ||
|
||
testImplementation(libs.junit) | ||
|
||
testImplementation(libs.mockk.android) | ||
testImplementation(libs.mockk.agent) | ||
|
||
testImplementation(libs.json) | ||
} |
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,3 @@ | ||
POM_NAME=UID2 Android SDK (Prebid) | ||
POM_ARTIFACT_ID=uid2-android-sdk-prebid | ||
POM_DESCRIPTION=An SDK for integrating UID2 and Prebid into Android applications. |
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,2 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" /> |
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,132 @@ | ||
package com.uid2.prebid | ||
|
||
import com.uid2.UID2Manager | ||
import com.uid2.UID2ManagerState | ||
import com.uid2.UID2ManagerState.Established | ||
import com.uid2.UID2ManagerState.Refreshed | ||
import kotlinx.coroutines.CoroutineDispatcher | ||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.SupervisorJob | ||
import kotlinx.coroutines.cancel | ||
import kotlinx.coroutines.launch | ||
import org.prebid.mobile.ExternalUserId | ||
import org.prebid.mobile.PrebidMobile | ||
|
||
/** | ||
* Interface to wrap access to [PrebidMobile]. This is used to improve testability, rather than having the [UID2Prebid] | ||
* access it via static methods. | ||
*/ | ||
internal fun interface PrebidExternalUserIdInteractor { | ||
operator fun invoke(ids: List<ExternalUserId>) | ||
} | ||
|
||
/** | ||
* Prebid integration that will observe a given [UID2Manager] instance and update Prebid when a new [ExternalUserId] is | ||
* available. After creating the instance, a consumer must explicitly call [initialize] for this instance to start | ||
* observing changes. | ||
*/ | ||
public class UID2Prebid internal constructor( | ||
private val manager: UID2Manager, | ||
private val externalUserIdFactory: () -> List<ExternalUserId>, | ||
private val prebidInteractor: PrebidExternalUserIdInteractor, | ||
dispatcher: CoroutineDispatcher, | ||
) { | ||
|
||
// We redirect to the logger owned by the UID2Manager, as it's been configured correctly. | ||
private val logger = manager.logger | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param manager The [UID2Manager] instance to be observed. | ||
* @param externalUserIdFactory A factory that will allow the consumer to add any other [ExternalUserId]s that should | ||
* also be included, rather than just a single list containing only UID2's instance. | ||
*/ | ||
@JvmOverloads | ||
public constructor( | ||
manager: UID2Manager = UID2Manager.getInstance(), | ||
externalUserIdFactory: () -> List<ExternalUserId> = { emptyList() }, | ||
) : this( | ||
manager, | ||
externalUserIdFactory, | ||
PrebidExternalUserIdInteractor { ids -> PrebidMobile.setExternalUserIds(ids) }, | ||
Dispatchers.Default, | ||
) | ||
|
||
private val scope = CoroutineScope(dispatcher + SupervisorJob()) | ||
|
||
/** | ||
* Initializes the integration which will start observing the associated [UID2Manager] instance for changes in the | ||
* availability of the advertising token. As the token is refreshed, this will automatically update Prebid's list | ||
* of ExternalUserIds. | ||
*/ | ||
public fun initialize() { | ||
// Once the UID2Manager instance has been initialized, we will start observing it for changes. | ||
manager.addOnInitializedListener { | ||
updateExternalUserId(manager.getAdvertisingToken(), "Initialized") | ||
observeIdentityChanges() | ||
} | ||
} | ||
|
||
/** | ||
* Releases this instance, to not be used again. | ||
*/ | ||
public fun release() { | ||
scope.cancel() | ||
} | ||
|
||
/** | ||
* Returns the list of UID2 scoped [ExternalUserId]s. | ||
*/ | ||
public fun getExternalUserIdList(): List<ExternalUserId> { | ||
return getExternalUserIdList(manager.getAdvertisingToken()) | ||
} | ||
|
||
/** | ||
* Observes changes in the [UID2ManagerState] of the [UID2Manager] to update Prebid's [ExternalUserId]s. | ||
*/ | ||
private fun observeIdentityChanges() { | ||
scope.launch { | ||
manager.state.collect { state -> | ||
when (state) { | ||
is Established -> updateExternalUserId(state.identity.advertisingToken, "Identity Established") | ||
is Refreshed -> updateExternalUserId(state.identity.advertisingToken, "Identity Refreshed") | ||
else -> updateExternalUserId(null, "Identity Changed: $state") | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Updates Prebid's [ExternalUserId]s. | ||
*/ | ||
private fun updateExternalUserId(advertisingToken: String?, reason: String) { | ||
// We should set the external user ids to contain both our own UID2 specific one, along with any provided | ||
// externally. | ||
logger.i(TAG) { "Updating Prebid: $reason" } | ||
val userIds = getExternalUserIdList(advertisingToken) | ||
prebidInteractor(externalUserIdFactory() + userIds) | ||
} | ||
|
||
/** | ||
* Converts the given token to the associated list of [ExternalUserId]s. | ||
*/ | ||
private fun getExternalUserIdList(advertisingToken: String?): List<ExternalUserId> { | ||
return advertisingToken?.toExternalUserIdList() ?: emptyList() | ||
} | ||
|
||
/** | ||
* Extension function to build a list containing the single [ExternalUserId] that is associated with UID2. | ||
*/ | ||
private fun String.toExternalUserIdList(): List<ExternalUserId> { | ||
return listOf( | ||
ExternalUserId(USER_ID_SOURCE, this, null, null), | ||
) | ||
} | ||
|
||
private companion object { | ||
const val TAG = "UID2Prebid" | ||
const val USER_ID_SOURCE = "uidapi.com" | ||
} | ||
} |
Oops, something went wrong.