Kotlin MultiplatformでKtorとSQLDelightを活用する完全ガイド

Kotlin Multiplatformを活用することで、iOS、Android、デスクトップ、Webといった複数のプラットフォームに対応するアプリを効率的に開発できます。本記事では、Kotlin Multiplatformのライブラリとして人気の高いKtor(API通信)とSQLDelight(データベース管理)を組み合わせ、実用的なアプリケーションを構築する方法を詳しく解説します。これにより、コードの共通化を図りつつ、各プラットフォーム向けに最適な処理を実現するための知識が身につきます。

目次

Kotlin Multiplatformとは何か


Kotlin Multiplatform(KMP)は、JetBrainsが開発したクロスプラットフォーム向けの技術で、共通のコードベースを使いながら、iOS、Android、Web、デスクトップ向けのアプリを効率的に開発できる仕組みです。

主な特徴

  • コードの再利用性:ビジネスロジックやデータ処理を共通化し、プラットフォーム固有のコードは必要な部分だけに限定します。
  • 柔軟な設計:UI部分は各プラットフォーム固有のコードを活用し、ネイティブな体験を維持できます。
  • インクリメンタルな導入:既存プロジェクトに段階的に導入可能で、完全に移行する必要がありません。

Kotlin Multiplatformの利点

  • 開発効率の向上:共通コードが増えるため、重複作業が減少し、開発速度が向上します。
  • 保守性の向上:共通ロジックを一箇所で管理するため、修正やアップデートが容易です。
  • 高パフォーマンス:プラットフォーム固有のコードを活用できるため、ネイティブ性能を保ちます。

Kotlin Multiplatformを利用することで、複数のプラットフォーム向けの開発コストを抑えつつ、品質の高いアプリケーションを提供できます。

Ktorの概要と特徴


Ktorは、JetBrainsが提供する非同期型のKotlin製Webフレームワークで、API通信やWebアプリケーションの開発に使われます。特にKotlin Multiplatformプロジェクトに適しており、サーバーサイドとクライアントサイドの両方で利用できます。

Ktorの主な特徴

  • 軽量で柔軟:必要な機能だけを選んで使えるため、プロジェクトに無駄がありません。
  • 非同期処理:Kotlinのコルーチンを活用し、効率的な非同期処理が可能です。
  • DSLベースの設定:直感的なDSL(Domain Specific Language)により、設定やルーティングが簡単に行えます。
  • マルチプラットフォーム対応:iOS、Android、Web、デスクトップといった複数のプラットフォームで動作します。

サーバーサイドとクライアントサイドの用途

  • サーバーサイド:REST APIやWebSocketの実装、サーバーレス関数の構築に適しています。
  • クライアントサイド:HTTPリクエストやAPI通信を行うクライアントアプリケーションで活用できます。

主な利用シーン

  • モバイルアプリ向けAPI通信
  • Webアプリケーションのバックエンド開発
  • デスクトップアプリやWebクライアントのHTTP通信

Ktorを使うことで、効率的にAPI通信やWebサービスを開発でき、Kotlin Multiplatformプロジェクトの可能性が大きく広がります。

SQLDelightの概要と特徴


SQLDelightは、Square社が開発したマルチプラットフォーム対応のデータベース管理ライブラリです。KotlinコードとしてSQLクエリを生成し、型安全なデータベース操作を可能にします。Kotlin Multiplatformプロジェクトで利用することで、共通のデータベースロジックを複数のプラットフォームで再利用できます。

SQLDelightの主な特徴

  • 型安全なSQLクエリ:SQLクエリがコンパイル時に検証され、型安全にデータを操作できます。
  • Kotlinコード生成:SQLファイルからKotlinインターフェースやクラスを自動生成します。
  • マルチプラットフォーム対応:iOS、Android、デスクトップ、Webで同じデータベースロジックを使用可能です。
  • IDEサポート:IntelliJやAndroid StudioでのSQL補完やエラー検出が可能です。

SQLDelightの主な用途

  • ローカルデータベース管理:モバイルアプリやデスクトップアプリでのデータ永続化に利用。
  • オフライン対応アプリ:オフライン時のデータ保存と同期処理に適しています。
  • シンプルなクエリ管理:複雑なSQLクエリでも簡単に管理・再利用が可能です。

SQLDelightのワークフロー

  1. SQLファイル作成.sqファイルにSQLクエリを記述。
  2. コード生成:SQLDelightがKotlinコードを自動生成。
  3. データ操作:生成されたKotlinコードを用いてデータのCRUD操作を行う。

SQLDelightを活用することで、型安全なデータベース操作が可能となり、エラーの少ない堅牢なデータ管理が実現できます。

Ktorの導入方法とセットアップ

Kotlin MultiplatformプロジェクトにKtorを導入する手順を解説します。Ktorはサーバーサイドとクライアントサイドで利用できるため、ここではクライアントサイドの導入手順を紹介します。

1. 依存関係の追加


build.gradle.ktsファイルにKtorクライアントの依存関係を追加します。

kotlin {
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-core:2.3.0")
                implementation("io.ktor:ktor-client-json:2.3.0")
                implementation("io.ktor:ktor-client-logging:2.3.0")
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-android:2.3.0")
            }
        }
        val iosMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-ios:2.3.0")
            }
        }
    }
}

2. Ktorクライアントの設定


共通モジュールにKtorクライアントを設定するコードを追加します。

import io.ktor.client.*
import io.ktor.client.engine.*
import io.ktor.client.engine.cio.*
import io.ktor.client.features.json.*
import io.ktor.client.features.logging.*

val client = HttpClient(CIO) {
    install(JsonFeature) {
        serializer = GsonSerializer()
    }
    install(Logging) {
        level = LogLevel.BODY
    }
}

3. HTTPリクエストの実装


Ktorクライアントを使用して、HTTPリクエストを実装します。

suspend fun fetchPosts(): String {
    return client.get("https://jsonplaceholder.typicode.com/posts")
}

4. プラットフォーム固有のエンジン設定

  • Androidktor-client-androidを使用。
  • iOSktor-client-iosを使用。

これでKotlin MultiplatformプロジェクトにKtorを導入し、API通信ができる準備が整いました。

SQLDelightの導入方法とセットアップ

Kotlin MultiplatformプロジェクトでSQLDelightを導入する手順を解説します。SQLDelightを使うと、型安全なSQLクエリを生成し、効率的にデータベース操作が可能になります。

1. 依存関係の追加


build.gradle.ktsファイルにSQLDelightの依存関係を追加します。

plugins {
    kotlin("multiplatform")
    id("com.squareup.sqldelight") version "1.5.5"
}

kotlin {
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("com.squareup.sqldelight:runtime:1.5.5")
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("com.squareup.sqldelight:android-driver:1.5.5")
            }
        }
        val iosMain by getting {
            dependencies {
                implementation("com.squareup.sqldelight:native-driver:1.5.5")
            }
        }
    }
}

2. SQLDelightの設定


build.gradle.ktsのルートにSQLDelightのデータベース設定を追加します。

sqldelight {
    Database {
        packageName = "com.example.database"
    }
}

3. SQLファイルの作成


src/commonMain/sqldelightにSQLファイル(例:Post.sq)を作成します。

CREATE TABLE Post (
    id INTEGER PRIMARY KEY,
    title TEXT,
    content TEXT
);

selectAllPosts:
SELECT * FROM Post;

insertPost:
INSERT INTO Post(id, title, content) VALUES (?, ?, ?);

4. データベースのインスタンス作成


Kotlinコードでデータベースインスタンスを作成します。

import com.example.database.Database
import com.squareup.sqldelight.db.SqlDriver
import com.squareup.sqldelight.android.AndroidSqliteDriver

fun createDatabase(driver: SqlDriver): Database {
    return Database(driver)
}

5. プラットフォームごとのドライバ設定

  • Androidの場合
  val driver = AndroidSqliteDriver(Database.Schema, context, "example.db")
  val database = createDatabase(driver)
  • iOSの場合
  val driver = NativeSqliteDriver(Database.Schema, "example.db")
  val database = createDatabase(driver)

これでSQLDelightを導入し、Kotlin Multiplatformで型安全なデータベース操作ができる環境が整いました。

KtorとSQLDelightの連携方法

Kotlin Multiplatformプロジェクトにおいて、Ktorを用いたAPI通信とSQLDelightを用いたデータベース管理を連携させることで、取得したデータを効率的に永続化できます。以下では、具体的な実装手順を解説します。

1. APIからデータを取得する


Ktorを使用してAPIからデータを取得します。

import io.ktor.client.*
import io.ktor.client.request.*

suspend fun fetchPosts(): List<Post> {
    return client.get("https://jsonplaceholder.typicode.com/posts")
}

2. 取得したデータをSQLDelightで保存


SQLDelightを使用して取得したデータをデータベースに保存します。

import com.example.database.Database
import com.example.database.Post

suspend fun savePostsToDatabase(database: Database, posts: List<Post>) {
    database.transaction {
        posts.forEach { post ->
            database.postQueries.insertPost(post.id, post.title, post.content)
        }
    }
}

3. データを取得し保存する処理を統合


KtorでAPIからデータを取得し、SQLDelightでデータベースに保存する統合処理を作成します。

suspend fun fetchAndSavePosts(database: Database) {
    try {
        val posts = fetchPosts()
        savePostsToDatabase(database, posts)
        println("データの取得と保存が完了しました")
    } catch (e: Exception) {
        println("エラーが発生しました: ${e.message}")
    }
}

4. データベースからデータを読み出す


SQLDelightのクエリを使用して、データベースに保存されたデータを読み出します。

fun getAllPosts(database: Database): List<Post> {
    return database.postQueries.selectAllPosts().executeAsList()
}

5. 実行例


Androidアプリの場合、ViewModelActivityでデータの取得と保存処理を呼び出します。

val driver = AndroidSqliteDriver(Database.Schema, context, "example.db")
val database = createDatabase(driver)

CoroutineScope(Dispatchers.IO).launch {
    fetchAndSavePosts(database)
    val posts = getAllPosts(database)
    println(posts)
}

処理の流れ

  1. KtorでAPIからデータを取得。
  2. SQLDelightでデータベースに保存。
  3. 保存したデータを読み出して表示。

これにより、Kotlin MultiplatformでAPI通信とデータベース管理を統合した効率的なデータ処理が実現できます。

実践例:KtorとSQLDelightを用いたアプリ開発

KtorとSQLDelightを使い、Kotlin Multiplatformプロジェクトで簡単なTo-Doリストアプリを作成する手順を紹介します。データの取得、保存、表示までの一連の流れを実装します。

1. プロジェクトのセットアップ


依存関係としてKtorSQLDelightを追加します(build.gradle.ktsに設定済みと仮定)。

2. データモデルの作成


To-Do項目のデータモデルを定義します。

data class TodoItem(val id: Long, val title: String, val isCompleted: Boolean)

3. SQLファイルの作成


SQLDelight用の.sqファイルを作成します(Todo.sq)。

CREATE TABLE TodoItem (
    id INTEGER PRIMARY KEY,
    title TEXT,
    isCompleted INTEGER
);

selectAllTodos:
SELECT * FROM TodoItem;

insertTodo:
INSERT INTO TodoItem(id, title, isCompleted) VALUES (?, ?, ?);

4. KtorでAPIからTo-Doリストを取得

import io.ktor.client.*
import io.ktor.client.request.*

suspend fun fetchTodos(): List<TodoItem> {
    return client.get("https://jsonplaceholder.typicode.com/todos")
}

5. データベースにTo-Doリストを保存

import com.example.database.Database

suspend fun saveTodos(database: Database, todos: List<TodoItem>) {
    database.transaction {
        todos.forEach { todo ->
            database.todoItemQueries.insertTodo(todo.id, todo.title, if (todo.isCompleted) 1 else 0)
        }
    }
}

6. データの取得、保存、表示を統合

suspend fun fetchAndSaveTodos(database: Database) {
    try {
        val todos = fetchTodos()
        saveTodos(database, todos)
        val savedTodos = database.todoItemQueries.selectAllTodos().executeAsList()
        println("保存されたTo-Doリスト: $savedTodos")
    } catch (e: Exception) {
        println("エラーが発生しました: ${e.message}")
    }
}

7. プラットフォーム固有コードで呼び出し


Androidの場合、Activityで処理を呼び出します。

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.squareup.sqldelight.android.AndroidSqliteDriver
import kotlinx.coroutines.*

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val driver = AndroidSqliteDriver(Database.Schema, this, "todos.db")
        val database = Database(driver)

        CoroutineScope(Dispatchers.IO).launch {
            fetchAndSaveTodos(database)
        }
    }
}

処理の流れ

  1. KtorでTo-DoリストのAPIからデータを取得。
  2. SQLDelightで取得したデータをローカルデータベースに保存。
  3. 保存されたデータを表示。

この実践例を通して、Kotlin MultiplatformでKtorとSQLDelightを連携させ、API通信とデータベース管理を効率的に統合する方法を理解できます。

よくあるエラーとトラブルシューティング

Kotlin MultiplatformでKtorSQLDelightを使用する際に発生しやすいエラーとその解決方法を紹介します。

1. Ktorクライアントのエラー

エラー: `Unresolved reference: HttpClient`


原因:依存関係が正しく設定されていない。
解決方法build.gradle.ktsに正しいKtor依存関係が追加されていることを確認してください。

implementation("io.ktor:ktor-client-core:2.3.0")
implementation("io.ktor:ktor-client-android:2.3.0")
implementation("io.ktor:ktor-client-ios:2.3.0")

エラー: `Network is unreachable`


原因:ネットワーク接続がない、またはAPIのURLが間違っている。
解決方法:インターネット接続を確認し、APIのエンドポイントURLが正しいことを確認してください。


2. SQLDelight関連のエラー

エラー: `No such table: [TableName]`


原因:データベースのスキーマが正しく作成されていない。
解決方法

  • SQLファイル(例: Todo.sq)にテーブル定義があることを確認。
  • データベースドライバが正しく設定されているか確認。
val driver = AndroidSqliteDriver(Database.Schema, context, "example.db")
val database = Database(driver)

エラー: `Type mismatch: inferred type is Int? but Int was expected`


原因:SQLクエリで型が一致していない。
解決方法:SQLDelightの型定義が正しいことを確認してください。

CREATE TABLE TodoItem (
    id INTEGER PRIMARY KEY,
    title TEXT,
    isCompleted INTEGER NOT NULL
);

3. 共通エラーと解決方法

エラー: `Unresolved reference: Database`


原因:SQLDelightのコード生成が行われていない。
解決方法

  • Gradleタスク./gradlew generateSqlDelightInterfaceを実行してコードを生成。
  • 正しいパッケージ名でインポートしているか確認。

エラー: `Compilation failed`


原因:依存関係のバージョンが競合している。
解決方法:依存関係のバージョンが互いに互換性があることを確認し、アップデートする。


デバッグのヒント

  • ログの確認:KtorのLogging機能を利用してネットワーク通信の詳細ログを出力します。
  • トランザクションの確認:SQLDelightでのデータ操作はトランザクション内で行うとエラーが減少します。
  • キャッシュのクリア:Gradleキャッシュをクリアしてビルドし直すことで問題が解決することがあります。
./gradlew clean

これらのトラブルシューティングを活用することで、KtorとSQLDelightを用いたKotlin Multiplatform開発の問題を効率的に解決できます。

まとめ

本記事では、Kotlin MultiplatformでKtorSQLDelightを活用する方法について解説しました。Ktorを使ったAPI通信と、SQLDelightを用いた型安全なデータベース管理を組み合わせることで、複数のプラットフォームで効率的にアプリを開発できます。導入方法から連携の実装、トラブルシューティングまで、実践的な手順を紹介しました。

Kotlin Multiplatformを活用することで、共通のビジネスロジックを再利用しつつ、プラットフォーム固有の要件にも対応可能です。KtorとSQLDelightを上手く組み合わせることで、コードの保守性や開発効率を大幅に向上させることができます。

コメント

コメントする

目次