Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin Multiplatform 始めました

mikan
January 10, 2025
91

Kotlin Multiplatform 始めました

DroidKaigi.collect { #15@Fukuoka }
https://droidkaigi.connpass.com/event/339218/

mikan

January 10, 2025
Tweet

More Decks by mikan

Transcript

  1. 自己紹介 object Mikan { val name = " 一瀬喜弘" val

    company = "karabiner.tech" val work = Engineer.Android val hobby = listOf( " 漫画", " アニメ", " ゲーム", " 折り紙", "OSS 開発・コントリビュート", ) }
  2. 年末から​ iOS/Android で​ 共通する​ ロジックを​ KMP で​ 作る​ タスクを​ 受け​

    持ったので、​ 既存の​ アプリに​ KMP を​ 導入しようとした​ ときに​ 遭遇した​ ことを​ 共有しようと​ 思います
  3. 補足: あとで既存のプロジェクトをマルチプラットフォームにするチュートリアルを見つけた https://www.jetbrains.com/help/kotlin-multiplatform-dev/multiplatform-integrate-in-existing-app.html#make- your-code-cross-platform File | New | New Module

    Java or Kotlin Library を選択 ルートディレクトリの build.gradle.kts を手で書き換える モジュールディレクトリの build.gradle.kts を手で書き換える → すごいアナログなやり方だった
  4. Regular framework とXCFramework 、どっちを選べばいいんだ??。 。 ↓ 出力したバイナリはSwift Package Manager 経由で取り込むからそれに都合いいほうがいいんだよなー

    ↓ 「kmp spm 」でググる ↓ 「おっ、なんかそれっぽい記事が公式にあるやん」 ↓ 「ふむふむ、このチュートリアルではXCFramework を使ってるのね」 ↓ 「じゃあ、XCFramework でいいや」
  5. iOS integration methods https://kotlinlang.org/docs/multiplatform-ios-integration-overview.html このドキュメントを読んだらiOS に統合するやり方として、 Local integration と Remote

    integration の 2 種類の方法があって、 Local integration ではRegular framework 、 Remote integration ではXCFramework を選択していた。 。 どっちでもいけるのか、 、 じゃあちゃんと善し悪し調べないといけないな と思ったのがこの資料作り始めたときだったのでだれか教えてください
  6. やりかた 1. XCFramework を生成する ./gradlew assembleSharedDebugXCFramework 2. SPM の依存に追加する .binaryTarget(

    name: "KmpShared", path: "/relative/path/to/kmp-module/build/XCFrameworks/debug/shared.xcframework" ), 3. iOS アプリをビルドする 4. import shared するとKMP のが提供するAPI が使えるようになる shared の部分はビルド設定に依存する it.binaries.framework { baseName = "shared" // <- // ...
  7. Ktor にはリフレッシュの機構が付いてる refreshTokens { runBlocking { val token = jwtApiClient.issueJwtToken().jwt

    BearerTokens( token, "", ) } } HttpClient(OkHttp) { install(Auth) { bearer { loadTokens { runBlocking { val token = jwtApiClient.issueJwtToken().jwt BearerTokens( token, "", ) } } }
  8. 原因: www-authenticate ヘッダーがHTTP の仕様を違反していた https://datatracker.ietf.org/doc/html/rfc7235#page-7 User agents are advised to

    take special care in parsing the field value, as it might contain more than one challenge, and each challenge can contain a comma-separated list of authentication parameters. ASIS www-authenticate: Bearer scope="" error="invalid_token" error_description="the token has expired" TOBE www-authenticate: Bearer scope="", error="invalid_token", error_description="the token has expired"
  9. 呼び出すときにパラメータ名の省略がしたければ @ObjCName("_") っていうアノテーションを付ける Kotlin: 名前が同じであってもパッケージ名が異なれば定義可能、Obj-C/Swift: パッケージ名などない 同名のクラスを定義してしまうと、片方は名前衝突を回避するためにアンダースコアがつけられる Item, Item_ Collection(List,

    Set, Map) のシグネチャにインターフェースを入れる( Set<HogeInterface> ) と、Swift から 見たときは Set<AnyHashable> になる interface を使うと苦しむことになりやすい 拡張関数を作っても、Swift から呼び出すときは ExampleKt.extensionFun(reciever) みたいな感じで残 念なことになる Kotlin が例外をthrow して、Swift でdo-try-cathc したのにcache がスルーされてクラッシュする 関数に @Throws(IOException::class) のようにアノテートしないと、NSError を吐いてくれない Coroutine は @MainActor で実行しなければいけないという制約がある