I have a project with following locale values directory:
values
values-en-rHK
values-en-rTH
values and values-en-rHK contains:
<string name="currency">$</string>
values-en-rTH contains:
<string name="currency">฿</string>
After the APK is compiled, it removed the currency key from the values-en-rHK directory. I have verified this by decompiling the APK and looking into the resources.
This causes the app to show ฿, even when the locale is en-HK. Also noticed that all the strings with same text as in values were removed from values-en-rHK in the compiled APK.
Your localized directories are not named correctly. They should follow the pattern specified here:
<resource type>-b+<language code>[+<country code>]
I'm not entirely sure what you were attempting, the following could possibly work:
values
values-b+en+HK
values-b+en+TH
Values that are identical in different localization versions may be removed when compiling the APK, since there is no point to have the same value in multiple resources.
Related
I need to parse string resources at the project build stage.
Before the aapt2, I did it like this. Now with the advent of aapt2, resources are collected in the *.arsc.flat format. Disabling apt2 is not suitable as a permanent solution. How can I parse resources in this format?
The correct way to do this would be to parse the output APK and get the symbols from it.
However, it is a lot of work and if you just want a hacky quick-fix you can instead inspect the R.txt file that's output by the process<Variant>Resources task. It's basically a list of all the resources in the project, including all the strings. The format is a line per resource in the form of:
<java type> <resource type> <resource name> <resource ID>
So you need to find all the lines with:
int string some_string_name <ID>
Our app name is defined in my build.gradle flavors as
appNameFlavor{
resValue "string", "app_name", "MyApp"
}
This is necessary due to a trademark issue in another country.
The name is also used a lot in our strings.xml file by using
<!DOCTYPE resources [
<!ENTITY appname "MyApp">
]>
<resources>
<string name="activity_intro" translatable="true">&appname; Tour</string>
</resources>
This is not ideal because the string is hard coded and needs to be switched for every flavor.
I tried using #strings/app_name instead of MyApp in the entity and while Android Studio actually rendered it correctly, the build failed.
There are several StackOverflow answers mentioning that I should use <!ENTITY % ents SYSTEM "./res/raw/entities.ent"> instead and simply create those files for each flavor, but the file cannot be resolved.
How could I solve this issue of having a variable app name without putting all the strings that reference the app name into a flavor specific strings.xml file, preferably sticking to the way the app name is currently defined?
The first error I got was the String.xml file contains more than one items with same name. It seems to be a common pattern across almost all the system apps you can check it here
The string value will have this format:
<string name="photoPickerNotFoundText" products="xxx">string value</string>
where xxx could be "tablet" or "default", etc.
How could I set up the Gradle to get the project built on my machine?
Thank!
UPDATE
I think that the solution is using the --product option of the aapt (android asset packaging tool). The current gradle android plugin doesn't support this aapt's option yet so maybe modifying the plugin could be a work around.
Every string should be identified by a unique ID. So you could not use same name for every string.
For example the below code wouldn't allow the gradle to build the project
<string name="abc" products="xxx">string value</string>
<string name="abc" products="xxx">string value</string>
Change one of the string ID as shown below
<string name="abc" products="xxx">string value</string>
<string name="def" products="xxx">string value</string>
Update: "You cannot use same string name while building from Eclipse. This type of naming is used only for building apps preloaded on platform. The correct string resource is preloaded according to PRODUCT_CHARACTERISTICS defined for a specific target build."
Reference: Android resource for a specific product
I am using to DexGuard to process my android applications.
On DexGuard's Homepage they say it features: XML resource obfuscation
I already tested DexGuard and decompiled my output .apks with apktool.
The problem is ALL resource files are decompiled succesffully, so they have not been obfuscated apparently.
Now my question is, does DexGuard automatically obfuscate XML resources or do i have to activate it somehow in my dexguard-project.txt file?
Is it possible to obfuscate XML resources like strings.xml or am I misunderstanding this feature?
Why do you want to obfuscate strings.xml? is it because you have api keys or oauth secrets in there? If so, then better to move them to assets/config.properties file and load to a java.util.Properties object like this...
Properties appConfigProperties = new Properties();
appConfigProperties.load(context.getAssets().open("config.properties"))
String myApiKey = appConfigProperties.get("my_api_key");
(for brevity I've removed the exception handling)
Be sure to enable asset encryption in your DexGuard config file:
-encryptassetfiles assets/**
I received the following statement from DexGuard:
Resource XML files are obfuscated automatically in release builds,
although the differences may be subtle. You can compare the
differences with for instance aapt d xmltree application.apk
AndroidManifest.xml. We are working on more obfuscation of resources
for upcoming versions.
After executing the proposed command aapt d xmltree application.apk (where application.apk is a simple HelloWorld Application) i finally could see what DexGuard actually obfuscates in XML files:
Each attribute in an XML resource file is identified by a name, but often also by a numeric identifier.
In AndroidManifest.xml for example:
android:versionName(0x010102lc) = "1.0"
In the obfuscation step, DexGuard can remove the name of an attribute, but only if this attribute also has a numeric identifier.
After DexGuard obfuscation the above attribute will look like this:
:(0x010102lc) = "1.0"
As XML elements of strings.xml for instance only have a name and no numeric identifier, there won't be any differences in the decompiled XML file.
In my Android app I:
generate an incrementing build number (integer) using a script as part of my build (uses Integer from SVN revision)
I generate an Android resource file with it defined as an integer:
399
I show that on the UI using the resource generated above
I reference the integer in the Manifest for the versionCode element
All that works fine, but when I attempt to upload to Market I get this error:
"The file is invalid: ERROR getting 'android:versionCode' attribute: attribute is not an integer value "
Question:
For Market, does the versionCode have to be a "literal" integer directly inside the manifest, or is there some way to reference an externally generated integer and not be touching my manifest all the time (manually or automatically).
thanks
(BTW: I have just realized that scheme might cause me issues with patch releases, so I will probably generate a bigger number or something, but would still like the answer to this question)
In the end, this is what I have done:
I create a tag in my version control system with the numbe rof the release in this format
X.YY.ZZ where they are all integers, like 1.20.00, and reserve the last two digits for unplanned patch releases maybe made on a branch after a later release is made....
So if I release 1.20.00 then 1.23.00, I can still go back and do a patch release to 1.22.00 called 1.22.01.
I have a build step that gets the tag name and generates a string resource "1.22.00" for Android that I use in the UI. It also generates it as a number 12200 and I use this as the version number.
BUT, I don't try and include this version number directly in the manifest, I set it for the package by setting an ant property for version code that the ant build picks up if defined and uses to create the .apk.
So I get an always increasing integer for Android Market, but a user with an older version can install a patch release, but you cannot install a patch release if you have a newer official release.
i.e. if you have 1.20.00 you can install patch 1.20.01, but if a user has moved onto 1.23.00 they cannot install the 1.20.01 patch...
To set the property you can use;
project.setProperty("version.name", versionName);
project.setProperty("version.code", versionCode);
if those properties are set, then the Android build system (both old and newer) will pick-up the property value and use it, no need to do anything else special.
Just make sure you set it using one of the pre-build/pre-compile ant extension points.
In the new build system (Platform Tools >= 12) in custom_rules.xml I have added
<project name="custom" default="help">
<import file="build_info.xml" />
<target name="-pre-build" depends="build-info" />
</project>
where build_info is my own ant project that calculates the version name/number from the Tag name (if you are building in a tag....).
From everything I've read, Google Play currently requires android:versionCode to be a 32-bit integer, not a resource. Like you, I also initialize android:versionCode with an #integer resource.
To work around the market's limitation, our build script parses the #integer value and injects it directly into android:versionCode for release builds. This was a simple solution for us. There's far more involved ways to achieve this using ant.properties and the build.xml -pre-build option, however, that is beyond my needs.
For more on that, see:
Reference an integer resource for Android manifest versionCode
https://groups.google.com/d/msg/android-developers/1dt0yxyNPsk/c9c6PlG84iwJ