How do I get Android string resources for flutter package? - android

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';

Related

How to define arguments and describe them enums with Flutter?

Is it possible to define enum in Flutter in the way to define specific values like color and type.
Regarding to this article I do not see such things:
https://www.educative.io/blog/dart-2-language-features
code from android where this is possible:
enum class AcceptedItemStatus(#ColorRes val color: Int, #StringRes val type: Int) {
#SerializedName("New")
NEW(R.color.green, R.string.accepted_chip_new),
#SerializedName("Standby")
STAND_BY(
R.color.orange,
R.string.accepted_chip_stand_by
)
}
Dart doesn't have out-of-the-box support for adding custom properties to Enums. It's a shame because I really like that feature of Kotlin and other languages and use it a lot. However you can work around it using some packages.
Add the built_value package to your dependencies in pubspec.yaml
Add build_runner and built_value_generator to dev_dependencies
Create accepted_item_status.dart
import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
part 'accepted_item_status.g.dart';
class AcceptedItemStatus extends EnumClass {
// #BuiltValueEnumConst is optional, if you want to use the built_value serialization and want to control
// what value each enum item serialises to:
#BuiltValueEnumConst(wireNumber: 1)
static const AcceptedItemStatus newItem = _$newItem;
#BuiltValueEnumConst(wireNumber: 2)
static const AcceptedItemStatus standby = _$standby;
const AcceptedItemStatus._(String name) : super(name);
static BuiltSet<AcceptedItemStatus> get values => _$values;
static AcceptedItemStatus valueOf(String name) => _$valueOf(name);
// This is optional, if you want to use the automatic serializer generation:
static Serializer<AcceptedItemStatus> get serializer => _$acceptedItemStatusSerializer;
Color get colour => _colour[this] ?? (throw StateError("No colour found for $this"));
static const _colour = {
newItem: Color(0xFF123456),
standby: Color(0xFF654321),
};
}
Run the code generator to automatically generate the companion file for your enum: flutter pub run build_runner build
Et voila! Now you can use AcceptedItemStatus just like an enum, and it will have your custom properies:
final status = AcceptedItemStatus.newItem;
Color statusColour = status.colour;
Perhaps, you can use extension for enum.
import 'package:flutter/material.dart';
enum AcceptedItemStatus {
isNew, standBy
}
extension AcceptedItemStatusExtension on AcceptedItemStatus {
Color get color {
switch (this) {
case AcceptedItemStatus.isNew:
return Colors.green;
case AcceptedItemStatus.standBy:
return Colors.orange;
}
}
String get title {
switch (this) {
case AcceptedItemStatus.isNew:
return "Is New";
case AcceptedItemStatus.standBy:
return "Is Stand By";
}
}
}
Usage:
debugPrint("${AcceptedItemStatus.isNew.color}");
debugPrint("${AcceptedItemStatus.isNew.title}");

Difference between file and classes in kotlin

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.

kotlin DSL retrieving keys from other file

I am trying to switch my gradle files to Kotlin DSL. My project is making call
to an API.
In build.gradle(app) I had a function to retrieve an api key stored in an other
file keys.properties.
After some problem (for example) I rewrote the function to get the
key. I wrote the following function in build.gradle.kts:
import import java.io.File
fun readFileLineByLineUsingForEachLine2(fileName: String): HashMap<String, String>{
val items = HashMap<String, String>()
File(fileName).forEachLine {
items[it.split("=")[0]] = it.split("=")[1]
}
return items
}
Then I set a variable to hold the value of a particular key:
buildConfigField(String!, "API_KEY", returnMapOfKeys()["API_KEY"])
After fixing some errors I am stuck with the following one:
app/build.gradle.kts:49:36: Expecting ')'
which point on the line above with buildConfigField.
Does someone know where is this error ?
Or does someone know how to retrieve keys from files with Kotlin DSL ?
I solved my problem (it seems so.. check the edit!!). I ended up with the following function:
// Retrieve key for api
fun getApiKey(): String {
val items = HashMap<String, String>()
val f = File("keys.properties")
f.forEachLine {
items[it.split("=")[0]] = it.split("=")[1]
}
return items["API_KEY"]!!
}
And then I call buildConfigField as follow:
buildConfigField("String", "API_KEY", getApiKey())
There are no errors anymore on this part.
Edit
Once I have fixed all errors in the build.gradle.kts, the build of my project return that the file keys.properties could not be found: I had to fix my function getApiKey. Finally I could build and run my project with the following implementation:
// Return value of api key stored in `app/keys.properties`
fun getApiKey(): String {
val items = HashMap<String, String>()
val fl = rootProject.file("app/keys.properties")
(fl.exists())?.let {
fl.forEachLine {
items[it.split("=")[0]] = it.split("=")[1]
}
}
return items["API_KEY"]!!
}
This function is far to be good with all its hardcoded stuff but it allows to build my project.
Alternative
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
val apiKey = gradleLocalProperties(rootDir).getProperty("key.properties")
..
buildConfigField("String", "API_KEY", "\"$apiKey\"")
In your kts file, first import
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.util.Properties
then you can do this:
fun getApiKey(): String {
val fl = rootProject.file("gradle.properties") <- the path for the file where your key is.
if (fl.exists()) {
val properties = Properties()
properties.load(FileInputStream(fl))
return properties.getProperty("API_KEY") <- the name your give to it
} else {
throw FileNotFoundException()
}
}
Now you call use it: buildConfigField("String", "API_KEY", getApiKey())

How to write / read internal files securely

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.

Kotlin: How to access field from another class?

package example
class Apple {
val APPLE_SIZE_KEY: String = "APPLE_SIZE_KEY"
}
Class:
package example
class Store {
fun buy() {
val SIZE = Apple.APPLE_SIZE_KEY
}
}
Error:
'APPLE_SIZE_KEY' has private access in 'example.Apple'
But official documentation describes that if we do not specify any visibility modifier, public is used by default.
Why is above error coming?
What you are trying to do is accessing a value of a class that has no instance. Here are three solutions:
package example
object Apple {
val APPLE_SIZE_KEY: String = "APPLE_SIZE_KEY"
}
This way you do not need to instantiate anything because of the way objects work in Kotlin.
You could also just instantiate your class like this:
package example
class Store {
fun buy() {
val SIZE = Apple().APPLE_SIZE_KEY
}
}
In this solution you also have an object of Apple, but Apple is still declared as a class.
The third option is a companion object, which behaves like static variables in Java.
package example
class Apple {
companion object {
val APPLE_SIZE_KEY: String = "APPLE_SIZE_KEY"
}
}
If you want this to be a class level property instead of an instance level property, you can use a companion object:
class Apple {
companion object {
val APPLE_SIZE_KEY: String = "APPLE_SIZE_KEY"
}
}
fun useAppleKey() {
println(Apple.APPLE_SIZE_KEY)
}
What you currently have is an instance property, which you could use like this:
fun useInstanceProperty() {
val apple = Apple()
println(apple.APPLE_SIZE_KEY)
}

Categories

Resources