How to maintain two variants of the same app in the market (free / paid)?

I am a bit troubled here: I want to put my game in two variants on the market - a paid and a free version (free one is out).

I figured out how to share code - I have created 3 projects, where one contains all the stuff and it is declared to be a library project, the other two projects are referring to that library and I can specify in the manifests the different classes, activities etc. That works fine (except I should have set that up that way in first place ;)).

However, I have a far more severe problem: The client’s data. If the player played a couple of stages through and decide to buy the full version, I’d want him to start from that place of where he started, so all the stats / progress information should be available in the other application as well. But this isn’t really working out so far. Right now I am using the SQLite database to store the data, but the database can’t be accessed from another application it seems.

Any suggestions? I have some ideas, but no clue if it’ll work or if there is a better solution.

You could try using shared user IDs. That would let you access the free app’s data directory.

Another thing you could try is to allow them to turn the free version into a paid version by using in app billing to unlock the rest of the content.

Or you could allow the user to backup the database to their sdcard and then import it back into the paid version. You could even have it backup periodically behind the scenes and then on startup of paid version scan for this file and if found ask if they would like to import their progress from free version. The problem there is that it would be easy for them to alter the database to show more progress than actually completed before importing unless you encrypted the data in the database.

The shared userid sounds like a good option unless they uninstall the free version before opening the paid version. In which case their data would already be gone and you would not be able to access it.

This works for files, but as far as I have found out, databases aren’t shared even then. I could only make a database dump to the shared directories.

Not even if you treat the database itself as a file and copy it over? This question shows where the database is actually stored in the app’s data folder. Or does it restrict access the the db even if you’re treating it as a raw file?

There’s a few ways to separate the paid and free versions. The main methods I’ve come across:
[ul]
[li]Library Project, with two Android Projects for Free and Paid versions
[/li](This is the method mentioned by the OP, and the method I prefer)
[li]In-App Purchase to upgrade from Free to Paid
[/li]Keep one APK on the Market, just use an in app purchase to unlock extra functionality
[li]Same code base, just run a script to export two different package names
[/li]Some people have had success running a build script to export the free version APK, then automatically flip a switch in the AndroidManifest.xml before exporting the paid version. This is more complicated though.
[/ul]

Personally I’d recommend the method mentioned by Jwsonic - use a Shared User ID to allow the apps to share user data (shared preferences, files & DBs)

I found a thread on StackOverflow and a Google Groups post which show how to share DBs between two apps with the same Share User ID.

However, I’ve also read (can’t remember where) that adding a Shared User ID to a project that has been previously released on the Market will cause you to lose any Shared Preferences which were previously stored by the app. The Shared User ID basically changes how Android treats your app’s security isolation, so it stores all the data under the Shared User ID instead of your old package name. This could cause issues for existing users of the free version, so I’d recommend testing extra thoroughly before releasing anything like this!

Personally I always add a Shared User ID to a new Android project as soon as I write the first line of code. Say the package name is com.test.example, I’d just call the Shared User ID “com.test.example” as well. Then if I decide to release a paid version down the track, I can just release two packages “com.test.example.free” and “com.test.example.paid”, with the same Shared User ID “com.test.example”. No need to worry about losing old app data in the process.

Hope this helps!

Thanks David - it all sounds reasonable… and copying the db is actually most interesting.

I have meanwhile thought of another method: The free app could provide an intent that when called externally, puts all the db data into extra information and call an intent of the paid app - passing all the data along.

Next to that, the free version could be modified to open the paid version by calling the intent, making sure that the player can’t play the free version. I think that would work too.

Inapp billing sounds btw also reasonable… I think I’ll be trying that out for one of the next projects I am planning.

Many thanks, you’ve been most helpful.

You’re welcome. :slight_smile: Glad to see so many people fielding suggestions here, there are lots of interesting perspectives.

That other idea you had actually looks quite good. The only thing you might have to do is put some code in the free version to check that the paid version is signed by your developer key. Otherwise anybody could write a dummy app (with the same package name as your paid version) which steals the db. Of course, if you don’t have any confidential information stored there it might not be a big deal. But something to keep in mind anyway.

You guys are good with your shared libraries and figuring out how to share databases and really actually trying to make your lives easier.

Me, I just keep a text file of steps to change the free version to the paid version. You know, copy the WS, change the name with the refractor, change this graphics file, change the free variable to false, edit this in the Manifest, blah blah blah. Like that.

Terrible! :slight_smile:

I really want to use in app purchases for all future games, distributing a single version and using an in app purchase for the upgrade. But in app purchases look so complicated.

Smart to think about that. But really anybody that knows how to write a dummy package to steal the db is probably somebody that has already rooted their phone and has the rights to go into your apps data directory and get the db. Best bet is to encrypt the db so no matter which way they are able to steal it they can’t easily read or edit the values in it.

Don’t be scared. I use in app purchases the the app I’m currently writting and its actually really easy to implement.

Noticed in the comments for your app that your billing doesn’t seem to be working correctly. Not so easy, huh? If you find a bug, I would be curious as to what you find.

Regards

I would suggest using a provider. Check the note sample in your Android SDK folder.
You could use the solution David stated in his post, but the Google guidelines are to use a content provider:
http://developer.android.com/guide/topics/providers/content-providers.html

thats way cool! Congrats!!

for your free one or lite one do you make any money or anything?

I’m using this easy solution:
Creating a free/paid app pair for the Android Market

That’s a great idea … I think that in-app-purchased mostly function like that of some sort behind the scenes :slight_smile:

thanks for the link

Great solution! I tried this out the other day, and actually found a slightly more efficient way of implementing the same method. Here’s the code:

[java]
protected static boolean isProInstalled(Context context) {
PackageManager manager = context.getPackageManager();
if (manager.checkSignatures(context.getPackageName(), “com.your.pro.key”)
== PackageManager.SIGNATURE_MATCH) {
//Pro key installed, and signatures match
return true;
}
return false;
}
[/java]

Turns out you don’t need to iterate through every package on the system. The method PackageManager.checkSignatures() is all that’s required, along with the full package name of your Pro key.

If I’m correct, that will not work with the new anti piracy functions of Google Play.

What new anti-piracy functions?

http://developer.android.com/guide/market/licensing/index.html

You’re right, it’s not designed to use the Google Play Licensing service. Theoretically, anyone could purchase your unlocker key and then distribute the APK on pirate websites. There’s nothing built into this function to prevent that from happening.

I guess it depends how concerned you are about piracy. You could still write some code to detect a pirated version (perhaps based on this idea), and then either disable or log the installation appropriately.