Android:自动选择调试/发布 Maps api 密钥?
Posted
技术标签:
【中文标题】Android:自动选择调试/发布 Maps api 密钥?【英文标题】:Android: automatically choose debug/release Maps api key? 【发布时间】:2011-03-03 01:41:25 【问题描述】:已过时:这个老问题是指已过时的 Google Maps v1 API。使用 v2 API 时,您可以在一个 Google API Console 条目中使用多个证书指纹。 API Key 不再存储在 Manifest 或代码中。
是否可以自动检测用于签署 APK 的证书?我想在应用程序中同时调试和发布地图证书,并将有效的证书传递给 MapView 构造函数。
通过这样的设置,我在发布应用程序时不会出错 - 我在模拟器和我的设备上使用调试证书,然后在将应用程序发送到 Market 之前使用发布版本签名。
我正在考虑检测我的特定设备或调试器是否已连接,但它并不完美。也许调试证书需要一些文件标记?有没有更好的办法?
【问题讨论】:
您可能会发现here 提供的答案也很合适。 对于 Map Api V2,如何动态使用键。检查我的答案***.com/a/40462174/1348522 【参考方案1】:SDK Tools, Revision 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
【讨论】:
是的,这看起来是正确的方式。一旦我获得 rev 17,我就会搬过来,在第一次下载之前给它几天。 在 SDK rev 17 可用时更改接受的答案,在某些情况下,其他高票数的答案仍然很有价值。 只是想用这个替换之前的调试检测代码,但提到的错误现在似乎仍然存在。 Issue 27940 于 2012 年 3 月关闭。【参考方案2】:API 密钥也有同样的麻烦。这是一个完整的解决方案,基于上面的链接和example from 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 key属性,使用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);
【讨论】:
一句话 - 我不喜欢你的两个布局,因为它需要同时在两个文件中进行任何更改,而是通过new MapView(this, isDebug?keyDebug:keyRelease );
创建 MapView 并将其添加到当前布局中。
是的,我一开始也是动态创建的,但是因为我的地图活动布局不会改变,我希望所有布局都在一个地方(xml 定义)并且没有混淆,所以我选择了以上。当然,两者都可以正常工作。
您始终可以拥有 3 个布局文件,而您打开的 2 个布局文件只有两个 确定它是否是调试版本更简单的方法是检查应用程序信息上的调试标志,而不是签名哈希。
public boolean isDebugBuild() throws Exception
PackageManager pm = _context.getPackageManager();
PackageInfo pi = pm.getPackageInfo(_context.getPackageName(), 0);
return ((pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
一旦找到调试版本,您可以使用不同的资源来显示地图或在应用程序中创建地图视图并添加到布局中。
if(isDebugBuild())
_mapView = new MapView(this, getString(R.string.debugmapskey));
else
_mapView = new MapView(this, getString(R.string.releasemapskey));
【讨论】:
如果您在开发时始终设置 android:debuggable=true 并且如果没有设置 android:debuggable=false,这是一个很好的解决方案。然而,我发现我只在开发和测试结束时才关闭可调试,但之前经常会向客户端发送签名的 .apks。因此,在这种情况下,签名密钥对我来说效果更好。 嗨 Bachi,来自 SDK Tools 修订版 8,developer.android.com/sdk/tools-notes.html(一般说明)您不需要在 AndroidManifest 中添加 debuggable 标志,这些工具会根据发布或开发自动设置它们。 我认为第 16 版不再这样做了...我在最新的应用程序中遇到了这个问题,不得不改变我的方法:***.com/questions/8480763/…【参考方案4】:这里的所有答案似乎都已经过时了,如果您使用的是 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"/>
source
如果你想保存一些密码以进行调试和发布,那么你应该关注this
【讨论】:
【参考方案5】:我已经解决了将 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
(它不能转到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_
android:layout_
android:clickable="true"
android:apiKey="@apiKey@"
/>
在预编译期间,模板被复制到正确的位置,@apiKey@ 被替换为真正的密钥。不幸的是,在这个阶段我还没有找到一种方法来区分调试和发布版本,所以为了编译发布,我只是将发布 apiKey 添加到 ant 参数中:
ant -DmapsApiKey=.... release
这种方法可以很好地与 SCM 集成(我不需要签入密钥)并且可以在构建过程中接受。
【讨论】:
【参考方案6】:如果您仍然感兴趣,我刚刚在博客中介绍了另一种方法。通过对 Android 构建脚本的简单更改,您可以切换 Map API 密钥以及所有其他必需的版本更改。我喜欢这个的一点是,发布中没有任何与调试相关的内容,您可以保持 XML 布局与以前一样。
http://blog.cuttleworks.com/2011/02/android-dev-prod-builds/
【讨论】:
谢谢安迪,我更新了回复。 (我真的必须修复丢失的重定向)【参考方案7】:我认为在 Google API 的控制台中创建一个包含您的发布密钥和调试密钥(都映射到同一个包)的条目效果很好,并且是一种更简单的方法,无需担心您是否正在调试或编译发布版本。 解决方案概述here
【讨论】:
添加多个 sha1 密钥非常适合 Maps API 2 - 这里提到的所有解决方案都适用于之前的 API 1,没有合适的解决方案。【参考方案8】:我最终得到了 SD 卡上的特殊文件 - 如果存在,请使用调试密钥;缺少 - 使用版本一。它有效。
编辑:查看新接受的答案,效果更好
【讨论】:
【参考方案9】:我不知道这是否对任何人有帮助,但我在此处合并了其他一些建议以生成以下 MapViewActivity。
在本例中,R.layout.map_dbg 仅在这是一个调试版本且文件存在时使用(将此文件添加到您的 .gitignore)。
这种方法的优点是:
-
你不需要写一个 ant 目标(如果你使用 eclipse 很好)
正确的发布密钥总是在 map.xml 中(希望调试密钥不会被错误签入)
发布密钥始终用于发布构建
可以使用多个调试键
这种方法的缺点是:
您需要记住每次更新 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;
【讨论】:
【参考方案10】:我设置了一个简单的 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>
【讨论】:
【参考方案11】:在 Map V2 中,使用 Android Studio Gradle 工具可以轻松发送单独的密钥。我为此实现了一个简单的方法。请查看链接here。
【讨论】:
以上是关于Android:自动选择调试/发布 Maps api 密钥?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在调试 android google maps 示例时没有调用我的 onLocationChanged() 方法?
Google Maps Android API 是不是在发布模式下工作?
Android- Google Maps V2:跟踪从当前位置到另一个目的地的路线
在 Google Maps Android API 中通过 onclick 选择功能