Android:自动selectdebugging/发布Maps api key?
OBSOLETED:这个老问题是指过时的Google Maps v1 API。 使用v2 API时,您可以在一个Google API Console条目中使用多个证书指纹。 API密钥不再存储在清单或代码中。
是否可以自动检测哪个证书用于签名APK? 我想同时在应用程序中debugging和发布地图证书,并将有效的证书传递给MapView构造函数。
有了这样的设置,我不会在发布应用程序时犯错 – 我在模拟器和我的设备上使用debugging证书,然后在发送应用程序到市场之前签署发行版。
我正在考虑检测我的特定设备或debugging器是否连接,但这并不完美。 也许一些文件标记需要debugging证书? 有没有更好的办法?
有一种新的方法可以确定它是SDK Tools,Revision 17中的debugging版本还是发布版本 。 摘自新function概述:
Builds现在生成一个名为BuildConfig的类,其中包含一个根据您的构buildtypes自动设置的DEBUG常量。 您可以检查代码中的( BuildConfig.DEBUG )常量以运行仅debuggingfunction。
所以现在你可以简单地写下这样的东西:
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
对API密钥有同样的麻烦。 这里有一个完整的解决scheme,基于上面的链接和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 eg 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; }
你必须找出你的debugging签名的hashValue()一次,只需输出sigs [i] .hashCode()。
然后,我不想dynamic添加MapView,而是使用xml文件。 你不能在代码中设置api键属性,并使用xml布局,所以我使用这个简单的方法(尽pipe复制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); }
通过检查应用程序信息上的debugging标志而不是签名哈希,可以更容易地确定它是否为debugging版本。
public boolean isDebugBuild() throws Exception { PackageManager pm = _context.getPackageManager(); PackageInfo pi = pm.getPackageInfo(_context.getPackageName(), 0); return ((pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0); }
一旦finddebugging版本,您可以使用不同的资源来显示地图,或者在应用程序内创build地图视图并添加到布局。
if(isDebugBuild()) { _mapView = new MapView(this, getString(R.string.debugmapskey)); } else { _mapView = new MapView(this, getString(R.string.releasemapskey)); }
我已经通过将其存储在local.properties
一个属性,将api密钥的可怕失误整合到构build过程和源代码控制中。 我不得不将以下内容添加到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>
现在,我必须在我的项目根目录下创buildmapview.xml.tpl
(它不能去res/layout
因为它会破坏构build过程):
<?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 @被真正的密钥replace。 不幸的是,在这个阶段,我还没有find区分debugging和发布版本的方法,所以要编译发布版本,我只是将发行版apiKey添加到ant参数中:
ant -DmapsApiKey=.... release
这种方法与SCM很好地集成(我不需要检查密钥)并且可以接受构build过程。
如果你仍然感兴趣,我只是在博客上讨论另一种方法。 通过对Android构build脚本的简单更改,您可以切换Map API键以及所有其他所需的发布更改。 我喜欢的是没有任何与debugging有关的内容进入到发行版中,您可以保持XML布局与以前一样。
http://blog.cuttleworks.com/2011/02/android-dev-prod-builds/
我认为在Google API的控制台中创build一个包含释放键和debugging键(两个都映射到同一个包)的控制台的条目非常好,而且更简单一些,不必担心是否正在debugging或编译发行版本。 这里概述了解决scheme
这里的所有答案都显得过时了,如果你使用的是android studio,那么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"/>
资源
如果你想保存一些密码来进行debugging和释放,那么你应该遵循这个
我已经结束与SD卡上的特殊文件 – 如果存在,使用debugging密钥; 丢失 – 使用释放一个。 它工作。
编辑:看到新的接受的答案,它效果更好
我不知道这是否有助于任何人,但我已经合并了一些其他的build议来产生以下的MapViewActivity。
在这个例子中,只有在debugging版本和文件存在的情况下才会使用R.layout.map_dbg(把这个文件添加到你的.gitignore中)。
这种方法的优点是:
- 你不需要写一个ant目标(如果你使用eclipse,那么这个目标很好)
- 正确的释放键总是在map.xml中(希望debugging键不会被误检入)
- 释放键始终用于发布版本
- 可以使用多个debugging密钥
这种方法的缺点是:
-
每次更新map.xml时都需要记住更新map_dbg.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目标,用debugging密钥或释放密钥replaceapikey。 这是非常简单的,并保持代码不需要的逻辑。
<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>
在地图V2它易于使用Android Studio Gradle工具发送单独的键。 我已经实现了一个简单的方法。 请在这里查看链接。