I'm trying to create a helper class that will handle reading and writing internal files in my android app using Kotlin.
Here are the links I followed in order:
https://developer.android.com/guide/topics/data/data-storage
https://developer.android.com/training/data-storage/files.html#WriteInternalStorage
https://developer.android.com/training/data-storage/files/internal
https://developer.android.com/topic/security/data
Here's my code:
package com.example.testapp
// Added
import android.content.Context
import java.io.File
// External
import androidx.security.crypto.EncryptedFile
import androidx.security.crypto.MasterKeys
#Suppress("unused")
class SystemMain {
fun writeFile(context: Context) {
// Although you can define your own key generation parameter specification, it's recommended that you use the value specified here.
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
// Creates a file with this name, or replaces an existing file that has the same name. Note that the file name cannot contain path separators.
val fileToWrite = "my_sensitive_data.txt"
val encryptedFile = EncryptedFile.Builder(File(fileToWrite), context, masterKeyAlias, EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB).build()
encryptedFile.bufferedWriter().use { writer ->
writer.write("MY SUPER-SECRET INFORMATION")
}
}
}
Here's my build.gradle:
...
implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0"
implementation "androidx.security:security-crypto:1.0.0-alpha02"
...
The error I'm getting is here: encryptedFile.bufferedWriter()
Unresolved reference. None of the following candidates is applicable
because of receiver type mismatch:
#InlineOnly public inline fun File.bufferedWriter(charset: Charset = ..., bufferSize: Int = ...): Buffered Writer defined in kotlin.io
#InlineOnly public inline fun OutputStream.bufferedWriter(charset: Charset = ...): BufferedWriter defined in kotlin.io
Am I missing a reference somewhere? Am I using the incorrect references? Has the code changed and the documentation on the links are outdated?
I'm very new at this. Any advice / help will be appreciated.
After looking at definitions and declarations; I've found this:
encryptedFile.openFileOutput().bufferedWriter().use {writer ->
writer.write("MY SUPER-SECRET INFORMATION")
}
Not sure how well this will work, but there's no error.
Hope this helps someone else.
Related
I am trying to use interface in swift, but it unable to find the property
commainMain
interface ApplicationToken {
val accessToken: String
val refreshToken: String
}
iosMain
Platform.kt
lateinit var tokenProvider: ApplicationToken
HttpClient.kt
actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Darwin) {
config(this)
engine {
configureRequest {
setAllowsCellularAccess(true)
}
}
install(Auth) {
bearer {
loadTokens {
BearerTokens(tokenProvider.accessToken, "")
}
}
}
}
Now when I am to access tokenProvider in my swift code. It cannot find. I am adding image please have a look.
I tried another options to create class and implement my interface and call the class
class getToken : ApplicationToken {
let accessToken: String = ""
let refreshToken: String = ""
}
_ = getToken()
But it gives me the error. I cannot paste it because I don't understand in xcode.
When generating code for extensions (e.g. fun SomeClass.extension()) and for global variables, like in your case, Kotlin creates kind of a namespace, related to the filename.
In your case your property should be under PlatformKt.tokenProvider.
Usually when it's hard to find how your kotlin code is visible on iOS side, it's useful to check out framework header file. It should be places somewhere around here(replace shared with your framework name):
shared/build/cocoapods/framework/shared.framework/Headers/shared.h
I prefer adding this file by reference in my Xcode project, so I can have fast access all the time:
Then you can easily search through this file for your variable/class/etc name.
I am a bit confuse that where to use file or class in kotlin can some one please suggest when to use file,it is not clear for me due to less documents for both the case.
You got to use a kotlin file to declare extension methods , and import that file to the class or file you're working on
Eg: the kotlin file contains
package com.something.mediaplayersystem
public fun String.toLowerCaseByAnExtensionMethod(){
this.toLowerCase()
}
And I want to use that extension method on a class
package com.something.mediaplayersystem
import com.something.mediaplayersystem.toLowerCase
class Classa {
var word:String = "WELCOME"
public fun Method(){
var lowerCaseWord = word.toLowerCaseByAnExtensionMethod()
}
}
In the case of String you don't need to import the method but in mayor cases you have to.
I want to read the stings.xml file in another package.
I'm creating a flutter package
What should I do?
flutter example app string xml
<string name="client_id">clientid</string>
flutter package
context.getString(R.stirng.client_id); // not found
You can read it from Context after set it in xml file:
Add this class to your plugin:
import android.content.Context
import androidx.annotation.NonNull
class PluginUtilities
{
companion object {
#JvmStatic
fun getResourceFromContext(#NonNull context: Context, resName: String): String {
val stringRes = context.resources.getIdentifier(resName, "string", context.packageName)
if (stringRes == 0) {
throw IllegalArgumentException(String.format("The 'R.string.%s' value it's not defined in your project's resources file.", resName))
}
return context.getString(stringRes)
}
}
}
Then when you need any string from resources, you can call getResourceFromContext method, for example i will get access_token from resources:
val accessToken: String = PluginUtilities.getResourceFromContext(context,"access_token")
I hope the answer is useful...
You won't be able to access xml file in flutter package
You can create a file Strings.dart
class Strings {
static const String client_id = "xxxxxxxx";
}
And use it like this
Text(Strings.client_id, /*Code*/),
Don't forget to import Strings.dart
import '../Strings.dart';
I've tried hundreds of ways to resolve this reference problem:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
val dm = DataManager()
val adapterCourses = ArrayAdapter<CourseInfo>(context: this,
android.R.layout)
but in ArrayAdapter<CourseInfo>(context: this, android.R.layout) I get unresolved reference: context and I have no idea why.
Android Studio version: 3.3.2
Kotlin version: 1.3.21
Could anyone help me?
I had a similar error message because I didn't import the Context.
If you haven't explicitly imported Context, try adding this to your import list near the start of your Activity file:
import android.content.Context
The column in Kotlin is used for some things, but not when passing named arguments. The syntax for passing a named parameter is parameterName = parameterValue.
When you write context = this, while passing a parameter, you are simply referring to the parameter context of the function you are calling, explicitly saying that this has to correspond to that context parameter. This is not very useful in this case unless you want to be very explicit.
The usefulness of using named arguments arise when you are dealing with optional parameters or when you are passing the parameters out of order.
E.g.
// DECLARATION of function abc
fun abc(s: String = "", i: Int = 0)
// USAGE of function abc passing only an Int
abc(i = 314)
The function abc has two parameters and they have a default value. In this case, you can avoid passing any parameter if you are fine with the defaults.
But if you only want to pass i, you can do it by specifying its name, as done in the example.
Similarly, you can choose to pass parameters out of order, in that case, you'll do:
abc(i = 314, s = "something")
I'm writing a simple import application and need to read a CSV file, show result in a grid and show corrupted lines of the CSV file in another grid.
Is there any built-in lib for it or any easy pythonic-like way?
I'm doing it on android.
[Edit October 2019] A couple of months after I wrote this answer, Koyama Kenta wrote a Kotlin targeted library which can be found at https://github.com/doyaaaaaken/kotlin-csv and which looks much better to me than opencsv.
Example usage: (for more info see the github page mentioned)
import com.github.doyaaaaaken.kotlincsv.dsl.csvReader
fun main() {
csvReader().open("src/main/resources/test.csv") {
readAllAsSequence().forEach { row ->
//Do something
println(row) //[a, b, c]
}
}
}
For a complete minimal project with this example, see https://github.com/PHPirates/kotlin-csv-reader-example
Old answer using opencsv:
As suggested, it is convenient to use opencsv. Here is a somewhat minimal example:
// You can of course remove the .withCSVParser part if you use the default separator instead of ;
val csvReader = CSVReaderBuilder(FileReader("filename.csv"))
.withCSVParser(CSVParserBuilder().withSeparator(';').build())
.build()
// Maybe do something with the header if there is one
val header = csvReader.readNext()
// Read the rest
var line: Array<String>? = csvReader.readNext()
while (line != null) {
// Do something with the data
println(line[0])
line = csvReader.readNext()
}
As seen in the docs when you do not need to process every line separately you can get the result in the form of a Map:
import com.opencsv.CSVReaderHeaderAware
import java.io.FileReader
fun main() {
val reader = CSVReaderHeaderAware(FileReader("test.csv"))
val resultList = mutableListOf<Map<String, String>>()
var line = reader.readMap()
while (line != null) {
resultList.add(line)
line = reader.readMap()
}
println(resultList)
// Line 2, by column name
println(resultList[1]["my column name"])
}
Dependency for Gradle: compile 'com.opencsv:opencsv:4.6' or for Gradle Kotlin DSL: compile("com.opencsv:opencsv:4.6") (as always, check for latest version in docs).
In terms of easiness, kotlin written csv library is better.
For example, you can write code in DSL like way with below library that I created:
https://github.com/doyaaaaaken/kotlin-csv
csvReader().open("test.csv") {
readAllAsSequence().forEach { row ->
//Do something with the data
println(row)
}
}
Use opencsv.
This is gonna work like a charm for reading a CSV file.
As far as logging the corrupted lines is concerned you can do it using this logic.
while(input.hasNextLine())
{
try
{
//execute commands by reading them using input.nextLine()
}
catch (ex: UserDefinedException)
{
//catch/log the exceptions you're throwing
// log the corrupted line the continue to next iteration
}
}
Hope this helps.
I used net.sourceforge.javacsv with my Kotlin code for parsing CSV files. It is a "java" library but within kotlin it is fairly straightforward to work with it like
val reader = CsvReader("/path/to/file.csv").apply {
trimWhitespace = true
skipEmptyRecords = true
readHeaders()
}
while (reader.readRecord()) {
// do whatever
}
Frankly speaking, it is quite easy to make a simple reader in Kotlin using modern Java features, check this (REMEMBER to handle BOM :-)):
fun processLineByLine(csv: File, processor: (Map<String, String>) -> Unit) {
val BOM = "\uFEFF"
val header = csv.useLines { it.firstOrNull()?.replace(BOM, "")?.split(",") }
?: throw Exception("This file does not contain a valid header")
csv.useLines { linesSequence ->
linesSequence
.drop(1)
.map { it.split(",") }
.map { header.zip(it).toMap() }
.forEach(processor)
}
}
Than you can use it as follows (depends on your file structure):
processLineByLine(File("./my-file.csv")) { row ->
println("UserId: ${row["userId"]}")
println("Email: ${row["email"]}")
}
If you prefer to use your own data class for each row you should have a look at my solution https://github.com/gmuth/ipp-client-kotlin/blob/master/src/main/kotlin/de/gmuth/csv/CSVTable.kt
data class User(
val name: String,
val phone: String,
val email: String
) {
constructor(columns: List<String>) : this(
name = columns[0],
phone = columns[1],
email = columns[2]
)
}
CSVTable.print(FileInputStream("users.csv"))
val userList = CSVTable(FileInputStream("users.csv"), ::User).rows
I know i'm a bit late, but I recently had problems with parsing CSV and there seemed to be no library good enough for what I was looking for, so I created my own called Kotlin CSV stream.
This library is special because it doesn't throw exceptions on an invalid input, but returns in the result instead, which might be useful in some cases.
Here is an example of how easy it is to use
val reader = CsvReader()
.readerForType<CsvPerson>()
val people = reader.read(csv).map { it.getResultOrThrow() }.toList()
For version of commons-csv version 1.9.0, have implemented below code to get results.
It uses CSVBuilder and CSVFormat to get records with skip headers and auto-identify headers on basis of first row.
fun csvReader(file: MultipartFile): ResultListObject? {
var result = ResultListObject()
var csvFormat=CSVFormat.Builder.create().setHeader().setSkipHeaderRecord(true).build()
var csvRecords = CSVParser(file.inputStream.bufferedReader(), csvFormat)
csvRecords.forEach{csvRecords->
rowRecord.field1=records.get("field1")
rowRecord.field2=records.get("field2")
...
...
result.add(rowRecord)
}
return result
}