既存のアプリへのKMPの適用:チームの経験と成果

この記事は、KINTOテクノロジーズ・アドベントカレンダー2024 の12日目の記事です🎅🎄
こんにちは。「KINTOかんたん申し込みアプリ」のAndroid開発チームメンバーです。今日は、私たちの既存のアプリに Kotlin Multiplatform (KMP) を実装するプロセス、その理由、そしてそれによってもたらされた変化と改善についてお話ししたいと思います。
私たちは去年からiOSとAndroidプラットフォーム間での開発効率を最大化する方法を探ってきました。
このプロセスの中で、KMPがチームの目に留まりました。この技術がどのように革新的に開発プロセスを改善したかを皆さんにお伝えしたいと思います。
目次
- 1. 既存のアプリにKMPを実装する理由
- 2. 既存のアプリへのKMPの統合
- 3. KMPコードの配布
- 4. AndroidおよびiOSの実装方法
- 5. KMPクロスプラットフォームモジュール実装における課題
- 6. 効果
- 7. 今後に向けて:今後の計画と課題
1. 既存のアプリにKMPを実装する理由
当時、私たちのチームはiOS開発リソースの不足に直面していました。
この課題に対処するために、AndroidチームはKotlin Multiplatform (KMP) を活用して、iOSとAndroidの両方のプラットフォームで共有されるビジネスロジックを作成することにしました。
このアプローチにより、オペレーティングシステム間でのコードの重複を削減し、Androidチームは専門知識を活用してiOS開発に対応できるようになりました。
この戦略は、人員の問題を軽減し、開発生産性を大幅に向上させる重要なソリューションとなり、KMPテクノロジーを既存のアプリに統合する決定的な理由となりました。
[背景の概要]
- iOS開発リソース不足への対処
- Kotlinに関するAndroidチームの専門知識の活用
- オペレーティングシステム間のコード重複の削減
- 開発生産性の向上とチーム連携の強化
※ ビジネスロジックをKMPライブラリにモジュール化することで、オペレーティングシステム間での重複作業を排除しましょう。
2. 既存のアプリへのKMPの統合
私たちは、KMPコードを実装する前に、私たちの共有コードをどこに配置し、どのように整理するかについていくつかの戦略的決定を下しました。
2.1 共有コードの配置決定
現在運営していますモバイルアプリには、Androidリポジトリで作業するAndroidチームと、iOSリポジトリで作業するiOSチームという2つの別々の開発チームによる典型的な設定があります。
KMPを導入するときに最初に生じる疑問は、「共有コードをどこに配置すべきか」ということです。
オプション1:別のリポジトリ内の共有コード
このオプションでは、共有コード用の新規リポジトリを作成し、AndroidリポジトリとiOSリポジトリの両方からアクセスできるようにします。このリポジトリ構造は次のようになります。
オプション2:Androidリポジトリ内の共有コード
このオプションでは、共有コードをAndroidリポジトリに配置し、Androidチームが共有コードベースを管理できるようにします。このリポジトリ構造は次のようになります。
オプション3:AndroidリポジトリとiOSリポジトリをモノレポに統合する
このオプションでは、AndroidリポジトリとiOSリポジトリをモノレポに統合し、両チームが共有コードベースにアクセスできるようにします。このリポジトリ構造は次のようになります。
[私たちの決定]
各オプションの長所と短所を検討した結果、共有コードをAndroidリポジトリに配置することに決定しました。この決定は以下の要因に基づいています:
- 既存のワークフローへの影響を最小限に抑える
- 共有コードベースの管理が容易になる
2.2 共有コードの整理
共有コードをどこに配置するかを決めたら、次はそれをどのように整理するかを決めました。
私たちの既存のAndroidアプリはマルチモジュール・アーキテクチャに従っているため、共有モジュールとプラットフォーム固有のモジュールを明確に区別したいと考えました。KMPモジュールを既存のAndroidモジュールと一緒に、Androidリポジトリ内のshared
ディレクトリに配置することにしました。例:
:app // Androidアプリのモジュール
:domain // Android 固有のモジュール
:shared:api // KMPモジュール
:shared:validation // KMPモジュール
2.3 KMPモジュールの作成
KMP用のGradleモジュールは次を含みます。
build.gradle.kts
ファイルsrc
サブフォルダー
Androidモジュールの場合、com.android.library
プラグインを適用し、android {}
ブロックを含めます。
plugins {
id("com.android.library")
}
android {
// Android固有の設定
}
KMPモジュールの場合、マルチプラットフォームプラグインを使用し、kotlin {}
ブロックを定義します。
plugins {
kotlin("multiplatform")
}
kotlin {
// KMPの設定
}
この設定により、共有コードベースにおいてAndroid固有の要件とKMP固有の要件の両方に対応できるようになりました。
-
2.4 マルチモジュール・アーキテクチャとアンブレラモジュール
複数モジュールの制限
Androidでは、複雑なプロジェクトのためにコードを複数のモジュールに分割するのが標準です。ただし、KMPは現在、iOSに対して1つのモジュールのみの公開に対応しています。
例えば、共有コードベースに、featureA
, featureB
, featureC
という3つのモジュールがあるとします。各モジュールはdata
モジュールに依存し、data
モジュールはapi
モジュールに依存しています。
これら3つのモジュールをiOSに公開したい場合、理想的なシナリオでは、iOS開発者は次のように必要なモジュールのみをインポートします。
import featureA
import featureB
<swift code here>
ただし、KMPの制限により、このアプローチではiOSアプリ内でコードが重複することになります。
以下のような構造が望ましいのですが、
実際には、以下のような構造(重複あり)になってしまいます。
アンブレラモジュール
この制限を克服するために、アンブレラモジュールを導入しました。
アンブレラモジュールは、ソースコードを含まない「空の」モジュールであり、依存関係を管理するために使用されます。
こちらがbuild.gradle.ktsの例です:
kotlin {
val xcf = XCFramework()
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
it.binaries.framework {
baseName = "Umbrella"
binaryOption("bundleId", "com.example.shared")
export(project(":shared:featureA"))
export(project(":shared:featureB"))
export(project(":shared:featureC"))
xcf.add(this)
}
}
sourceSets {
val commonMain by getting {
dependencies {
api(project(":shared:featureA"))
api(project(":shared:featureB"))
api(project(":shared:featureC"))
}
}
}
}
アンブレラモジュールは、iOS開発者の統合プロセスを簡素化し、プラットフォーム間でシームレスかつ効率的な開発体験を確保します。
2.5 CI:AndroidおよびiOSでの共有コードのテスト
私たちは常にコードのテストを記述しており、共有コードも例外ではありません。プラットフォームの違いにより、一部の機能はiOSでは期待どおりに動作しない場合があります。互換性を確保するために、AndroidとiOSの両方でテストを実行します。AndroidはどのOSでもテストを実行できますが、iOSのテストはmacOSで実行する必要があります。
3.KMPコードの配布
KMPコードの記述が完了したら、次のステップはそれをiOSアプリに配布することです。
3.1 KMPコードの配布オプション
KMPコードは、ソースコードまたはバイナリで配布できます。
ソースコードの配布
ソースコード配布では、iOS開発者はKMPコードを自らコンパイルする必要があります。このアプローチでは、Java VMやGradleなどのツールを含むKotlinビルド環境をセットアップする必要があります。
課題:
- すべてのiOS開発者は、KMPビルド環境を設定する必要があります。
- これにより、KMPコードを iOSプロジェクトに導入する際の複雑さが増します。
バイナリ配布
より良いオプションはバイナリ配布です。私たちは、プリコンパイル済みのライブラリを提供することで、iOS開発者が追加のビルド環境を管理する必要性をなくし、共有コードの統合がはるかに簡単になるようにしています。
利点:
- iOS開発者のセットアップ作業を削減します。
- 環境間で一貫したビルドを確保します。
3.2 Swift Package Manager (SPM)
iOSには主に2つの依存管理システムがあります。それは、CocoaPods と Swift Package Manager (SwiftPM)です。どちらを選択するかは、iOSチームの好みによります。幸いなことに、私たちのiOSチームは SwiftPMに完全移行しているため、SwiftPMのみに対応すれば済みます。
Swift Packageとは?
Swift Packageは基本的に、次を含むGitリポジトリです。
- Swiftソースコード
- Package.swiftマニフェストファイル
- Gitタグによるセマンティック・バージョニング
SwiftPMによるバイナリ配布
SwiftPM 5.3以降、SwiftPMはbinaryTarget
に対応しており、ソースコードの代わりに予めコンパイルされたライブラリを配布できるようになっています。
バイナリ配布によるSwift Packageの作成
KMPコードをSwift Packageとして公開する方法を簡単に説明します。
- KMPコードを
.xcframework
にコンパイルします。 .xcframework
をzipファイルにパッケージ化し、そのチェックサムを計算します。- GitHubに新しいリリースページを作成し、リリースアセットの一部としてzipファイルをアップロードします。
- リリースページからzipファイルのURLを取得します。
- URLとチェックサムに基づいて
Package.swift
ファイルを生成します。 Package.swift
ファイルをコミットし、gitタグを追加してリリースをマークします。- gitタグをリリースページに関連付け、GitHubリリースを正式に公開します。
詳細な手順については、[リモートSPMエクスポートに関するKMPドキュメント] を参照してください。(https://kotlinlang.org/docs/native-spm.html)
// swift-tools-version:5.10
import PackageDescription
let packageName = "Umbrella"
let package = Package(
name: packageName,
platforms: [
.iOS(.v13)
],
products: [
.library(
name: packageName,
targets: [packageName]),
],
targets: [
.binaryTarget(
name: packageName,
url: "https://url/to/some/remote/xcframework.zip",
checksum:"The checksum of the ZIP archive that contains the XCFramework."
]
)
3.3 配布の自動化
手動での配布は時間がかかる場合があります。プロセスを円滑化するために、自動化用のGitHub Actionsワークフローを作成しました。
name:Publish KMP for iOS
on:
workflow_dispatch:
inputs:
release_version:
description:'Semantic Version'
required: true
default:'1.0.0'
env:
DEVELOPER_DIR: /Applications/Xcode_15.3.app
jobs:
build:
runs-on: macos-14
steps:
- name:Checkout
uses: actions/checkout@master
- name: set up JDK 17
uses: actions/setup-java@v4
with:
java-version:'17'
distribution: 'zulu'
- name:"Build and Publish"
env:
RELEASE_VERSION: ${{ github.event.inputs.release_version }}
GH_TOKEN: ${{ github.token }}
run: ./scripts/publish_iOS_Framework.sh $RELEASE_VERSION
#!/bin/sh
set -e
MODULE_NAME="<your module name>"
VERSION=$1
# Github リリース用のバージョン名
RELEASE_VERSION="$MODULE_NAME-$VERSION"
# Gitタグ名
TAG="$VERSION"
TMP_BRANCH="kmp_release_$VERSION"
# VERSIONがsemver仕様であるか確認
if [[ ! $VERSION =~ ^[0-9]+.[0-9]+.[0-9]+$ ]]; then
echo "VERSION should be in semver format like 1.0.0"
exit 1
fi
ZIPFILE=./shared/$MODULE_NAME/build/XCFrameworks/release/$MODULE_NAME.xcframework.zip
echo "Building $MODULE_NAME $VERSION"
./gradlew assembleKintoOneCoreReleaseXCFramework
echo "creating zip file"
pushd ./shared/$MODULE_NAME/build/XCFrameworks/release/
zip -r $MODULE_NAME.xcframework.zip $MODULE_NAME.xcframework
popd
# タグを取得
git fetch --tags
# 直前のリリースタグを取得
PREVIOUS_RELEASE_TAG=$(git tag --sort=-creatordate | grep -v ^version | head -n 1)
echo "previous release tag: $PREVIOUS_RELEASE_TAG"
# Github ドラフトリリースを作成
echo "creating github release $RELEASE_VERSION"
gh release create $RELEASE_VERSION -d --generate-notes --notes-start-tag $PREVIOUS_RELEASE_TAG
gh release upload $RELEASE_VERSION $ZIPFILE
echo "retrieving asset api url"
# Github リリースからアップロードされたzip ファイルのAsset APIのURLを取得
# 例: "https://api.github.com/repos/{username}/{repo}/releases/assets/132406451"
ASSET_API_URL=$(gh release view $RELEASE_VERSION --json assets | jq -r '.assets[0].apiUrl')
# URLの末尾に拡張子(.zip)を追加
ASSET_API_URL="${ASSET_API_URL}.zip"
# Package.swiftを生成
./scripts/generate_SPM_Manifest_File.sh $ZIPFILE $ASSET_API_URL
# Package.swiftをコミットし、タグを追加
git checkout -b $TMP_BRANCH
git add .
git commit -m "release $VERSION"
git tag -a $TAG -m "$MODULE_NAME $VERSION"
git push origin $TAG
# Githubリリースを更新し、新しいタグに置き換える
gh release edit $RELEASE_VERSION --tag $TAG
4.AndroidおよびiOSの実装方法
このプロジェクトで私たちは、Kotlin Multiplatform (KMP) を使用して、既存のアプリに新規共通モジュールを導入しました。プラットフォーム固有の潜在的な問題を最小限に抑えるために、AndroidとiOSで確実に動作する機能を慎重に選択して実装しました。OSに依存しない機能を選択して本番環境での初期テストのために実装をシンプルに保つことによって、クロスプラットフォームモジュールの確立に重点を置きました。以下は、機能選択基準と実装プロセスの概要です。
4.1 機能の選択
KMPを本番環境に導入する際の潜在的な問題を特定するために、プラットフォーム固有の実装に依存せず、かつ最小限の依存関係で扱える機能を優先しました。機能選択の基準に次を含めました:
- OSに依存しない機能性:本番環境で予期しない問題が発生するのを避けるために、OSに依存しない機能を選択し、通信、ストレージ、権限など特定のOSレベル制御を必要とする要素を除外しました。
- 追加ライブラリの最小化:メンテナンスのリスクを軽減するために、追加ライブラリに依存せずにKotlin標準ライブラリのみで実装できる機能を選択します。
- ライブラリの優先順位:ライブラリを選択する際に、まず公式Kotlinライブラリ、次に公式Kotlinドキュメントで推奨されているライブラリ、最後にサードパーティのライブラリ、と優先順位をつけました。
これらの基準に基づいて、KMPで実装する最初のクロスプラットフォーム機能として入力検証を選択しました。そして、全角/半角文字変換機能を追加しました。
Android
入力検証の実施
デフォルトでは、Android実装にはライブラリ機能の不足やインターフェースの違いといった問題しかありませんが、それは大した問題ではありませんでした。
入力検証機能を、一般的なオブジェクト指向プログラミング (OOP) の原則に従って構造化し、再利用性と一貫性を重視しました。
1.共通インターフェースの定義:両方のプラットフォーム間で入力を検証するための一貫した基盤を作るために、Validator
インターフェースと ValidationResult
インターフェースを定義しました。
abstract class ValidationResult(
/**
* Informations about input and fail reason.
*/
val arguments:Map<String, Any?>,
requiredKeys:Set<String>
)
fun interface Validator<T, R :ValidationResult> {
/**
* @return validation result or `null` if the target is valid.
*/
operator fun invoke(target:T):R?
}
2.入力タイプ別のバリデータの実装:電子メールやパスワードの検証など、入力タイプごとにバリデータと結果クラスを分けて作成しました。
class IntRangeValidator(
/**
* min bound(inclusive).
*/
val min:Int,
/**
* Max bound(inclusive).
*/
val max:Int
) :Validator<String, IntRangeValidationResult> {
companion object {
const val PATTERN = "0|(-?[1-9][0-9]*)"
val REGEX = PATTERN.toRegex()
const val ARG_NUMBER = "number"
const val ARG_RANGE = "range"
const val ARG_PATTERN = "pattern"
}
val range = min..max
override fun invoke(target:String):IntRangeValidationResult? {
when {
target.isEmpty() ->
return RequiredIntRangeValidationResult()
!target.matches(REGEX) ->
return IllegalPatternIntRangeValidationResult(target, PATTERN)
}
return try {
target.toInt(10).let { number ->
if (number !in range) {
OutOfRangeIntRangeValidationResult(target, range)
} else {
null
}
}
} catch (e:NumberFormatException) {
OutOfRangeIntRangeValidationResult(target, range)
}
}
}
3.テストコードの作成:プラットフォーム間でのモジュールの精度を検証するために、kotlin-test
パッケージを使用して広範なテストケースを実施し、AndroidとiOSの両方で安定した機能を確保しました。
import kotlin.random.Random
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertContains
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertIs
import kotlin.test.assertNotNull
import kotlin.test.assertNull
class IntRangeValidatorTest {
private var min = 0
private var max = 0
private lateinit var validator:IntRangeValidator
@BeforeTest
fun setUp() {
min = Random.nextInt()
max = Random.nextInt(min + 1, Int.MAX_VALUE)
validator = IntRangeValidator(min, max)
}
@AfterTest
fun tearDown() {
min = 0
max = 0
}
@Test
fun `invoke - decimal number string`() {
val validator = IntRangeValidator(Int.MIN_VALUE, Int.MAX_VALUE)
for (number in listOf(
"0",
"1",
"111",
"${Int.MAX_VALUE}",
"-1",
"${Int.MIN_VALUE}",
"${Random.nextInt(Int.MAX_VALUE)}",
"-${Random.nextInt(Int.MAX_VALUE - 1)}"
)) {
// 以下の場合
val result = validator(number)
/// したがって、以下の通りになる
assertNull(result)
}
}
}
全角/半角文字変換の実装
入力検証に加えて、文字変換機能を実装し、アプリケーション要件に基づいて全角文字と半角文字を自動的に変換しました。
1.拡張可能なインターフェースの定義:多様で複雑な文字変換に対応するため、インターフェースを定義し、あらゆる変換処理を継承できるようにしました。Kotlinには、これを実装するのに役立つ関数型インターフェース (fun interface
) と演算子関数 (operator fun
) の機能が備わっています。
fun interface TextConverter {
operator fun invoke(input:String):String
operator fun plus(other:TextConverter) = TextConverter { input ->
other(this(input))
}
}
2.変換用のマッピング定数の定義:全角/半角文字とそれらの変換をリストアップした文字マッピングテーブルを作成し、定義済みマッピングを参照して変換できるようにしました。
open class SimpleTextConverter(
val map:Map<String, String>
) :TextConverter {
override operator fun invoke(input:String):String {
var result = input
for ((key, value) in map) {
result = result.replace(key, value)
}
return result
}
}
class RemoveLineSeparator(
map:Map<String, String> = mapOf(
"\n" to "",
"\r" to ""
)
) :SimpleTextConverter(map)
object HalfwidthDigitToFullwidthDigitConverter :SimpleTextConverter(
mapOf(
"0" to "0",
"1" to "1",
"2" to "2",
"3" to "3",
"4" to "4",
"5" to "5",
"6" to "6",
"7" to "7",
"8" to "8",
"9" to "9"
)
)
val NUMBER_CONVERTER = FullwidthDigitToHalfwidthDigitConverter +
RemoveLineSeparator()
3.自動変換機能:変換機能は、全角文字を半角文字に、またはその逆に自動変換するように設計されており、一貫性のある予測可能な入力体験を実現します。
これらのOS非依存性機能を選択し、それらをKMP で実装することで、AndroidとiOS間で確実に導入できる安定した再利用可能なモジュールを確立できました。
iOSへの統合
私たちのKMPコードはSwift Packageとして配布され、iOSチームはXcodeGenを使用してXcodeプロジェクトファイルを管理しました。iOSアプリへのKMPコードの統合は、project.yml
ファイルに4行のコードを追加するだけで簡単に実行できます。
packages:
+ Umbrella:
+ url: https://github.com/your-org/your-android-repository
+ minorVersion:1.0.0
targets:
App:
dependencies:
+ - package:Umbrella
- package: ...
ただし、私たちのコードはプライベートリポジトリに格納されているため、いくつかの追加設定が必要です。詳細については、以下をご覧ください:SwiftPMでのプライベートリポジトリの資格情報設定
5.KMPクロスプラットフォームモジュール実装における課題
KMP共通モジュールの開発中に、技術的な問題がいくつか発生しました。特に目立ったのは、基本的な機能、マルチバイト文字、符号化の処理に関する問題でした。以下は、これらの問題の概要と、それらをどのように解決したかについてです。
Kotlin標準ライブラリはUnicodeコードポイントに対応していません
入力検証において漢字やサロゲートペアなどのマルチバイト文字を正確に処理するために、Unicodeコードポイントベースの正規表現を実装することにしました。このアプローチにより、文字を単なる個々の文字として扱うのではなく、Unicode範囲内での文字の位置に基づいて文字を正確に一致させて検証できるようになりました。しかし、問題が発生しました。
Kotlinの String
クラスは、Unicodeコードポイントの処理をネイティブに対応しておらず、この目的(特にサロゲートペア)のための公式ライブラリも提供していません。
そのため、コードポイントに基づいてマルチバイト文字を正確に処理するために、サードパーティのライブラリを使用しています。これにより、漢字などの複雑な文字を私たちの正規表現内でより正確に一致させることができるようになりました。
非UTFの文字における符号化には対応していません
レガシーシステムとの互換性を維持するには、Shift-JIS (MS932) の符号化に対応する必要がありました。しかし、KMPはShift-JIS符号化において、ネイティブに対応していません。
レガシーシステムへのテキスト転送では、MS932で符号化が可能であるか否かを確認する必要があり、そのため、ktor-client
ライブラリを使用して符号化を処理することにしました。ただし、ktor-client
のiOSバージョンはUTFベースの符号化スキームしか対応していないため、MS932符号化を実施するのは困難です。
MS932符号化の制限により、漢字検証のためのコードポイントの使用を断念しました。代わりに、検証に必要な漢字のリスト全体を含む定数を宣言し、必要に応じて参照できるように、これらをUnicodeコードポイントに変換しました。
Unicodeコードポイントの問題
全角文字と半角文字の変換を実施する際に、特定の文字間のコードポイントの不一致が発生し、単純な加算/減算アプローチが効果的でなくなりました。
例えば、日本語の全角文字ァ'
(U+30A1
) と ア
(U+30A2
)は、コードポイントが1つ異なるだけです。対照的に、半角文字ァ
(U+FF67
)とア
(U+FF71
)は、コードポイントが10異なります。この不一致は、統一された変換アプローチが実現不可能であることを意味していました。
私たちは、すべての変換に対して定数マッピングテーブルを作成し、すべての全角文字と半角文字、およびそれぞれのマッピングを明確に定義することで、この問題を解決しました。このアプローチにより、変換操作においてさまざまな文字を正確に処理できるようになりました。
これらの問題に対処することで、私たちのKMP共通モジュールの安定性と完全性が向上し、AndroidとiOSの両方のプラットフォームで正確な機能を確保できました。
6.効果
技術的な効果:
- プロセスの一貫性:KMPの実装により、iOSとAndroid間での動作の不一致が最小化され、QA時のエラー頻度が低下しました。
- コードの再利用性:Androidチームが検証したコードはiOSでも使用されるため、両方のプラットフォームにわたって開発効率が向上します。
OS連携と開発リソースの最適化:
- コミュニケーション負担の軽減:KMPにより、Androidチームはほとんどのメンテナンスを単独で処理できるようになり、iOSチームはバージョン アップグレードと軽微なメンテナンスに集中できるようになります。
- これは、開発リソースのより効率的な使用と、チーム間の連携強化をもたらします。
プロジェクト管理上の問題:
- 開発およびメンテナンスのコスト:初期設定には時間がかかりますが、その後は通常通り開発を続けることができます。ただし、Android固有のライブラリおよびJavaベースのライブラリの使用には制限があるため、開発コストが増加する可能性があります。
- リソースの割り当て:Androidチームに重点を置いた開発プロセスは、繁忙期におけるリソース不足につながる可能性があります。
- KMPで実装された機能は主にAndroid チームが管理しているため、iOSチームの理解度は比較的低く、バランスの取れたリソース配分とトレーニングが求められます。
7.今後に向けて:今後の計画と課題
継続的な教育とトレーニングを通じた将来の拡張計画の実施
現在、私たちのチームは、Kotlin Multiplatform(KMP)技術をより効果的に活用するために、社内教育およびトレーニングプログラムの開発と実施に取り組んでいます。このプログラムは技術的な詳細にとどまらず、チームワークやプロジェクト管理スキルの向上にも重点を置いています。これにより私たちは、技術力の向上だけでなく、プロジェクトの効果的な管理やチーム間の連携強化も目指しています。
今後の計画:KMPへの共通ロジックの移行
今後、私たちのチームは、より多くの共通ロジックをKMPへ移行する予定です。これにより、iOSアプリケーションとAndroidアプリケーション間でのコード再利用を最大化し、メンテナンスの複雑さを軽減することで、開発効率の向上を図ります。
移行へのキーロジック:
- APIクライアント: BFF、OCR
- ビジネスロジック: キャッシュ管理など
- ユーティリティ: テキストの書式設定(時間、使用料)、バージョン比較(利用規約)など
- ローカルストレージ: アプリ設定、認証トークンなど
これらの計画を実行することで、クロスプラットフォーム開発の効率と連携が強化され、私たちのチームがプラットフォーム間での開発タスクをより効果的に行えるようになることが期待されます。
お読みいただきありがとうございました。これが、まだKMPテクノロジーを適用していないチームにとって、役立つ参考資料となることを願っています。
関連記事 | Related Posts

既存のアプリへのKMPの適用:チームの経験と成果

Mobile App Development Using Kotlin Multiplatform Mobile (KMM) and Compose Multiplatform

Mobile App Development Using Kotlin Multiplatform Mobile (KMM)

Credential Setup for Private Repositories in SwiftPM

Kotlin Multiplatform Mobile (KMM)を使ったモバイルアプリ開発

A to Z of Testing in Kotlin Multiplatform (KMP)
We are hiring!
【プロダクト開発バックエンドエンジニア(リーダークラス)】共通サービス開発G/東京・大阪
共通サービス開発グループについてWebサービスやモバイルアプリの開発において、必要となる共通機能=会員プラットフォームや決済プラットフォームなどの企画・開発を手がけるグループです。KINTOの名前が付くサービスやKINTOに関わりのあるサービスを同一のユーザーアカウントに対して提供し、より良いユーザー体験を実現できるよう、様々な共通機能や顧客基盤を構築していくことを目的としています。
【部長・部長候補】/プラットフォーム開発部/東京
プラットフォーム開発部 について共通サービス開発GWebサービスやモバイルアプリの開発において、必要となる共通機能=会員プラットフォームや決済プラットフォームの開発を手がけるグループです。KINTOの名前が付くサービスやTFS関連のサービスをひとつのアカウントで利用できるよう、様々な共通機能を構築することを目的としています。