I have Compose multiplatform project that implement datastore. I use multiplatform datastore as reference. I have problem when injecting the data store.
commonMain :
fun getDataStore(producePath: () -> String): DataStore<Preferences> =
synchronized(lock) {
if (::dataStore.isInitialized) {
dataStore
} else {
PreferenceDataStoreFactory.createWithPath(produceFile = { producePath().toPath() })
.also { dataStore = it }
}
}
internal const val dataStoreFileName = "app.preferences_pb"
androidMain :
fun getDataStore(context: Context): DataStore<Preferences> = getDataStore(
producePath = { context.filesDir.resolve(dataStoreFileName).absolutePath }
)
iOSMain :
@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
fun createDataStore(): DataStore<Preferences> = getDataStore(
producePath = {
val documentDirectory: NSURL? = NSFileManager.defaultManager.URLForDirectory(
directory = NSDocumentDirectory,
inDomain = NSUserDomainMask,
appropriateForURL = null,
create = false,
error = null,
)
requireNotNull(documentDirectory).path + "/$dataStoreFileName"
}
)
and I have this class that access dataStore
class GameskiiSettingRepository(
private val dataStore: DataStore<Preferences>
)
I don't know how to inject that dataStore and I keep getting this error
Caused by: org.koin.core.error.NoBeanDefFoundException: No definition
found for type 'androidx.datastore.core.DataStore'. Check your Modules
configuration and add missing type and/or qualifier!
I solved this issue by declaring an expect actual
koin module that instantiates the datastore. Your getDataStore
signature is a little different but this should work for you as well.
Declare a preferenceModule
in commonMain
:
// commonMain
expect val preferenceModule: Module
Define the actual
implementations for preferenceModule
in androidMain
and iosMain
:
// androidMain
actual val preferenceModule: Module = module {
single { createDataStore(androidContext()) }
}
// iosMain
actual val preferenceModule: Module = module {
// Here you don't need to pass null
single { createDataStore(null) }
}
Add this module to the Koin initializer for both Android
and iOS
:
// androidMain
actual class KoinInitializer(
private val context: Context,
) {
actual fun init() {
startKoin {
androidContext(context)
androidLogger()
modules(
appModule, viewModelModule, preferenceModule
)
}
}
}
// iosMain
actual class KoinInitializer {
actual fun init() {
startKoin {
modules(appModule, viewModelModule, preferenceModule)
}
}
}
Finally, provide the GameskiiSettingRepository
dependency like this:
single { GameskiiSettingRepository(get()) }
Now you can inject this Repo into Viewmodel.