Android: автоматически выбирает debug/release Maps api key?
OBSOLETED: этот старый вопрос относится к устаревшему API Google Maps v1. При использовании API v2 вы можете использовать несколько отпечатков сертификата в одной записи Google API Console. API-ключ больше не сохраняется в манифесте или коде.
Можно ли автоматически определить, какой сертификат использовался для подписания APK? Я хотел бы иметь как отлаживать, так и выпускать сертификаты Карты в приложении и передавать их в конструктор MapView.
При такой настройке я не ошибаюсь при выпуске приложения - я использую сертификат отладки на эмуляторе и моем устройстве, а затем подписываюсь с выпуском до отправки приложения на рынок.
Я думал об обнаружении моего конкретного устройства или подключен ли отладчик, но он не идеален. Может быть, для проверки отладки требуется некоторая маркировка файлов? Есть ли лучший способ?
Ответы
Ответ 1
Существует новый способ определить, является ли это отладочной сборкой или выпуском в SDK Tools, редакция 17. Выдержка из обзора новых функций:
Теперь сборки генерируют класс с именем BuildConfig, содержащий константу DEBUG, которая автоматически устанавливается в соответствии с вашим типом сборки. Вы можете проверить константу (BuildConfig.DEBUG) в вашем коде для запуска функций только для отладки.
Итак, теперь вы можете просто написать что-то вроде этого:
if (BuildConfig.DEBUG)
{
//Your debug code goes here
}
else
{
//Your release code goes here
}
ОБНОВЛЕНИЕ: Я столкнулся с ошибкой в ADT: иногда BuildConfig.DEBUG
есть true
после экспорта пакета приложения. Описание находится здесь: http://code.google.com/p/android/issues/detail?id=27940
Ответ 2
Имел ту же самую проблему с ключом 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);
}
Ответ 3
Более простой способ определить, является ли это отладочной сборкой, - это проверить флаг отладки на информации приложения, чем хеш-подпись.
public boolean isDebugBuild() throws Exception
{
PackageManager pm = _context.getPackageManager();
PackageInfo pi = pm.getPackageInfo(_context.getPackageName(), 0);
return ((pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
}
После обнаружения сборки debug вы можете использовать другой ресурс для отображения карты или создания карты в приложении и добавления в макет.
if(isDebugBuild())
{
_mapView = new MapView(this, getString(R.string.debugmapskey));
}
else
{
_mapView = new MapView(this, getString(R.string.releasemapskey));
}
Ответ 4
Я работал над ужасной неверной интеграцией ключей 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="@[email protected]"
/>
Во время предварительной компиляции шаблон копируется в нужное место, а @apiKey @заменяется реальным ключом. К сожалению, я не нашел способа отличить отладочную и выпускную сборки на этом этапе, поэтому для компиляции для выпуска я просто добавляю apiKey для выпуска в параметры ant:
ant -DmapsApiKey=.... release
Этот подход хорошо интегрируется с SCM (мне не нужно проверять ключи) и приемлемо с процессом сборки.
Ответ 5
Если вам все еще интересно, я просто написал о другом способе сделать это. С простым изменением в Android build script вы можете переключить ключ API карты, а также все другие необходимые изменения выпуска. Что мне нравится в этом, так это то, что в релиз не входит связанное с отладкой, и вы можете хранить XML-макеты так, как раньше.
http://blog.cuttleworks.com/2011/02/android-dev-prod-builds/
Ответ 6
Я думаю, что создание записи в консоли Google API, которая включает в себя как ключ освобождения, так и ваш ключ отладки (оба сопоставления с одним и тем же пакетом) отлично работает, и это гораздо более простой способ не беспокоиться о том, что вы отлаживаете или компиляции версии выпуска.
Решение представлено здесь
Ответ 7
Все ответы здесь выглядят устаревшими, если вы используете андроид-студию, тогда gradle - это путь
Используйте разные клавиши в файле build.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"/>
источник
И если вы хотите сохранить несколько паролей для отладки и выпуска по-разному, вы должны следовать этим
Ответ 8
Я получил специальный файл на SD-карте - если есть, используйте отладочный ключ; отсутствует - используйте выпуск один. И это работает.
EDIT: см. новый принятый ответ, он работает лучше
Ответ 9
Я не знаю, помогает ли это кому-либо, но я объединил некоторые другие предложения здесь, чтобы создать следующую MapViewActivity.
В этом примере R.layout.map_dbg используется, только если это сборка отладки и файл существует (добавьте этот файл в свой .gitignore).
Преимущества этого подхода заключаются в следующем:
- вам не нужно писать цель ant (хорошо, если вы используете eclipse)
- правильный ключ освобождения всегда находится в map.xml(надеюсь, что ключ отладки не будет проверен по ошибке)
- ключ освобождения всегда используется для сборки релиза.
- можно использовать несколько клавиш отладки
К недостаткам этого подхода относятся:
-
вам нужно помнить об обновлении map_dbg.xml каждый раз, когда обновляется map.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;
}
}
Ответ 10
У меня установлена простая цель ant, которая заменяет apikey либо отладочным ключом, либо ключом release. Это действительно просто, и код не содержит нежелательной логики.
<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>
Ответ 11
В Map V2 Легко отправлять отдельные ключи с помощью инструмента Android Studio Gradle. Я применил для этого простой способ. пожалуйста, проверьте ссылку здесь.