Skip to content

Feat kmp sdk #1040

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open

Feat kmp sdk #1040

wants to merge 28 commits into from

Conversation

camka14
Copy link

@camka14 camka14 commented Feb 27, 2025

What does this PR do?

Adds a KMP SDK

Test Plan

Run KMPAndroid14Java17Test
Test OAuth2, cookies, and iOS file uploads using custom project in Android Studio

Related PRs and Issues

Have you read the Contributing Guidelines on issues?

yes

@abnegate abnegate self-assigned this Mar 19, 2025
The socket was being created unnecessarily whenever a subscription was removed. This change ensures that the socket is only created when there are active channels.
}
}

rootProject.name = "Appwrite_KMP_SDK"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's name this sdk-for-kmp

Comment on lines +47 to +61
} else {
engine {
config {
val trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
trustManagerFactory.init(null as KeyStore?)
val sslContext = SSLContext.getInstance("TLS").apply {
init(null, trustManagerFactory.trustManagers, SecureRandom())
}
sslSocketFactory(
sslContext.socketFactory,
trustManagerFactory.trustManagers[0] as X509TrustManager
)
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this else block be skipped? Is it the same as a the default behaviour?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not super familiar with certificates, but from my understanding this uses a PKIX algorithm instead of Trust All. I'm not sure if that's the correct approach, but I figured if there was an option to not run setSelfSigned then it should use a standard algorithm?

@@ -466,7 +466,7 @@ protected function getReturnType(array $method, array $spec, string $namespace,

$ret = $this->toPascalCase($method['responseModel']);

if ($this->hasGenericType($method['responseModel'], $spec)) {
if ($this->hasGenericType($method['responseModel'], $spec) && $withGeneric) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the use case for skipping the generic?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's for situations like this:
serializer = io.appwrite.models.Document.serializer(actualSerializer)

without the skip I would get serializer = io.appwrite.models.Document<T>.serializer(actualSerializer)

I just found how it's been done for the same situation:
{{sdk.namespace | caseDot}}.models.{{ method.responseModel | caseUcfirst }}

I can change it to match the original method and get rid of this change if you like that better.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file shouldn't be changed right? Just the KMP version should be added?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the iOS and Android versions of their implementations. At the time I don't think this was working.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized this was the Android file, yes you're right. I think I was going between the two files and didn't realize I made changes to it in the first go around.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's revert this file as unrelated

Comment on lines 28 to 31
"origin" to "appwrite-jvm://app",
"content-type" to "application/json",
"origin" to "{{ spec.title | caseLower }}-jvm://app",
"user-agent" to "JVM/$appVersion, ${System.getProperty("java.version")}",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove the first origin

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's changed in these php tests?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing, I think they got caught in me updating the line endings. I'll revert them

'chmod +x tests/sdks/kmp/gradlew',
];
protected string $command =
'docker run --rm --platform linux/amd64 --network="mockapi" -v $(pwd):/app -w /app/tests/sdks/kmp alvrme/alpine-android:android-34-jdk17 sh -c "./gradlew :shared:testDebugUnitTest --stacktrace -q && cat shared/result.txt"';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to specify platform here? I think this image is multi-arch right?

'chmod +x tests/sdks/kmp/gradlew',
];
protected string $command =
'docker run --rm --platform linux/amd64 --network="mockapi" -v $(pwd):/app -w /app/tests/sdks/kmp alvrme/alpine-android:android-34-jdk17 sh -c "./gradlew :shared:testDebugUnitTest --stacktrace -q && cat shared/result.txt"';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to specify platform here? I think this image is multi-arch

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add tests for iOS and JVM too. We can also add them in .github/workflows/tests.yml so they run for each PR

camka14 and others added 10 commits May 22, 2025 10:20
This commit refactors the OAuth2 authentication flow on iOS to use `ASWebAuthenticationSession` instead of `UIApplication.openURL`. This provides a more secure and user-friendly authentication experience.

Key changes:
- `WebAuthComponent.ios.kt`:
    - Replaced `UIApplication.openURL` with `ASWebAuthenticationSession`.
    - Added `PresentationContextProviderImpl` to provide a presentation anchor for the authentication session.
    - Updated `PendingAuth` to store the `ASWebAuthenticationSession`.
    - Improved error handling and cancellation.
    - Added `setCookieStorage` to allow passing the cookie storage instance.
    - Modified `handleIncomingCookie` to parse cookie details from the callback URL and store them using the provided `IosCookieStorage` and `NSUserDefaults`.
    - Added a `cleanup` method to cancel pending authentication sessions.
- `OAuth2Extensions.kt`:
    - Updated `createOAuth2Session` and `createOAuth2Token` to use the new `WebAuthComponent` and pass the `iosCookieStorage`.
    - Ensured cookies are correctly constructed and stored.
    - Improved error handling for missing authentication cookies.
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants