Skip to main content

Android: automatically choose debug/release Maps api key?


Is it possible to automatically detect, which certificate was used for signing APK? I'd like to have both debug and release Maps certificates in application and pass valid one to MapView constructor.



With such setup I will not make mistake while releasing application - I'm using debug certificate on emulator and my device, then sign with release one before sending app to Market.



I was thinking about detecting my particular device or whether debugger is connected but it is not perfect. Maybe some file marking need for debug certificate? Is there any better way?


Source: Tips4allCCNA FINAL EXAM

Comments

  1. There is a new way to determine is it a debug build or release one in SDK Tools, Revision 17. An excerpt from new features overview:


    Builds now generate a class called BuildConfig containing a DEBUG constant that is automatically set according to your build type. You can check the (BuildConfig.DEBUG) constant in your code to run debug-only functions.


    So now you can simply write something like this:

    if (BuildConfig.DEBUG)
    {
    //Your debug code goes here
    }
    else
    {
    //Your release code goes here
    }


    UPDATE: I've encountered bug in ADT: sometimes BuildConfig.DEBUG is true after exporting application package. Description is here: http://code.google.com/p/android/issues/detail?id=27940

    ReplyDelete
  2. Had the same hassle with the API key. Here's a full solution, based on the above link and example from Bijarni (which somehow didn't work for me), I use now this method:

    // Define the debug signature hash (Android default debug cert). Code from sigs[i].hashCode()
    protected final static int DEBUG_SIGNATURE_HASH = <your hash value>;

    // Checks if this apk was built using the debug certificate
    // Used e.g. for Google Maps API key determination (from: http://whereblogger.klaki.net/2009/10/choosing-android-maps-api-key-at-run.html)
    public static Boolean isDebugBuild(Context context) {
    if (_isDebugBuild == null) {
    try {
    _isDebugBuild = false;
    Signature [] sigs = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
    for (int i = 0; i < sigs.length; i++) {
    if (sigs[i].hashCode() == DEBUG_SIGNATURE_HASH) {
    Log.d(TAG, "This is a debug build!");
    _isDebugBuild = true;
    break;
    }
    }
    } catch (NameNotFoundException e) {
    e.printStackTrace();
    }
    }
    return _isDebugBuild;
    }


    You have to find out your debug signature's hashValue() once, just output sigs[i].hashCode().

    Then, I didn't want to dynamically add the MapView, but rather use the xml file. You cannot set the api key attribute in the code and use an xml layout, so I use this simple method (though copying the xml layout isn't so beautiful):

    In my MapActivity:

    public void onCreate(Bundle savedInstanceState)
    {
    super.onCreate(savedInstanceState);

    // Select the proper xml layout file which includes the matching Google API Key
    if (isDebugBuild(this)) {
    setContentView(R.layout.map_activity_debug);
    } else {
    setContentView(R.layout.map_activity_release);
    }

    ReplyDelete
  3. Much easier way to determine whether it is a debug build is by checking the debug flag on the application info than the signature hash.

    public boolean isDebugBuild() throws Exception
    {
    PackageManager pm = _context.getPackageManager();
    PackageInfo pi = pm.getPackageInfo(_context.getPackageName(), 0);

    return ((pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
    }


    Once debug build is found, either you can use different resource for showing map or create the mapview within the app and add to a layout.

    if(isDebugBuild())
    {
    _mapView = new MapView(this, getString(R.string.debugmapskey));
    }
    else
    {
    _mapView = new MapView(this, getString(R.string.releasemapskey));
    }

    ReplyDelete
  4. If you're still interested I just blogged about another way to do this. With a simple change to the Android build script, you can switch the Map API key as well as all other required release changes. What I like about this is that nothing debug-related goes into the release, and you can keep the XML layouts just the way they were before.

    http://blog.cuttleworks.com/2011/02/android-dev-prod-builds/

    ReplyDelete
  5. I've ended up with the special file on SD card - if present, use debug key; missing - use release one. And it works.

    EDIT: see new accepted answer, it works better

    ReplyDelete
  6. I don't know if this helps anyone but I have merged some of the other suggestions here to produce the following MapViewActivity.

    In this example R.layout.map_dbg is only used if this is a debug build and the file exists (add this file to your .gitignore).

    The advantages of this approach are :


    you don't need to write an ant target (good if you use eclipse)
    the correct release key is always in map.xml (hopefully a debug key won't be checked in by mistake)
    the release key is always used for a release build
    multiple debug keys can be used


    The disadvantages of this approach are :


    you need to remember to update map_dbg.xml every time map.xml is updated

    public class MapViewActivity extends MapActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //
    // copy the map.xml to map_dbg.xml and update the api key.
    //
    int id = getLayoutId("map_dbg");
    if(id ==0)
    id = R.layout.map;

    setContentView(id);
    }

    int getLayoutId(String name) {
    return isDebugBuild() ? getResources().getIdentifier(name, "layout", getPackageName()) : 0;
    }

    public boolean isDebugBuild()
    {
    boolean dbg = false;
    try {
    PackageManager pm = getPackageManager();
    PackageInfo pi = pm.getPackageInfo(getPackageName(), 0);

    dbg = ((pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
    } catch (Exception e) {
    }
    return dbg;
    }

    }

    ReplyDelete

Post a Comment

Popular posts from this blog

[韓日関係] 首相含む大幅な内閣改造の可能性…早ければ来月10日ごろ=韓国

div not scrolling properly with slimScroll plugin

I am using the slimScroll plugin for jQuery by Piotr Rochala Which is a great plugin for nice scrollbars on most browsers but I am stuck because I am using it for a chat box and whenever the user appends new text to the boxit does scroll using the .scrollTop() method however the plugin's scrollbar doesnt scroll with it and when the user wants to look though the chat history it will start scrolling from near the top. I have made a quick demo of my situation http://jsfiddle.net/DY9CT/2/ Does anyone know how to solve this problem?

Why does this javascript based printing cause Safari to refresh the page?

The page I am working on has a javascript function executed to print parts of the page. For some reason, printing in Safari, causes the window to somehow update. I say somehow, because it does not really refresh as in reload the page, but rather it starts the "rendering" of the page from start, i.e. scroll to top, flash animations start from 0, and so forth. The effect is reproduced by this fiddle: http://jsfiddle.net/fYmnB/ Clicking the print button and finishing or cancelling a print in Safari causes the screen to "go white" for a sec, which in my real website manifests itself as something "like" a reload. While running print button with, let's say, Firefox, just opens and closes the print dialogue without affecting the fiddle page in any way. Is there something with my way of calling the browsers print method that causes this, or how can it be explained - and preferably, avoided? P.S.: On my real site the same occurs with Chrome. In the ex