Custom build script to avoid libraries name collisions? - android

When using Android libraries if more than one project (main or libraries) defines the same resource, the higher-priority project's copy gets used and replaces the previous one.
This is a problem when writing a reusable library because it forces you to prefix every resource name to avoid conflicts. See the Android Parcel Project for more information on the topic.
Now what I'd like to do is a script that would, prior to compilation, prefix the name of every resource from all libraries with their package name. For this I intend to use the generated ant build script and add a custom step to it.
Do you know if that would be possible? Do you see a better solution to fix this issue?

Do you know if that would be possible?
If you have source code to the library, I suppose you could do this. Any place you refer to resource IDs dynamically (reflection, getIdentifier(), etc.) would have to be adjusted manually, I suspect. And you may not be able to get assistance from the library author given that you modified their code.
I'd also work on trying to convince the library author to add resource prefixes in future editions of their library.

Related

Can someone actually explain the workings of Resource.Designer.cs?

I routinely have problems during project builds where Resource.Designer gets generated but will no longer compile. My search engine shows that I'm not the only one that has this problem, but I've also not found any reliable "fix" for when it happens.
For example, right now I have a project that works just fine, but if I add a reference to a NuGet library (that I created) then the app will no longer compile because of loads of errors in Resource.Designer.cs.
On another project, I simply upgraded Xamarin Forms and now I can no longer compile, again due to a load of errors in Resource.Designer.cs.
Of course the immediate issue is "how do I fix the errors in these projects" but really I want to understand what is fundamentally going on here. What causes Resource.Designer to get generated and regenerated? What algorithm is used to decide what items get put into that file? Why do we so often end up with a file getting generated that then cannot actually compile? Why is it not getting the references it needs for those items?
I'd really like to understand this at a fundamental level so that once I get past the current thing causing me headaches, I can avoid it in the future when it comes up again (and I most certainly will come up again).
Resource.Designer.cs is synonymous with R.java in Android. Which of course is an application's resources that are referred to by a generated constant Resource ID.
These items are usually defined in your Xamarin.Android's .csproj via:
<AndroidResgenClass>Resource</AndroidResgenClass> (This might be outdated)
or
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile> (Current)
This is part of the Android Build process in which the aapt tooling will generate respective constant resource IDs per each resource defined in your project(res/ - Android, Resources/ - Xamarin.Android). These are then processed into binary form and embedded into the .apk. Thus the Resource.designer.cs is generated after a successful aapt.
It then goes a bit further to define a Resource in a specific Resource Type:
http://code.google.com/android/reference/android/R.html
anim
animator
array
attr
bool
color
dimen
drawable
fraction
id
integer
interpolator
layout
menu
mipmap
plurals
raw
string
style
styleable
transition
xml
Since aapt is called in the Android Build tooling, it is highly recommended to not manually invoke it unless you understand the complete Android build process.
https://developer.android.com/studio/command-line/index.html
As far as an "Algorithm", I don't think it's really that complex other than simply mapping a Resource ID to a resource as defined above. There are some complexities in the sense of Merging Resources in a project. For example a library project -> your application project:
The build tools merge resources from a library module with those of a dependent app module. If a given resource ID is defined in both modules, the resource from the app is used.|
If conflicts occur between multiple AAR libraries, then the resource from the library listed first in the dependencies list (toward the top of the dependencies block) is used.
To avoid resource conflicts for common resource IDs, consider using a prefix or other consistent naming scheme that is unique to the module (or is unique across all project modules).
https://developer.android.com/studio/projects/android-library.html#Considerations
Given the majority of people's issues with Resource.designer.cs, they typically come from a point of view of understanding where actual third-party Resources come from and how they are supported. Here are some tips that I personally use:
Ensure your Application project is compiled against the latest API version. Typically this will be the <TargetFrameworkVersion> MSBuild property. One of my colleagues has an amazing blog post that stands the test of time about this factor:
http://redth.codes/such-android-api-levels-much-confuse-wow/
Find where the Resource is coming from. Does it come from an official NuGet package? When was the Resource introduced into the Android framework? (Useful for mostly Material Design items).
For example, if I had an error message regarding colorPrimary, I might check what API it was introduced in:
Added in API level 21
https://developer.android.com/reference/android/R.attr.html#colorPrimary
Thus we now know we require API 21+ at minimum to use this item.
Take a deep dive into the dependencies you are loading into your project. You can use a decompiler like dotPeek to look through an assembly and see what Resources it's trying to give your project. Additionally you can look at the cache of respective .aar and view it's res/ folder. This is mostly useful for larger bindings like the Android Support / Google Play Services ones. For smaller projects, look for the /res string inside the decompiled .dll
For example let's take a look at com.android.support:appcompat-v7:24.2.1:
First we need to find the cache on our machine:
AppData\Local\Xamarin\Xamarin.Android.Support.v7.AppCompat\24.2.1\embedded\res (If you get stuck here on OSX, I wrote a guide awhile back about finding these paths here - https://developer.xamarin.com/guides/android/troubleshooting/resolving-library-installation-errors/)
So we can now look through all of the respective Resources this library is trying to give to us.
Finally the last item is that people tend to delete the Resource.designer.cs file from their project. After the aapt process is complete, it will generate a new one or it will fail on aapt. It is up to you to figure out whether that step passed or not (i.e. Check the main project Resources folder for the newly generated Resource.designer.cs file so you can re-include it into your project).

How to Use Ant Script replace strings, switch resources folders, auto generate R.java and compile final Apk?

We hope to build multiple applications based on the same source code. The base source code will be stored in SVN so at daily development we just need to modify one codebase.
While for different customers, we hope to given some some level of branding. Mostly changing images and titles, these can be done by just change the resources.
After some research, We find that it is really touch to do these multiple version applications. The main problem is that R.java is generated based on the package name. And package name identify the application. In the source code there are many files import this package.name.R, which means for different application, there will be different package name, and different R's reference need to be change in most source code file.
We find some articles on web about using Ant to do this task, but none of them are really specified. We hope someone could help!
Generally the workflow will be like this:
Changing the package name in AndroidManifest.xml
Go over all source code file, find and replace anything referenced to R to the new package name.
Switch the res folder to the new client's res folder (We will have this folder ready)
Auto generate R.java file.
Start normal compile and build process.
Get Apk.
We hope someone could point out how can we achieve these task by using Ant, or any other better solution.
Thank you!
I think you should create an Android Library Project (http://developer.android.com/tools/projects/index.html#LibraryProjects) with the common code, check it into VCS, and then create separate projects for every customer which you should also check into VCS to keep track of them.
You will be able to generate different customized versions from same source code.

Can I share code & resources between Android projects without using a library?

The standard advice for sharing code & resources between Android projects is to use a library. Personally I find this works poorly if (a) the shared code changes a lot, or (b) your computer isn't fast enough.
I also don't want to get into deploying multiple APK's, which seems to be necessary when I use dependent projects (i.e. Java Build Path, Projects Tab).
On the other hand, sharing a folder of source code by using the Eclipse linked source feature works great (Java Build Path, Source tab, Link Source button), but for these two issues:
1) I can't use the same technique to share resources. I can create the link to the resources parent folder but then things get wonky and the shared resources don't get compiled (I'm using ADT 21).
2) So then I settle for copying the shared resources into each project, but this doesn't work because either. The shared code can't import the copy of its resources because it doesn't know the package name of the project that uses it. The solution I've been using is to access the resources dynamically, but that has become cumbersome as the number of resources grows.
So, I need a solution to either (1) or (2), or I'll have to go back to a library project. (Or maybe there is another option I haven't thought of?)
Your real problem is (2). Fixing (1) would eliminate some copying, but you would still run into problems with (2).
Unfortunately, that really isn't possible. There's a fair bit of fancy footwork that goes on to make multiple packages possible with library projects, and there's no good way to get that same result without library projects. Anything in res/ of a project is accessed via that project's R class, including your copied resources.
The solution I've been using is to access the resources dynamically
I translated that into you using getIdentifier(). That certainly works. Another approach is to having the hosting app supply resource IDs as parameters to the library code -- this is the pattern that the Android SDK itself uses. This is faster at runtime than the reflection-based getIdentifier(), and it gives the hosting app somewhat more flexibility, but you do wind up adding a bunch of parameters to your methods and constructors as needed to supply the various project-specific R values.

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.

Building an android library and passing the client's R.java when making the library call, how?

I would like to build a library and be able to distribute it as a jar without having to give the source. In the library, layouts are used for specifying the UI, however android doesn't seem to facilitate easily bundling a jar and distributing it, as it doesn't properly scope the resources (anything in '/res/*') in this jar file, the references made with R.xxxx within the jar don't work.
I can give the xml layouts and other resources to the client and ask them to put them into their resources directory, thus their R.java would have these references, now, how can the client pass this R.java to the library when invoking a method in the library?
Guess, answer to part of the question would be through answer to 'How to pass class in java?"
Yes, I am new to android and java too.
Thanks,
Krishna
If you have just simple layouts you could also create them in Java and not define them in XML.
It's not so nice but you don't have to distribute some other files.

Categories

Resources