Skip to content

Commit 5d516e0

Browse files
committed
add ios implementation for auth
1 parent 28d712e commit 5d516e0

File tree

10 files changed

+137
-86
lines changed

10 files changed

+137
-86
lines changed

build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
2-
31
plugins {
42
kotlin("multiplatform") version "1.3.61" apply false
53
}
@@ -48,6 +46,8 @@ subprojects {
4846
"jvmMainImplementation"("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3")
4947
"jvmMainApi"("app.teamhub:firebase-java:0.3.0")
5048
"jvmMainApi"("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.3.3")
49+
"iosMainImplementation"("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:1.3.3")
50+
"iosMainImplementation"("org.jetbrains.kotlinx:kotlinx-coroutines-core-native:1.3.3")
5151
}
5252
}
5353
}

firebase-app/build.gradle.kts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,7 @@ kotlin {
6969
val jvmMain by getting {
7070
kotlin.srcDir("src/androidMain/kotlin")
7171
}
72-
val iosMain by creating {
73-
dependencies {
74-
}
75-
}
72+
val iosMain by creating
7673

7774
configure(listOf(iosArm64, iosX64)) {
7875
compilations.getByName("main") {
Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,43 @@
11
package dev.teamhub.firebase
22

3-
actual class FirebaseApp {
4-
actual val name: String
5-
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
6-
actual val options: FirebaseOptions
7-
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
8-
}
9-
10-
/** Returns the default firebase app instance. */
11-
actual val Firebase.app: FirebaseApp
12-
get() = kotlin.TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
3+
import cocoapods.FirebaseCore.*
134

14-
actual fun Firebase.app(name: String): FirebaseApp = kotlin.TODO("not implemented")
5+
actual open class FirebaseException(message: String) : Exception(message)
6+
actual open class FirebaseNetworkException(message: String) : FirebaseException(message)
7+
actual open class FirebaseTooManyRequestsException(message: String) : FirebaseException(message)
8+
actual open class FirebaseApiNotAvailableException(message: String) : FirebaseException(message)
159

16-
actual fun Firebase.apps(context: Any?): List<FirebaseApp> = kotlin.TODO("not implemented")
17-
18-
actual fun Firebase.initialize(context: Any?): FirebaseApp? = kotlin.TODO("not implemented")
10+
actual val Firebase.app: FirebaseApp
11+
get() = FirebaseApp(FIRApp.defaultApp()!!)
1912

20-
/** Initializes and returns a FirebaseApp. */
21-
actual fun Firebase.initialize(context: Any?, options: FirebaseOptions): FirebaseApp = kotlin.TODO("not implemented")
13+
actual fun Firebase.app(name: String): FirebaseApp =
14+
FirebaseApp(FIRApp.appNamed(name)!!)
2215

23-
/** Initializes and returns a FirebaseApp. */
24-
actual fun Firebase.initialize(context: Any?, options: FirebaseOptions, name: String): FirebaseApp = kotlin.TODO("not implemented")
16+
actual fun Firebase.initialize(context: Any?): FirebaseApp? =
17+
FIRApp.configure().let { app }
2518

26-
actual open class FirebaseException : Exception()
19+
actual fun Firebase.initialize(context: Any?, options: FirebaseOptions, name: String): FirebaseApp =
20+
FIRApp.configureWithName(name, options.toIos()).let { app(name) }
2721

28-
actual class FirebaseNetworkException : FirebaseException()
22+
actual fun Firebase.initialize(context: Any?, options: FirebaseOptions) =
23+
FIRApp.configureWithOptions(options.toIos()).let { app }
2924

30-
actual open class FirebaseTooManyRequestsException : FirebaseException()
25+
actual class FirebaseApp internal constructor(val ios: FIRApp) {
26+
actual val name: String
27+
get() = ios.name
28+
actual val options: FirebaseOptions
29+
get() = ios.options.run { FirebaseOptions(bundleID, APIKey!!, databaseURL!!, trackingID, storageBucket, projectID) }
30+
}
3131

32-
actual open class FirebaseApiNotAvailableException : FirebaseException()
32+
actual fun Firebase.apps(context: Any?) = FIRApp.allApps()!!
33+
.values
34+
.map { FirebaseApp(it as FIRApp) }
35+
36+
private fun FirebaseOptions.toIos() = FIROptions().apply {
37+
bundleID = this@toIos.applicationId
38+
APIKey = this@toIos.apiKey
39+
databaseURL = this@toIos.databaseUrl
40+
trackingID = this@toIos.gaTrackingId
41+
storageBucket = this@toIos.storageBucket
42+
projectID = this@toIos.projectId
43+
}

firebase-auth/build.gradle.kts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,7 @@ kotlin {
6363
api("com.google.firebase:firebase-auth:19.1.0")
6464
}
6565
}
66-
val iosMain by creating {
67-
dependencies {
68-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-native:1.3.3")
69-
}
70-
}
66+
val iosMain by creating
7167
val jvmMain by getting {
7268
kotlin.srcDir("src/androidMain/kotlin")
7369
}
Lines changed: 96 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,122 @@
11
package dev.teamhub.firebase.auth
22

3+
import cocoapods.FirebaseAuth.*
34
import dev.teamhub.firebase.Firebase
45
import dev.teamhub.firebase.FirebaseApp
56
import dev.teamhub.firebase.FirebaseException
7+
import kotlinx.cinterop.*
8+
import kotlinx.coroutines.channels.awaitClose
9+
import platform.Foundation.*
610

7-
actual val Firebase.auth: FirebaseAuth
8-
get() = kotlin.TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
11+
actual val Firebase.auth
12+
get() = FirebaseAuth(FIRAuth.auth())
913

10-
actual fun Firebase.auth(app: FirebaseApp): FirebaseAuth {
11-
kotlin.TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
12-
}
14+
actual fun Firebase.auth(app: FirebaseApp) =
15+
FirebaseAuth(FIRAuth.authWithApp(app.ios))
16+
17+
actual class FirebaseAuth internal constructor(val ios: FIRAuth) {
1318

14-
actual class FirebaseAuth {
1519
actual val currentUser: FirebaseUser?
16-
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
17-
actual val authStateChanged: kotlinx.coroutines.flow.Flow<FirebaseUser?>
18-
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
20+
get() = ios.currentUser?.let { FirebaseUser(it) }
1921

20-
actual suspend fun signInWithCustomToken(token: String): AuthResult {
21-
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
22-
}
22+
actual suspend fun signInWithCustomToken(token: String) =
23+
AuthResult(ios.awaitResult { signInWithCustomToken(token, it) })
2324

24-
actual suspend fun signInAnonymously(): AuthResult {
25-
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
26-
}
25+
actual suspend fun signInAnonymously() =
26+
AuthResult(ios.awaitResult { signInAnonymouslyWithCompletion(it) })
27+
28+
actual suspend fun signOut() = ios.throwError { signOut(it) }.run { Unit }
2729

28-
actual suspend fun signOut() {
30+
actual val authStateChanged get() = callbackFlow {
31+
val handle = ios.addAuthStateDidChangeListener { _, user -> offer(user?.let { FirebaseUser(it) }) }
32+
awaitClose { ios.removeAuthStateDidChangeListener(handle) }
2933
}
3034
}
3135

32-
actual class AuthResult {
36+
actual class AuthResult internal constructor(val ios: FIRAuthDataResult) {
3337
actual val user: FirebaseUser?
34-
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
38+
get() = ios.user?.let { FirebaseUser(it) }
3539
}
3640

37-
actual class FirebaseUser {
41+
actual class FirebaseUser internal constructor(val ios: FIRUser) {
3842
actual val uid: String
39-
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
43+
get() = ios.uid
4044
actual val isAnonymous: Boolean
41-
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
45+
get() = ios.isAnonymous()
46+
actual suspend fun delete() = ios.await { deleteWithCompletion(it) }.run { Unit }
47+
actual suspend fun reload() = ios.await { reloadWithCompletion(it) }.run { Unit }
48+
}
49+
50+
actual open class FirebaseAuthException(message: String): FirebaseException(message)
51+
actual open class FirebaseAuthActionCodeException(message: String): FirebaseAuthException(message)
52+
actual open class FirebaseAuthEmailException(message: String): FirebaseAuthException(message)
53+
actual open class FirebaseAuthInvalidCredentialsException(message: String): FirebaseAuthException(message)
54+
actual open class FirebaseAuthInvalidUserException(message: String): FirebaseAuthException(message)
55+
actual open class FirebaseAuthRecentLoginRequiredException(message: String): FirebaseAuthException(message)
56+
actual open class FirebaseAuthUserCollisionException(message: String): FirebaseAuthException(message)
57+
actual open class FirebaseAuthWebException(message: String): FirebaseAuthException(message)
58+
59+
60+
private fun <T, R> T.throwError(block: T.(errorPointer: CPointer<ObjCObjectVar<NSError?>>) -> R): R {
61+
memScoped {
62+
val errorPointer: CPointer<ObjCObjectVar<NSError?>> = alloc<ObjCObjectVar<NSError?>>().ptr
63+
val result = block(errorPointer)
64+
val error: NSError? = errorPointer.pointed.value
65+
if (error != null) {
66+
throw error.toException()
67+
}
68+
return result
69+
}
70+
}
4271

43-
actual suspend fun delete() {
72+
private suspend fun <T, R> T.awaitResult(function: T.(callback: (R?, NSError?) -> Unit) -> Unit): R {
73+
val job = CompletableDeferred<R>()
74+
function { result, error ->
75+
if(result != null) {
76+
job.complete(result)
77+
} else if(error != null) {
78+
job.completeExceptionally(error.toException())
79+
}
4480
}
81+
return job.await()
82+
}
4583

46-
actual suspend fun reload() {
84+
private suspend fun <T> T.await(function: T.(callback: (NSError?) -> Unit) -> Unit) {
85+
val job = CompletableDeferred<Unit>()
86+
function { error ->
87+
if(error == null) {
88+
job.complete(Unit)
89+
} else {
90+
job.completeExceptionally(error.toException())
91+
}
4792
}
93+
job.await()
4894
}
4995

50-
actual open class FirebaseAuthException : FirebaseException()
51-
actual class FirebaseAuthActionCodeException : FirebaseAuthException()
52-
actual class FirebaseAuthEmailException : FirebaseAuthException()
53-
actual class FirebaseAuthInvalidCredentialsException : FirebaseAuthException()
54-
actual class FirebaseAuthInvalidUserException : FirebaseAuthException()
55-
actual class FirebaseAuthRecentLoginRequiredException : FirebaseAuthException()
56-
actual class FirebaseAuthUserCollisionException : FirebaseAuthException()
57-
actual class FirebaseAuthWebException : FirebaseAuthException()
96+
97+
private fun NSError.toException() = when(domain) {
98+
FIRAuthErrorDomain -> when(code) {
99+
FIRAuthErrorCodeInvalidActionCode,
100+
FIRAuthErrorCodeExpiredActionCode -> FirebaseAuthActionCodeException(toString())
101+
102+
FIRAuthErrorCodeInvalidEmail,
103+
FIRAuthErrorCodeEmailAlreadyInUse -> FirebaseAuthEmailException(toString())
104+
105+
FIRAuthErrorCodeInvalidCredential -> FirebaseAuthInvalidCredentialsException(toString())
106+
107+
FIRAuthErrorCodeInvalidUserToken -> FirebaseAuthInvalidUserException(toString())
108+
109+
FIRAuthErrorCodeRequiresRecentLogin -> FirebaseAuthRecentLoginRequiredException(toString())
110+
111+
FIRAuthErrorCodeEmailAlreadyInUse,
112+
FIRAuthErrorCodeAccountExistsWithDifferentCredential,
113+
FIRAuthErrorCodeCredentialAlreadyInUse -> FirebaseAuthUserCollisionException(toString())
114+
115+
FIRAuthErrorCodeWebContextAlreadyPresented,
116+
FIRAuthErrorCodeWebContextCancelled,
117+
FIRAuthErrorCodeWebInternalError -> FirebaseAuthWebException(toString())
118+
119+
else -> FirebaseAuthException(toString())
120+
}
121+
else -> FirebaseAuthException(toString())
122+
}

firebase-auth/src/jsMain/kotlin/dev/teamhub/firebase/auth/auth.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,4 @@ private fun errorToException(cause: Throwable) = when(val code = cause.asDynamic
8282
// "auth/too-many-arguments" ->
8383
// "auth/unauthorized-domain" ->
8484
else -> FirebaseAuthException(code, cause)
85-
}
85+
}

firebase-common/src/iosMain/c_interop/FirebaseCore.def

Lines changed: 0 additions & 4 deletions
This file was deleted.

firebase-database/build.gradle.kts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,7 @@ kotlin {
7676
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:0.14.0")
7777
}
7878
}
79-
val iosMain by creating {
80-
dependencies {
81-
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:0.14.0")
82-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-native:1.3.3")
83-
}
84-
}
79+
val iosMain by creating
8580

8681
configure(listOf(iosArm64, iosX64)) {
8782
compilations.getByName("main") {

firebase-firestore/build.gradle.kts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,7 @@ kotlin {
6565
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.14.0")
6666
}
6767
}
68-
val iosMain by creating {
69-
dependencies {
70-
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:0.14.0")
71-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-native:1.3.3")
72-
}
73-
}
68+
val iosMain by creating
7469
val jvmMain by getting {
7570
dependencies {
7671
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.14.0")

firebase-functions/build.gradle.kts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,7 @@ kotlin {
6565
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.14.0")
6666
}
6767
}
68-
val iosMain by creating {
69-
dependencies {
70-
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:0.14.0")
71-
}
72-
}
68+
val iosMain by creating
7369
val jvmMain by getting {
7470
dependencies {
7571
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.14.0")

0 commit comments

Comments
 (0)