Issue
Background
I've found these new classes of Android 11 (ResourcesLoader and ResourcesProvider) and I think they can let you provide your own resource loading for the entire app, which can help you to prefer strings from the cloud (like on Lokalise and Crowdin) , load themes, etc...
The problem
I can't find any example of how to use them, and if I'm indeed correct on what I've found.
The only thing I've found about it is from this cached article of "Taming Android Resources and LayoutInflater for string manipulation":
Android 11 has introduced ability to load resources dynamically via ResourcesLoader and ResourcesProvider. This is not just restricted to string files but also allows dynamic loading of drawables and other resource files. This is an approximate way of using these classes
val provider = ResourcesProvider.loadFromDirectory("/somepath/", null) // or loadFromApk()
val loader = ResourcesLoader() loader.addProvider(provider) resources.addLoaders(loader) // Application resources
There aren’t proper samples of this API provided right now and it’s only available on Android 11 and above, so there is a long time for this API to be usable for majority of apps.
What I've found
I wanted to try it for the Lokalise library, which offers an instance of Resources (wrote about this here).
Sadly, I'm stuck right in the beginning, of finding how to use it to provide it with this instance.
It seems it's such a rare use case and new classes that almost nobody bothered writing about it. Even about the article I've found from 2020, it was removed and I had to use a cached version of it...
The questions
- Is it true that these classes can used for this purpose, of offering resources (strings/themes) dynamically?
- Can it be used with Lokalise, so that I give it the instance of its SDK ?
- Is there a support library for these classes, so that it could be used before Android API 30 ?
EDIT: found a sample here. There, they use an APK file that is loaded, to use its resources as top priority:
class App : Application() {
override fun onCreate() {
super.onCreate()
val file = File(cacheDir, "overrideResources")
unzip(ZipInputStream(assets.open("override.apk")), file)
val rl = ResourcesLoader()
rl.addProvider(ResourcesProvider.loadFromDirectory(file.path, null))
resources.addLoaders(rl)
}
}
Solution
How to use ResourcesLoader/ResourceProvide?
- Create compiled resources. For this, you can use aapt or aapt2, for example.
Example with aapt:
./aapt package -f -M AndroidManifest.xml -S ./res -I android.jar -F unsigned.apk
(./res folder must be have structure hierarchy , like ./res/drawable, ./res/layout , etc. with resources)
Example with aapt2:
./aapt2 compile "drawable\your_res_name.xml" -o "drawable"
./aapt2 link -o unsigned.apk -I "android.jar" -R "drawable\your_res_name_drawable.xml.flat" --manifest AndroidManifest.xml -v
AndroidManifest.xml should have the same package name for correct work with your main app. android.jar , aapt , aapt2 files you can find in your sdk folder. About all of flags you can read -> aapt -h , aapt2 -h
AndroidStudio IDE
Example - steps for building apk:
- Create an empty project;
- Add to AndroidManifest.xml the correct package name
<manifest package="your package">
Remove unnecessary tags
<application android:label, android:icon, etc...>
;
- Add your resources to the project ./res folder;
- Remove all unnecessary resources;
- Remove from build.gradle file all dependecies.
plugins {
... //your settings
}
android {
...//your settings
}
dependencies {
}
- Build -> Build APK.
- After that, you got compiled resources, then: (or How to use compiled resources in your app dynamically)
File f = new File("unsigned.apk");
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f, MODE_READ_ONLY);
ResourcesProvider rp = ResourcesProvider.loadFromApk(pfd);
ResourcesLoader rl = new ResourcesLoader();
rl.addProvider(rp);
getResouces().addLoaders(rl);
That's all! Your resources in your app. You downloaded resources dynamically.
For reading resource, you can use:
getResouces().getIdentifier("your_res_name", "drawable", getPackageName());
Is there a support library for these classes, so that it could be used before Android API 30 ?
ResourcesLoader can not be used in previous API.
Answered By - Yevhenii Buhera
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.