feat: add platform OAuth implementations (Android, iOS, Desktop)
- AndroidOAuthClient: ACTION_VIEW + OAuthCallbackActivity (myice://callback) - IosOAuthClient: ASWebAuthenticationSession with presentation context provider - DesktopOAuthClient: local HTTP server + system browser - AndroidManifest: register OAuthCallbackActivity intent filter - Align Kotlin to 2.3.20 (required by Compose MP 1.11.1 klibs) and compileSdk to 36 (required by activity-compose 1.13.0); fix missing Text import and stray brace in placeholder iOS/Android entry points
This commit is contained in:
@@ -15,6 +15,17 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".OAuthCallbackActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="myice" android:host="callback" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.material3.Text
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package ch.parano.myice
|
||||
|
||||
import android.app.Activity
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import ch.parano.myice.auth.OAuthCallbackHolder
|
||||
|
||||
class OAuthCallbackActivity : Activity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val uri: Uri? = intent?.data
|
||||
if (uri != null) {
|
||||
OAuthCallbackHolder.handleCallback(uri)
|
||||
}
|
||||
finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package ch.parano.myice.auth
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
|
||||
class AndroidOAuthClient(private val context: Context) : OAuthClient {
|
||||
|
||||
override fun redirectUri(): String = "myice://callback"
|
||||
|
||||
override suspend fun authenticate(loginUrl: String): String? {
|
||||
OAuthCallbackHolder.deferred = CompletableDeferred()
|
||||
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(loginUrl)).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
|
||||
val callbackUri = OAuthCallbackHolder.deferred?.await() ?: return null
|
||||
|
||||
val fragment = callbackUri.fragment ?: return null
|
||||
val params = fragment.split("&").associate { pair ->
|
||||
val idx = pair.indexOf("=")
|
||||
if (idx >= 0) pair.substring(0, idx) to pair.substring(idx + 1)
|
||||
else pair to ""
|
||||
}
|
||||
return params["access_token"]
|
||||
}
|
||||
}
|
||||
|
||||
object OAuthCallbackHolder {
|
||||
var deferred: CompletableDeferred<Uri>? = null
|
||||
|
||||
fun handleCallback(uri: Uri) {
|
||||
deferred?.complete(uri)
|
||||
deferred = null
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user