Skip to content

Commit dffcd3a

Browse files
committed
Implement Android target
1 parent eb682a4 commit dffcd3a

File tree

15 files changed

+448
-2
lines changed

15 files changed

+448
-2
lines changed

build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ tasks {
4343
"firebase-common:updateVersion", "firebase-common:updateDependencyVersion",
4444
"firebase-database:updateVersion", "firebase-database:updateDependencyVersion",
4545
"firebase-firestore:updateVersion", "firebase-firestore:updateDependencyVersion",
46-
"firebase-functions:updateVersion", "firebase-functions:updateDependencyVersion"
46+
"firebase-functions:updateVersion", "firebase-functions:updateDependencyVersion",
47+
"firebase-remoteconfig:updateVersion", "firebase-remoteconfig:updateDependencyVersion"
4748
)
4849
}
4950
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
* Copyright (c) 2020 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
6+
7+
version = project.property("firebase-remoteconfig.version") as String
8+
9+
plugins {
10+
id("com.android.library")
11+
kotlin("multiplatform")
12+
//id("com.quittle.android-emulator") version "0.2.0"
13+
}
14+
15+
android {
16+
compileSdkVersion(property("targetSdkVersion") as Int)
17+
defaultConfig {
18+
minSdkVersion(property("minSdkVersion") as Int)
19+
targetSdkVersion(property("targetSdkVersion") as Int)
20+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
21+
}
22+
sourceSets {
23+
getByName("main") {
24+
manifest.srcFile("src/androidMain/AndroidManifest.xml")
25+
}
26+
getByName("androidTest"){
27+
java.srcDir(file("src/androidAndroidTest/kotlin"))
28+
manifest.srcFile("src/androidAndroidTest/AndroidManifest.xml")
29+
}
30+
}
31+
testOptions {
32+
unitTests.apply {
33+
isIncludeAndroidResources = true
34+
}
35+
}
36+
packagingOptions {
37+
pickFirst("META-INF/kotlinx-serialization-core.kotlin_module")
38+
pickFirst("META-INF/AL2.0")
39+
pickFirst("META-INF/LGPL2.1")
40+
}
41+
lintOptions {
42+
isAbortOnError = false
43+
}
44+
}
45+
46+
// Optional configuration
47+
//androidEmulator {
48+
// emulator {
49+
// name("givlive_emulator")
50+
// sdkVersion(28)
51+
// abi("x86_64")
52+
// includeGoogleApis(true) // Defaults to false
53+
//
54+
// }
55+
// headless(false)
56+
// logEmulatorOutput(false)
57+
//}
58+
59+
kotlin {
60+
61+
android {
62+
publishAllLibraryVariants()
63+
}
64+
65+
fun nativeTargetConfig(): KotlinNativeTarget.() -> Unit = {
66+
val nativeFrameworkPaths = listOf(
67+
rootProject.project("firebase-app").projectDir.resolve("src/nativeInterop/cinterop/Carthage/Build/iOS"),
68+
projectDir.resolve("src/nativeInterop/cinterop/Carthage/Build/iOS")
69+
)
70+
71+
binaries {
72+
getTest("DEBUG").apply {
73+
linkerOpts(nativeFrameworkPaths.map { "-F$it" })
74+
linkerOpts("-ObjC")
75+
}
76+
}
77+
78+
compilations.getByName("main") {
79+
cinterops.create("FirebaseRemoteConfig") {
80+
compilerOpts(nativeFrameworkPaths.map { "-F$it" })
81+
extraOpts("-verbose")
82+
}
83+
}
84+
}
85+
86+
if (project.extra["ideaActive"] as Boolean) {
87+
iosX64("ios", nativeTargetConfig())
88+
} else {
89+
ios(configure = nativeTargetConfig())
90+
}
91+
92+
js {
93+
useCommonJs()
94+
nodejs {
95+
testTask {
96+
useMocha {
97+
timeout = "5s"
98+
}
99+
}
100+
}
101+
browser {
102+
testTask {
103+
useMocha {
104+
timeout = "5s"
105+
}
106+
}
107+
}
108+
}
109+
110+
sourceSets {
111+
all {
112+
languageSettings.apply {
113+
apiVersion = "1.4"
114+
languageVersion = "1.4"
115+
progressiveMode = true
116+
useExperimentalAnnotation("kotlinx.coroutines.ExperimentalCoroutinesApi")
117+
}
118+
}
119+
120+
val commonMain by getting {
121+
dependencies {
122+
api(project(":firebase-app"))
123+
implementation(project(":firebase-common"))
124+
}
125+
}
126+
127+
val androidMain by getting {
128+
dependencies {
129+
api("com.google.firebase:firebase-config-ktx:20.0.3")
130+
}
131+
}
132+
133+
val iosMain by getting
134+
135+
val jsMain by getting
136+
}
137+
}
138+
139+
signing {
140+
val signingKey: String? by project
141+
val signingPassword: String? by project
142+
useInMemoryPgpKeys(signingKey, signingPassword)
143+
sign(publishing.publications)
144+
}

firebase-remoteconfig/package.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "@gitlive/firebase-remoteconfig",
3+
"version": "1.0.0",
4+
"description": "Wrapper around firebase for usage in Kotlin Multiplatform projects",
5+
"main": "firebase-remoteconfig.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/GitLiveApp/firebase-kotlin-sdk.git"
12+
},
13+
"keywords": [
14+
"kotlin",
15+
"multiplatform",
16+
"kotlin-js",
17+
"firebase"
18+
],
19+
"author": "dev.gitlive",
20+
"license": "Apache-2.0",
21+
"bugs": {
22+
"url": "https://github.com/GitLiveApp/firebase-kotlin-sdk/issues"
23+
},
24+
"homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk",
25+
"dependencies": {
26+
"@gitlive/firebase-app": "1.3.1",
27+
"firebase": "8.5.0",
28+
"kotlin": "1.4.31",
29+
"kotlinx-coroutines-core": "1.4.3"
30+
}
31+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
package="dev.gitlive.firebase.remoteconfig">
3+
4+
<application android:usesCleartextTraffic="true" />
5+
</manifest>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Copyright (c) 2020 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
@file:JvmName("tests")
6+
package dev.gitlive.firebase.remoteconfig
7+
8+
import androidx.test.platform.app.InstrumentationRegistry
9+
import kotlinx.coroutines.runBlocking
10+
11+
actual val emulatorHost: String = "10.0.2.2"
12+
13+
actual val context: Any = InstrumentationRegistry.getInstrumentation().targetContext
14+
15+
actual fun runTest(test: suspend () -> Unit) = runBlocking { test() }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<manifest package="dev.gitlive.firebase.remoteconfig"/>
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package dev.gitlive.firebase.remoteconfig
2+
3+
import android.util.Log
4+
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
5+
import com.google.firebase.remoteconfig.FirebaseRemoteConfigInfo
6+
import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings
7+
import com.google.firebase.remoteconfig.ktx.remoteConfig
8+
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
9+
import dev.gitlive.firebase.Firebase
10+
import dev.gitlive.firebase.FirebaseApp
11+
import dev.gitlive.firebase.app
12+
import kotlinx.coroutines.tasks.await
13+
import com.google.firebase.ktx.Firebase as AndroidFirebase
14+
15+
actual val Firebase.remoteConfig: RemoteConfig by lazy { RemoteConfig() }
16+
17+
actual fun Firebase.remoteConfig(app: FirebaseApp): RemoteConfig = RemoteConfig(Firebase.app)
18+
19+
actual class RemoteConfig internal constructor(private val app: FirebaseApp? = null) {
20+
val android: FirebaseRemoteConfig
21+
get() = app?.let { AndroidFirebase.remoteConfig(app.android) }
22+
?: AndroidFirebase.remoteConfig
23+
24+
actual suspend fun activate(): Boolean = android.activate().await()
25+
26+
actual suspend fun ensureInitialized(): RemoteConfigInfo {
27+
val info = android.ensureInitialized().await()
28+
return info.asCommon()
29+
}
30+
31+
actual suspend fun fetch(minimumFetchIntervalInSeconds: Long?) {
32+
minimumFetchIntervalInSeconds
33+
?.also { android.fetch(it) }
34+
?: run { android.fetch() }
35+
.await()
36+
}
37+
38+
actual suspend fun fetchAndActivate(): Boolean = android.fetchAndActivate().await()
39+
40+
actual fun getAll(): Map<String, RemoteConfigValue> {
41+
Log.d("RemoteConfig", "${android.all.keys}")
42+
return android.all.mapValues { RemoteConfigValue(it.value) }
43+
}
44+
45+
actual fun getBoolean(key: String): Boolean = android.getBoolean(key)
46+
actual fun getDouble(key: String): Double = android.getDouble(key)
47+
actual fun getInfo(): RemoteConfigInfo = android.info.asCommon()
48+
actual fun getKeysByPrefix(prefix: String): Set<String> = android.getKeysByPrefix(prefix)
49+
actual fun getLong(key: String): Long = android.getLong(key)
50+
actual fun getString(key: String): String = android.getString(key)
51+
actual fun getValue(key: String): RemoteConfigValue = RemoteConfigValue(android.getValue(key))
52+
53+
actual suspend fun reset() {
54+
android.reset().await()
55+
}
56+
57+
actual suspend fun setConfigSettings(settings: RemoteConfigSettings) {
58+
val androidSettings = remoteConfigSettings {
59+
minimumFetchIntervalInSeconds = settings.minimumFetchIntervalInSeconds
60+
fetchTimeoutInSeconds = settings.fetchTimeoutInSeconds
61+
}
62+
android.setConfigSettingsAsync(androidSettings).await()
63+
}
64+
65+
actual suspend fun setDefaults(defaults: Map<String, Any>) {
66+
android.setDefaultsAsync(defaults).await()
67+
}
68+
69+
private fun FirebaseRemoteConfigSettings.asCommon(): RemoteConfigSettings {
70+
return RemoteConfigSettings(
71+
fetchTimeoutInSeconds = fetchTimeoutInSeconds,
72+
minimumFetchIntervalInSeconds = minimumFetchIntervalInSeconds,
73+
)
74+
}
75+
76+
private fun FirebaseRemoteConfigInfo.asCommon(): RemoteConfigInfo {
77+
val lastFetchStatus = when (lastFetchStatus) {
78+
FirebaseRemoteConfig.LAST_FETCH_STATUS_SUCCESS -> LastFetchStatus.Success
79+
FirebaseRemoteConfig.LAST_FETCH_STATUS_NO_FETCH_YET -> LastFetchStatus.NoFetchYet
80+
FirebaseRemoteConfig.LAST_FETCH_STATUS_FAILURE -> LastFetchStatus.Failure
81+
FirebaseRemoteConfig.LAST_FETCH_STATUS_THROTTLED -> LastFetchStatus.Throttled
82+
else -> error("Unknown last fetch status value: $lastFetchStatus")
83+
}
84+
85+
return RemoteConfigInfo(
86+
configSettings = configSettings.asCommon(),
87+
fetchTimeMillis = fetchTimeMillis,
88+
lastFetchStatus = lastFetchStatus
89+
)
90+
}
91+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package dev.gitlive.firebase.remoteconfig
2+
3+
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
4+
import com.google.firebase.remoteconfig.FirebaseRemoteConfigValue
5+
6+
actual class RemoteConfigValue internal constructor(private val android: FirebaseRemoteConfigValue) {
7+
actual fun asBoolean(): Boolean = android.asBoolean()
8+
actual fun asByteArray(): ByteArray = android.asByteArray()
9+
actual fun asDouble(): Double = android.asDouble()
10+
actual fun asLong(): Long = android.asLong()
11+
actual fun asString(): String = android.asString()
12+
actual fun getSource(): ValueSource = when (android.source) {
13+
FirebaseRemoteConfig.VALUE_SOURCE_STATIC -> ValueSource.Static
14+
FirebaseRemoteConfig.VALUE_SOURCE_DEFAULT -> ValueSource.Default
15+
FirebaseRemoteConfig.VALUE_SOURCE_REMOTE -> ValueSource.Remote
16+
else -> error("Unknown value source:${android.source}")
17+
}
18+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package dev.gitlive.firebase.remoteconfig
2+
3+
import dev.gitlive.firebase.Firebase
4+
import dev.gitlive.firebase.FirebaseApp
5+
6+
expect val Firebase.remoteConfig: RemoteConfig
7+
8+
expect fun Firebase.remoteConfig(app: FirebaseApp): RemoteConfig
9+
10+
expect class RemoteConfig {
11+
suspend fun activate(): Boolean
12+
suspend fun ensureInitialized(): RemoteConfigInfo
13+
suspend fun fetch(minimumFetchIntervalInSeconds: Long? = null)
14+
suspend fun fetchAndActivate(): Boolean
15+
fun getAll(): Map<String, RemoteConfigValue>
16+
fun getBoolean(key: String): Boolean
17+
fun getDouble(key: String): Double
18+
fun getInfo(): RemoteConfigInfo
19+
fun getKeysByPrefix(prefix: String): Set<String>
20+
fun getLong(key: String): Long
21+
fun getString(key: String): String
22+
fun getValue(key: String): RemoteConfigValue
23+
suspend fun reset()
24+
suspend fun setConfigSettings(settings: RemoteConfigSettings)
25+
suspend fun setDefaults(defaults: Map<String, Any>)
26+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package dev.gitlive.firebase.remoteconfig
2+
3+
data class RemoteConfigInfo(
4+
val configSettings: RemoteConfigSettings,
5+
val fetchTimeMillis: Long,
6+
val lastFetchStatus: LastFetchStatus,
7+
)
8+
9+
enum class LastFetchStatus { Success, Failure, Throttled, NoFetchYet }

0 commit comments

Comments
 (0)