Now Solver was written to solve the corporate world's problems. But it has been so successful, you decide to make a slightly different flavor of the application to solve household problems.
So you want two flavors: Solver Enterprise, which you have, and Solver Domestic, which you are creating from the Solver Enterprise code base.
Hey, I've got an idea...
You discover that the same code can support both apps, and you want to build each flavor just by flipping a couple switches in your project config files.
Now here's the nub. Odds are you've got some domesticated corporate types who will want both flavors installed on the same Android device.
Oh, yeah, that's a problem. And Solver can't help you. (Solver can't solve its own problems. Godel's Incompleteness theorem, etc...)
Your AndroidManifest.xml file looks something like this:
<manifest android:versioncode="1" android:versionname="1.0" package="org.inanity" xmlns:android="http://schemas.android.com/apk/res/android"> <uses-sdk android:minsdkversion="10">
Package Blues
Notice that attribute: package="org.inanity"
Android does two things with this package name. First, it uses it to uniquely identify your application. That means org.inanity becomes your Linux user id and, therefore, also your app's directory in the file system: /data/data/org.inanity.
So what? Well, if you want to install two flavors of the same app, you probably don't want them sharing the same configuration files and databases. So you have to do one of three things: 1) name everything according to its flavor (e.g., solver-domestic.db) -- including SharedPreferences files -- or 2) have a different package name for each flavor, or 3) move all of the shared code (which is just about all of it) to a common library.
Sounds easier and cleaner just to use a different package, right? Well, er, no. It's not -- because of the second thing the Android SDK uses that package name for (by default): the package of your resource class: R.java.
If you change the package in the manifest to, say, com.inanity.domestic, most of your code will not compile because it's importing com.inanity.R, not com.inanity.domestic.R.
So now what? Well, it's actually pretty easy just to turn your app into a "library" and create a couple of new applications that reference it. Each has their own AndroidManifest.xml, with unique package names. See the TicTacToeMain sample app to see how that's done.
Really all you have to do is add one line to your default.properties file:
android.library=true
I put "library" in quotes above because the Android SDK doesn't actually build a library artifact -- like a jar or apk -- from your "library" project. Instead, it lets other projects put their grubby little fingers into your project and use its source and resource files directly. It's source-code re-use, rather than binary re-use. So don't plan on versioning them independently.
That may seem terrible, but in our case, it's our own grubby hands, reaching into our own cookie jar to get our own crumby cookies.... so, what the heck... me want cookie !!!
If you're in Eclipse, this also means the projects will have to be in the same workspace. Meh, okay.
Once you've created your new application projects, just add a reference to the library project via your project properties.
That's all there is to it. The library option is really the best solution.
If you choose the file-naming option instead of the "library" option to solve the original problem, you'll quickly run into a likely-fatal limitation: You cannot install and uninstall or upgrade the flavors independently. It's really just a single app, not two, as far as Android is concerned. The best solution, therefore is the "library" solution.
No comments:
Post a Comment