Android: автоматически выберите ключ API debug / release Maps?

OBSOLETED: этот старый вопрос относится к устаревшему API Google Maps v1. При использовании V2 API вы можете использовать несколько отпечатков пальцев сертификата в одном консоль Google API запись. Ключ API больше не хранится в Манифесте или коде.


можно ли автоматически определить, какой сертификат использовался для подписания APK? Я хотел бы иметь сертификаты debug и release Maps в приложении и передать действительный в MapView конструктор.

с такой настройкой я не ошибусь при выпуске приложения - я использую сертификат отладки на эмуляторе и моем устройстве, а затем подписываю с выпуском один перед отправкой приложения на рынок.

Я думал об обнаружении моего конкретного устройства или о том, подключен ли отладчик, но он не идеален. Может быть, какая-то маркировка файла нужна для сертификата отладки? Есть ли лучший способ?

11 ответов


существует новый способ определить, является ли это отладочной сборкой или выпуском в SDK Tools, редакция 17. Отрывок из обзора новых функций:

сборки теперь генерируют класс под названием BuildConfig содержащий DEBUG константа, которая автоматически устанавливается в соответствии с типом сборки. Вы можете проверить (BuildConfig.DEBUG) константа в коде для запуска функций только отладки.

Итак, теперь вы можете просто написать что-то вроде этого:

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

обновление: я столкнулся с ошибкой в ADT: иногда BuildConfig.DEBUG is true после того, как пакет документов на экспорт. Описание здесь: http://code.google.com/p/android/issues/detail?id=27940


были те же проблемы с ключом API. Вот полное решение, основанное на приведенной выше ссылке и пример из Bijarni (что почему-то не сработало для меня), я использую теперь этот метод:

// 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;
}

вы должны узнать hashValue() вашей отладочной подписи один раз, просто выведите sigs[i].hashCode ().

затем я не хотел динамически добавлять MapView, а скорее использовать xml-файл. Вы не можете установить атрибут ключа api в коде и использовать XML-макет, поэтому я использую этот простой метод (хотя копирование XML-макете не так красиво):

в моей 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);
    }

гораздо проще определить, является ли это отладочной сборкой, проверив флаг отладки в информации о приложении, чем хэш подписи.

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

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

Как только отладочная сборка найдена, вы можете использовать другой ресурс для отображения карты или создать mapview в приложении и добавить в макет.

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

Я работал вокруг ужасной неправильной интеграции ключей api в процесс сборки и управления версиями, сделав его свойством, хранящимся в local.properties. Я должен был добавить следующее к build.xml:

<property name="mapviewxml" value="res/layout/mapview.xml" />
<target name="-pre-build">
    <fail unless="mapsApiKey">You need to add mapsApiKey=... to local.properties</fail>
    <copy file="mapview.xml.tpl" tofile="${mapviewxml}" overwrite="true">
        <filterchain>
            <replacetokens>
                <token key="apiKey" value="${mapsApiKey}"/>
            </replacetokens>
        </filterchain>

    </copy>
</target>

теперь, конечно, я должен был создать mapview.xml.tpl в моих проектах root (он не может перейти в res/layout потому что это нарушит процесс сборки):

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.maps.MapView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mapview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clickable="true"
    android:apiKey="@apiKey@"
    />

во время предварительной компиляции шаблон копируется в нужное место и @apiKey@ заменяется реальным ключом. К сожалению, я не нашел способа различать сборки debug и release на этом этапе, поэтому для компиляции для release я просто добавляю релиз apiKey к параметрам ant:

ant -DmapsApiKey=.... release 

этот подход хорошо интегрируется с SCM (мне не нужно проверять ключи) и приемлемо с процессом сборки.


Если вы все еще заинтересованы, я просто написал в блоге о другом способе сделать это. С простым изменением скрипта сборки Android вы можете переключить ключ API карты, а также все другие необходимые изменения выпуска. Что мне нравится в этом, так это то, что ничего отладочного не входит в выпуск, и вы можете сохранить макеты XML так, как они были раньше.

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


Я думаю, что создание записи в консоли Google API, которая включает в себя как ваш ключ выпуска, так и ключ отладки (оба сопоставления с одним и тем же пакетом), отлично работает и является гораздо более простым способом не беспокоиться о том, отлаживаете ли вы или компилируете версию выпуска. Решение изложено здесь


все ответы здесь кажутся устаревшими, если вы используете Android studio, то gradle-это путь

используйте разные ключи в своей сборке.Gradle в

android {
  .. .. ...
    buildTypes {
       debug {
          resValue "string", "google_maps_api_key", "[YOUR DEV KEY]"
       }
       release {
           resValue "string", "google_maps_api_key", "[YOUR PROD KEY]"
       }
    }
  }

и в AndroidManifest.в XML

<meta-data
        android:name="com.google.android.maps.v2.API_KEY"
        android:value="@string/google_maps_api_key"/>

источник

и если вы хотите сохранить некоторые пароли для отладки и выпуска по-разному, то вы должны следовать этой


Я закончил со специальным файлом на SD-карте - если есть, используйте ключ отладки; отсутствует-используйте выпуск один. И это работает.

EDIT: см. новый принятый ответ, он работает лучше


Я не знаю, помогает ли это кому-нибудь, но я объединил некоторые другие предложения здесь, чтобы создать следующую MapViewActivity.

в этом примере R. layout.map_dbg используется, только если это отладочная сборка и файл существует (добавьте этот файл в свой .gitignore).

преимущества этого подхода:

  1. вам не нужно писать цель муравья (хорошо, если вы используете eclipse)
  2. правильный ключ выпуска всегда находится на карте.XML (надеюсь, ключ отладки не будет проверен по ошибке)
  3. ключ выпуска всегда используется для сборки выпуска
  4. можно использовать несколько ключей отладки

недостатками этого подхода являются :

  1. вы должны помнить, чтобы обновить map_dbg.xml каждый раз карта.xml обновляется

    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;
        }
    
    }
    

Я установил простую цель ant, которая заменяет apikey либо ключом отладки, либо ключом выпуска. Это очень просто и сохраняет код свободным от нежелательной логики.

<target name="apikey">
    <!-- Location of target layout file -->
    <first id="first">
        <fileset dir="." includes="res/layout/kondi_training_templates.xml" />
    </first>
    <property name="layout-file" value="${toString:first}"/>
    <echo>template-file: ${template-file}</echo>

    <replaceregexp file="${template-file}"
        match="android:apiKey=.*"
        replace='android:apiKey="${mapview.apikey}"'
        byline="true"
    />
</target>

В Map V2 его легко отправить отдельные ключи с помощью Android Studio Gradle tool. Я реализовал простой способ для этого. пожалуйста, проверьте ссылку здесь.