
Lightweight, fault-tolerant append-journal key–value store with in-memory cache, sync reads, atomic append/batched writes, CRC-backed recovery, change listeners, multi-process sync and declarative migration.
軽量・耐障害・マルチプロセス対応の Kotlin Multiplatform key-value ストア。
Android では SharedPreferences のドロップイン置き換えにもなる。
インメモリキャッシュ + 追記ジャーナル方式。会計の daybook(仕訳帳)のように、すべての更新を一次記録として追記し、閾値を超えたら compaction(元帳への転記)で整理する。 エンジンは純 Kotlin・外部依存ゼロで、プラットフォームのネイティブストア(SharedPreferences / NSUserDefaults)に依存しない。 ラッパーではなく自前フォーマットのエンジンを全プラットフォームに持ち込むことで、永続化のセマンティクスがどこでも同一になる:
apply() がメインスレッドを同期ブロックする framework の問題(QueuedWork 起因の ANR)が構造的に存在しないMODE_MULTI_PROCESS の実際に動く代替設定・フラグより大きなデータ(リスト・ドキュメント構造)は Room / SQLDelight の領分。タスク寿命の作業中データには jotter を。
| ターゲット | 保証水準 |
|---|---|
| Android(minSdk 21+) | 全機能。実機回帰 + エミュレータ CI |
| JVM デスクトップ | 全機能 |
| iOS(iosArm64 / iosSimulatorArm64) | シングルプロセス利用(読み書き・永続化・リスナー・マイグレーション)。multiProcess は実装ありだが保証外。検証はシミュレータ CI |
JS / WasmJS は非対応(ファイルシステム前提のエンジンのため)。
同カテゴリ(key-value の設定ストア)の選択肢との比較。それぞれ得意分野が違うので、必要な軸で選ぶこと。
| SharedPreferences | DataStore | MMKV | daybook | |
|---|---|---|---|---|
| 同期読み出し | ○ | × | ○ | ○ |
| 書き込みが ANR 源にならない | × | ○ | ○ | ○ |
| クラッシュ・電源断からの復旧 | △ | ○ | △ | ○ |
| マルチプロセス | × | △ | ○ | ○ |
| 変更通知 | ○ | ○ | × | ○ |
| Flow | × | ○ | × | ○ |
| 型安全 API | × | ○ | × | ○ |
| KMP 共通コードから利用 | × | ○ | × | ○ |
| SharedPreferences からのドロップイン移行 | — | × | △ | ○ |
| 7 種を超える値型(任意の型の格納) | × | ○ | ○ | × |
| 公式サポート・大規模実績 | ○ | ○ | ○ | × |
| ネイティブコードなし | ○ | ○ | × | ○ |
apply() のライフサイクル境界での同期待ち(QueuedWork)がヘビーユースで ANR になる。破損には .bak 待避で概ね耐えるが、書き換え中の電源断でコミット済みの編集が失われうる。マルチプロセスは MODE_MULTI_PROCESS が deprecated(もともと信頼できない)KMP のデファクトである multiplatform-settings はネイティブストアの薄いラッパーで、各プラットフォームの癖(QueuedWork・NSUserDefaults の同期タイミング)とセマンティクス差をそのまま継承する — daybook が置き換えを狙うのはまさにここ。
既存の Settings 利用コードには daybook を ObservableSettings / FlowSettings 実装として渡せるため(daybook-multiplatform-settings)、対立ではなく差し替え可能なバックエンドの関係になる。
Maven Central から取得できる。
// KMP 共有モジュール
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.kr9ly:daybook-core:2.0.2")
implementation("io.github.kr9ly:daybook-coroutines:2.0.2") // Flow で受けたい場合のみ
implementation("io.github.kr9ly:daybook-multiplatform-settings:2.0.2") // Settings 実装として渡す場合のみ
}
commonTest.dependencies {
implementation("io.github.kr9ly:daybook-test:2.0.2")
}
}
}
// Android 単体アプリ(SharedPreferences 置き換え)
dependencies {
implementation("io.github.kr9ly:daybook:2.0.2")
}要件: Kotlin 2.0+ / Android は minSdk 21+
ストア宣言(スキーマ)を書き、開いて、型安全プロパティで読み書きする。
// commonMain: ストア名とキー一式を 1 箇所に固定する宣言
object Settings : DaybookSchema(name = "settings") {
val darkMode = boolean("dark_mode")
val userName = string("user_name")
}
// 開く(Android では context.openDaybook(Settings) が正規の入口)
val daybook = Daybook.open(directory, Settings)
// 型安全プロパティ
var darkMode by daybook.property(Settings.darkMode, default = false)
darkMode = true // アトミックに永続化
// 複数キーのアトミックな一括更新
daybook.edit {
putBoolean("dark_mode", false)
putString("user_name", "alice")
}
// 観測
daybook.addChangeListener { key, newValue -> /* ... */ }Flow で観測する場合(daybook-coroutines が必要):
daybook.property(Settings.darkMode, default = false).asFlow() // Flow<Boolean>Android で SharedPreferences をそのまま置き換える場合:
// Context.getSharedPreferences(name, MODE_PRIVATE) の置き換え。返り値は SharedPreferences そのもの
val prefs = context.getDaybookSharedPreferences("settings")続きはユースケース別ガイドへ。
Apache License 2.0 — 詳細は LICENSE を参照。
軽量・耐障害・マルチプロセス対応の Kotlin Multiplatform key-value ストア。
Android では SharedPreferences のドロップイン置き換えにもなる。
インメモリキャッシュ + 追記ジャーナル方式。会計の daybook(仕訳帳)のように、すべての更新を一次記録として追記し、閾値を超えたら compaction(元帳への転記)で整理する。 エンジンは純 Kotlin・外部依存ゼロで、プラットフォームのネイティブストア(SharedPreferences / NSUserDefaults)に依存しない。 ラッパーではなく自前フォーマットのエンジンを全プラットフォームに持ち込むことで、永続化のセマンティクスがどこでも同一になる:
apply() がメインスレッドを同期ブロックする framework の問題(QueuedWork 起因の ANR)が構造的に存在しないMODE_MULTI_PROCESS の実際に動く代替設定・フラグより大きなデータ(リスト・ドキュメント構造)は Room / SQLDelight の領分。タスク寿命の作業中データには jotter を。
| ターゲット | 保証水準 |
|---|---|
| Android(minSdk 21+) | 全機能。実機回帰 + エミュレータ CI |
| JVM デスクトップ | 全機能 |
| iOS(iosArm64 / iosSimulatorArm64) | シングルプロセス利用(読み書き・永続化・リスナー・マイグレーション)。multiProcess は実装ありだが保証外。検証はシミュレータ CI |
JS / WasmJS は非対応(ファイルシステム前提のエンジンのため)。
同カテゴリ(key-value の設定ストア)の選択肢との比較。それぞれ得意分野が違うので、必要な軸で選ぶこと。
| SharedPreferences | DataStore | MMKV | daybook | |
|---|---|---|---|---|
| 同期読み出し | ○ | × | ○ | ○ |
| 書き込みが ANR 源にならない | × | ○ | ○ | ○ |
| クラッシュ・電源断からの復旧 | △ | ○ | △ | ○ |
| マルチプロセス | × | △ | ○ | ○ |
| 変更通知 | ○ | ○ | × | ○ |
| Flow | × | ○ | × | ○ |
| 型安全 API | × | ○ | × | ○ |
| KMP 共通コードから利用 | × | ○ | × | ○ |
| SharedPreferences からのドロップイン移行 | — | × | △ | ○ |
| 7 種を超える値型(任意の型の格納) | × | ○ | ○ | × |
| 公式サポート・大規模実績 | ○ | ○ | ○ | × |
| ネイティブコードなし | ○ | ○ | × | ○ |
apply() のライフサイクル境界での同期待ち(QueuedWork)がヘビーユースで ANR になる。破損には .bak 待避で概ね耐えるが、書き換え中の電源断でコミット済みの編集が失われうる。マルチプロセスは MODE_MULTI_PROCESS が deprecated(もともと信頼できない)KMP のデファクトである multiplatform-settings はネイティブストアの薄いラッパーで、各プラットフォームの癖(QueuedWork・NSUserDefaults の同期タイミング)とセマンティクス差をそのまま継承する — daybook が置き換えを狙うのはまさにここ。
既存の Settings 利用コードには daybook を ObservableSettings / FlowSettings 実装として渡せるため(daybook-multiplatform-settings)、対立ではなく差し替え可能なバックエンドの関係になる。
Maven Central から取得できる。
// KMP 共有モジュール
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.kr9ly:daybook-core:2.0.2")
implementation("io.github.kr9ly:daybook-coroutines:2.0.2") // Flow で受けたい場合のみ
implementation("io.github.kr9ly:daybook-multiplatform-settings:2.0.2") // Settings 実装として渡す場合のみ
}
commonTest.dependencies {
implementation("io.github.kr9ly:daybook-test:2.0.2")
}
}
}
// Android 単体アプリ(SharedPreferences 置き換え)
dependencies {
implementation("io.github.kr9ly:daybook:2.0.2")
}要件: Kotlin 2.0+ / Android は minSdk 21+
ストア宣言(スキーマ)を書き、開いて、型安全プロパティで読み書きする。
// commonMain: ストア名とキー一式を 1 箇所に固定する宣言
object Settings : DaybookSchema(name = "settings") {
val darkMode = boolean("dark_mode")
val userName = string("user_name")
}
// 開く(Android では context.openDaybook(Settings) が正規の入口)
val daybook = Daybook.open(directory, Settings)
// 型安全プロパティ
var darkMode by daybook.property(Settings.darkMode, default = false)
darkMode = true // アトミックに永続化
// 複数キーのアトミックな一括更新
daybook.edit {
putBoolean("dark_mode", false)
putString("user_name", "alice")
}
// 観測
daybook.addChangeListener { key, newValue -> /* ... */ }Flow で観測する場合(daybook-coroutines が必要):
daybook.property(Settings.darkMode, default = false).asFlow() // Flow<Boolean>Android で SharedPreferences をそのまま置き換える場合:
// Context.getSharedPreferences(name, MODE_PRIVATE) の置き換え。返り値は SharedPreferences そのもの
val prefs = context.getDaybookSharedPreferences("settings")続きはユースケース別ガイドへ。
Apache License 2.0 — 詳細は LICENSE を参照。