android app/business-logic config - android

how does an app developer store app-specific (ie. my server addresses, path endpoints, etc.) global and build variant specific config values in an android app? further, is it possible to have overrides? ie. i want to set a default value in my global.config, but collisions in staging-build-variant.config and prod-build-variant.config should override this, while dev-build-variant.config would simply use the default value.
i've read about SharedPreferences but this seems for storing user input at runtime for later runs, and i've read about people using a class to hold constants, but that doesn't quite fit either as i don't get any benefit of a specific configuration values overriding common ones. there is also a lot of seemingly outdated articles out there which i'm not sure are accurate anymore.
i asked this as a comment in this question which seems to be close to what i'm looking for, but thought i'd ask as a question for more exposure.
EDIT: maybe i explained this poorly - to clarify, this comment.

Justin, it seems that what you whant is a library project. You will have to create a library project with one default configuration.
Let's say that project is called Core and then it has the following strings.xml:
<string name="server_address">htt://path.to.server</string>
This way you can create a module (called app1) for the project that uses the 'Core' library project. Then you will end with two strings.xml file.
So the strings.xml file from your app module will override the strings.xml from the library project. Then you can have:
<string name="server_address">htt://app1.path.to.server</string>
Resources:
Create a library Project
[UPDATED]
Instead of use a library you can try a grade variable. See this question:
Gradle Variables
And this link about build variants:
Build variants

Related

Replace android string resource values with a Gradle Task with resValue() or something similar

I'm looking into changing string resource values with a Gradle Task. I'm looking at most likely using a Copy Task, to copy string.xml and overwrite.
At this point I think I'm going to be rewriting the contents of the xml file and replacing using a regex pattern. This seems like a bad way to do this, isnt there a better way to use something like resValue() within a Gradle Task?
I see three ways to do this, details will depend on your exact setup, so I will just point at things that may help you:
1) We do the copying via type: Copy too in some cases. The way we go about it is to have the possible versions of the files that are variable stored in specific subfolders which are excluded from building. Then we copy the version required by a specific build into source, where the build process depends on the copy tasks which ensures the correct file is available before compilation.
2) You can look into gradle.properties. This is where you can store key-value-pairs to be available to gradle and managing your build pipeline. You can define properties like this:
someProperty=abc123
This is then loaded in Gradle via ${someProperty} during configuration stage.
3) For your various builds you can introduce different build pipelines. This is not distinct from 1), 2), but you can use this to control which config you use. You can for example use configuration tasks to set gradle.properties and let Gradle execute a specific build pipeline using a specific settings.xml depending on the values in gradle.properties. Or you can just define tasks for each possible settings.xml and then execute these.
If there are more efficient ways to achieve this, then I am also interested in the answer. Hope any of this helps.

How do I remove unused languages from the final APK file with Xamarin.Android?

I've added some of the Android support libraries to my project and now I'm basically facing the same problem as described in this question:
Android Studio exports strings from support library to APK
Since I can't use Gradle settings with Xamarin, I can't use the solution described in the StackOverflow answer.
Does anyone have an idea, how I can keep only specific localization in my final APK file?
Generally, in Xamarin, The AndroidManifest handles special instructions for uses of libraries The Android.App.UsesLibraryAttribute(string name, bool required) sets specific inclusions and exclusion that will be in the generated Manifest.XML.
Also as far as I know there are only three ways to set link exclusions, the first and second are mentioned by #sunseeker, however Xamarin documentation and dev notes strongly recommend not using Full as indicated above and in general advocate using the following:
SdkOnly(default)
the second also mentioned above is for specific exclusions, it is also recommended not using this unless you are sure a particular package is not getting called "behind the scenes" by an extended class further up in the hierarchy.
Finally in the third method is to set LinkMode to None, while specific linkings are stipulated using the AndroidManifest interface.
Some other ways to get efficiencies are to:
set AndroidUseSharedRuntime property to true at least while debugging to reduce package size.
set AotAssemblies property to true when you have a stable build to precompile the libraries that are included.
set EmbedAssembliesIntoApk to false unless it is a release build.
That's about as far build knowledge goes with Xamarin, hope it helps.
Can't really check it now, but have you had a look at AndroidLinkSkip and AndroidLinkMode (reference) tags in a solution .csproj file?
So, it'd be something like
<AndroidLinkMode>Full</AndroidLinkMode>
<AndroidLinkSkip>Mono.Android.Export;I18N;I18N.West</AndroidLinkSkip>
Also, have a look at MandroidI18n. From the same reference above:
Specifies the internationalization support included with the
Application, such as collation and sorting tables. The value is a
comma- or semicolon-separated list of one or more of the
case-insensitive values
<MandroidExtraArgs>-i18n=west</MandroidExtraArgs>
or
<MandroidI18n>West</MandroidI18n>
So I've finally managed to do this in a sane way
Download Apktool from https://ibotpeaches.github.io/Apktool/
Create your final .apk with Xamarin and decompile it with apktool d MyApp.apk
Go into the MyApp directory that Apktool has created and look for the res directory
Remove all values directories that end with a language identifier that you don't need, e.g if your app only supports the German language, remove values-fr, values-es, etc..., but not values-de. Don't remove non-language directories, e.g values-v11!
Recompile your app with apktool b MyApp
The recompiled app package is now in MyApp/dist/MyApp.apk. Take this file and sign it with the signtool, then zipalign it.
Upload the apk to Google Play
I'm sure this process can be automated, I'll update this answer as soon as I have a script for that.
Have you tried solution from Borris Spinner:
You can provide AndroidResgenExtraArgs in your project file and add -c en,de etc.
See aapt documentation:
-c specify which configurations to include. The default is all
configurations. The value of the parameter should be a comma
separated list of configuration values. Locales should be specified
as either a language or language-region pair. Some examples:
en
port,en
port,land,en_US

Android compile with different resources (white label)

We have an Android project where we maintain a single code base for different customers, what will be the fastest/most efficient way to compile for different customers every time? Few options I found and my questions:
writing scripts: to replace resources folder and edit app name, version, etc.
Using Android Library Projects It is gonna be quite impractical to separate current project as Library projects, I am thinking whether it is possible to save some settings and resources files as a Library project and just import different library projects for different compilation?
Storing settings and resources on a remote server Is it possible to store resource files and some app settings (xml, constants, etc) on a remote server, and download them and replace to the app when the user first launch the apk? Where will these files be stored?
Any other options you would suggest?
Android Studio provides a feature called "flavors" that allow you to quickly define different configurations from a single code base. I have just learned about this in the last couple of days, so I don't know a lot more than this.
The best way I've found is a post build script step. Use a default set of resources/assets for your main build. This is your default apk, use it for default testing. Save the unsigned apk this builds. Then for the customer specific APKs, open up the unsigned apk (its just a zip file), overwrite any overwritten files, then sign the new version.
This works fine so long as you don't need to change code for different customers. It also doesn't put any unneeded assets/resources in any build, so you don't leak info to one customer about your other customers by including their files.
If you do need to change code, the best way is to do a runtime check on a variable from a settings file. And overwrite the settings file the same way you do everything else.
As an added bonus, if you need to you can write a very fancy system that would allow the customer to upload his own files to override your defaults (including allowing them to override some of your settings), so you don't need to deal with a dozen change requests. That requires a lot more work though.

Customizing parts of Android Manifest

I am developing Android application for which I want to ship several different apks for different languages in the market (every language includes a huge bundle of files and I want to avoid creating one huge apk with all language bundles).
So what I need is to customize a bit the Manifest file for each language: e.g. the package of the application and possibly the application version etc. I know how I can template the manifest so that I can manually insert my values in certain points in the file (see this post). The problem is that I use ant for preparing my production apks, but otherwise I develop using Eclipse and so I need my project working in the IDE too. Eclipse requires complete Manifest file and will not understand of the templating I will use for the ant builds as far as I know (please somebody prove me wrong).
My problem is that I want to avoid maintaining two manifest files that are identical in large part (one templated and one complete for Eclipse). Currently I can think of two possible approaches, but I do not know how to accomplish them:
Use some kind of definition injection in the manifest file: if I am able to inject certain xml file in the body of AndroidManifest file, I can keep the identical part in one xml part and customize only the points of difference
If it is possible to configure Eclipse to use some sequence of ant tasks to build Android projects instead of the prebuild routines I might be able to integrate the way I build my production apks in the IDE.
Please if there is anyone who knows how to accomplish any of the above two, or has any other idea how can I solve my issue: help!
Take a look on ant replace task:
<replace file="${build.out}/src/config.prop" token="###" value="${build.version}-${build.type}"/>
But again you should be careful with values that they are unique.
You could also replace your eclipse manifest with generated manifest by echoxml task.
Or you could reuse this nice task about xml manipulation.
At the company I work for, we pretty much use the approach given by Eugen to automate the build process of apps that e.g. should simply be branded differently by exchanging certain assets, styles, strings and configurations. We tend to set up the project and build process as follows:
Create the Android project and set it up such that it works for a specific branding. This will make sure that you can still build and run from Eclipse. Assuming that the codebase does not change between differently branded releases, that should be fine.
Create an ant build configuration that:
copies any files that are going to be changed to a backup directory
modifies the project files according to a configuration file (see below)
compiles the project sources and signs it with a release key (if making a release build)
copies back the files from step 1, overwriting any changes and returning the project to its original state
Create configuration files for every 'branding', or language specific release in your scenario.
Basically these steps will allow you to create branded/partner/language specific builds by simply providing the appropriate configuration with the ant build command. In our case it looks somewhat like this:
ant partner-release -Dpartner=stackoverflow
where 'stackoverflow' will point to a configuration with the same name. In our case these configuration files are small xml files that contain all the parameters that are to be replaced for that specific build. It could contain strings, but might as well point to other files (e.g. logo images) that should be copied into the assets/resources. For example:
<config>
<version_name>1.00</version_name>
<version_code>1</version_code>
...
</config>
Some more pointers:
We use xmltask to modify any xml files in the project; e.g. the manifest and resources.
Since the aforementioned task is really easy to use, our build configuration files are also set up as xml files, as illustrated above. It's quite human readable and easy and straightforward to change.
You can also use replace and ReplaceRegExp tasks to change configuration-dependent variables in almost any file. The latter can be especially convenient to make build-time changes to source code.

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 :(

Categories

Resources