14

First of all I have done a search and can't find a specific answer to my question so here goes...

I am writing my first Android application and plan to have a Lite version (limited features) and a paid version (full features).

The Lite and Pro version will use the same SQLite database structure, and if the user starts with the Lite version and upgrades to the Pro version, I dont want them to lose the data they have created in the Lite version.

As the Lite and Pro versions will (from my understanding) have to be in separate packages to allow the Android Market to distinguish between them, how can the Pro version see the Lite database?

Many thanks in advance for your answers.

MPelletier
  • 16,256
  • 15
  • 86
  • 137
Justin Phillips
  • 1,358
  • 2
  • 12
  • 26
  • This appears to be a duplicate of http://stackoverflow.com/questions/7053809/share-sqlite-database-between-2-android-apps where there is an answer (second one down). – EdJ Jan 20 '12 at 13:10
  • 1
    @EdJellard I don't believe it's a duplicate. While the questions are _similar_, they're different. That question is asking about sharing the DB between two apps, not necessarily two versions of the _same_ app. – Chris Cashwell Jan 20 '12 at 13:21
  • @GuardianAngel please remember to accept an answer once you believe you've learned what you need. – Chris Cashwell Jan 20 '12 at 14:01
  • OK, but unfortunately they are all potential answers but I can only select one! I will do so once I have played around with my app. – Justin Phillips Jan 20 '12 at 14:10

3 Answers3

12

What I did in and it seems to work for Hexaddicus, is have both Lite and Pro versions run as the same user and then on the first time run of the Pro version, copy the Lite database over. Then inform the user of the copy.

Set the android:sharedUserId to be the same in both products...

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.mycompany.package"
      android:sharedUserId="com.mycompany.package" <---- IMPORTANT
      android:versionCode="10"
      android:versionName="@string/app_version"
      android:installLocation="auto">

And then the code to copy the DB...

    try {
        final Context free_context = this.createPackageContext("com.mycompany.package", Context.CONTEXT_INCLUDE_CODE);
        final File    full_db      = this.getDatabasePath(GameData.DATABASE_NAME);
        final File    full_db_dir  = full_db.getParentFile();
        final File    free_db      = free_context.getDatabasePath(GameData.DATABASE_NAME);
        final File    free_db_dir  = free_db.getParentFile();

        if (free_db.exists() == false)     return;
        if (full_db_dir.exists() == false) full_db_dir.mkdir();
        if (full_db.exists() == false)     full_db.createNewFile();

        FileUtils.copyDirectory(free_db_dir, full_db_dir);
        this.gameData.getWritableDatabase();
    }
    catch (NameNotFoundException e) {
        /* do nothing here since this is an semi expected case */
        Log.w("mytag", "No Lite version found");
    } catch (IOException e) {
        Log.w("mytag", "Failed to create file");
    }
}

The only downside of this is that once the copy is done, there is no syncing between the two versions. You also have to make sure that the user of the Lite version is running a version that is running as the sharedUserId or the copy will fail.

Update: please consider ChrisCashwells comments and answer too since he brings up a valid point and I can't remember what I did in his example.

Andrew White
  • 52,720
  • 19
  • 113
  • 137
  • I've just wanted to propose the same solution. Just to add to this answer you should look at the android:sharedUserId parameter in the manifest file. – Yury Jan 20 '12 at 13:13
  • This requires having an `sharedUserId`, but could be a viable solution. If you don't already have a `sharedUserId` set, sending out an update that *does* have one set would mean invalidating the app's access to the same DB. – Chris Cashwell Jan 20 '12 at 13:15
  • @ChrisCashwell: Are you 100% sure about that? I seem to remember that problem but I thought I worked around it. Either that OR I thought of that from the beginning. Updating my answer. – Andrew White Jan 20 '12 at 13:24
  • I see, thanks. I am not worried about synching the databases once the upgrade is done, because from my understanding this would only be an issue if they went back to the Lite version from the Pro version? – Justin Phillips Jan 20 '12 at 13:26
  • @GuardianAngel: correct and I'm sure you could add in some reverse copy logic but I wouldn't bother unless there is demand to do so. – Andrew White Jan 20 '12 at 13:27
2

You might want to do more of an "unlock" approach than a separate paid app if possible. That way you're only ever using one package. If for no other reason, you'll be avoiding the issue of database ownership.

Using the same android:sharedUserId would be a good approach if your app already has one set. If not, you'll invalidate access to all of your users' data if you send out an update that does have one set. If you're starting from square zero and don't already have an app in the wild with users expecting to keep their data, definitely set a sharedUserId from day one.

Chris Cashwell
  • 22,308
  • 13
  • 63
  • 94
  • Yes a single application sounds a desirable option, because it keeps things simple. My app is still in development so at the moment I am open to ideas...food for thought! – Justin Phillips Jan 20 '12 at 13:28
  • @GuardianAngel this also makes it easier to manage later. For instance, you find a bug, do you want to fix it in two separate apps (free and paid) or just one? – Chris Cashwell Jan 20 '12 at 13:35
1

As @Chris told that you can use "unlock" approach, i will explain it how i do in such conditions.

You can have a table like 'Features' should have have a column/flag IsAvailable. If you want to restrict certain features you can set its IsAvailable flag to FALSE.

If you have changes in DB structure, then you should upgrade the DB using:

@Override
public void onUpgrade()
{
  if (condition == true)
    // alter table
}
Yaqub Ahmad
  • 27,569
  • 23
  • 102
  • 149