22

Possible Duplicate:
Supporting Amazon and Android market links inside application

I was wondering if and how you could differentiate between an Amazon App Store installed app and one installed from the Market.

For example, say I have my app called "Example App", and I want to develop for Amazon and the Market. In the app I have links to rate Example App. I also have a link to buy Example App Pro. This poses a problem because Amazon will not release my app if it links to a different App store.

This requires me to make 2 APK files, which is a pain. It only takes about 30 seconds extra to export both, but it creates extra clutter and testing time.

So has anyone found a way to make a single APK that can be uploaded to both Amazon and Android Market without making any changes between the two so that at run time I can check whether it's the Amazon or the Market that installed it and change the links accordingly?

Konrad Borowski
  • 11,584
  • 3
  • 57
  • 71
Reed
  • 14,703
  • 8
  • 66
  • 110
  • This is really interesting and useful. However, I think you need to separate it into an answer and question (answer your own question) to meet the Stack Overflow FAQ. First, state the question clearly, then answer it yourself. – haimg Oct 07 '11 at 05:45

1 Answers1

17

Edit: At the time of this post, I wasn't aware of it, but there does exist getInstallerPackageName() but I'm not sure how reliable that is. I'm also not sure what it returns for Amazon / Market, etc. It might be worth looking at, but if it doesn't work, then the below method works for Google vs Amazon.

You will have to sign the application as normal, run on your test device, get the value of sig.hashCode() from your logs, then replace -1545485543 with whatever value you got for sig.hashCode() then export and sign again (WITH THE SAME KEY AS BEFORE) and then upload to Amazon and Market both - from the same APK.

Do it:

public static boolean isMarket(Context context){
    boolean isMarketSig = false;
    int currentSig = 1; // I just set this to 1 to avoid any exceptions later on.
    try {
        Signature[] sigs = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
        for (Signature sig : sigs)
        {
            currentSig = sig.hashCode();


    Log.i("MyApp", "Signature hashcode : " + sig.hashCode());
// This Log is for first time testing so you can find out what the int value of your signature is.
            }
            } catch (Exception e){
                e.printStackTrace();


}
//-1545485543 was the int I got from the log line above, so I compare the current signature hashCode value with that value to determine if it's market or not.
        if (currentSig==-1545485543){
            isMarketSig = true;
    } else {
        isMarketSig = false;
    }

    return isMarketSig;
}
public static void openStore(Context context){
    if (isMarket(context)){
        Intent goToMarket = new Intent(Intent.ACTION_VIEW,Uri.parse("market://d" +
        "etails?id=com.jakar.myapp"));
        goToMarket.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(goToMarket);  
    } else {
        Intent goToAppstore = new Intent(Intent.ACTION_VIEW,Uri.parse("http://www.amazon.com/gp/mas/dl/andro" +
        "id?p=com.jakar.myapp"));
        goToAppstore.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(goToAppstore);
    }
}

Basically, the hashCode() that you get from the app installed on your testing device will be the same one from the market. The hash code from the app store will be different because according to https://developer.amazon.com/help/faq.html, the app store signs the application with a signature specific to your developer account, so that will return a different value that what you actually signed it with.

And I put the isMarket and openStore methods in a different class called OtherClass so that I only have to code it once. Then from any activity where I need to open the proper link, I just call OtherClass.openStore(context);

Note: It works to open the market successfully, but I haven't yet deployed this method on the App Store, so I haven't completely tested it. I am confident it will work, but can make no guarantees, so if you use what I've suggested and it fails, please don't hold me accountable.

This was a big help in coming up with an answer so I could test which signature was being used.

Community
  • 1
  • 1
Reed
  • 14,703
  • 8
  • 66
  • 110
  • Awesome stuff Jakar, thanks. Question, when you grab your signatures you store it in a `Signature[]`. Then you compare the last signature in the array to whatever hashcode you previously determined. That means you assume the package was signed with only one certificate. This is not a problem since this is usually the case, just found it interesting since I recently learned you can sign APKs with more than one cert. What's weird is Amazon will also accept signed APKs, so when they go to sign with their own there will be two certs. Could this lead to false positives in your check? – Tony Chan Oct 12 '11 at 09:45
  • I don't really know. I think Amazon actually basically unpacks it, which removes your own signature, and then they sign it again. If it does contain more than one signature after Amazon signs it, I guess that could make it a little more difficult, but you could always compare every entry in the array and if one of them != yourSig, then use Amazon link. – Reed Oct 14 '11 at 03:45
  • @Jakar Have you tested this on an app published to both Google and Amazon's markets? – CrackerJack9 Oct 15 '11 at 01:28
  • @CrackerJack9 Sorry for the late reply. Didn't notice you commented.. Yes, I have now. It worked. :) – Reed Nov 09 '11 at 03:28
  • @Turbo It may possibly lead to issues, but I have two apps on Amazon and two on the Market and I use this method and it has worked. I signed my APKs when packaging them (using Eclipse), so it appears that my method works. – Reed Nov 09 '11 at 03:29