Let's say f开发者_JAVA百科or example that I have some Android app that does X. The free version has ads or basic features. I want to have a paid version that removes the ads and adds extra features.
How can I use the paid app as a "license key" to unlock the features in the free app?
So the user would install the free app, then install the paid app to get the extra features, but they would still run the free app (which would now be unlocked). What's the best approach to doing this?
Use PackageManager to ensure your paid package is installed. AND ensure your free package signature matches installed premium package signature. Otherwise somebody would be able to install unsigned app with package name matching your paid package name and unlock premium this way.
This post can help you to find your signature Detect if app was downloaded from Android Market
I'm using this:
PackageManager manager = getPackageManager();
if (manager.checkSignatures("core.package.name", "key.package.name")
== PackageManager.SIGNATURE_MATCH) {
//full version
}
It's pretty simple and it works.
Here's a simple function which checks for the presence of the Pro Key, and checks that the package signature matches the free version:
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;
}
Code is from this forum post, based on the method outlined at yoki.org.
As someone else pointed out, yes, you can use PackageManager to detect the presence of the paid 'key' app, but that's problematic if someone only installs the paid version, uninstalls the free version, etc. Users might get annoyed at having to keep around two downloads to make your one app work. FWIW, I think DoubleTwist Air Sync does it this way. I'm pretty sure the Air Sync app doesn't do anything except enable the functionality in the free DoubleTwist app.
A more practical route might be to have two separate apps, then give the ability to import prefs and data from one to the other using a ContentProvider and/or sharedUserId. You can then share most of your code using a shared library project. However this means both apps need to use a different content URI since two apps can't use the same authority, which is sort of a pain, because your shared library code can't just have a static CONTENT_URI or AUTHORITY field like you'd normally find in a ContentProvider implementation.
I'm starting to think two separate apps with two more-or-less separate codebases is the way to go, because copying code between two projects might actually be easier than trying to maintain a shared library with all sorts of switches to enable or disable features between a free and paid version.
Actually, edgman's recommendation for using a single app and using licensing is probably the best way to go about managing a free and paid version of an app. It solves all of the problems listed above, although to be fair I haven't used licensing yet myself.
EDIT licensing appears to only be allowed for paid apps (bummer) so it's a no-go if you want to offer a free version. However in-app billing might be the "right" way for you to manage a free/paid version. Maybe it's Ok for the OP but I don't feel like requiring two apps to always be installed on a user's device is ideal. If a paying user installs the app on a new device, it appears to be possible to download prior transactions so they don't have to pay twice.
Provided both apps are from the same developer and signed by the same key, they should be able to share information privately. You could probably use a file (stored with MODE_PRIVATE) , but I think the easiest route is to use SharedPreferences - set a flag in the paid app which will be read by the free one. See http://developer.android.com/guide/topics/data/data-storage.html. No idea if it would be easy to circumvent, especially on rooted devices...
Another way would be to check if the paid app is installed, for example by checking if it accept a specific Intent. See also: http://developer.android.com/resources/articles/can-i-use-this-intent.html; in that example they check if ZXing's barcode scanner is available that way.
In any case, another twist on the idea would be that you could "enable" multiple apps with only one paying, if you so wished. Your paid app would be a simple "support this developer" which would remove ads from all your apps. That's an interesting paying model IMHO.
Here is one example of how it can be done:
Intent unlockerAppPresence = null;
APP_LITE_VERSION = false;
try
{
unlockerAppPresence = context.getPackageManager().getLaunchIntentForPackage("nameofthepackagethatunlockyoursoftware");
}
catch (Exception e1)
{
APP_LITE_VERSION = true;
}
if (unlockerAppPresence == null)
APP_LITE_VERSION = true;
Combine this with checking of the app's developer signature (as noted by @Fedor) and you should be good to go.
What absolut distributing only a free/demo app and implement in-app to make it pro? Therefore there will be only one app user have to install, they can test basic functions and there will be a button like "upgrade to pro $1,99" that will call in-app purchase.
Apparently I cannot comment without 50 reputation, so I will put this in its own answer.
The PackageManager method cited by others seems like a nice and simple way to go, but as hackbod mentions, having two installed applications is annoying (and a bit confusing) for the user.
However - and I haven't tried this, because I haven't published my app yet - it seems like you could keep a variable that starts as false and then updates to true if it finds the Pro version installed. The variable would not revert to false just because the Pro version is not there. Then, you could let the user know in both versions that they need to install Pro, then open up the Trial and click Unlock. Once this is done, the Trial version would become a Full version and inform you (if it found the Pro version installed) that you can now uninstall the Pro version and you will continue to have full access.
Something a bit like this:
String msg = "";
boolean sigMatch = isProInstalled(context);
if (unlocked)
{
// If you get here by clicking a button that goes away once the app is unlocked, then you may never see this. Still, better safe than sorry.
msg += "Thanks! You already have access to the full game.";
}
else
{
if (sigMatch)
{
unlocked = true;
saveData(); // I assume you already know how to store variables.
msg += "Unlock successful. You now have access to the full game."
}
else
{
msg += "You are using a Trial version of this game. (blah, blah). To unlock the full version, please purchase XYZ Pro. Install the application and then start this application again and go into this screen again. You should get a message letting you know that the app has been successfully unlocked, after which you may uninstall the Pro version. You do not have to keep it on your device after unlocking the game.";
}
}
if (sigMatch)
{
msg += " If you like, you may now uninstall the Pro application. You will continue to have full access to XYZ.";
}
Now, this cannot tell you whether the user paid for the Pro version and then returned it within 24 hours, as hackbod also mentioned is possible.** But it seems like this scenario might not happen very often. If someone paid and then returned it (especially if you are not charging very much), then they probably decided to stop using the app... or they are trying to steal it, in which case there are other ways to do it anyway. If this possibility concerns you, then In-App Billing may be your best choice. But if you are only looking for a simple measure by which to keep out the casual user, and you don't want to force them to keep two applications installed for all time, then this might be an option.
** I suppose you could keep a timestamp with another variable, and require the user to keep the Pro version installed until some number of hours after that timestamp, THEN allow them to uninstall...
The route most app developers take on this is to only have one version of the app, but features are enabled (extras) or disabled (ads) based on the presence of the "license key".
精彩评论