1. Sebelum memulai
Prasyarat
- Pemahaman dasar tentang Kotlin Multiplatform.
- Pengalaman dengan Kotlin.
- Pemahaman dasar tentang sintaksis Swift.
- Xcode dan simulator iOS telah diinstal.
Yang Anda perlukan
- Versi stabil terbaru Android Studio.
- Komputer Mac dengan sistem macOS.
- Xcode 16.1 dan simulator iPhone dengan iOS 16.0 atau yang lebih baru.
Yang Anda pelajari
- Cara membagikan Database Room antara aplikasi Android dan aplikasi iOS.
2. Memulai persiapan
Untuk memulai, ikuti langkah-langkah ini:
- Clone repositori GitHub dengan perintah terminal berikut:
$ git clone https://github.com/android/codelab-android-kmp.git
Atau, Anda dapat mendownload repositori sebagai file zip:
- Di Android Studio, buka project
migrate-room, yang berisi cabang berikut:
main: Berisi kode awal untuk project ini, yang dapat Anda ubah untuk menyelesaikan codelab.end: Berisi kode solusi untuk codelab ini.
Sebaiknya Anda memulai dengan cabang main dan mengikuti codelab langkah demi langkah sesuai kemampuan Anda.
- Jika Anda ingin melihat kode solusi, jalankan perintah ini:
$ git clone -b end https://github.com/android/codelab-android-kmp.git
Selain itu, Anda dapat mendownload kode solusi:
3. Memahami aplikasi contoh
Tutorial ini terdiri dari aplikasi contoh Fruitties yang dibangun dalam framework native (Jetpack Compose di Android, SwiftUi di iOS).
Aplikasi Fruitties menawarkan dua fitur utama:
- Daftar item Buah, masing-masing dengan tombol untuk menambahkan item ke Keranjang.
- Keranjang ditampilkan di bagian atas, yang menunjukkan jumlah buah yang telah ditambahkan dan jumlahnya.

Arsitektur aplikasi Android
Aplikasi Android mengikuti panduan arsitektur Android resmi untuk mempertahankan struktur yang jelas dan modular.

Arsitektur aplikasi iOS

Modul Bersama KMP
Project ini telah disiapkan dengan modul bersama untuk KMP, meskipun saat ini kosong. Jika project Anda belum disiapkan dengan modul bersama, mulailah dengan codelab Mulai Menggunakan Kotlin Multiplatform.
4. Menyiapkan database Room untuk integrasi KMP
Sebelum memindahkan kode database Room dari aplikasi Android Fruitties ke modul shared, Anda harus memastikan bahwa aplikasi tersebut kompatibel dengan Kotlin Multiplatform (KMP) Room API. Bagian ini akan memandu Anda menjalani proses tersebut.
Salah satu pembaruan penting adalah menggunakan driver SQLite yang kompatibel dengan Android dan iOS. Untuk mendukung fungsi database Room di beberapa platform, Anda dapat menggunakan BundledSQLiteDriver. Driver ini menggabungkan SQLite langsung ke dalam aplikasi, sehingga cocok untuk penggunaan multiplatform di Kotlin. Untuk mendapatkan panduan mendetail, lihat panduan migrasi Room KMP.
Memperbarui dependensi
Pertama, tambahkan dependensi room-runtime dan sqlite-bundled ke file libs.versions.toml:
# Add libraries
[libraries]
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "androidx-room" }
androidx-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.ref = "androidx-sqlite" }
Selanjutnya, perbarui build.gradle.kts modul :androidApp untuk menggunakan dependensi ini, dan hapus penggunaan libs.androidx.room.ktx:
// Add
implementation(libs.androidx.room.runtime)
implementation(libs.androidx.sqlite.bundled)
// Remove
implementation(libs.androidx.room.ktx)
Sekarang, sinkronkan project di Android Studio.
Mengubah modul database untuk BundledSQLiteDriver
Selanjutnya, ubah logika pembuatan database di aplikasi Android untuk menggunakan BundledSQLiteDriver, sehingga kompatibel dengan KMP sekaligus mempertahankan fungsi di Android.
- Buka file
DatabaseModule.ktyang berada diandroidApp/src/main/kotlin/com/example/fruitties/kmptutorial/android/di/DatabaseModule.kt - Perbarui metode
providesAppDatabaseseperti dalam cuplikan berikut:
import androidx.sqlite.driver.bundled.BundledSQLiteDriver
@Module
@InstallIn(SingletonComponent::class)
internal object DatabaseModule {
...
@Provides
@Singleton
fun providesAppDatabase(@ApplicationContext context: Context): AppDatabase {
val dbFile = context.getDatabasePath("sharedfruits.db")
return Room.databaseBuilder<AppDatabase>(context, dbFile.absolutePath)
.setDriver(BundledSQLiteDriver())
.build()
}
Membangun dan menjalankan aplikasi Android
Setelah Anda mengalihkan driver SQLite Native ke driver yang digabungkan, verifikasi build aplikasi dan pastikan semuanya berfungsi dengan benar sebelum Anda memigrasikan database ke modul :shared.
5. Memindahkan kode database ke modul :shared
Pada langkah ini, kita akan mentransfer penyiapan database Room dari aplikasi Android ke modul :shared, sehingga database dapat diakses oleh Android dan iOS.
Memperbarui konfigurasi build.gradle.kts dari modul :shared
Mulai dengan memperbarui build.gradle.kts modul :shared untuk menggunakan dependensi multiplatform Room.
- Tambahkan plugin KSP dan Room:
plugins {
...
// TODO add KSP + ROOM plugins
alias(libs.plugins.ksp)
alias(libs.plugins.room)
}
- Tambahkan dependensi
room-runtimedansqlite-bundledke blokcommonMain:
sourceSets {
commonMain {
// TODO Add KMP dependencies here
implementation(libs.androidx.room.runtime)
implementation(libs.androidx.sqlite.bundled)
}
}
- Tambahkan konfigurasi KSP untuk setiap target platform dengan menambahkan blok
dependencieslevel teratas baru. Untuk memudahkan, Anda cukup menambahkannya ke bagian bawah file:
// Should be its own top level block. For convenience, add at the bottom of the file
dependencies {
add("kspAndroid", libs.androidx.room.compiler)
add("kspIosSimulatorArm64", libs.androidx.room.compiler)
add("kspIosX64", libs.androidx.room.compiler)
add("kspIosArm64", libs.androidx.room.compiler)
}
- Di tingkat teratas, tambahkan juga blok baru untuk menetapkan lokasi skema
Room:
// Should be its own top level block. For convenience, add at the bottom of the file
room {
schemaDirectory("$projectDir/schemas")
}
- Lakukan sinkronisasi Gradle pada project
Memindahkan skema Room ke modul :shared
Pindahkan direktori androidApp/schemas ke folder root modul :shared di samping folder src/:
Dari: 
Kepada: 
Memindahkan DAO dan entity
Setelah menambahkan dependensi Gradle yang diperlukan ke modul bersama KMP, Anda perlu memindahkan DAO dan entity dari modul :androidApp ke modul :shared.
Tindakan ini akan melibatkan pemindahan file ke lokasi masing-masing di set sumber commonMain dalam modul :shared.
Memindahkan model Fruittie
Anda dapat memanfaatkan fungsi Refactor → Move untuk beralih modul tanpa merusak impor:
- Temukan file
androidApp/src/main/kotlin/.../model/Fruittie.kt, klik kanan file, lalu pilih Refactor → Move (atau tekan tombol F6):
- Pada dialog Move, pilih ikon
...di samping kolom Destination directory.
- Pilih set sumber commonMain di dialog Choose Destination Directory, lalu klik OK. Anda mungkin harus menonaktifkan kotak centang Show only existing source roots.

- Klik tombol Refactor untuk memindahkan file.
Memindahkan model CartItem dan CartItemWithFruittie
Untuk file androidApp/.../model/CartItem.kt, Anda perlu mengikuti langkah-langkah berikut:
- Buka file, klik kanan class
CartItem, lalu pilih Refactor > Move. - Tindakan ini akan membuka dialog Move yang sama, tetapi dalam hal ini Anda juga mencentang kotak untuk anggota
CartItemWithFruittie.
Lanjutkan dengan memilih ikon ...dan memilih set sumbercommonMainseperti yang Anda lakukan untuk fileFruittie.kt.
Memindahkan DAO dan AppDatabase
Lakukan langkah yang sama untuk file berikut (Anda dapat memilih ketiga file secara bersamaan):
androidApp/.../database/FruittieDao.ktandroidApp/.../database/CartDao.ktandroidApp/.../database/AppDatabase.kt
Memperbarui AppDatabase bersama agar berfungsi di berbagai platform
Setelah memindahkan class database ke modul :shared, Anda perlu menyesuaikannya untuk menghasilkan implementasi yang diperlukan di kedua platform.
- Buka file
/shared/src/commonMain/kotlin/com/example/fruitties/kmptutorial/android/database/AppDatabase.kt. - Tambahkan penerapan
RoomDatabaseConstructorberikut:
import androidx.room.RoomDatabaseConstructor
// The Room compiler generates the `actual` implementations.
@Suppress("NO_ACTUAL_FOR_EXPECT")
expect object AppDatabaseConstructor : RoomDatabaseConstructor<AppDatabase> {
override fun initialize(): AppDatabase
}
- Anotasikan class
AppDatabasedengan@ConstructedBy(AppDatabaseConstructor::class):
import androidx.room.ConstructedBy
@Database(
entities = [Fruittie::class, CartItem::class],
version = 1,
)
// TODO Add this line
@ConstructedBy(AppDatabaseConstructor::class)
abstract class AppDatabase : RoomDatabase() {
...

Memindahkan pembuatan database ke modul :shared
Selanjutnya, Anda akan memindahkan penyiapan Room khusus Android dari modul :androidApp ke modul :shared. Tindakan ini diperlukan karena pada langkah berikutnya, Anda akan menghapus dependensi Room dari modul :androidApp.
- Cari file
androidApp/.../di/DatabaseModule.kt. - Pilih konten fungsi
providesAppDatabase, klik kanan, lalu pilih Refactor > Extract Function to Scope:
- Pilih
DatabaseModule.ktdari menu.
Tindakan ini akan memindahkan konten ke fungsi appDatabaseglobal. Tekan Enter untuk mengonfirmasi nama fungsi.
- Buat fungsi menjadi publik dengan menghapus pengubah visibilitas
private. - Pindahkan fungsi ke modul
:shareddengan mengklik kanan Refactor > Move. - Pada dialog Move, pilih ikon ... di samping kolom Destination directory.

- Pada dialog Choose Destination Directory, pilih set sumber shared >androidMain dan pilih folder /shared/src/androidMain/, lalu klik OK.

- Ubah akhiran di kolom To package dari
.dimenjadi.database
- Klik Refactor.
Membersihkan kode yang tidak diperlukan dari :androidApp
Pada tahap ini, Anda telah memindahkan database Room ke modul multiplatform dan tidak ada dependensi Room yang diperlukan dalam modul :androidApp, sehingga Anda dapat menghapusnya.
- Buka file
build.gradle.ktsdi modul:androidApp. - Hapus dependensi dan konfigurasi seperti dalam cuplikan berikut:
plugins {
// TODO Remove
alias(libs.plugins.room)
}
android {
// TODO Remove
ksp {
arg("room.generateKotlin", "true")
}
dependencies {
// TODO Keep room-runtime
implementation(libs.androidx.room.runtime)
// TODO Remove
implementation(libs.androidx.sqlite.bundled)
ksp(libs.androidx.room.compiler)
}
// TODO Remove
room {
schemaDirectory("$projectDir/schemas")
}
- Lakukan sinkronisasi Gradle pada project.
Membangun dan menjalankan aplikasi Android
Jalankan aplikasi Android Fruitties untuk memastikan aplikasi berjalan dengan baik dan sekarang menggunakan database dari modul :shared. Jika sebelumnya Anda telah menambahkan item keranjang, Anda juga akan melihat item yang sama pada tahap ini meskipun database Room kini berada di modul :shared.
6. Menyiapkan Room untuk digunakan di iOS
Guna menyiapkan database Room untuk platform iOS, Anda perlu menyiapkan beberapa kode pendukung di modul :shared untuk digunakan di langkah berikutnya.
Mengaktifkan pembuatan database untuk aplikasi iOS
Hal pertama yang harus dilakukan adalah menambahkan builder database khusus iOS.
- Tambahkan file baru di modul
:shareddalam set sumberiosMainbernamaAppDatabase.ios.kt:
- Tambahkan fungsi bantuan berikut. Fungsi ini akan digunakan oleh aplikasi iOS untuk mendapatkan instance database Room.
package com.example.fruitties.kmptutorial.shared
import androidx.room.Room
import androidx.sqlite.driver.bundled.BundledSQLiteDriver
import com.example.fruitties.kmptutorial.android.database.AppDatabase
import kotlinx.cinterop.BetaInteropApi
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.ObjCObjectVar
import kotlinx.cinterop.alloc
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.ptr
import kotlinx.cinterop.value
import platform.Foundation.NSDocumentDirectory
import platform.Foundation.NSError
import platform.Foundation.NSFileManager
import platform.Foundation.NSUserDomainMask
fun getPersistentDatabase(): AppDatabase {
val dbFilePath = documentDirectory() + "/" + "fruits.db"
return Room.databaseBuilder<AppDatabase>(name = dbFilePath)
.setDriver(BundledSQLiteDriver())
.build()
}
@OptIn(ExperimentalForeignApi::class, BetaInteropApi::class)
private fun documentDirectory(): String {
memScoped {
val errorPtr = alloc<ObjCObjectVar<NSError?>>()
val documentDirectory = NSFileManager.defaultManager.URLForDirectory(
directory = NSDocumentDirectory,
inDomain = NSUserDomainMask,
appropriateForURL = null,
create = false,
error = errorPtr.ptr,
)
if (documentDirectory != null) {
return requireNotNull(documentDirectory.path) {
"""Couldn't determine the document directory.
URL $documentDirectory does not conform to RFC 1808.
""".trimIndent()
}
} else {
val error = errorPtr.value
val localizedDescription = error?.localizedDescription ?: "Unknown error occurred"
error("Couldn't determine document directory. Error: $localizedDescription")
}
}
}
Menambahkan akhiran "Entity" ke entity Room
Karena Anda menambahkan wrapper untuk entity Room di Swift, sebaiknya gunakan nama entity Room yang berbeda dengan nama wrapper. Pastikan hal tersebut dengan menambahkan akhiran Entity ke entity Room menggunakan anotasi @ObjCName.
Buka file Fruittie.kt di modul :shared dan tambahkan anotasi @ObjCName ke entity Fruittie. Karena anotasi ini bersifat eksperimental, Anda mungkin perlu menambahkan anotasi @OptIn(ExperimentalObjC::class) ke file.
Fruittie.kt
import kotlin.experimental.ExperimentalObjCName
import kotlin.native.ObjCName
@OptIn(ExperimentalObjCName::class)
@Entity(indices = [Index(value = ["id"], unique = true)])
@ObjCName("FruittieEntity")
data class Fruittie(
...
)
Kemudian, lakukan hal yang sama untuk entity CartItem dalam file CartItem.kt.
CartItem.kt
import kotlin.experimental.ExperimentalObjCName
import kotlin.native.ObjCName
@OptIn(ExperimentalObjCName::class)
@ObjCName("CartItemEntity")
@Entity(
foreignKeys = [
ForeignKey(
entity = Fruittie::class,
parentColumns = ["id"],
childColumns = ["id"],
onDelete = ForeignKey.CASCADE,
),
],
)
data class CartItem(@PrimaryKey val id: Long, val count: Int = 1)
7. Menggunakan Room di aplikasi iOS
Aplikasi iOS adalah aplikasi yang sudah ada yang menggunakan Core Data. Dalam codelab ini, Anda tidak perlu khawatir tentang memigrasikan data yang ada di database karena aplikasi ini hanyalah prototipe. Jika memigrasikan aplikasi produksi ke KMP, Anda harus menulis fungsi untuk membaca database Core Data saat ini dan menyisipkan item tersebut ke database Room saat peluncuran pertama setelah migrasi.
Membuka project Xcode
Buka project iOS di Xcode dengan membuka folder /iosApp/ dan membuka Fruitties.xcodeproj di aplikasi terkait.

Menghapus class entity Core Data
Pertama, Anda harus menghapus class entity Core Data untuk memberi ruang bagi wrapper entity yang akan Anda buat nanti. Bergantung pada jenis data yang disimpan aplikasi Anda di Core Data, Anda dapat menghapus entity Core Data sepenuhnya, atau menyimpannya untuk tujuan migrasi data. Untuk tutorial ini, Anda dapat menghapusnya, karena Anda tidak perlu memigrasikan data yang ada.
Di Xcode:
- Buka Project Navigator.
- Buka folder Resources.
- Buka file
Fruitties. - Klik dan hapus setiap entity.

Agar perubahan ini tersedia dalam kode, bersihkan dan buat ulang project.
Tindakan ini akan menggagalkan build dengan error berikut, yang diharapkan terjadi.

Membuat wrapper entity
Selanjutnya, kita akan membuat wrapper entity untuk entity Fruittie dan CartItem guna menangani perbedaan API antara entity Room dan Core Data dengan lancar.
Wrapper ini akan membantu proses transisi dari Core Data ke Room dengan meminimalkan jumlah kode yang harus segera diperbarui. Anda harus berupaya mengganti wrapper ini dengan akses langsung ke entity Room pada masa mendatang.
Untuk saat ini, kita akan membuat wrapper untuk class FruittieEntity, yang akan memberikan properti opsional.
Membuat wrapper FruittieEntity
- Buat file Swift baru di direktori
Sources/Repositorydengan mengklik kanan nama direktori dan memilih New File from Template...

- Beri nama
Fruittiedan pastikan hanya target Fruitties yang dipilih, bukan target pengujian.
- Tambahkan kode berikut ke file Fruittie baru:
import sharedKit
struct Fruittie: Hashable {
let entity: FruittieEntity
var id: Int64 {
entity.id
}
var name: String? {
entity.name
}
var fullName: String? {
entity.fullName
}
}
Struct Fruittie menggabungkan class FruittieEntity, sehingga properti menjadi opsional dan meneruskan properti entity. Selain itu, kita akan membuat struct Fruittie sesuai dengan protokol Hashable, sehingga dapat digunakan di tampilan ForEach SwiftUI.
Membuat wrapper CartItemEntity
Selanjutnya, buat wrapper serupa untuk class CartItemEntity.
Buat file Swift baru bernama CartItem.swift di direktori Sources/Repository.
import sharedKit
struct CartItem: Hashable {
let entity: CartItemWithFruittie
let fruittie: Fruittie?
var id: Int64 {
entity.cartItem.id
}
var count: Int64 {
Int64(entity.cartItem.count)
}
init(entity: CartItemWithFruittie) {
self.entity = entity
self.fruittie = Fruittie(entity: entity.fruittie)
}
}
Karena class CartItem Core Data asli memiliki properti Fruittie, kami juga telah menyertakan properti Fruittie dalam struct CartItem. Meskipun class CartItem tidak memiliki properti yang bersifat opsional, properti count memiliki jenis yang berbeda di entity Room.
Memperbarui repositori
Setelah wrapper entity diterapkan, Anda perlu memperbarui DefaultCartRepository dan DefaultFruittieRepository untuk menggunakan Room, bukan Core Data.
Update DefaultCartRepository
Mari kita mulai dengan class DefaultCartRepository karena lebih sederhana dari keduanya.
Buka file CartRepository.swift di direktori Sources/Repository.
- Pertama, ganti impor
CoreDatadengansharedKit:
import sharedKit
- Kemudian, hapus properti
NSManagedObjectContextdan ganti dengan propertiCartDao:
// Remove
private let managedObjectContext: NSManagedObjectContext
// Replace with
private let cartDao: any CartDao
- Perbarui konstruktor
inituntuk melakukan inisialisasi properticartDaobaru:
init(cartDao: any CartDao) {
self.cartDao = cartDao
}
- Selanjutnya, perbarui metode
addToCart. Metode ini diperlukan untuk mengambil item keranjang yang ada dari Core Data, tetapi implementasi Room kita tidak memerlukannya. Sebagai gantinya, item baru akan disisipkan atau jumlah item keranjang yang ada akan bertambah.
func addToCart(fruittie: Fruittie) async throws {
try await cartDao.insertOrIncreaseCount(fruittie: fruittie.entity)
}
- Terakhir, perbarui metode
getCartItems(). Metode ini akan memanggil metodegetAll()diCartDaodan memetakan entityCartItemWithFruittieke wrapperCartItem.
func getCartItems() -> AsyncStream<[CartItem]> {
return cartDao.getAll().map { entities in
entities.map(CartItem.init(entity:))
}.eraseToStream()
}
Update DefaultFruittieRepository
Untuk memigrasikan class DefaultFruittieRepository, terapkan perubahan serupa seperti yang dilakukan untuk DefaultCartRepository.
Perbarui file FruittieRepository dengan perubahan berikut:
import ConcurrencyExtras
import sharedKit
protocol FruittieRepository {
func getData() -> AsyncStream<[Fruittie]>
}
class DefaultFruittieRepository: FruittieRepository {
private let fruittieDao: any FruittieDao
private let api: FruittieApi
init(fruittieDao: any FruittieDao, api: FruittieApi) {
self.fruittieDao = fruittieDao
self.api = api
}
func getData() -> AsyncStream<[Fruittie]> {
let dao = fruittieDao
Task {
let isEmpty = try await dao.count() == 0
if isEmpty {
let response = try await api.getData(pageNumber: 0)
let fruitties = response.feed.map {
FruittieEntity(
id: 0,
name: $0.name,
fullName: $0.fullName,
calories: ""
)
}
_ = try await dao.insert(fruitties: fruitties)
}
}
return dao.getAll().map { entities in
entities.map(Fruittie.init(entity:))
}.eraseToStream()
}
}
Mengganti wrapper properti @FetchRequest
Kita juga perlu mengganti wrapper properti @FetchRequest di tampilan SwiftUI. Wrapper properti @FetchRequest digunakan untuk mengambil data dari Core Data dan mengamati perubahan, sehingga kita tidak dapat menggunakannya dengan entity Room. Sebagai gantinya, gunakan UIModel untuk mengakses data dari repositori.
- Buka
CartViewdi fileSources/UI/CartView.swift. - Ganti implementasi dengan yang berikut:
import SwiftUI
struct CartView : View {
@State
private var expanded = false
@ObservedObject
private(set) var uiModel: ContentViewModel
var body: some View {
if (uiModel.cartItems.isEmpty) {
Text("Cart is empty, add some items").padding()
} else {
HStack {
Text("Cart has \(uiModel.cartItems.count) items (\(uiModel.cartItems.reduce(0) { $0 + $1.count }))")
.padding()
Spacer()
Button {
expanded.toggle()
} label: {
if (expanded) {
Text("collapse")
} else {
Text("expand")
}
}
.padding()
}
if (expanded) {
VStack {
ForEach(uiModel.cartItems, id: \.self) { item in
Text("\(item.fruittie!.name!): \(item.count)")
}
}
}
}
}
}
Memperbarui ContentView
Perbarui ContentView dalam file Sources/View/ContentView.swift untuk meneruskan FruittieUIModel ke CartView.
CartView(uiModel: uiModel)
Memperbarui DataController
Class DataController di aplikasi iOS bertanggung jawab untuk menyiapkan stack Core Data. Karena kita beralih dari Core Data, kita perlu memperbarui DataController untuk melakukan inisialisasi pada database Room.
- Buka file
DataController.swiftdiSources/Database. - Tambahkan impor
sharedKit. - Hapus impor
CoreData. - Buat instance database Room di class
DataController. - Terakhir, hapus panggilan metode
loadPersistentStoresdari penginisialisasiDataController.
Class akhir akan terlihat seperti ini:
import Combine
import sharedKit
class DataController: ObservableObject {
let database = getPersistentDatabase()
init() {}
}
Memperbarui injeksi dependensi
Class AppContainer di aplikasi iOS bertanggung jawab untuk melakukan inisialisasi pada grafik dependensi. Karena kita memperbarui repositori untuk menggunakan Room, bukan Core Data, kita perlu memperbarui AppContainer untuk meneruskan DAO Room ke repositori.
- Buka
AppContainer.swiftdi folderSources/DI. - Tambahkan impor
sharedKit. - Hapus properti
managedObjectContextdari classAppContainer. - Ubah inisialisasi
DefaultFruittieRepositorydanDefaultCartRepositorydengan meneruskan DAO Room dari instanceAppDatabaseyang disediakan olehDataController.
Setelah selesai, class akan terlihat seperti ini:
import Combine
import Foundation
import sharedKit
class AppContainer: ObservableObject {
let dataController: DataController
let api: FruittieApi
let fruittieRepository: FruittieRepository
let cartRepository: CartRepository
init() {
dataController = DataController()
api = FruittieNetworkApi(
apiUrl: URL(
string:
"https://android.github.io/kotlin-multiplatform-samples/fruitties-api"
)!)
fruittieRepository = DefaultFruittieRepository(
fruittieDao: dataController.database.fruittieDao(),
api: api
)
cartRepository = DefaultCartRepository(
cartDao: dataController.database.cartDao()
)
}
}
Terakhir, perbarui FruittiesApp di main.swift untuk menghapus managedObjectContext:
struct FruittiesApp: App {
@StateObject
private var appContainer = AppContainer()
var body: some Scene {
WindowGroup {
ContentView(appContainer: appContainer)
}
}
}
Membangun dan menjalankan aplikasi iOS
Terakhir, setelah Anda membangun dan menjalankan aplikasi dengan menekan ⌘R, aplikasi akan dimulai dengan database yang dimigrasikan dari Core Data ke Room.

8. Selamat
Selamat! Anda telah berhasil memigrasikan aplikasi Android dan iOS mandiri ke lapisan data bersama menggunakan Room KMP.
Sebagai referensi, berikut adalah perbandingan arsitektur aplikasi untuk melihat hasil yang dicapai:
Sebelum
Android | iOS |
|
|
Arsitektur Pasca Migrasi

Pelajari lebih lanjut
- Pelajari library Jetpack lain yang mendukung KMP.
- Baca dokumentasi Room KMP.
- Baca dokumentasi SQLite KMP.
- Lihat dokumentasi Kotlin Multiplatform resmi.