Skip to content

Commit 2524033

Browse files
authored
Merge branch 'master' into publish_maven_central
2 parents ff365ef + 2d440a7 commit 2524033

File tree

6 files changed

+115
-24
lines changed

6 files changed

+115
-24
lines changed

README.md

Lines changed: 106 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,129 @@
1-
<h1 align="left">Firebase Kotlin SDK <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/teamhubapp/firebase-kotlin-sdk?style=flat-square"></h1>
1+
<h1 align="left">Firebase Kotlin SDK <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/gitliveapp/firebase-kotlin-sdk?style=flat-square"></h1>
22
<img align="left" width="75px" src="https://avatars2.githubusercontent.com/u/42865805?s=200&v=4">
33
<b>Built and maintained with 🧡 by <a href="https://teamhub.dev">TeamHub</a></b><br/>
44
<i>Real-time code collaboration inside any IDE</i><br/>
55
🔓 <a href="https://teamhub.typeform.com/to/uSS8cv">Request Early Access</a>
66
<h4></h4>
77

8-
The Firebase Kotlin SDK is a Kotlin-first SDK for Firebase. It's API is similar to the [Firebase Android SDK Kotlin Extensions](https://firebase.github.io/firebase-android-sdk/reference/kotlin/firebase-ktx/) but it also supports multiplatform projects, enabling you to use Firebase directly from your common source targeting *iOS*, *Android* or *JS*.
9-
10-
## Kotlin-first design
11-
8+
The Firebase Kotlin SDK is a Kotlin-first SDK for Firebase. It's API is similar to the [Firebase Android SDK Kotlin Extensions](https://firebase.github.io/firebase-android-sdk/reference/kotlin/firebase-ktx/) but also supports multiplatform projects, enabling you to use Firebase directly from your common source targeting *iOS*, *Android* or *JS*.
129

1310
## Available libraries
1411

1512
The following libraries are available for the various Firebase products.
1613

1714
| Service or Product | Gradle Dependency | API Coverage |
1815
| ------------------------------------------------------------------------------------ | :-----------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
19-
| [Authentication](https://firebase.google.com/docs/auth#kotlin-android) | [`dev.teamhub.firebase:firebase-auth:0.1.0`](https://mvnrepository.com/artifact/dev.teamhub.firebase/firebase-auth/0.1.0) | [![0-50%](https://img.shields.io/badge/-0--50%25-red?style=flat-square)](/firebase-auth/src/commonMain/kotlin/dev/teamhub/firebase/auth/auth.kt) [![Android: 50%](https://img.shields.io/badge/Android-50%25-green?style=flat-square)](/firebase-auth/src/androidMain/kotlin/dev/teamhub/firebase/auth/auth.kt) [![JS: 50%](https://img.shields.io/badge/Web-50%25-red?style=flat-square)](/firebase-auth/src/jsMain/kotlin/dev/teamhub/firebase/auth/auth.kt) [![iOS: 0%](https://img.shields.io/badge/iOS-0%25-blue?style=flat-square)](/firebase-auth/src/iosMain/kotlin/dev/teamhub/firebase/auth/auth.kt) |
20-
| [Realtime Database](https://firebase.google.com/docs/database#kotlin-android) | [`dev.teamhub.firebase:firebase-database:0.1.0`](https://mvnrepository.com/artifact/dev.teamhub.firebase/firebase-database/0.1.0) | [![0-50%](https://img.shields.io/badge/-0--50%25-red?style=flat-square)](/firebase-database/src/commonMain/kotlin/dev/teamhub/firebase/auth/database.kt) [![Android: 50%](https://img.shields.io/badge/Android-50%25-green?style=flat-square)](/firebase-database/src/androidMain/kotlin/dev/teamhub/firebase/database/database.kt) [![JS: 50%](https://img.shields.io/badge/Web-50%25-red?style=flat-square)](/firebase-database/src/jsMain/kotlin/dev/teamhub/firebase/database/database.kt) [![iOS: 0%](https://img.shields.io/badge/iOS-0%25-blue?style=flat-square)](/firebase-database/src/iosMain/kotlin/dev/teamhub/firebase/database/database.kt) |
21-
| [Cloud Firestore](https://firebase.google.com/docs/firestore#kotlin-android) | [`dev.teamhub.firebase:firebase-firestore:0.1.0`](https://mvnrepository.com/artifact/dev.teamhub.firebase/firebase-firestore/0.1.0) | [![0-50%](https://img.shields.io/badge/-0--50%25-red?style=flat-square)](/firebase-firestore/src/commonMain/kotlin/dev/teamhub/firebase/firestore/firestore.kt) [![Android: 50%](https://img.shields.io/badge/Android-50%25-green?style=flat-square)](/firebase-auth/src/androidMain/kotlin/dev/teamhub/firebase/firestore/firestore.kt) [![JS: 50%](https://img.shields.io/badge/Web-50%25-red?style=flat-square)](/firebase-firestore/src/jsMain/kotlin/dev/teamhub/firebase/firestore/firestore.kt) [![iOS: 0%](https://img.shields.io/badge/iOS-0%25-blue?style=flat-square)](/firebase-firestore/src/iosMain/kotlin/dev/teamhub/firebase/firestore/firestore.kt) |
22-
| [Cloud Functions](https://firebase.google.com/docs/functions/callable#kotlin-android)| [`dev.teamhub.firebase:firebase-functions:0.1.0`](https://mvnrepository.com/artifact/dev.teamhub.firebase/firebase-functions/0.1.0) | [![0-50%](https://img.shields.io/badge/-0--50%25-orange?style=flat-square)](/firebase-functions/src/commonMain/kotlin/dev/teamhub/firebase/functions/functions.kt) [![Android: 50%](https://img.shields.io/badge/Android-50%25-green?style=flat-square)](/firebase-functions/src/androidMain/kotlin/dev/teamhub/firebase/functions/functions.kt) [![JS: 50%](https://img.shields.io/badge/Web-50%25-red?style=flat-square)](/firebase-functions/src/jsMain/kotlin/dev/teamhub/firebase/functions/functions.kt) [![iOS: 0%](https://img.shields.io/badge/iOS-0%25-blue?style=flat-square)](/firebase-functions/src/iosMain/kotlin/dev/teamhub/firebase/functions/functions.kt) |
23-
| [Cloud Messaging](https://firebase.google.com/docs/messaging#kotlin-android) | [`dev.teamhub.firebase:firebase-messaging:0.1.0`](https://mvnrepository.com/artifact/dev.teamhub.firebase/firebase-messaging/0.1.0) | ![0%](https://img.shields.io/badge/-0%25-lightgrey?style=flat-square) |
24-
| [Cloud Storage](https://firebase.google.com/docs/storage#kotlin-android) | [`dev.teamhub.firebase:firebase-storage:0.1.0`](https://mvnrepository.com/artifact/dev.teamhub.firebase/firebase-storage/0.1.0) | ![0%](https://img.shields.io/badge/-0%25-lightgrey?style=flat-square) |
16+
| [Authentication](https://firebase.google.com/docs/auth#kotlin-android) | [`dev.gitlive.firebase:firebase-auth:0.1.0`](https://mvnrepository.com/artifact/dev.teamhub.firebase/firebase-auth/0.1.0) | [![40%](https://img.shields.io/badge/-40%25-red?style=flat-square)](/firebase-auth/src/commonMain/kotlin/dev/teamhub/firebase/auth/auth.kt) |
17+
| [Realtime Database](https://firebase.google.com/docs/database#kotlin-android) | [`dev.gitlive.firebase:firebase-database:0.1.0`](https://mvnrepository.com/artifact/dev.teamhub.firebase/firebase-database/0.1.0) | [![70%](https://img.shields.io/badge/-70%25-orange?style=flat-square)](/firebase-database/src/commonMain/kotlin/dev/teamhub/firebase/auth/database.kt) |
18+
| [Cloud Firestore](https://firebase.google.com/docs/firestore#kotlin-android) | [`dev.gitlive.firebase:firebase-firestore:0.1.0`](https://mvnrepository.com/artifact/dev.teamhub.firebase/firebase-firestore/0.1.0) | [![60%](https://img.shields.io/badge/-60%25-orange?style=flat-square)](/firebase-firestore/src/commonMain/kotlin/dev/teamhub/firebase/firestore/firestore.kt) |
19+
| [Cloud Functions](https://firebase.google.com/docs/functions/callable#kotlin-android)| [`dev.gitlive.firebase:firebase-functions:0.1.0`](https://mvnrepository.com/artifact/dev.teamhub.firebase/firebase-functions/0.1.0) | [![80%](https://img.shields.io/badge/-80%25-green?style=flat-square)](/firebase-functions/src/commonMain/kotlin/dev/teamhub/firebase/functions/functions.kt) |
20+
| [Cloud Messaging](https://firebase.google.com/docs/messaging#kotlin-android) | [`dev.gitlive.firebase:firebase-messaging:0.1.0`](https://mvnrepository.com/artifact/dev.teamhub.firebase/firebase-messaging/0.1.0) | ![0%](https://img.shields.io/badge/-0%25-lightgrey?style=flat-square) |
21+
| [Cloud Storage](https://firebase.google.com/docs/storage#kotlin-android) | [`dev.gitlive.firebase:firebase-storage:0.1.0`](https://mvnrepository.com/artifact/dev.teamhub.firebase/firebase-storage/0.1.0) | ![0%](https://img.shields.io/badge/-0%25-lightgrey?style=flat-square) |
22+
23+
Is the Firebase library or API you need missing? [Create an issue](https://github.com/GitLiveApp/firebase-kotlin-sdk/issues/new?labels=API+coverage&template=increase-api-coverage.md&title=Add+%5Bclass+name%5D.%5Bfunction+name%5D+to+%5Blibrary+name%5D+for+%5Bplatform+names%5D) to request additional API coverage or be awesome and [submit a PR](https://github.com/GitLiveApp/firebase-kotlin-sdk/fork)
24+
25+
## Kotlin-first design
2526

26-
Is the Firebase library or API you need missing? [Create an issue](https://github.com/TeamHubApp/firebase-kotlin-sdk/issues/new?labels=API+coverage&template=increase-api-coverage.md&title=Add+%5Bclass+name%5D.%5Bfunction+name%5D+to+%5Blibrary+name%5D+for+%5Bplatform+names%5D) to request additional API coverage or be awesome and [submit a PR](https://github.com/TeamHubApp/firebase-kotlin-sdk/fork)
27+
Unlike the Kotlin Extensions for the Firebase Android SDK this project does not extend a Java based SDK so we get the full power of Kotlin including coroutines and serialization!
2728

28-
## Getting started
29+
<h3><a href="https://kotlinlang.org/docs/tutorials/coroutines/async-programming.html#coroutines">Suspending functions</a></h3>
2930

30-
### New to Firebase?
31+
Asynchronous operations that return a single or no value are represented by suspending functions in the SDK instead of callbacks, listeners or OS specific types such as [Task](https://developer.android.com/reference/com/google/android/play/core/tasks/Task), for example:
3132

32-
Head over to the main Firebase documentation and follow the steps
33+
```kotlin
34+
suspend fun signInWithCustomToken(token: String): AuthResult
35+
```
36+
37+
It is important to remember that unlike a callback based API, wating for suspending functions to complete is implicit and so if you don't want to wait for the result you can `launch` a new coroutine:
3338

34-
### Configure Firebase
39+
```kotlin
40+
//TODO don't use GlobalScope
41+
GlobalScope.launch {
42+
Firebase.auth.signOut()
43+
}
44+
```
3545

36-
Since you most likely want to share your firebase configuration across platforms you should configure Firebase programatically in your common source instead of a platform-specific configuration file.
46+
<h3><a href="https://kotlinlang.org/docs/reference/coroutines/flow.html">Flows</a></h3>
3747

38-
You can do this as follows:
48+
Asynchronous streams of values are represented by Flows in the SDK instead of repeatedly invoked callbacks or listeners, for example:
3949

4050
```kotlin
41-
val options = FirebaseOptions.Builder()
42-
.setApplicationId("1:27992087142:android:ce3b6448250083d1") // Required for Analytics.
43-
.setApiKey("AIzaSyADUe90ULnQDuGShD9W23RDP0xmeDc6Mvw") // Required for Auth.
44-
.setDatabaseUrl("https://myproject.firebaseio.com") // Required for RTDB.
45-
.build()
51+
val snapshots: Flow<DocumentSnapshot>
4652
```
53+
54+
The flows are cold, which means a new listener is added every time a terminal operator is applied to the resulting flow. A buffer with the [default size](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel/-b-u-f-f-e-r-e-d.html) is used to buffer values received from the listener, use the [`buffer` operator](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/buffer.html) on the flow to specify a user-defined value and to control what happens when data is produced faster than consumed, i.e. to control the back-pressure behavior. Often you are only interested in the latest value received, in this case you can use the [`conflate` operator](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/conflate.html) to disable buffering.
55+
56+
The listener is removed once the flow [completes](https://kotlinlang.org/docs/reference/coroutines/flow.html#flow-completion) or is [cancelled](https://kotlinlang.org/docs/reference/coroutines/flow.html#flow-cancellation).
57+
58+
<h3><a href="https://github.com/Kotlin/kotlinx.serialization">Serialization</a></h3>
59+
60+
The official Firebase SDKs use different platform-specific ways to support writing data with and without custom classes in [Cloud Firestore](https://firebase.google.com/docs/firestore/manage-data/add-data#custom_objects), [Realtime Database](https://firebase.google.com/docs/database/android/read-and-write#basic_write) and [Functions](https://firebase.google.com/docs/functions/callable).
61+
62+
The Firebase Kotlin SDK uses Kotlin serialization to read and write custom classes to Firebase. To use Kotlin serialization in your project add the plugin to your gradle file:
63+
64+
```groovy
65+
plugins {
66+
kotlin("multiplatform") // or kotlin("jvm") or any other kotlin plugin
67+
kotlin("plugin.serialization") version "1.3.70"
68+
}
69+
```
70+
71+
Then mark you custom classes `@Serializable`:
72+
73+
```kotlin
74+
@Serializable
75+
data class City(val name: String)
76+
```
77+
78+
Instances of these classes can now be passed [along with their serializer](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/runtime_usage.md#obtaining-serializers) to the SDK:
79+
80+
```kotlin
81+
db.collection("cities").document("LA").set(City.serializer(), city)
82+
```
83+
84+
You can also omit the serializer for classes that does not have generic type arguments, these functions are marked [`@ImplicitReflectionSerializer`](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/runtime_usage.md#implicit-reflection-serializers) and their usage is discouraged in general because it is implicit and uses reflection (and therefore not working on Kotlin/Native), but may be useful shorthand in some cases.
85+
86+
<h3><a href="https://kotlinlang.org/docs/reference/functions.html#named-arguments">Named arguments</a></h3>
87+
88+
To improve readability functions such as the Cloud Firestore query operators use named arguments:
89+
90+
```kotlin
91+
citiesRef.whereEqualTo("state", "CA")
92+
citiesRef.whereArrayContains("regions", "west_coast")
93+
//...becomes...
94+
citiesRef.where("state", equalTo = "CA")
95+
citiesRef.where("regions", arrayContains = "west_coast")
96+
````
97+
98+
## Multiplatform
99+
100+
The Firebase Kotlin SDK provides a common API to access Firebase for projects targeting *iOS*, *Android* and *JS* meaning you can use Firebase directly in your common code. Under the hood, the SDK achieves this by binding to the respective official Firebase SDK for each supported platform.
101+
102+
### Accessing the underlying Firebase SDK
103+
104+
In some cases you might want to access the underlying official Firebase SDK in platform specific code, for example when the common API is missing the functionality you need. For this purpose each class in the SDK has `android`, `ios` and `js` properties which holds the equivalent object of the underlying official Firebase SDK.
105+
106+
These properties are only accessible from the equivalent target's source set. For example to disable persistence in Cloud Firestore on Android you can write the following in your Android specific code (e.g. `androidMain` or `androidTest`):
107+
108+
```kotlin
109+
Firebase.firestore.android.firestoreSettings = FirebaseFirestoreSettings.Builder(Firebase.firestore.android.firestoreSettings)
110+
.setPersistenceEnabled(false)
111+
.build()
112+
```
113+
114+
### NPM modules
115+
116+
If you are building a Kotlin multiplatform library which will be consumed from JS code you may need to include the SDK in your `package.json`, you can do it as follows:
117+
118+
```json
119+
"dependencies": {
120+
"@gitlive/firebase-auth": "0.1.0",
121+
"@gitlive/firebase-database": "0.1.0",
122+
"@gitlive/firebase-firestore": "0.1.0",
123+
"@gitlive/firebase-functions": "0.1.0",
124+
"@gitlive/firebase-storage": "0.1.0",
125+
"@gitlive/firebase-messaging": "0.1.0"
126+
}
127+
```
128+
129+

firebase-common/src/iosMain/kotlin/dev/teamhub/firebase/_decoders.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import kotlinx.serialization.SerialDescriptor
66
import kotlinx.serialization.StructureKind
77

88
actual fun FirebaseDecoder.structureDecoder(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder = when(desc.kind as StructureKind) {
9-
StructureKind.CLASS -> (value as Map<*, *>).let { map ->
9+
StructureKind.CLASS, StructureKind.OBJECT -> (value as Map<*, *>).let { map ->
1010
FirebaseClassDecoder(map.size, { map.containsKey(it) }) { desc, index -> map[desc.getElementName(index)] }
1111
}
1212
StructureKind.LIST -> (value as List<*>).let {

firebase-database/src/androidMain/kotlin/dev/teamhub/firebase/database/database.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ import dev.teamhub.firebase.database.ChildEvent.Type
1111
import dev.teamhub.firebase.decode
1212
import kotlinx.coroutines.channels.awaitClose
1313
import kotlinx.coroutines.coroutineScope
14+
import kotlinx.coroutines.flow.Flow
1415
import kotlinx.coroutines.flow.callbackFlow
16+
import kotlinx.coroutines.flow.filter
17+
import kotlinx.coroutines.flow.produceIn
1518
import kotlinx.coroutines.selects.select
1619
import kotlinx.coroutines.tasks.asDeferred
1720
import kotlinx.coroutines.tasks.await

firebase-database/src/iosMain/kotlin/dev/teamhub/firebase/database/database.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import kotlinx.coroutines.CompletableDeferred
1111
import kotlinx.coroutines.channels.awaitClose
1212
import kotlinx.coroutines.coroutineScope
1313
import kotlinx.coroutines.flow.callbackFlow
14+
import kotlinx.coroutines.flow.filter
15+
import kotlinx.coroutines.flow.produceIn
1416
import kotlinx.coroutines.selects.select
1517
import kotlinx.serialization.DeserializationStrategy
1618
import kotlinx.serialization.SerializationStrategy

firebase-firestore/src/iosMain/kotlin/dev/teamhub/firebase/firestore/firestore.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dev.teamhub.firebase.firestore
22

33
import cocoapods.FirebaseFirestore.*
4+
import dev.teamhub.firebase.*
45
import kotlinx.cinterop.*
56
import kotlinx.coroutines.CompletableDeferred
67
import kotlinx.coroutines.channels.awaitClose

gradle.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
kotlin.code.style=official
22
kotlin.js.experimental.generateKotlinExternals=true
3+
org.gradle.daemon=true
4+
org.gradle.jvmargs=-Xmx2560m

0 commit comments

Comments
 (0)