Read local file from project directory | Kotlin Multiplatform Mobile | KMM - android

I am trying to read JSON file which is saved in my project locally and want to fetch and read using Kotlin Multiplatform Mobile, so I can share with Android and iOS
Following approch I'm doing:
In commonMain :
package com.example.readJSON.shared
import kotlinx.serialization.Serializable
#Serializable
data class DataRequest(
val dataRegimenRequest: List<DataRegimenRequest>?
)
expect class FileResource(location: String){
val json: String?
}
In androidMain :
package com.example.readJSON.shared
actual class FileResource actual constructor(location: String) {
actual val json: String? = this::class.java.classLoader!!.getResource(location)?.readText()
}
In iosMain :
package com.example.readJSON.shared
actual class FileResource actual constructor(location: String) {
actual val json: String? = null //TODO: write a code to read from local file
}
Can someone will help me, how can I fetch my local JSON file for iOS?
For Android, I am able to read local JSON file.

You'll probably need to write some gradle to copy the file to your iOS app source, then load it by reading iOS resource files from the Bundle. It's a little hard to follow, but we push in a Swift function to handle that here. You could write that code in iOS Kotlin as well.
You might be able to add the file to Xcode directly without needing to copy it in Gradle. From Xcode, right-click your source folder and select "Add Files to ___", then point it at the file. If all of your source is in a single repo, you should be able to point at that file with a relative path from Xcode, and load it at runtime.
For Android, you'd probably want to put that file in assets rather than load it with the class loader, but that's a different discussion.

Related

Rename Realm DB file name in Android

I have a Realm DB file, with name "abc.realm". How to change this name to something else? Should I just replace the file name using IO operations or can I do it with migrations? Not able to find any satisfactory answer neither on the web nor on StackOverflow.
Realm stores 2 files, the realm itself and a .lock file. So if you call your realm "abc.realm", then next to this file there is also "abc.realm.lock".
The way to go about renaming your realm file is,
Make sure you find the location of both files
Rename both files with the same name but keeping the ".lock" extension on the lock file
Modify the path to the realm that you pass to the RealmConfigurationBase inheritor
Clearly before doing any of this, make sure to backup your database, just in case.
I don't know what programming language you're writing your android application in, so I'll go with a skeleton in pseudocode
private void BackupRealmFile(string realmLocation, string saveLocation)
{
// make a copy of the file and store it somewhere
}
void YourMainMethod()
{
BackupRealmFile("some/path", "your/backup/path");
IOLib.RenameFile("some/path/abc.realm", "some/path/newName.realm");
IOLib.RenameFile("some/path/abc.realm.lock", "some/path/newName.realm.lock");
var config = new RealmConfiguration("some/path/newName.realm");
// maybe some more settings on your conf
var realm = Realm.GetInstance(config);
}
I hope this helps.

typealias from a lib : Unresolved Reference

I got an Unresolved Reference for a typeAlias I use from my library.
Everything works fine in local, but when using the imported released library I got this error.
Anyone had this issue already please ?
Here is my code :
sealed class CountingRequestResult<ResultT> {
data class Progress<ResultT>(
val progressFraction: Double
) : CountingRequestResult<ResultT>()
data class Completed<ResultT>(
val result: ResultT
) : CountingRequestResult<ResultT>()
}
typealias AttachmentUploadRemoteResult = CountingRequestResult<UploadUserDocumentResponse>
Kotlin, like other programming languages, lets you define a type alias for other existing types. For instance, we can use them to attach more context to an otherwise general type, like naming type String as UserName or Password:
typealias UserName = String
typealias Password = String
fun checkUserName(userName: UserName) {
// some code here
}
fun checkPassword(password: Password) {
// some code here
}
Type aliases are merely artifacts of the source code. Therefore, they’re not introducing any new types at runtime. For instance, every place where we’re using a UserName instance, the Kotlin compiler translates it to a String:
$ kotlinc TypeAlias.kt
$ javap -c -p com.example.alias.TypeAliasKt
Compiled from "TypeAlias.kt"
public final class com.example.alias.TypeAliasKt {
public static final void checkUserName(java.lang.String);
// truncated
}
Therefore, in local everything works as expected, but building a library results in losing the aliasing, hence: Unresolved Reference.
In your project using the lib, you can define the same alias name. However I will say that it is not such a good idea. Making a change in the lib's alias will not be changed in the project's alias and also you won't be warned in cases such parsing from or to Json.
A better approach will be using a data class. For instance:
data class UserName(val userName: String)
And that class will be defined in both lib and project.

java.lang.FileNotFoundException in Android/Kotlin even though file is present

I have a data class called Contact which has a companion object property 'allContacts: List' which returns contacts after parsing them from a JSON file.
Relevant code:
val allContacts: List<Contact>
get() {
val json = JSONObject(File("app/src/main/res/data/contacts.json").readText()).getJSONArray("contacts")
val contacts = mutableListOf<Contact>()
...
I do indeed have a contacts.json in res/data package. (data package created manually).
Here's the proof:
Why is this happening? Is the contacts.json file not included in the final .apk?
I have tried logging the current path of the app using
Log.i('.MainActivity', System.getProperty('user.dir'))
But always get . in Logcat.
EDIT: I decompiled the apk in Android Studio and found no traces of contacts.json
Your file doesn't exist in the same project directory you expect it to.
You have to create a resource directory raw and paste your file in there.
Then, you can reference your file as R.raw.contacts wherever you need to reference the file.
Reading the file is another story.
I found it best to create a separate top-level extension function for reading and returning the file contents
fun Activity.readFile(fileID: Int): String {
val inputStream = this.resources.openRawResources(fileID)
return inputStream.use{it.readText()} // Returns entirety of file contents as string.
}

How to use CreateFromAsset with Room databasebuilder

I am trying to have this new feature working but I keep getting an empty database. There is not much documentation and the articles on medium are not detailed enough.
Using the debugImplementation com.amitshekhar.android:debug-db:1.0.6 plugin to look into my database and manually add an entry to it.
After doing so I download the database.
The file itself is not a *.db file but I change the name and put the .db extension (I have tried both with and without).
I add it to my assets folder and on my databasebuilder I add a .createFromAsset with the path so that I can use the database.
When restarting the app (deleting and reinstalling) I find that is it not pre populated.
What exactly am I doing wrong?
This is how I create the database. There is nothing special with it.
single(createdAtStart = true) {
Room.databaseBuilder(
get(),
CountryDatabase::class.java,
"country_database"
).createFromAsset("database/country_database.db").build()
}
single(createdAtStart = true) {
get<CountryDatabase>().countryDao()
}
#Database(entities = [LocalCountryData::class], version = 4)
abstract class CountryDatabase : RoomDatabase() {
abstract fun countryDao(): CountryDao
}
#Entity(tableName = "countries")
data class LocalCountryData(
#PrimaryKey
val country_name: String,
val country_short_code: String,
val regions_name: String,
val regions_short_code: String
)
When restarting the app I find that is it not pre populated.
createFromAssets will only be invoked and copy the database from the database folder of the assets folder if there is no existing database.
Rather than restarting the App, you should either :-
delete the App's data or
uninstall the App
and then run the App.

Create a ArrayList of data class objects from a String in Kotlin

I have a Kotlin data class
data class Item (val content: String) {}
In my app I use an myData: ArrayList<Item>.
To provide persistant storage the app writes this list to a file everytime it is changed:
configFile.writeText(myData.toString())
At startup it reads the file and with configfile.readFile(). The returned string look like this:
[Item(content=Click #1), Item(content=Click #2)]
How can I create the arraylist from this string?
You can write data in some well known format such as JSON or XML. You can still parse your written string, but JSON / XML can be preferrable.
For reading / writing JSON / XML, you can use jackson library which is quite easy to use.
Here is the link for quickstart.

Categories

Resources