I have different configurations for my Android project (e.g. google, amazon). Gradle allows generating BuildConfig parameters, that can be checked at runtime, but this isn't what I am really after. I want to have a particular code (method, class, etc) to be present or absent (not just bypassed) in the project, depending on configuration.
This is how I implement that in Eclipse. I have a folder in an Eclipse project (named e.g. platform-specific), not included in BuildPath as well as several Ant scripts (make-google, make-amazon), that copy relevant files from platform-specific folder to src folder and delete irrelevant files from src folder.
Since Eclipse provides an Ant window to view all scripts, I can run a particular script and reconfigure the project to suit chosen configuration.
Is there a way to do that in Android Studio? I know that Gradle allows running and even importing an Ant script, but it isn't a convenient as with 'true' Ant, and I can't find a way to choose a script to run. Maybe Gradle provides its own way to do that?
For two flavours it will work, but if I have say 3 flavours, module 1 appears in flavours 1 and 2, module 2 in flavours 1 and 3, will it mean replicating those modules in each folder? So, every time I modify a code a such a module, I need to replicate the modification in another folder.
Not if you organize your code.
You appear to be using "modules" generically. Android Studio has a specific definition of that term (what Gradle refers to as sub-projects). And you can leverage those to help your cause.
Suppose that you create google, amazon, and yandex product flavors. Then:
Any code that is common to all three goes in src/main/.
Any code that is unique to a single flavor goes in that flavor's source set (e.g., src/yandex/).
Any code that is shared by two flavors goes into a library module that is added to the appropriate flavors using flavor-specific dependencies (e.g., yandexCompile and amazonCompile).
In all cases, there is one copy of your code. Whether it can go in the application module (e.g., app/) or goes into a library module depends on which flavors need that code. For a scenario like this, dependency injection will help you manage what code then gets wired together for each flavor.
Related
I am preparing a white label application (called product later in this post) and I want to set up a very good architecture. This will easily and quickly set up a new client by changing the design, activating features...
I have several servers (dev, pre-prod, prod) so the flavorDimensions server are present in the product and the flavorDimension client is on the client side.
I thought of this solution:
Set up one git per customer and one git for the product.
Clients will have access to the product code by git submodule. This allows me to separate the specific code from my client and the source code of the product.
Git -> Client 1
Submodule -> Product v1
Git -> Client 2
Submodule -> Product v1.2
...
Git -> Product v1.4
But I have a problem how to run it all correctly. The use of flavorDimensions client is hard because I need to make a copy-paste (with gradle) from my submodule to the app module before the build.
The generation of this structure breaks Gradle because its need to be synced every time. (Always Sync Now flag on Android Studio)
So I ask myself, is a good architecture or not ? What do you think ?
Or do you have other ideas and how to implement them?
Thanks for your support.
Hmm interesting take on it.
I have done similar things, but not quite like that. I use flavors for the deltas only. For example, themes, skins, app_icons, and Strings.xml. Maybe a few variations in layout or activities, but do my best to keep it generically served to minimize the maintenance of the code for various customer deployments as each additional flavor slows down the CI process significantly.
However, one key difference in what you are doing is you are not building a platform (aka everyone uses the same code GIT repo and API Server per se, you are building stand alone applications to supply full code and everything else to individual customers.
This sounds like it could be a maintenance nightmare, but if your situation requires that customer's get access to the code base for their product flavor, then I guess it makes sense. Not sure why they would get access to the code though as it is your product you are reskinning for customers right?
At any rate, you aren't asking for me to ask your reasoning haha, you are asking about architectural solutions. So here is my thoughts.
Make a task that copies the respective folders into a new module structure exactly like the modules you have now, but with changes to the package name so that they all slightly differ, then run your GIT push. You can run bash files from Gradle, so you can either write scripts and execute them from relative paths or you can write it directly in your Gradle file itself.
So I would update my Gradle to have separate dependency file like libs.gradle
->Put dependencies in that file like ext.libs {gson:"com.whatever:version"}
->apply from ../libs.gradle
->dependencies { libs.gson, etc..}
So i would assume your build task would do
->Create a new Module from All Source by copying files properly with new names if necessary to rename
->if using maven server, then deploy aar or jar for compiled new module
->Create a new dynamic Gradle file libs.gradle to replace current libs.gradle file that is updated source pointer to deployed artifacts
or created module
->run gradlesync, when complete run assembleRelease, then you can do your git push etc..
All of this can be synchronized and done from terminal and localized into commands. Flavors may not help a ton in this area as they are part of the build process so you kinda need pre build processes which you can create tasks to do pre-build, but the key is the packaging of dependencies and updating your libs.gradle file and making sure that you replace it per flavor. Or if you have fixed flavors you can just make a specific libs.gradle for each flavor and update it based on the compiled dependencies.
I don't know your overall picture, but it is all doable. Hope that helps. Goodluck.
I have an Android Studio project
which consists of a login activity with relative style, manifest, IntentService and other stuff.
I want to insert this little project in many other apps, what is the best way to proceed ?
Is Module the right way ?
The ultimate goal is still to easy maintenance, such as if one day the server should change URL, I would not have to make changes in any application that uses this login activity :-)
You need to extract these components in a separate module:
A module is a discrete unit of functionality which you can compile,
run, test and debug independently.
Modules contain everything that is required for their specific tasks:
source code, build scripts, unit tests, deployment descriptors, and
documentation. However, modules exist and are functional only in the
context of a project.
Then, include that module in all projects using it.
In fact, you can create the module in an independent "library" project of its own. And add it as a dependency for all projects using it.
Going a step further, you can publish the output of an open source library project as .aar or .jar on maven central, jcenter and other public repositories. Then other people will also be able to use your module.
Some important points to remember when creating android library projects:
The resources (strings, layouts, xmls, images) of a library will be merged with those of final project on build. Still your module's R class will stay under your module's package name.
Some attributes from manifest file of library might be merged to that of final project (like that of <application> ). So, a library module should have a minimal manifest file, with at most, the package name.
You may include an example application project inside a library module, but do not redestribute the example app project with library. It will cause trouble for someone building an application using your library.
I think that what you need to do is to export your original project first:
File>>Export
Then go to your new project and import the original one.
Dont forget to amend the setContentView() method to point to your original activity(the one you imported)
and finally dont forget your intent method!
if you have any issues let me know and i will create a detailed answer for you but i think that you will be ok!
I have started working on a project where I will need to share a bunch of Java classes across a bunch of apps. In Eclipse it was possible to create one project with all such classes and use it as a library in a workspace with all your dependent projects, but in Android Studio it doesn't seem possible to do so (At least not easily).
I have been reading a bunch of posts and a lot of them suggest setting up a library project, generating an aar file and then using that in my projects. But, as I understand it, this will make my library open-source (Am I right?), which I don't want. I am doing this for a client and I want the code base to be private.
Also, I know that a module can be imported into a new project. But this creates a COPY of the original module. This is not what I want at all. I don't wanna maintain multiple copies of the same classes, which completely defeats the purpose of 'code sharing'.
Is there any good way of achieving what I am looking for? Any help is appreciated.
You have a couple different options.
One option is to maintain your libraries as separate projects and compile them to an archive format, such as JAR or AAR; JAR files are for pure Java libraries, and AAR is for Android libraries (which contain code that accesses Android APIs and/or has Android resources). As was pointed out in the comments, AAR doesn't force you to publish your code to the world any more than JAR files would; it's just an archive file format whose files can be local to your machine or your organization.
With that archive file in hand, you can include it in other projects. If you're part of a multi-developer organization, you may find it convenient to use a repository manager to publish and maintain those libraries within your organization, and you can use Maven coordinate-style specs to include libraries in your projects, which you don't have to manually copy over to your development machine.
The disadvantage of this approach is that it makes it a little harder to make changes to those libraries: you need to load up the project, make changes, build an archive, and distribute the archive.
The other approach is to keep the library as a source module like you did in Eclipse. You observed that Android Studio will make a copy of the module if you import it via UI, but if you bypass the UI and modify the build scripts directly, you can do what you want, which is to use the module in-place and share a single copy among multiple projects. To do this, work in your settings.gradle file and add this:
include ':module_name'
project(':module_name').projectDir = new File(settingsDir, '../relative/path/to/module')
I would strongly encourage you to not use a pure relative path here; in this example, the path is anchored to the settingsDir variable supplied by Gradle, which is defined to be the directory where settings.gradle is found. If you use a pure relative path (i.e isn't anchored to anything), you're dependent on the working directory being the same in all environments where the build file is run (command line vs. Android Studio vs. CI server), which isn't a good thing to assume.
You need to think in the eclipse projects as Android Studio/IntelliJ Idea modules. Then, you can generate android (or java) libraries and then include them in your project.
To mark an Android Studio module as a library you can go to File -> Project Structure -> Facets and there click on Library Module
I was in same situation as you, and i founded an approach using git.
Steps to do, to have library:
Create project in Android Studio.
Create android library module in that project.
In that library module create git repository.
Add modulename.iml in .gitignore file
Use GitHub or Bitbucket for private cloud repository. and push your library to it.
Create new android library model in any project that you want.
Close Android Studio (not sure is that mandatory).
Using explorer go to your created module folder.
Remove all data in it, except modulename.iml.
Clone your library from "GitHub" into it.
That's all.
Now you are able to use library in multiple project whether you are at home or at work. Just after finishing you work not forget to push library changes. And after opening new one pull them.
I think you can automate this thing somehow.
The benefit is that you don't need to build any jar, or aar.
You can certainly create and use a library without making it open source or available to others.
First, you don't need to make it an aar unless it contains Resources.
If it's just plain classes, you can just make it a .jar file.
Either way, the easiest way to share these libraries (either aar or jar) is to set up your own repository. Nexus and Artifactory are the two most common repository managers.
You keep the library in its own project, and then publish it to your own, in-house repository.
Then, projects that need to use the library are configured (in gradle) to use the in-house repository, and get the library from it.
I have an App that is produced for different brands. Now I have two flavors, brand1 and brand2. The difference between brand1 and brand2 are only the resource files.
First I assumed I could set all shared data into my main path and the differences into the flavored path. But in this scenario my build failed, because resources in my main path are missing.
I would go on like this: set all resource differences between the brands in the main path as dummy data. The merge will do the rest for me.
In iOS I can set a build path for each build target.
Is something like this possible with flavors? Or what is the best practice in this situation?
[EDIT 2013 08 07]
The problem in my case was that I created the app in eclipse and exported it to android studio.
Here the problem and solution is described more precisely.
Another solution is to put everything shared (basically the a "vanilla" version of your app) as a libary project, including default resources.
Then you can create seperate "brand" projects that use the library project. Any resources you put in these will "overwrite" the library project resources.
http://developer.android.com/tools/projects/projects-eclipse.html#SettingUpLibraryProject
I've done this for clients and it's worked quite well.
I have an Android code base which uses APIs with settings to get different data for several apps. All apps use the same code base but with one or two design tweaks. So how do I re-use the main code base without having to copy the whole Android project each time?
iPhone uses multiple targets in the same project which works well. If android cant do this do I need to compile binaries of the code base in one project and then import into each new app project? If so how? I'm using Eclipse and am an intermediate Java developer.
Any help much appreciated!
Doug
Check out "Working With Library Projects" from the Android documentation. This should be just what you're looking for: http://developer.android.com/tools/projects/projects-eclipse.html#SettingUpLibraryProject
The current way to approach this issue if you are using Android Studio with Gradle is by using Gradle, Build Type + Product Flavor
http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
Build Variants
One goal of the new build system is to enable creating different versions of the same application.
There are two main use cases:
Different versions of the same application
For instance, a free/demo version vs the “pro” paid application.
Same application packaged differently for multi-apk in Google Play Store.
This new concept is designed to help when the differences are very minimum. If the answer to “Is this the same application?” is yes, then this is probably the way to go over Library Projects.
Note: This answer is basically obsolete now that one can create .aar libraries with resources. It still works, though, and there may be times when the portability of a .jar is desirable, so I'm leaving it here.
Blumer's answer is a good one, and you should definitely look into Android's idea of library projects. However, there is another alternative. If you have a module that contains only Java code, but no resources of any kind (images, layouts, etc.), you can compile it to a .jar file separately and use the resulting .jar in multiple application projects. It works like this:
Create a new Java project in Eclipse (not an Android project) and move the source code of your module there.
If your module references any classes from the SDK, you'll need to add the Android SDK .jar to the project's classpath (Project > Properties > Java Build Path > Libraries > Add JAR).
When your module is ready to use, bundle up its .class files into a .jar. You can do this manually, or you can look around to figure out how to get Eclipse to do it for you.
Copy your module .jar file into the "libs" directory of your app's main project.
Add the module .jar to the project's classpath (again, Project > Properties > Java Build Path > Libraries > Add JAR).
Now you should be able to build multiple apps using the same .jar, while maintaining only one copy of the module's source code.
Depending on your particular situation, this may or may not work any better for you than the standard Android library mechanism. But it's worth considering as an alternative.
The Android documentation recommends another approach if there aren't too many "different APIs" used.
The idea is to use reflection instead of making direction references to the code. Make sure to use optimized reflection instead of lookups every time.
References
http://developer.android.com/training/multiple-apks/api.html
http://developer.android.com/google/play/publishing/multiple-apks.html#ApiLevelOptions
You might want to consider using a source control system like Subversion (or GIT). Keep your most feature complete version in the trunk, and make branches for your separate versions that use different data sources or require minor layout changes, etc.