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, tempat Anda membuat perubahan 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.kt
yang berada diandroidApp/src/main/kotlin/com/example/fruitties/kmptutorial/android/di/DatabaseModule.kt
- Perbarui metode
providesAppDatabase
seperti 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-runtime
dansqlite-bundled
ke 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
dependencies
level 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:
Ke:
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 sumbercommonMain
seperti 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.kt
androidApp/.../database/CartDao.kt
androidApp/.../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
RoomDatabaseConstructor
berikut:
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
AppDatabase
dengan@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.kt
dari menu.Tindakan ini akan memindahkan konten ke fungsi
appDatabase
global. Tekan Enter untuk mengonfirmasi nama fungsi. - Buat fungsi menjadi publik dengan menghapus pengubah visibilitas
private
. - Pindahkan fungsi ke modul
:shared
dengan 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
.di
menjadi.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.kts
di 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
:shared
dalam set sumberiosMain
bernamaAppDatabase.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)
@Serializable
@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/Repository
dengan mengklik kanan nama direktori dan memilih New File from Template... - Beri nama
Fruittie
dan 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.
Memperbarui DefaultCartRepository
Mari kita mulai dengan class DefaultCartRepository
karena lebih sederhana dari keduanya.
Buka file CartRepository.swift
di direktori Sources/Repository
.
- Pertama, ganti impor
CoreData
dengansharedKit
:
import sharedKit
- Kemudian, hapus properti
NSManagedObjectContext
dan ganti dengan propertiCartDao
:
// Remove
private let managedObjectContext: NSManagedObjectContext
// Replace with
private let cartDao: any CartDao
- Perbarui konstruktor
init
untuk melakukan inisialisasi properticartDao
baru:
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()
diCartDao
dan memetakan entityCartItemWithFruittie
ke wrapperCartItem
.
func getCartItems() -> AsyncStream<[CartItem]> {
return cartDao.getAll().map { entities in
entities.map(CartItem.init(entity:))
}.eraseToStream()
}
Memperbarui 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
CartView
di 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.swift
diSources/Database
. - Tambahkan impor
sharedKit
. - Hapus impor
CoreData
. - Buat instance database Room di class
DataController
. - Terakhir, hapus panggilan metode
loadPersistentStores
dari 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.swift
di folderSources/DI
. - Tambahkan impor
sharedKit
. - Hapus properti
managedObjectContext
dari classAppContainer
. - Ubah inisialisasi
DefaultFruittieRepository
danDefaultCartRepository
dengan meneruskan DAO Room dari instanceAppDatabase
yang 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.