Skip to content

Commit c786b25

Browse files
authored
Merge pull request #98 from IABTechLab/dave/euid
EUID Support
2 parents 0a8762e + 429d744 commit c786b25

File tree

22 files changed

+348
-55
lines changed

22 files changed

+348
-55
lines changed

dev-app/src/main/AndroidManifest.xml

+4
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,17 @@
1111
android:icon="@mipmap/ic_launcher"
1212
android:allowBackup="false"
1313
android:supportsRtl="true"
14+
android:networkSecurityConfig="@xml/network_security_config"
1415
tools:targetApi="31">
1516

1617
<!-- Metadata Required for Server-Side Integration -->
1718
<!-- This information is only consumed by the DevApp (not the SDK) to simulate a server side integration. -->
1819
<meta-data android:name="uid2_api_key" android:value=""/>
1920
<meta-data android:name="uid2_api_secret" android:value=""/>
2021

22+
<!-- Metadata for toggling UID2 and EUID environments. If true, EUID is used. -->
23+
<meta-data android:name="uid2_environment_euid" android:value="false"/>
24+
2125
<activity android:name="com.uid2.dev.MainActivity"
2226
android:exported="true">
2327
<intent-filter>

dev-app/src/main/java/com/uid2/dev/DevApplication.kt

+23-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ package com.uid2.dev
33
import android.app.Application
44
import android.os.StrictMode
55
import android.util.Log
6+
import com.uid2.EUIDManager
67
import com.uid2.UID2Manager
8+
import com.uid2.dev.utils.getMetadata
9+
import com.uid2.dev.utils.isEnvironmentEUID
710
import com.uid2.prebid.UID2Prebid
811
import org.prebid.mobile.PrebidMobile
912

@@ -13,16 +16,32 @@ class DevApplication : Application() {
1316
override fun onCreate() {
1417
super.onCreate()
1518

19+
val isEnvironmentEUID = getMetadata().isEnvironmentEUID()
20+
1621
// Initialise the UID2Manager class. We will use it's DefaultNetworkSession rather than providing our own
1722
// custom implementation. This can be done to allow wrapping something like OkHttp.
18-
UID2Manager.init(context = this, serverUrl = INTEG_SERVER_URL, isLoggingEnabled = true)
23+
if (isEnvironmentEUID) {
24+
EUIDManager.init(
25+
context = this,
26+
EUIDManager.Environment.Custom(EUID_INTEG_SERVER_URL),
27+
isLoggingEnabled = true,
28+
)
29+
} else {
30+
UID2Manager.init(
31+
context = this,
32+
UID2Manager.Environment.Custom(UID2_INTEG_SERVER_URL),
33+
isLoggingEnabled = true,
34+
)
35+
}
1936

2037
// Alternatively, we could initialise the UID2Manager with our own custom NetworkSession...
2138
// UID2Manager.init(this, INTEG_SERVER_URL, OkNetworkSession(), true)
2239

2340
// Create the Prebid integration and allow it to start observing the UID2Manager instance.
2441
PrebidMobile.initializeSdk(this) { Log.i(TAG, "Prebid: $it") }
25-
prebid = UID2Prebid().apply {
42+
prebid = UID2Prebid(
43+
if (isEnvironmentEUID) EUIDManager.getInstance() else UID2Manager.getInstance(),
44+
).apply {
2645
initialize()
2746
}
2847

@@ -45,6 +64,7 @@ class DevApplication : Application() {
4564
private companion object {
4665
const val TAG = "DevApplication"
4766

48-
const val INTEG_SERVER_URL = "https://operator-integ.uidapi.com"
67+
const val UID2_INTEG_SERVER_URL = "https://operator-integ.uidapi.com"
68+
const val EUID_INTEG_SERVER_URL = "https://integ.euid.eu/v2"
4969
}
5070
}

dev-app/src/main/java/com/uid2/dev/MainActivity.kt

+12-1
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,34 @@ import androidx.activity.ComponentActivity
55
import androidx.activity.compose.setContent
66
import androidx.activity.viewModels
77
import androidx.compose.material.MaterialTheme
8+
import com.uid2.EUIDManager
89
import com.uid2.UID2Manager
910
import com.uid2.dev.network.AppUID2Client
1011
import com.uid2.dev.ui.MainScreen
1112
import com.uid2.dev.ui.MainScreenViewModel
1213
import com.uid2.dev.ui.MainScreenViewModelFactory
14+
import com.uid2.dev.utils.getMetadata
15+
import com.uid2.dev.utils.isEnvironmentEUID
16+
import com.uid2.devapp.R
1317

1418
class MainActivity : ComponentActivity() {
1519

1620
private val viewModel: MainScreenViewModel by viewModels {
21+
val isEUID = getMetadata().isEnvironmentEUID()
1722
MainScreenViewModelFactory(
1823
AppUID2Client.fromContext(baseContext),
19-
UID2Manager.getInstance(),
24+
if (isEUID) EUIDManager.getInstance() else UID2Manager.getInstance(),
25+
isEUID,
2026
)
2127
}
2228

2329
override fun onCreate(savedInstanceState: Bundle?) {
2430
super.onCreate(savedInstanceState)
31+
32+
if (getMetadata().isEnvironmentEUID()) {
33+
setTitle(R.string.app_name_euid)
34+
}
35+
2536
setContent {
2637
MaterialTheme {
2738
MainScreen(viewModel)

dev-app/src/main/java/com/uid2/dev/network/AppUID2Client.kt

+1-17
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
package com.uid2.dev.network
22

33
import android.content.Context
4-
import android.content.pm.ApplicationInfo
5-
import android.content.pm.PackageManager
6-
import android.os.Build
7-
import android.os.Bundle
84
import android.util.Base64
95
import com.uid2.data.UID2Identity
6+
import com.uid2.dev.utils.getMetadata
107
import com.uid2.network.DataEnvelope
118
import kotlinx.coroutines.Dispatchers
129
import kotlinx.coroutines.withContext
@@ -191,18 +188,5 @@ class AppUID2Client(
191188
it.getString(UID2_API_SECRET_KEY, ""),
192189
)
193190
}
194-
195-
private fun Context.getMetadata(): Bundle = packageManager.getApplicationInfoCompat(
196-
packageName,
197-
PackageManager.GET_META_DATA,
198-
).metaData
199-
200-
private fun PackageManager.getApplicationInfoCompat(packageName: String, flags: Int = 0): ApplicationInfo =
201-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
202-
getApplicationInfo(packageName, PackageManager.ApplicationInfoFlags.of(flags.toLong()))
203-
} else {
204-
@Suppress("DEPRECATION")
205-
getApplicationInfo(packageName, flags)
206-
}
207191
}
208192
}

dev-app/src/main/java/com/uid2/dev/ui/MainScreenViewModel.kt

+16-7
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,15 @@ sealed interface MainScreenState : ViewState {
5151
class MainScreenViewModel(
5252
private val api: AppUID2Client,
5353
private val manager: UID2Manager,
54+
isEUID: Boolean,
5455
) : BasicViewModel<MainScreenAction, MainScreenState>() {
5556

5657
private val _viewState = MutableStateFlow<MainScreenState>(UserUpdatedState(null, NO_IDENTITY))
5758
override val viewState: StateFlow<MainScreenState> = _viewState.asStateFlow()
5859

60+
private val subscriptionId: String = if (isEUID) SUBSCRIPTION_ID_EUID else SUBSCRIPTION_ID_UID2
61+
private val publicKey: String = if (isEUID) PUBLIC_KEY_EUID else PUBLIC_KEY_UID2
62+
5963
init {
6064
// Observe the state of the UID2Manager and translate those into our own ViewState. This will happen when the
6165
// Identity is initial set, or refreshed, or reset.
@@ -98,8 +102,8 @@ class MainScreenViewModel(
98102
// Generate the identity via Client Side Integration (client side token generation).
99103
manager.generateIdentity(
100104
IdentityRequest.Email(action.address),
101-
SUBSCRIPTION_ID,
102-
PUBLIC_KEY,
105+
subscriptionId,
106+
publicKey,
103107
onGenerateResult,
104108
)
105109
} else {
@@ -120,8 +124,8 @@ class MainScreenViewModel(
120124
// Generate the identity via Client Side Integration (client side token generation).
121125
manager.generateIdentity(
122126
IdentityRequest.Phone(action.number),
123-
SUBSCRIPTION_ID,
124-
PUBLIC_KEY,
127+
subscriptionId,
128+
publicKey,
125129
onGenerateResult,
126130
)
127131
} else {
@@ -149,19 +153,24 @@ class MainScreenViewModel(
149153
private companion object {
150154
const val TAG = "MainScreenViewModel"
151155

152-
const val SUBSCRIPTION_ID = "toPh8vgJgt"
156+
const val SUBSCRIPTION_ID_UID2 = "toPh8vgJgt"
157+
const val SUBSCRIPTION_ID_EUID = "w6yPQzN4dA"
158+
159+
@Suppress("ktlint:standard:max-line-length")
160+
const val PUBLIC_KEY_UID2 = "UID2-X-I-MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKAbPfOz7u25g1fL6riU7p2eeqhjmpALPeYoyjvZmZ1xM2NM8UeOmDZmCIBnKyRZ97pz5bMCjrs38WM22O7LJuw=="
153161

154162
@Suppress("ktlint:standard:max-line-length")
155-
const val PUBLIC_KEY = "UID2-X-I-MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKAbPfOz7u25g1fL6riU7p2eeqhjmpALPeYoyjvZmZ1xM2NM8UeOmDZmCIBnKyRZ97pz5bMCjrs38WM22O7LJuw=="
163+
const val PUBLIC_KEY_EUID = "EUID-X-I-MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEH/k7HYGuWhjhCo8nXgj/ypClo5kek7uRKvzCGwj04Y1eXOWmHDOLAQVCPquZdfVVezIpABNAl9zvsSEC7g+ZGg=="
156164
}
157165
}
158166

159167
class MainScreenViewModelFactory(
160168
private val api: AppUID2Client,
161169
private val manager: UID2Manager,
170+
private val isEUID: Boolean,
162171
) : ViewModelProvider.Factory {
163172
@Suppress("UNCHECKED_CAST")
164173
override fun <T : ViewModel> create(modelClass: Class<T>): T {
165-
return MainScreenViewModel(api, manager) as T
174+
return MainScreenViewModel(api, manager, isEUID) as T
166175
}
167176
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.uid2.dev.utils
2+
3+
import android.os.Bundle
4+
5+
private const val UID2_ENVIRONMENT_EUID = "uid2_environment_euid"
6+
7+
fun Bundle.isEnvironmentEUID(): Boolean = getBoolean(UID2_ENVIRONMENT_EUID, false)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.uid2.dev.utils
2+
3+
import android.content.Context
4+
import android.content.pm.PackageManager
5+
import android.os.Bundle
6+
7+
fun Context.getMetadata(): Bundle = packageManager.getApplicationInfoCompat(
8+
packageName,
9+
PackageManager.GET_META_DATA,
10+
).metaData
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.uid2.dev.utils
2+
3+
import android.content.pm.ApplicationInfo
4+
import android.content.pm.PackageManager
5+
import android.os.Build
6+
7+
fun PackageManager.getApplicationInfoCompat(packageName: String, flags: Int = 0): ApplicationInfo =
8+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
9+
@Suppress("WrongConstant")
10+
getApplicationInfo(packageName, PackageManager.ApplicationInfoFlags.of(flags.toLong()))
11+
} else {
12+
@Suppress("DEPRECATION")
13+
getApplicationInfo(packageName, flags)
14+
}

dev-app/src/main/res/values/strings.xml

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<resources>
22
<string name="app_name">UID2 SDK Dev App</string>
3+
<string name="app_name_euid">EUID SDK Dev App</string>
34

45
<string name="email">Email</string>
56
<string name="phone">Phone Number</string>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<network-security-config>
2+
<debug-overrides>
3+
<trust-anchors>
4+
<!-- Trust user added CAs while debuggable only -->
5+
<certificates src="user" />
6+
</trust-anchors>
7+
</debug-overrides>
8+
</network-security-config>
+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package com.uid2
2+
3+
import android.content.Context
4+
import com.uid2.UID2Manager.Companion.APPLICATION_ID_DEFAULT
5+
import com.uid2.network.DefaultNetworkSession
6+
import com.uid2.network.NetworkSession
7+
import com.uid2.storage.FileStorageManager
8+
import com.uid2.storage.FileStorageManager.Store.EUID
9+
import com.uid2.storage.StorageManager
10+
import com.uid2.utils.InputUtils
11+
import com.uid2.utils.Logger
12+
import com.uid2.utils.TimeUtils
13+
import kotlinx.coroutines.Dispatchers
14+
15+
public object EUIDManager {
16+
17+
public sealed interface Environment {
18+
public val serverUrl: String
19+
20+
/**
21+
* AWS EU West 2 (London).
22+
*/
23+
public data object London : Environment {
24+
override val serverUrl: String = EUID_API_URL_PRODUCTION
25+
}
26+
27+
/**
28+
* The default Environment, equivalent to [London].
29+
*/
30+
public data object Production : Environment {
31+
override val serverUrl: String = EUID_API_URL_PRODUCTION
32+
}
33+
34+
/**
35+
* An Environment with its own API endpoint, such as for integration testing.
36+
*/
37+
public data class Custom(
38+
override val serverUrl: String,
39+
) : Environment
40+
}
41+
42+
// The default API server.
43+
internal const val EUID_API_URL_PRODUCTION = "https://prod.euid.eu/v2"
44+
45+
private var serverUrl: String = EUID_API_URL_PRODUCTION
46+
private var applicationId: String = APPLICATION_ID_DEFAULT
47+
private var networkSession: NetworkSession = DefaultNetworkSession()
48+
private var storageManager: StorageManager? = null
49+
private var isLoggingEnabled: Boolean = false
50+
51+
private var instance: UID2Manager? = null
52+
53+
/**
54+
* Initializes the class with the given [Context], along with a [NetworkSession] that will be responsible
55+
* for making any required network calls.
56+
*
57+
* @param context The context to initialise from. This will be used to obtain the package's metadata to extract
58+
* the API URL.
59+
* @param environment The API Environment to use.
60+
* @param networkSession A custom [NetworkSession] which can be used for making any required network calls.
61+
* The default implementation supported by the SDK can be found as [DefaultNetworkSession].
62+
*/
63+
@JvmStatic
64+
@JvmOverloads
65+
@Throws(InitializationException::class)
66+
public fun init(
67+
context: Context,
68+
environment: Environment = Environment.Production,
69+
networkSession: NetworkSession = DefaultNetworkSession(),
70+
isLoggingEnabled: Boolean = false,
71+
) {
72+
if (instance != null) {
73+
throw InitializationException()
74+
}
75+
76+
this.serverUrl = environment.serverUrl
77+
this.applicationId = context.packageName
78+
this.networkSession = networkSession
79+
this.storageManager = FileStorageManager(context.applicationContext, EUID)
80+
this.isLoggingEnabled = isLoggingEnabled
81+
}
82+
83+
/**
84+
* Returns True if the manager is already initialised, otherwise False.
85+
*/
86+
@JvmStatic
87+
public fun isInitialized(): Boolean = instance != null
88+
89+
/**
90+
* Gets the current singleton instance of the manager.
91+
*
92+
* @throws InitializationException Thrown if the manager has not yet been initialised.
93+
*/
94+
@JvmStatic
95+
public fun getInstance(): UID2Manager {
96+
if (storageManager == null) {
97+
throw InitializationException()
98+
}
99+
val storage = storageManager ?: throw InitializationException()
100+
val logger = Logger(isLoggingEnabled)
101+
102+
return instance ?: UID2Manager(
103+
UID2Client(
104+
apiUrl = serverUrl,
105+
session = networkSession,
106+
applicationId = applicationId,
107+
logger = logger,
108+
),
109+
storage,
110+
TimeUtils,
111+
InputUtils(),
112+
Dispatchers.Default,
113+
true,
114+
logger,
115+
).apply {
116+
instance = this
117+
}
118+
}
119+
}

0 commit comments

Comments
 (0)