Dynamically Determine Android Resources - android

I have a number of different string resource files that are built with my Android application using our build system. These string files can be added incrementally at any time and our build system will pick them up from their separate directory. I want to enumerate all of the string files or be able to obtain a single string in them without having to know the name or id of the string resource in them. I also don't want the person adding these to have to edit a main string file in my package that includes an array listing the different files. Is there any way to accomplish this?
Example:
SoccerStrings.xml
id="SoccerDetails" value="soccer"
CricketStrings.xml
id="CricketDetails" value="cricket"
Without knowing these files exist how can I provide a list view with two items: Cricket and Soccer in addition to automatically supporting any additional files that might appear.
I was thinking the best possible approach would be to have the build system pull the individual files under assets folder and then use the getAssets().list("") functionality along with the XMLResourceParser class to access the string values. Would this work and allow me to have id conflicts (ex: id="name")? Is there an easier way?

I would look at aapt. I know you can get the resources out of the .apk with the following command --
aapt d --values resources app.apk
It might be possible to use aapt to get the resources earlier in the build process. It has the following option which looks prosmising, but aapt documentation is a bit thin.
--output-text-symbols
Generates a text file containing the resource symbols of the R class in the
specified folder.
As another alternative, you could modify your build process and parse the string class directly out of the gen/<package>/R.java file after it has been generated. You could store that in a loadable file, or generate your own source file to add to the build.

I am not going to tell you how to do it. I am answering the question to advise against it.
What you are planning to do does not go well with the resource files. These files are basically code. What you want to do is about data. You should have your data in assets directory. Then these files won't be precompiled in your build like the resource file. You can process these files any way you want. There will be then quite a bit coding involved to convert all that into business logic, but that would be price to pay to write good, maintainable code.
Playing with resource files the way you are suggesting is akin to Java reflection. You want to use it only because you have functionality that is about such feature, not because it's the easiest way out.
Having said that, you might be exactly in a situation where you have to handle the resource files the way you stated. In that case, please accept my apologies.

Related

Android Studio - What is the Java Resources Folder?

I know there are two well-known folders where one can put resources.
The first is the /assets folder, the documentation says:
Contains file that should be compiled into an .apk file as-is. You can navigate this directory in the same way as a typical file system using URIs and read files as a stream of bytes using the AssetManager. For example, this is a good location for textures and game data.
The second is the /res folder, the documentation says:
Contains application resources, such as drawable files, layout files, and UI string. See Application Resources for more information.
Now i was wondering, there is a third option to create a resource folder "New > Folder > Java Resources Folder"
To me i looks like some part of the Android Plugin in IntelliJ because it has a little Android symbol in front of it .
Any ideas what the use of it could be? I couldn't find any documentation about it.
My first guess would be to use it in situations where you want to supply resources to a JVM Test.
In standard java world
Resources can be embedded directly in "your source tree" and used with Class's method getResource (see java documentation for a more precise description).
In android world
This practice is not recommanded (do not work at all, because such resources are removed from generated APK). You can still declare Java resources folders (see build.gradle :
sourceSets {
main {
resources.srcDirs = ['src/main/java/yourresourcesfolder']
}
}
And the result in the apk :
Conclusion
As resources's folder tree is removed,using java's resource folder become from my point of view, useless (in an android projet). Using android's asset folder is a better choice (also avoid resource's name conflict, but it's an another story :D )
This post is a bit old, but I want to bring an answer that explain one use case for the java resources directory on Android. If this folder exists in the options of a project it's because something can be done with it...
Enters the Service Loader, that helps to connect other services (aka libraries) into your main app, it can be used as a Gateway for your Android library to extend the functionality of a feature, exposing only the interfaces or abstract classes, with the Service Loader providing the implementation instead of your project having direct access to them.
Here is an example of how it's implemented. So, in summary the folder (META-INF/services) and files you have to create in order to use the Service Loader on an Android App, NEED to be inside this Java Resources Folder, otherwise your provider won't be able to see any implementation.
You can see it working in my sample here if you want to check it out: https://github.com/difereto-globant/test-library-feature/tree/1.0.9.

How safe is to save properties files in assests or raw folders?

For the application I'm working on I was thinking to define few property files, something like: debug.properties, beta.properties, release.properties. These files mostly will contain urls to their corresponding environments. Depending of some flag I will set, the application will load the corresponding property file and read the values from there.
I was thinking to put these files in assets or raw resource folder, but after changing the extension from .apk to .zip of my application, I noticed that these file are accessible and readable.
If you had prior experience, what are the best practices for configuring different build environments in Android?
Is there a better place where I could put the properties files so they cannot be accessed?
I had the same need in my app and found the same problem you found: It's to easy to open the apk and edit the properties files.
The solution I chose was to put those environment-specific properties in some Java source files.
We have one Android project per environment. Each project is almost empty and refers to an Android Library that actually contains the app's code. Each Android project contains a Java file declaring its environment properties.
This seems counter-intuitive to use Java instead of properties file, but when fighting against piracy, all ways are good. The Java files can be obfuscated if you use Proguard. Even better, you can use Dexguard that can encrypt the strings in the Java source so that it will extremely hard to tamper the source and make the properties point elsewhere.

Is it possible to make use of the Android resource resolver on a self-created folder in the file system?

I'd like the ability to "overwrite" the Android resources packaged within my apk by having the app periodically download a zipped file containing overrides that follow the same naming convention as the source does. For example, the zip might consist of the following paths:
res/values/strings.json
res/values-land/strings.json
My code would parse those files and produce a Map> that would map the string resource id to a folder->value pair (or something along these lines). At this point I'm really only concerned with strings and images (maybe arrays), but not layouts, etc.
To the point: Is there any method available, that, given a list of folder names, would tell me which one the Android resolver would choose based on current state? I'm assuming this is difficult because the compiler breaks everything down to ids, but figured it was worth a shot. Any ideas?
Is there any method available, that, given a list of folder names, would tell me which one the Android resolver would choose based on current state?
No. You are welcome to roll this yourself based on Configuration, DeviceMetrics, and kin. You will also need to create your own parsers for your own files, as Android's resource system only works with resources, not arbitrary files retrieved from arbitrary locations.
The expectation in Android is that if you want to update resources, you update the app, probably because there were also code changes as well. Admittedly, this approach has its limitations.

Is there a way to add or change Android apps language after packaging it into an APK?

In the case of a windows application(EXE/DLL), we can change or add language resources within the binary without re-compiling it. Can the same be done in case of an Android application? Is there any editor available to make this happen?
My plan is to develop the application in English and then release it to the sales department, where they will be responsible for the localization of the application without compiling and packaging it into a new APK. I just want to split the development part and localization part of the app.
The correct way to localize is to create a string resource for your base language and then have that localized and reimported into your project for every language that you support.
Much more detail can be found in the Localization documentation.
I don't believe there is a safe/supported way to inject localized strings into your app after it's been built.
No. You can not, because once your apk is signed then modifying it after this (you can always do that as apk is just a zip file) will corrupt the signed binary.
When having multiple languages with your application you have to build them into the application itself. Android uses XML files to store strings used within your application. Android allows you to add language localization files containing local specific strings. You can't do this without recompiling your project so you'll want to do it as a future update or right from the start. But you can't have the marketing department do it, that's just not a good idea.
As others have said, the short answer is no. The long(er) answer is sort of. If you pack all your language resources into remote XML that can be updated from the web, then with a little bit of forethought you can do all sorts of live updates to your app's strings, graphics, etc.
So if you want to use the standard R.string method for everything it will be a little difficult. I think it's possible to do something funky with a dynamic classloader for the assets and static dex classes (basically classes of data with just inline byte arrays that can be decoded after). However that would still require compiling. See Custom Class Loading in Dalvik for more info.
Another approach would be more of a standard Java implementation. Java has a class known as ResourceBundle. You could create a ResourceBundle from a property file (key-value plain text, or even property xml). Then these files could be loaded outside the apk, via a network connection or sdcard or other file type resource and deleted as necessary. You will have to write the loader code for it, but that's going to happen with any solution. This solution will be less performant and outside the standard design methods for android but it will solve the problem being asked to solve. Like you won't be able to use R.string or #string/whatever for any of these resources but I think you may be able to write an adapter to such resources (like your own TextView extension and whatever that would allow all of this). It's a matter mostly of how much work you want to invest in solving this actual problem.
Honestly I would opt for trying to distribute whole apks with only the targeted language if you are trying to save space, but then there is no way to change locale for the app at runtime :(

why does android create the R.java file

why not just leave the data( strings.xml, main.xml ) in the .xml files? why convert it into the R.java?
it seems that android can read xml ( eg. androidmanifest.xml ). so why not just leave the strins.xml data and main.xml data in .xml form and send those xml's to the android device?
I am new ... maybe I will eventually see that there is a lot more in the R.java other than mere static variables that derived directly from those .xml's.
thanks,
Shannon
so that you can easily reference you object that you have created in you layout, drawable and string files. this class represents all the resources that can be instantiated inside a code or can be used inside your coding
So that you can easily reference your resources ids from your code with the R class object avoiding compile errors, I think
If you have a bug in your program, you want it detected as early as possible.
If resources are retained as XML any bug will be found at runtime (either test-driven or user-driven). Testing can never prove the absence of all defects, so some bugs may be found by the users of your software!
However, if resources are converted to source in R then all references to them will be checked by the compiler. Any bugs (relating to resource references) are detected at this much earlier stage, long before your customers get to seem them.
Transferring the id references of the XML content into code makes it easy to use these references while coding and the correct usage is visible during compile time. So runtime exceptions are avoided.
I do not know if this is the core reason but that's what counts for me :-).
R.java is a handler to all the resources.
You create your resources, and the R.java automatically build a connection between your code and your res. You can easily fetch your various kind of resources from R, and android provide lots of API supporting R.java and its handlers(those ints). You dont need to manually open a stream to res files, do file reading, images decoding and etc. Its great convience.
R.java doesn't contain any data. It's generated by aapt during the build process when it prepares resources to pack them into the APK, including compiling XML files in a format that's easier to read and parse. R.java contains static int members that are only indexes to the packed resources.
See A Detailed Look at the Build Process, and also take a look into a project's bin/ folder.

Categories

Resources