Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public void onCreate() {
super.onCreate();

OptableConfig config = new OptableConfig(this, "prebidtest", "android-sdk");
config.setOrigin("https://www.optable.co");
optable = new OptableSDK(config);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ class TheApplication : Application() {
override fun onCreate() {
super.onCreate()

val config = OptableConfig(this, "prebidtest", "android-sdk", "ca.edge.optable.co")
val config = OptableConfig(
providedContext = this,
tenant = "prebidtest",
originSlug = "android-sdk",
host = "ca.edge.optable.co",
origin = "https://www.optable.co",
)
optable = OptableSDK(config)
}

Expand Down
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ developers running the DCN locally for testing.
- `customUserAgent` An optional custom user agent string for network requests.
- `skipAdvertisingIdDetection` Boolean flag to skip the detection of advertising IDs. Default is false.
- `consents` Optional `OptableConsents` object for providing custom consent information. If not provided, default values will be used.
- `origin` An optional value for the HTTP `Origin` header sent with Optable API requests. Unrelated to `originSlug`.

```kotlin
val config = OptableConfig(
Expand All @@ -116,6 +117,7 @@ val config = OptableConfig(
customUserAgent = "",
skipAdvertisingIdDetection = false,
consents = OptableConsents(),
origin = "https://www.acmeco.com",
)
```

Expand All @@ -135,7 +137,7 @@ val config = OptableConfig(
)
```

Finally, an optional sixth boolean parameter `skipAdvertisingIdDetection` can be used to skip any ID info detection from
An optional boolean parameter `skipAdvertisingIdDetection` can be used to skip any ID info detection from
`AdvertisingIdClient` which by default runs in a background co-routine. Disabling ad ID detection means that the SDK
will not be able to automatically obtain the Google Advertising ID. For example, to disable ad ID detection, in Kotlin:

Expand All @@ -146,6 +148,26 @@ val config = OptableConfig(
)
```

Finally, an optional string parameter `origin` can be used to set the value of the HTTP `Origin` header sent with every
Optable API request. Mobile HTTP stacks do not send an `Origin` header by
default, and your DCN uses the request origin for several server-side features: some EID resolvers require it to be
present, and it also feeds site attribution and origin validation. Set it to the origin you want your mobile traffic
attributed to, for example:

```kotlin
val config = OptableConfig(
...
origin = "https://www.acmeco.com"
)
```

`origin` can also be set after the config has been created, which is the convenient form from Java:

```java
OptableConfig config = new OptableConfig(this, "prebidtest", "android-sdk");
config.setOrigin("https://www.acmeco.com");
```

### OptableIdentifiers

There are many fields to identify the users. You can provide any user information using `OptableIdentifiers` class.
Expand Down
3 changes: 3 additions & 0 deletions android_sdk/src/main/java/co/optable/sdk/OptableConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import android.content.Context
* @param customUserAgent An optional custom user agent string for network requests.
* @param skipAdvertisingIdDetection Boolean flag to skip the detection of advertising IDs. Default is false.
* @param consents Optional `OptableConsents` object for providing custom consent information. If not provided, default values will be used.
* @param origin An optional value for the HTTP `Origin` header sent with Optable API requests. Unrelated to `originSlug`.
* Settable after construction, which is how Java callers set it without passing every preceding parameter.
*/
class OptableConfig @JvmOverloads constructor(
providedContext: Context,
Expand All @@ -27,6 +29,7 @@ class OptableConfig @JvmOverloads constructor(
internal val customUserAgent: String? = null,
internal val skipAdvertisingIdDetection: Boolean = false,
var consents: OptableConsents = OptableConsents(),
var origin: String? = null,
) {

internal val context = providedContext.applicationContext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ internal class RequestInterceptor(
modifiedRequest.addHeader("Authorization", "Bearer $apiKey")
}

val origin = config.origin
if (!origin.isNullOrBlank()) {
modifiedRequest.addHeader("Origin", origin)
}

val userAgent = userAgentHolder.getUserAgent()
if (userAgent != null) {
modifiedRequest.addHeader("User-Agent", userAgent)
Expand Down
20 changes: 19 additions & 1 deletion android_sdk/src/test/java/co/optable/sdk/OptableConfigTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class OptableConfigTest {
assertNull(config.apiKey)
assertNull(config.customUserAgent)
assertFalse(config.skipAdvertisingIdDetection)
assertNull(config.origin)
assertEquals(mockApplicationContext, config.context)
}

Expand All @@ -55,7 +56,8 @@ class OptableConfigTest {
apiKey = "test-api-key",
customUserAgent = "TestAgent/1.0",
skipAdvertisingIdDetection = true,
consents = customConsents
consents = customConsents,
origin = "https://www.optable.co"
)

assertEquals("custom-tenant", config.tenant)
Expand All @@ -67,6 +69,7 @@ class OptableConfigTest {
assertEquals("TestAgent/1.0", config.customUserAgent)
assertTrue(config.skipAdvertisingIdDetection)
assertEquals(customConsents, config.consents)
assertEquals("https://www.optable.co", config.origin)
}

@Test
Expand Down Expand Up @@ -99,6 +102,21 @@ class OptableConfigTest {
assertEquals(expectedUrl, config.getBaseUrl())
}

@Test
fun `origin property should be updatable`() {
val config = OptableConfig(
providedContext = mockContext,
tenant = "test-tenant",
originSlug = "test-slug"
)

assertNull(config.origin)

config.origin = "https://www.acmeco.com"

assertEquals("https://www.acmeco.com", config.origin)
}

@Test
fun `consents property should be updatable`() {
val config = OptableConfig(
Expand Down
40 changes: 40 additions & 0 deletions android_sdk/src/test/java/co/optable/sdk/core/MockWebServerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class MockWebServerTest {
assertNull(request.headers["Authorization"])
assertNull(request.headers["X-Optable-Visitor"])
assertNull(request.headers["User-Agent"])
assertNull(request.headers["Origin"])

assertEquals("application/json", request.headers["Accept"])
assertEquals(
Expand Down Expand Up @@ -97,19 +98,58 @@ class MockWebServerTest {
assertEquals("passport", request.headers["X-Optable-Visitor"])
}

@Test
fun `optional header, origin`() {
whenever(config.origin).thenReturn("https://www.optable.co")

val request = makeRequest().request

assertEquals("https://www.optable.co", request.headers["Origin"])
}

@Test
fun `no origin header when origin is blank`() {
whenever(config.origin).thenReturn(" ")

val request = makeRequest().request

assertNull(request.headers["Origin"])
}

@Test
fun `no origin header when origin is empty`() {
whenever(config.origin).thenReturn("")

val request = makeRequest().request

assertNull(request.headers["Origin"])
}

@Test
fun `no origin header when origin is null`() {
whenever(config.origin).thenReturn(null)

val request = makeRequest().request

assertNull(request.headers["Origin"])
}

@Test
fun `complete request`() {
whenever(config.tenant).thenReturn("tenant")
whenever(config.originSlug).thenReturn("originSlug")
whenever(config.apiKey).thenReturn("apiKey")
whenever(storage.getPassport()).thenReturn("passport")
whenever(userAgentHolder.getUserAgent()).thenReturn("userAgent")
whenever(config.origin).thenReturn("https://www.optable.co")

val request = makeRequest().request

assertEquals("application/json", request.headers["Accept"])
assertEquals("Bearer apiKey", request.headers["Authorization"])
verify(config, times(1)).apiKey
assertEquals("https://www.optable.co", request.headers["Origin"])
verify(config, times(1)).origin
assertEquals("passport", request.headers["X-Optable-Visitor"])
verify(storage, times(1)).getPassport()
assertEquals("userAgent", request.headers["User-Agent"])
Expand Down
Loading