Sandstone
Sandstone

Reputation: 148

Detect if App is Production/Release Version from Code

I have a home made logging system in my app. Of the things that it does is preform alot of logging (to file and logcat) while in development and can be turned off completely with one varible change. For a functionality example:

static public  final boolean DEVELOPMENT_VERBOSE = true;

public static void developmentLogMessage(String message) {
    if (DEVELOPMENT_VERBOSE)
        Log.i("com.xxx.app",  message);
}

The problem (maybe more an annoyance) I have is that I must remember to set DEVELOPMENT_VERBOSE = false for release. Is there a way in code to detect when the app is finalized for release (say checking for a signed apk for example) so I can set DEVELOPMENT_VERBOSE to false programmatically?

I looked at Detect if app was downloaded from Android Market but it seems my app has a signature even before signing it for the market.

try {
    PackageManager manager = context.getPackageManager(); 
    PackageInfo appInfo = manager.getPackageInfo(
                    "com.xxx.app", PackageManager.GET_SIGNATURES
        );

    System.out.println(appInfo.signatures[0].toCharsString());
} catch (NameNotFoundException e) {
}

I was hoping the signatures array would be empty and I could key of of that. But no go.

Upvotes: 2

Views: 1761

Answers (3)

Sandstone
Sandstone

Reputation: 148

After some research/work we can up with a solution that checks against the singed cert.

        static public boolean DEVELOPMENT_VERBOSE = false;
        static private final  X500Principal RELEASE_DN = new X500Principal(
            "CN=aaa,OU=bbb,O=ccc,L=ddd,ST=eee,C=fff"
            );

        // auto disable the development logs if the apk is signed with a cert
        try {
            PackageManager manager = context.getPackageManager();
            PackageInfo appInfo = manager.getPackageInfo("com.xxx.app",
                    PackageManager.GET_SIGNATURES);
            Signature raw = appInfo.signatures[0];

            try {
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(raw.toByteArray()));

                //DEVELOPMENT_VERBOSE = cert.getSubjectX500Principal().equals(DEBUG_DN);
                if (!cert.getSubjectX500Principal().equals(RELEASE_DN))
                    DEVELOPMENT_VERBOSE = true;

            } catch (CertificateException e) {  

            }           
        } catch (NameNotFoundException e) {

        }

As long as you use the same cert from version to version of the app this will always work.

Upvotes: -3

praetorian droid
praetorian droid

Reputation: 3029

You can use ProGuard to completely turn appropriate logs off when building a release. ProGuard can do a lot of interesting stuff. Among other things it can shrink unneeded code during the building process. For example, if you use debug log (Log.d()) during development, but want to disable it in release then you can add these lines to your proguard.cfg:

-assumenosideeffects class android.util.Log {
  public static int d(...);
}

To enable ProGuard, set the property

proguard.config=proguard.cfg

to your project.properties (if you use default locations). Be noted that ProGuard will also do some other things by default so you probably should take some additional steps when releasing your project. At least you certainly want to save generated mapping.txt file. See the ProGuard guide for more details.

Upvotes: 4

Jacob Nordfalk
Jacob Nordfalk

Reputation: 3533

You can look at which certificate was used to sign the app, and act accordingly.

For example:

  for (Signature sig : getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES).signatures) {
    // Get some (pseudo)uniqe value:
    long sigHash = Arrays.hashCode(sig.toByteArray());
    if (sigHash == releaseSigHash) DEVELOPMENT_VERBOSE = false;
  }

Here is what I do for Google MapView, to decide which API Key to use, which is a similar problem

  for (Signature sig : getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES).signatures) {
    MessageDigest m = MessageDigest.getInstance("MD5");
    m.update(sig.toByteArray());
    md5 = new BigInteger(1, m.digest()).toString(16);

    Log.d("findApiNøgle", "md5fingerprint: "+md5);

    // Jacobs debug-nøgle
    if (md5.equals("5fb3a9c4a1ebb853254fa1aebc37a89b")) return "0osb1BfVdrk1u8XJFAcAD0tA5hvcMFVbzInEgNQ";
    // Jacobs officielle nøgle
    if (md5.equals("d9a7385fd19107698149b7576fcb8b29")) return "0osb1BfVdrk3etct3WjSX-gUUayztcGvB51EMwg";

    // indsæt din egen nøgle her:
  }

Upvotes: 0

Related Questions