Android - Multiple .apk file from single code base - android

I had developed 3 applications in android where the major functionalities are the same but the UI looks different. Images and the background color of the screens are different.
NOw, i want to create a single code base from which i can generate multiple .apk files for the 3 apps.
I tried creating 3 different packages for src folder for the 3 apps. But i dont know how to set the res folder for these apps.
Need pointers on creating a single code base from which we can generate multiple .apk files which includes only the respective src and res folders.

Use an Android Library Project that contains all your common code.
Create separate Android projects that reference the Library Project (you will need to copy your Manifest into each of these and make sure all components are declared with their full Java package name).
Put any resources specific to each app (drawables, colors etc) into the individual project resource folders and they will override similarly named resources in the library project at build time.

i think the best option is to use ant, you'll need to add an ant target for each build and change the resource folder.
if you use the generated build.xml, the res folder is defined like this
<property name="resource.absolute.dir" location="res" /> so you'll want to override that

Can't you put all of your common code into a library project and then just reference that project from each of the 3 unique projects that each contain the relevant resources.
Update: This answer is now obsolete when using the Gradle build system.

Why don't you use a single application, that does three different things based on SharedPreferences values set by the user, or from context at install time. If you really want to separate, you can have three different activities, and you decide which one to launch from a silent main Activity that redirects to either of the different ones.
An alternative is to have a unique activity that inflates itself dynamically from 3 different layouts at onCreate time.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (...custom check for layout... equals(layout1)) {
setContentView(R.layout.main_layout1);
} else if (... equals(layout2)) {
setContentView(R.layout.main_layout2);
} else if (... equals(layout3)) {
setContentView(R.layout.main_layout3);
} else {
throw new IllegalStateException("Unknown layout!");
}
... your onCreate stuff....
}
It will make code maintenance easier (only one code source to modify, only one version-list and changeset to maintain)
Check here:
How to use SharedPreferences in Android to store, fetch and edit values

I would suggest using Gradle flavors.
It seems to explain all the basics really well. I just finished converting to Gradle today, and it works great. Custom app icons, names, and strings, etc.
As the website explains, part of the purpose behind this design was to make it more dynamic and more easily allow multiple APKs to be created with essentially the same code, which sounds similar what you're doing.
Also see a recent question I had, referring to your project structure and using custom code for each app.

Related

Is it possible to use strings.xml from one localization values folder for another similar language?

I've been looking on Internet for this but didn't find any article/blog (probably I have been looking poorly) so I'd decided to ask question here: is it possible to use same strings.xml (translations) from one language folder for another language, which is very similar? To be more specific, I'd like to use translations from values-sk also for values-cz language.
I was thinking about writing a Gradle script which would make a copy of strings.xml file in values-sk folder and copy it into values-cz folder on build, but I'd like to know if there's an easier/out of the box solution.
Well, I solved it using Gradle script before build. In case someone's interested, I added new task in app.gradle (at the end of the file, but that shouldn't matter):
gradle.projectsEvaluated {
preBuild.dependsOn(copySkStringsFileToCsFolder)
}
task copySkStringsFileToCsFolder(type: Copy) {
description = 'Copies strings.xml from values-sk to values-cs'
from 'src/main/res/values-sk/strings.xml'
into 'src/main/res/values-cs'
}
From what I overview, it copies the file on every Sync/Build operation - works pretty neatly for me, but I am still interested in other possibilities (if there are any).
Also I would like to apologize to Czech people that I misinterpreted the code for values folder (using -cz instead of -cs) - sorry 'bout that, I didn't know I was supposed to use the other one. :)
Create both values-sk & values-cz folder in your /res directory of your project and then copy-paste the strings.xml to each. As you can see, those will be different directories but with the same strings.xml so, it probably should work.
After that, Android will detect that you have two different directory-strings for two different localization then, you can change, modify each one of them (If needed).

Android Modular Programming

My Problem might not be valid. And the points I mention here might be little incorrect as I am neither perfect nor expert.
I have a shopping application and I want to start building a modular application. Like I want to add Affiliate User( the module which adds certain functionality or this will display some extra pages in an application) in the application.
A similar situation happens in the Frameworks: We add and enable the certain module and in return framework load everything as required.
for this, I want following changes like:
add an entry in the NavigationView displaying "Affiliate Label".
load fragments (just adding one more fragment for one more label/option from navigation view).
Let's say I have a library project that contains a Fragment and all relevant code.
How can I build the application automatically let's say just by writing "true" somewhere in the XML?
Automatically here means label is added, Intents are performed on click of label etc.
<Modules>
<enable>true/false</enable>
</Modules>
This is just the simple scenario.
You could do this (like everywhere when it comes to writing code) in many possible ways.
The "file" way:
Make a new file named something like modules.txt with key value pairs. Load the file and check whether a module is enabled or not.
The "Constant" way:
Make an abstract class which only contains public static final variables which describe your modules.
The "package manager" way:
See create Android Application plugins/extensions (apk)
The "multiple" apk way:
Note that this is not reccomended!
we encourage you to develop and publish a single APK
multiple apk support
To add to codewing's answer, you can also use Gradle's resource management capabilities to accomplish this, so you only ever need to look in one place for an enabled/disabled status.
For this, you have 2 solid options.
The first starts with a boolean which can be split by flavor:
<bool name="module_x_enabled">true</bool>
The second would be to inject your values into a String resource after Gradle merges the resources by adding something like this to your build.gradle file, then comparing that enabled value:
<string name="module_x_enabled">MODULE_X_ENABLED_PLACEHOLDER</string>
android.applicationVariants.all{ variant ->
variant.mergeResources.doLast{
replaceInValues(variant, 'MODULE_X_ENABLED_PLACEHOLDER', MODULE_X_ENABLED)
}
}
def replaceInValues(variant, fromString, toString) {
File valuesFile = file("${buildDir}/intermediates/res/merged/${variant.dirName}/values/values.xml")
String content = valuesFile.getText('UTF-8')
content = content.replaceAll(fromString, toString)
valuesFile.write(content, 'UTF-8')
}
Where MODULE_X_ENABLED would be a setting in your gradle.properties file like:
MODULE_X_ENABLED=true
Edit: or better yet,
Why not pull the settings from some kind of server so that you don't need to rebuild and relaunch to update a client's module?

How should a library source file reference a string resource in its parent project?

I have just made my game app into a library so that I can incorporate it into a variety of "wrapper" projects, each with their own manifest file. This is so that I can easily maintain a variety of different versions e.g. free, paid, alternative markets etc.
I also wanted each wrapper to be able to affect the value of various boolean flags like include_adverts or allow_feature_x. I thought that a good way to do this (correct me if this is a dumb idea) would be for each wrapper project to have its own set of strings defined in its own strings.xml. So it could have things like:
<string name="allow_feature_x">true</string>
But now I have a problem scooping these strings from within the library.
I tried this:
boolean allow_feature_x = my_str2bool(getString(R.string.allow_feature_x));
But I get a allow_feature_x cannot be resolve error.
Can this strings.xml thing be made to work? Or was my scheme fundamentally flawed from the start?
This is exactly what I do for many of my projects.
Just make sure your library project has all the default set of strings defined in it, otherwise you won't be able to reference them, since the library does not know about the "parent".
Then override them in your "parent" projects. You only need to override the ones that are different from default, otherwise it will take the value from the library project.
Hope that makes sense.
Edit: By the way you can reference booleans like so:
<bool name="allow_feature_x">true</bool>
and then access getResources().getBoolean(R.bool.allow_feature_x);

How to have code in my Library Project operate on configuration data in my android application?

I have 10 apps based of of one Library Project. I have an activity in the Library Project that shows a list of images. The images are different for every App, and are in the individual project. How can I create a data structure of the image data so that the Library Project activity can loop through it?
CommonsWare's answer seems like a good idea and I would try that first.
Another approach would be to create an empty integer-list inside your library:
<integer-array name="resources">
</integer-array>
and inside every project list drawables that would be actually used:
<integer-array name="resources">
<item>#drawable/res1</item>
<item>#drawable/res2</item>
<item>#drawable/res3</item>
</integer-array>
This way you have a reference to it inside library and can loop over the list, that will override library's empty list.
No code is running on the app that can call any of those APIs or sent anything to with Intents
Then how is your library code ever going to get executed?
If the answer is "I am publishing components that go in the manifest of the hosting app", then use <meta-data> elements in the manifest to allow the hosting app to point you to an XML resource file that contains this configuration information. You can see this with app widgets, searchable activities, and so forth.

what R.java file actually does and how

I have been working on a simple android tutorial and while browsing through the project folders I found this R.java file in gen folder...
When I opened it seemed to me as a mess...
first R itself is a class.
it had multiple Inner classes defined within eg drawable,id,layout,etc.
and that inner classes had lots of variables declared as below which were assigned with hex values
public static final int addr=0x7f080003;
...
...
and much more
R is auto generated and acts as some pointer for other files
Questions for R.java
what it is basically for
how it works
why
values are in hex
what role did it performs while the actual application is running
"Acts as some pointer to other files" is actually absolutely correct, now the question is which files it points to how it is done.
What does it contain?
R file contains IDs for all the resources in the res folder of your project and also some additional IDs that you define on your own (in the layouts, for example). The IDs are needed for the Android resource management system to retrieve the files from the APK. Each ID is basically a number which corresponds to some resource in the resource management system.
The file itself is needed so you can access or reference the resource from code by giving the ID of the resource to the resource manager. Say, if you want to set the view in the activity, you call
setContentView(R.layout.main);
main in the R file contains the number which is understood by the Android resource management system as the layout file which is called main.
Why is it better than just plain file names?
It's harder to make a mistake with the generated fields. If you write the field name incorrectly, your program won't compile and you will know that there's an error immediately. If you write an incorrect string, however, the application won't fail until it is launched.
If you want to read more on this topic, you should check the Android documentation, especially the Accessing Resources part.
This holds your resource ids. So when you do something like
TextView tv = (TextView) findViewById(R.id.mytextview);
it looks up your id here for that View, layout, etc... This way the app has an easy way to look up your ids while you can use easy to remember names. Anytime you create a resource it automatically creates an id for it and stores it here. That's why you never want to try and edit this file yourself.
One way to think about how valuable R.java is, imagine a world without it. Its amazing how android brings the xml and java world together to help avoid coding the UI manually completely. With legacy java building UI using the java language was a pain. Invaluable.
With Android you can not only build your UI using only xml, but also see it while you build it. Invaluable.
Every element in the xml can be referenced in the java code WITHOUT writing a single line of code to parse the xml :). Just R.id.nameOfElement. Invaluable.
Rapid development is beautifully done in android. Imagine if iPhone would have 5000 screens to fit that one piece of code, they would crumble on their XCode. Google has done a wonderful job with just R.java. Invaluable.

Categories

Resources