I have an app which is going to have multiple instances. The instances will differ in some resources, which can be divided into two groups:
differs only in (un)commented code, whole code is present
colors
strings
small differences in layouts (e.g. in one instance some components will be gone, in another instance they will be visible, but code remains)
complete substitution (name, files)
package name
drawables
certificates in res/raw (all certs mustn't be stored there, only for particular instance)
What is the best approach to deal with these requirements? Use different git branches?
I use git (smartgit client). I guess that all requirements could be met when I use different branches for different instances. But I am afraid that this approach won't work for second group - complete substitution (name, files). Any suggestions?
PS: I understand that When adding new features I need to merge from some master branch into all other branches.
After all git approach wasn't that right. Building multiple app instances (product flavours) with Gradle was just the right thing to do:
1) Specific files and resources per the instance of app
colors and strings are located in resource files: Project/module/src/instance_name/res/values/instance_name_cfg.xml.
layouts are located in: Project/module/src/instance_name/res/layout/instance_name_cfg.xml
Java code is located in: Project/module/src/instance_name/java/package.name/MyClass.java
drawables (PNG images) are located in: Project/module/src/instance_name/res/drawable/, ic_launcher images are in the same path only in different folders (drawable-hdpi,...)
Common files and resources are located in Project/module/src/main/ folder.
2) In the first picture there is the whole file structure.
Instances are in my case cities (Dammam, Jeddah, Prague, Reading). Screenshots are taken from Android Studio, where you can switch build variants (flavours) - at the bottom of the picture.
3) In the second picture there is a fragment of the build.gradle file.
Mixing app (instance) resources is quite powerful. As you can see in the picture below, resources, java files and even manifest files could be combined together in directive sourceSets. For example Dammam and Jeddah have the same java files, some common resources and specific resources per instance. Using name of instance (e.g. dammam) in sourceSets must precede declaration in directive productFlavours.
Related
I know there are two well-known folders where one can put resources.
The first is the /assets folder, the documentation says:
Contains file that should be compiled into an .apk file as-is. You can navigate this directory in the same way as a typical file system using URIs and read files as a stream of bytes using the AssetManager. For example, this is a good location for textures and game data.
The second is the /res folder, the documentation says:
Contains application resources, such as drawable files, layout files, and UI string. See Application Resources for more information.
Now i was wondering, there is a third option to create a resource folder "New > Folder > Java Resources Folder"
To me i looks like some part of the Android Plugin in IntelliJ because it has a little Android symbol in front of it .
Any ideas what the use of it could be? I couldn't find any documentation about it.
My first guess would be to use it in situations where you want to supply resources to a JVM Test.
In standard java world
Resources can be embedded directly in "your source tree" and used with Class's method getResource (see java documentation for a more precise description).
In android world
This practice is not recommanded (do not work at all, because such resources are removed from generated APK). You can still declare Java resources folders (see build.gradle :
sourceSets {
main {
resources.srcDirs = ['src/main/java/yourresourcesfolder']
}
}
And the result in the apk :
Conclusion
As resources's folder tree is removed,using java's resource folder become from my point of view, useless (in an android projet). Using android's asset folder is a better choice (also avoid resource's name conflict, but it's an another story :D )
This post is a bit old, but I want to bring an answer that explain one use case for the java resources directory on Android. If this folder exists in the options of a project it's because something can be done with it...
Enters the Service Loader, that helps to connect other services (aka libraries) into your main app, it can be used as a Gateway for your Android library to extend the functionality of a feature, exposing only the interfaces or abstract classes, with the Service Loader providing the implementation instead of your project having direct access to them.
Here is an example of how it's implemented. So, in summary the folder (META-INF/services) and files you have to create in order to use the Service Loader on an Android App, NEED to be inside this Java Resources Folder, otherwise your provider won't be able to see any implementation.
You can see it working in my sample here if you want to check it out: https://github.com/difereto-globant/test-library-feature/tree/1.0.9.
TL;DR
I'm an android developer and I have essentially several copies of the same app that feature slight differences. Despite my best efforts I'm having to resort to copy-and-paste style modification for each app-copy (hereafter "flavor") whenever I need to roll out a single change to all of the apps. This is particularly heinous in Android because of the number of languages/file-types involved in a given app - C for native code, Java for regular code, .xml files for data, layouts, and os permissions, etc. Tricks I know to avoid copy-and-paste coding that work in Java or C alone won't extend to both at once, or over to the .xml files. I've been using Apache ANT with some success to create a custom build/ folder on the fly and include relevant files there for different build-targets, but it's a little cludgy, and there are some cases it just can't handle.
I'm wondering if there is a build system that could handle all of this for me; I'm open to any advice, though the solution I have in mind is particular to a sort of language-independent/filesystem #include approach, which for a given flavor at build time injects either whole files into a src/ tree, or else injects code fragments into various .java, .c, and .xml template files in that src/ tree.
A Really Long Explanation with Concrete Examples:
Examples of the differences between flavors: in the Google Store I have to use the Google in-app purchasing sdk; but in the Amazon store I have to use the Amazon in-app purchasing sdk. Different flavors are paired with different advertising partners. Certain flavors require different i18n language files; or graphics and layout assets for different devices; etc. etc. Any given flavor is essentially the base code, plus any number of these "add ons", where each add on requires a little bit of custom code and file additions to the src/ tree for that app. Whenever I need to change an add-on, I end up having to copy-and-paste the change in each flavor of the app that uses it, which is a terrible pain.
As a concrete example, imagine I have an android game and I have implemented a custom Flurry Appcircle ad view. This would typically involve the following:
The addition of "<activity>", "<service>", and/or "<uses-permission>" tags to the game's AndroidManifest.xml
The addition of various "<string>" lines for the ad in the apk's res/values-xx/strings.xml folder system, where xx is a language code (ie Spanish translations would go in res/values-es/strings.xml)
One or more image or layout resources in res/layout, or assets/, for the ad.
The actual Flurry Inc sdk in the form of a Java .jar file in libs/ - possibly multiple jar files if different hardware architectures need to be handled differently.
Java Code in the game's Activity class, e.g. in onStart or onStop, to query for an Appcircle ad and show it. To avoid code duplication, I would normally write this in a base class that surrounds all code in a "if(appcircleAdsEnabled(){...}", create a default implementation of that method that returns false, and #Override and return true in various children Activity classes.
This causes a few problems:
The Flurry .jar is now a dependency for the base class to compile whether or not the ads are enabled or not in any given flavor. I can hope that the builder notices code or resources are unused at build time and removes it from the final apk; but there are no guarantees, and failure leads to (A) bloated final binary size and (B) potential P.R. issues or worse (especially from automated scanners searching for code inclusions - in a slightly different example, I'd have a hard time assuring the Amazon App Store that "yes Google Play Billing is there but it's not used.")
Because of the way Android turns resource files into java constants, and in the same way as (1), the res/* files may also become unnecessary dependencies of all games deriving from this Base Class.
Some libraries/methodologies I've found insist on their code being added in specific places or in specific ways which precludes the base class approach altogether.
For each individual game I still have to at least edit its AndroidManifest to "turn this on" and request relevant OS permissions necessary to show the ad.
It's tedious to remember which "add on" goes with which changes in which files. For instance, in any given flavor's AndroidManifest.xml, I can't keep track of which permissions are needed by which add ons. If I remove the Flurry add on, do I still need the INTERNET permission for something else?
What I'm hoping exists, and what I'm asking about, is if there's some way to inject files and code fragments into/on-top-of some skeleton file system, each add-on composed of a collection of such files and code fragments and injected dynamically at build time, with the build system merging lines across multiple add ons, and handling dependency inclusion on the fly. IE for my Flurry Ad add-on I would have:
Some collection of files 'FILES' that includes my xml additions to various .xml files (like AndroidManifest.xml), my code additions to various .java files (like the Activity subclass), and in some cases whole files themselves to be injected in various places (like the ad layout files)
In some skeleton template file tree, incomplete versions of e.g. AndroidManifest.xml, MyActivity.java, etc. with something like a language-independent #include syntax indicating that data from FILES will go there.
Also in that template file tree, directories in src/ with 'missing files' that will be copied in dynamically at build time from FILES
Some sort of build directive script for FILES indicating what goes where when this add-on is included, to take the skeleton template file tree and turn it into a fully fleshed out build/ tree.
And again, ideally it would be able to handle multiple "add ons" at the same time; ie I might have some FILES for this Advertiser, and some FILES for that billing provider, etc. etc., and a given product is just a list of which modules it includes, the build system magically knitting them together at build time.
This seems like exactly the problem the Gradle Build Variants system was designed to solve - it handles merging multiple versions of the AndroidManifest.xml, resources, and Java packages together into one or more separate apps. Specifically, the Multi-flavor variants seem to cover your requirements for combining multiple features together in various ways.
Gradle is offered as part of Android Studio, an IntelliJ based IDE specifically built for Android Gradle projects. You may consider reviewing one of the many Gradle Build guides if you are not familiar with Gradle.
Why choose one over the other? How are they stored on the phone?
Thanks
With resources, there's built-in support for providing alternatives for different languages, OS versions, screen orientations, etc., as described here. None of that is available with assets. Also, many parts of the API support the use of resource identifiers. Finally, the names of the resources are turned into constant field names that are checked at compile time, so there's less of an opportunity for mismatches between the code and the resources themselves. None of that applies to assets.
So why have an assets folder at all? If you want to compute the asset you want to use at run time, it's pretty easy. With resources, you would have to declare a list of all the resource IDs that might be used and compute an index into the the list. (This is kind of awkward and introduces opportunities for error if the set of resources changes in the development cycle.) You can retrieve a resource ID by name using getIdentifier, but this loses the benefits of compile-time checking. Assets can also be organized into a folder hierarchy, which is not supported by resources. It's a different way of managing data. Although resources cover most of the cases, assets have their occasional use.
One other difference: resources defined in a library project are automatically imported to application projects that depend on the library. For assets, that doesn't happen; asset files must be present in the assets directory of the application project(s).
I have an app on the iPhone and need to port it to android. For this I would like to group screen related files like classes and xml per screen in one "screen group" per screen somehow, ideally also strings and other value files
if I use folders I can only group res files separately and src files separately.
what would be the best way?
Thanks very much!
EDIT:
If that should not be possible, how to best then solve this issue? Do you create a subfolder in the src and another in the res for each screen?
The way you group files for the iphone is not possible for an android project. Android has pre determined folders which hold specific files, if you break this structure, your building process will fail. Its not ideal but that just how it it.
When it comes to source java files, they follow the concept of packages which are basically folders. The 'src' folder is the part where you can create sub folders as you desire. If you are adamant about keeping the files related to a screen in one place, you should create the layouts with java code and not use layout xml files.
But using xml layout files make development much easier and faster. Consider that as the presentation and java files as the logic+data. So group java files as you want and leave xml files in the layout folder with easy to identify names.
android uses certain directory layout for project structures (i.e. convention over configuration). Basically you will want to put your XML layout files in res/layout directory. Please read http://developer.android.com/guide/developing/projects/index.html#ApplicationProjects for further information.
Unfortunately, there's no easy way to do this in Eclipse. You can't create custom directories in your Android app's /res directory, you can only use permitted dir-names. E.g. you can't have a /res/layout-myscreen1 and /res/layout-myscreen2. You also must put your resources in /res, and your code files in packages, so they're at separate places in your project.
You can use Working Sets to group related files together however, but they're quite painful to use IMHO. Check the eclipse docs and tutorials out on them.
I have 3 editions of my android app. one free with ads, one paid and one branded with company CI.
so the difference betwenn them is minimal.
what is the best practice to manage multiple editions of this app.
one project, in code if (editionA) { ... }
multiple projects, reference common code in extra project
or something else ?
Update on the link and detailed description;
1. Library Modules
2. Setting up Library Project
Use an Android library project for the common code, with tiny projects for each specific flavor.
I do something similar with my apps. Common code base, several different sets of resources. I have a python script that copies my generic source from a common location to the src directory, copies the res_project directories to the res directory, updates the package names to reflect the new application package and update the AndroidManifest with the appropriate values.
I felt like there should have been a better way to do this, since your resources are already nicely segregated from your source, but had problems with an application package name that differed from my src package name. I blogged about that process in detail here.
I'd say 2, makes for the most flexibility + you can have different package names so your able to have them all installed at the same time on you device (if you want/need to)
Create a Master activity that has all the functionality, use sub activities and layouts for the 3 types of access?
This way you only have to maintain 1 project and core functionality.
Just have an initializer on start up which detects which activity to start.