I'm currently writing an android app, that interacts with an external server.
I want to make sure that during the development, Android makes connection to a test server instance, but the application should make connection to a production server otherwise.
Currently, URL of the server is stored in one of the xml files - res/values/strings.xml as
<string name="server_url">XYZ.example.com</string>.
Right now, I'm just modifying the xml files in local machines depending on my situation.
What is the idiomatic way to handle case like this?
The XML files are pretty much it. An example would by the mapview api key.
To develop mapview apps you need a key based on your build certificate. Most folks build and test with a debug key and then deploy with a release key. You need to request a different api key for each build key. I keep both map api keys in my resource file, and then comment out the one I don't need when debugging.
An alternative would be to keep two strings in your strings file, and then use some programatic means of selecting which key to use. AdMob uses this type of approach, i.e. if you are testing, you add a test device to the add request. Since you don't want everyone in the world who uses the same phones as you to only see the test adds, you need to wrap the calls in a check for test versus release build. I control this with an integer resource value defined in an xml file. This ends up behaving similarly to a C/C++ DEBUG macro. I still have to change to value of the resource value, but I only have to do that in one place. Alternatively you could use comments to hide the test server: eg
String server = context.getString(R.string.realserver);
server = context.getString(R.string.testserver); //comment out this line prior to release
I am not a fan of comment/uncomment method because its to easy to forget, especially if you have multiple places where the resource is accessed.
If there is a better way to handle this, I too would be interested.
Related
I am implementing Remote Config in my app. The idea is to be able to A/B test some of the messages shown to the user.
I might want to run some of the experiments with the English messages only and I am trying to figure out what is the best (or most practical) way to do this.
One way would be having an xml file with default values for each language in the res/xml- directory. The main drawback I see is that this will be hard to maintain as every single value needs to be copied to all the xml files (some experiments might be language independent such as a layout color).
A second way would be setting language dependent values to an empty string and then implement some logic to look for the right string in R.strings if the value provided by remote config is empty. This seems like too much overhead for what I want to accomplish.
What is the recommended way to run experiments only for a certain language with A/B testing and Remote Config?
It is a default way in android to provide a localized string resources. Is hard to maintain but there are a service which can help you https://phraseapp.com/ . They have a lot of nice features, like manual translation, cross platform app and ide plugins which can replace/add/append/remove new strings to your xml localized files, also it works for ios.
You can keep string resources name in remote config and load it by some kid of reflection. Here is an nice answer How to get a resource id with a known resource name? . Here is an example for your case:
int resourceId = context.getResources().getIdentifier(nameFromRemoteConfig, "string", context.getPackageName())
Localization a very static logic, boring and expensive process in terms of time and maintaining. From my point of view better solution is to develop your own maximum abstract mechanism for localization and reuse it in all your projects. For example a backend service or library which will provide localized data by your own format, and a library for clients which will deserialize that data. As a result you will obtain production ready api for future projects.
Our App supports different languages, some of the translations contain mistakes. The translations on the server are correct.
What is the recommended way to update the strings.xml from the server and how it could be done? Which technologies would be involved?
You cannot update your app's resources without deploying a new APK.
If you want to continue keeping the translations in XML resources, you will need to update them appropriately then deploy a new version of your application.
If you would like those strings to come only from the server in the future, you will need to set up an API service to expose the strings, and consume that API in your app instead of loading the strings from resource files.
Isn't strings.xml is supposed to be used as a text storage for easing the translation of text in the app to other languages?
For example - Facebook app id according to facebook manuals is advised to be stored in strings.xml.
It means that if I want to share this file with 3-th parties for translation - I will have to manually remove all ids by myself, or share those ids with 3-th parties.
Isn't strings.xml is supposed to be used as a text storage for easing the translation of text in the app to other languages?
No. It's string storage for any kind of strings. Majority of use is localization related but it is perfectly fine to have anything that is string there like API keys, tokens whatever.
Please be aware that you are not limited to just strings.xml file. You can have as many *.xml files holding string resources as you like (so it's quite common to split localization per class/functional module and keep it in separate xml file).
You can create more then one strings.xml you could name it appids.xml and store all your ids inside this file. It is common software design pardigm to seperate data from code, so you won't just use a String constant for your id.
For Android best practices, Google is the source to go, for example they propose the usage of an appids.xml file here: Getting started with Play Games
Facebook might be using this simpler form of storing your id to make the tutorial easier to follow.
Basically it may happen that the ids that you're going to use inside your app may occur in multiple java class files. So by mistake there may be a chance that you mistype the id or secret key which will result in failure of result that you are expecting. As a good practice you should store such things in strings.xml which will help you minimizing the possibility of error in your result. Also if you change your id or key because of any reason then you might have to change that in each file where you've mentioned it. Instead of that if you just change it in strings.xml then it will automatically reflect at every instance where you've used it.
Going further, Android is open source. Thus any app that you create can be reverse engineered and all the code can be read. This leads to leakage of your id's and may be some secret keys for any api that you've used inside your app.
MD5 fingerprint of any app can be easily acquired using keytool. Then what is the most unique identifier an app has?
I am trying to build a client server app and I want a secure the communications.
My problem revolves around these two assumptions -
1) Someone can reverse engineer my app and understand how I interact with server webservices
2) My app can be simply uninstalled and replaced with malicious app with similar package name.
The system can easily compromised using these two loopholes.
My solution to these problems was transmitting MD5 signature of my app to the server. The MD5 signature will be conveyed to server before hand. MD5 signature is unique for every app, But there is big problem in this approach. MD5 signature of any apk can be generated using keytool. Anyone may pull my apk and generate MD5 and use it in the webservices communication.
What is the unique identifier of an android app?
Package name and MD5 fingerprint can be easily compromised!
Basically you want to be sure that you are talking to your client app at server end.
Verify Back-End Calls from Android. This link could be helpful as it gives high confidence for such a case. (HTTPS is must here)
As an additional step for #Maddy 's answer, you might think about tamper resistance/integrity protection techniques, that will make your app inoperable in case somebody tried to modify it. DexProtector (http://dexprotector.com) could be the solution here. The slides under the link also should be helpful.
N.B.
I am Licel's CEO, thus I am affiliated with DexProtector.
First question
1) My app can be simply uninstalled and replaced with malicious app with similar package name.
best approach is probably the use of ANDROID_ID
Try this link http://blog.vogella.com/2011/04/11/android-unique-identifier/
Check this also http://android-developers.blogspot.in/2011/03/identifying-app-installations.html
Solution for the second issue
2) Someone can reverse engineer my app and understand how I interact with server webservices
Use DexGuard, which can make reverse engineering even harder, like by encrypting strings
https://www.saikoa.com/dexguard
Proguard
“The ProGuard tool shrinks, optimizes, and obfuscates your code by removing unused code and renaming classes, fields, and methods with semantically obscure names. The result is a smaller sized .apk file that is more difficult to reverse engineer.”
When you create android project.
1. proguard.cfg file is automatically generated in the root directory of the project.
2. The default configuration file only covers general cases, so customize as per your needs.
Enable it
“Set the proguard.config property in the /project.properties file. The path can be an absolute path or a path relative to the project’s root.”
Case1: Just add proguard.config=proguard.cfg if the proguard.cfg is in projects root path.
Case2: Configure from other location [proguard.config=/path/to/proguard.cfg]
Remove the “#” (or uncomment) the proguard configuring statement in project.properties. Which will be in commented initially.
Customize it. try this link http://1belong2jesus.wordpress.com/
I have some configuration I want to save it in my Android application and read it whenever I need , for instance, the server URL that it should try to access like that.
Is there any similar mechanism like web.config in ASP.NET available in Android?
A central configuration file that can be set up manually and then read by the application? Any help would be appreciated!
We use a .properties file in assets folder. It works out very well for us as we support multiple carriers with this, write to it (in case some values, sent from server, need to change. This is done at app start time, thus making our code configurable from server).
You can throw things like that into your strings.xml file. But, since you can't actually modify these values in real-time (since it's a distributed application rather than running on a server), throwing it into a constants class is quite acceptable.
Use Shared Preferences.
Here's a link Shared Preferences
You can use sq lite database files for it. You have a native API to read and write those and on top of that a command line tool.
If you want to create an XML file instead, then it's no different than any other xml file (unless you are thinking about the Shared Preferences, which use an xml format to save the data, but I believe it's not the best API for your application).
I was stumped on this too, but came across Managed Configurations in the Android documentation.
Managed configurations, previously known as application restrictions, allow the enterprise administrator to remotely specify settings for apps. This capability is particularly useful for enterprise-approved apps deployed to a managed profile.
It allows you to set a default value in case you rather not getting into the enterprise admistration business but leaves that option open for the future.
There is a caveat. This only works if your app is registered for EMM. Otherwise you will retrieve an empty map of restrictions.