Skip to content

Commit 2aa84da

Browse files
committed
Refactor KMP SDK templates and improve cookie handling in WebAuthComponent
1 parent 327cb68 commit 2aa84da

File tree

12 files changed

+65
-48
lines changed

12 files changed

+65
-48
lines changed

src/SDK/Language/KMP.php

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ protected function getPropertyType(array $property, array $spec, string $generic
138138
{
139139
$type = parent::getPropertyType($property, $spec, $generic);
140140
if ($contextual && ($type === 'List<Any>' || $type === 'List<Any>?')) {
141-
$type = 'List<@Contextual Any>';
141+
$nullable = str_ends_with($type, '?');
142+
$type = 'List<@Contextual Any>' . ($nullable ? '?' : '');
142143
}
143144
return $type;
144145
}
@@ -369,8 +370,8 @@ public function getFiles(): array
369370
],
370371
[
371372
'scope' => 'default',
372-
'destination' => 'shared/src/commonMain/kotlin/{{ sdk.namespace | caseSlash }}/serializers/StringCollectionSeriailizer.kt',
373-
'template' => '/kmp/shared/src/commonMain/kotlin/io/package/serializers/StringCollectionSeriailizer.kt.twig',
373+
'destination' => 'shared/src/commonMain/kotlin/{{ sdk.namespace | caseSlash }}/serializers/StringCollectionSerializer.kt',
374+
'template' => '/kmp/shared/src/commonMain/kotlin/io/package/serializers/StringCollectionSerializer.kt.twig',
374375
],
375376

376377
// Services
@@ -603,16 +604,16 @@ public function getFiles(): array
603604
'destination' => 'androidApp/src/main/res/values/colors.xml',
604605
'template' => '/kmp/androidApp/src/main/res/values/colors.xml',
605606
],
606-
[
607-
'scope' => 'default',
608-
'destination' => 'androidApp/src/main/res/values/strings.xml',
609-
'template' => '/kmp/androidApp/src/main/res/values/strings.xml.twig',
610-
],
611-
[
612-
'scope' => 'default',
613-
'destination' => 'androidApp/src/main/res/values/themes.xml',
614-
'template' => '/kmp/androidApp/src/main/res/values/themes.xml.twig',
615-
],
607+
[
608+
'scope' => 'default',
609+
'destination' => 'androidApp/src/main/res/values/strings.xml',
610+
'template' => '/kmp/androidApp/src/main/res/values/strings.xml.twig',
611+
],
612+
[
613+
'scope' => 'default',
614+
'destination' => 'androidApp/src/main/res/values/themes.xml',
615+
'template' => '/kmp/androidApp/src/main/res/values/themes.xml.twig',
616+
],
616617

617618

618619
// Models, Services, and other common components
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#Wed Nov 27 15:47:26 PST 2024
22
distributionBase=GRADLE_USER_HOME
33
distributionPath=wrapper/dists
4-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
4+
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
55
zipStoreBase=GRADLE_USER_HOME
66
zipStorePath=wrapper/dists

templates/kmp/shared/build.gradle.kts.twig

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ publishing {
181181

182182
android {
183183
namespace = "{{ sdk.namespace | caseDot }}.kmp"
184-
compileSdk = 36
184+
compileSdk = 35
185185
defaultConfig {
186186
minSdk = 21
187187
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -196,11 +196,4 @@ android {
196196
all { it.useJUnit() }
197197
}
198198
}
199-
}
200-
201-
dependencies {
202-
implementation(libs.androidx.activity.ktx)
203-
implementation(libs.androidx.browser)
204-
implementation(libs.androidx.espresso.core)
205-
implementation(libs.firebase.crashlytics.buildtools)
206199
}

templates/kmp/shared/src/androidMain/kotlin/io/package/cookies/SerializableCookie.kt.twig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ data class SerializableCookie(
1313
val maxAge: Int? = null,
1414
val secure: Boolean = false,
1515
val httpOnly: Boolean = false,
16-
val expiration: Long = System.currentTimeMillis() + (maxAge?.times(1000L) ?: 2592000000L)
16+
val expiration: Long = maxAge?.let { System.currentTimeMillis() + it * 1000L } ?: (System.currentTimeMillis() + 2592000000L)
1717
) {
1818
fun toCookie(): Cookie = Cookie(
1919
name = name,
@@ -47,8 +47,8 @@ data class SerializableCookie(
4747
return if (cd != null && host != null) {
4848
if (cd.startsWith(".")) {
4949
host == cd.substring(1) || host.endsWith(cd)
50-
} else if (requestHost.startsWith(".")) {
51-
host == host.substring(1) || cd.endsWith(cd)
50+
} else if (host.startsWith(".")) {
51+
cd == host.substring(1) || cd.endsWith(host)
5252
} else {
5353
host == cd
5454
}

templates/kmp/shared/src/androidMain/kotlin/io/package/extensions/OAuth2Extensions.kt.twig

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {{ sdk.namespace | caseDot }}.webInterface.UrlParser
88
import io.ktor.http.Url
99
import kotlinx.coroutines.CoroutineScope
1010
import kotlinx.coroutines.launch
11+
import io.ktor.http.encodeURLParameter
1112

1213
{% for service in spec | webAuthServices %}
1314
{% for method in service.methods %}
@@ -35,17 +36,30 @@ suspend fun {{ sdk.namespace | caseDot }}.services.{{ service.className | caseUc
3536
{%~ endif %}
3637
)
3738

38-
val apiQuery = mutableListOf<String>()
39-
apiParams.forEach {
40-
when (it.value) {
41-
null -> return@forEach
42-
is List<*> -> apiQuery.add("${it.key}[]=${it.value.toString()}")
43-
else -> apiQuery.add("${it.key}=${it.value.toString()}")
39+
val apiQuery = buildList {
40+
apiParams.forEach { (key, value) ->
41+
when (value) {
42+
null -> Unit
43+
is Iterable<*> -> value.forEach { item ->
44+
if (item != null) {
45+
add("${key}[]=${item.toString().encodeURLParameter()}")
46+
}
47+
}
48+
49+
else -> add("$key=${value.toString().encodeURLParameter()}")
50+
}
4451
}
4552
}
46-
4753
val urlParser = UrlParser()
48-
val fullUrl = "${client.endpoint}${apiPath}?${apiQuery.joinToString("&")}"
54+
val queryString = apiQuery.joinToString("&")
55+
val fullUrl = buildString {
56+
append(client.endpoint)
57+
append(apiPath)
58+
if (queryString.isNotEmpty()) {
59+
append('?')
60+
append(queryString)
61+
}
62+
}
4963
val apiUrl = urlParser.parse(fullUrl)
5064
val callbackUrlScheme = "{{ spec.title | caseLower }}-callback-${client.config["project"]}"
5165
val webAuthScope = CoroutineScope(client.coroutineContext)

templates/kmp/shared/src/androidMain/kotlin/io/package/models/InputFile.android.kt.twig

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ import java.net.URLConnection
66
import java.nio.file.Files
77
import java.io.File
88

9-
@RequiresApi(Build.VERSION_CODES.O)
109
actual fun guessMimeType(input: String): String {
1110
val file = File(input)
12-
return Files.probeContentType(file.toPath()) ?:
13-
URLConnection.guessContentTypeFromName(file.name) ?: ""
11+
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
12+
Files.probeContentType(file.toPath()) ?:
13+
URLConnection.guessContentTypeFromName(file.name) ?: ""
14+
} else {
15+
URLConnection.guessContentTypeFromName(file.name) ?: ""
16+
}
1417
}

templates/kmp/shared/src/commonMain/kotlin/io/package/BaseClient.kt.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ abstract class BaseClient<This : BaseClient<This>>(
280280
params = emptyMap(),
281281
responseType = Map::class,
282282
)
283-
chunksUploaded = current["chunksUploaded"] as Long
283+
chunksUploaded = (current["chunksUploaded"] as? Number)?.toLong() ?: 0L
284284
offset = chunksUploaded * CHUNK_SIZE
285285
} catch (e: Exception) {
286286
// Swallow exception

templates/kmp/shared/src/commonMain/kotlin/io/package/serializers/StringCollectionSeriailizer.kt.twig renamed to templates/kmp/shared/src/commonMain/kotlin/io/package/serializers/StringCollectionSerializer.kt.twig

File renamed without changes.

templates/kmp/shared/src/iosMain/kotlin/io/package/WebAuthComponent.ios.kt.twig

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package {{ sdk.namespace | caseDot }}
33
import {{ sdk.namespace | caseDot }}.cookies.IosCookieStorage
44
import io.ktor.http.Cookie
55
import io.ktor.http.Url
6+
import kotlinx.coroutines.CoroutineScope
7+
import kotlinx.coroutines.launch
68
import kotlinx.coroutines.suspendCancellableCoroutine
79
import platform.AuthenticationServices.ASPresentationAnchor
810
import platform.AuthenticationServices.ASWebAuthenticationPresentationContextProvidingProtocol
@@ -30,11 +32,17 @@ actual class WebAuthComponent {
3032
)
3133

3234
private val pendingAuth = mutableMapOf<String, PendingAuth>()
35+
private var cookieScope: CoroutineScope = createDefaultCookieScope()
36+
37+
fun setCookieScope(scope: CoroutineScope?) {
38+
cookieScope = scope ?: createDefaultCookieScope()
39+
}
3340

3441
private var cookieStorage: IosCookieStorage? = null
3542

36-
fun setCookieStorage(storage: IosCookieStorage) {
43+
fun setCookieStorage(storage: IosCookieStorage, scope: CoroutineScope? = null) {
3744
cookieStorage = storage
45+
scope?.let { setCookieScope(it) }
3846
}
3947

4048
internal suspend fun authenticate(
@@ -147,7 +155,7 @@ actual class WebAuthComponent {
147155
)
148156

149157
if (cookieStorage != null) {
150-
kotlinx.coroutines.runBlocking {
158+
cookieScope.launch {
151159
cookieStorage!!.addCookie(
152160
requestUrl = Url("https://$domain"),
153161
cookie = cookie

templates/kmp/shared/src/iosMain/kotlin/io/package/cookies/IosCookieStorage.kt.twig

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@ class IosCookieStorage : CookiesStorage {
169169
}
170170

171171
private fun recreateCookie(storedCookie: StoredCookie) {
172-
// Build a Map<Any?, Any> using Foundation keys directly (no explicit cast to Any needed)
173172
val props = buildMap<Any?, Any> {
174173
put(NSHTTPCookieName, storedCookie.name)
175174
put(NSHTTPCookieValue, storedCookie.value)
@@ -183,7 +182,6 @@ class IosCookieStorage : CookiesStorage {
183182
val date = NSDate.dateWithTimeIntervalSince1970(ms / 1000.0)
184183
put(NSHTTPCookieExpires, date)
185184
}
186-
// HttpOnly uses raw string key
187185
put("HttpOnly", storedCookie.isHttpOnly)
188186
}
189187

0 commit comments

Comments
 (0)