41

已过时:这个老问题是指已过时的 Google Maps v1 API。使用 v2 API 时,您可以在一个Google API 控制台条目中使用多个证书指纹。API Key 不再存储在 Manifest 或代码中。


是否可以自动检测用于签署 APK 的证书?我想在应用程序中同时调试和发布 Maps 证书,并将有效的证书传递给 MapView 构造函数。

通过这样的设置,我在发布应用程序时不会出错 - 我在模拟器和我的设备上使用调试证书,然后在将应用程序发送到 Market 之前使用发布版本进行签名。

我正在考虑检测我的特定设备或调试器是否已连接,但它并不完美。也许调试证书需要一些文件标记?有没有更好的办法?

4

11 回答 11

48

在SDK Tools, Revision 17中有一种新方法可以确定它是调试版本还是发布版本。新功能概述的摘录:

构建现在会生成一个名为BuildConfig的类,其中包含一个根据您的构建类型自动设置的DEBUG常量。您可以检查代码中的 ( BuildConfig.DEBUG ) 常量以运行仅调试功能。

所以现在你可以简单地写这样的东西:

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

更新:我在 ADT 中遇到了错误:有时BuildConfig.DEBUGtrue在导出应用程序包之后。说明在这里:http ://code.google.com/p/android/issues/detail?id=27940

于 2012-03-24T08:26:02.280 回答
27

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 key 属性,使用 xml 布局,所以我用这个简单的方法(虽然复制 xml 布局不太美观):

在我的地图活动中:

    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);
    }
于 2010-09-30T08:11:03.473 回答
10

确定它是否是调试版本更简单的方法是检查应用程序信息上的调试标志,而不是签名哈希。

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));
    }
于 2011-05-16T21:56:00.147 回答
5

这里的所有答案似乎都已经过时了,如果您使用的是 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"/>

资源

如果您想保存一些密码以进行调试和以不同的方式发布,那么您应该遵循这个

于 2016-03-30T13:15:10.417 回答
3

如果您仍然感兴趣,我刚刚在博客中介绍了另一种方法。通过对 Android 构建脚本的简单更改,您可以切换 Map API 密钥以及所有其他必需的版本更改。我喜欢这个的一点是,发布中没有任何与调试相关的内容,您可以保持 XML 布局与以前一样。

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

于 2011-02-01T03:00:29.440 回答
3

我认为在 Google API 的控制台中创建一个包含您的发布密钥和调试密钥(都映射到同一个包)的条目效果很好,并且是一种更简单的方法,不必担心您是在调试还是编译发布版本。解决方案概述here

于 2013-08-31T05:47:36.357 回答
3

我已经解决了将 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_width="fill_parent"
    android:layout_height="fill_parent"
    android:clickable="true"
    android:apiKey="@apiKey@"
    />

在预编译期间,模板被复制到正确的位置,@apiKey@ 被替换为真实的密钥。不幸的是,在这个阶段我还没有找到区分调试和发布版本的方法,所以要编译发布,我只需将发布 apiKey 添加到 ant 参数中:

ant -DmapsApiKey=.... release 

这种方法可以很好地与 SCM 集成(我不需要签入密钥),并且可以与构建过程集成。

于 2010-12-12T09:57:17.393 回答
1

我最终得到了 SD 卡上的特殊文件 - 如果存在,请使用调试密钥;缺少 - 使用版本一。它有效。

编辑:查看新接受的答案,效果更好

于 2010-06-13T23:15:11.617 回答
1

我不知道这是否对任何人有帮助,但我在此处合并了其他一些建议以生成以下 MapViewActivity。

在这个例子中,R.layout.map_dbg 仅在这是一个调试版本并且文件存在时使用(将此文件添加到您的 .gitignore)。

这种方法的优点是:

  1. 你不需要写一个 ant 目标(如果你使用 eclipse 很好)
  2. 正确的发布密钥总是在 map.xml 中(希望调试密钥不会被错误地签入)
  3. 发布密钥始终用于发布构建
  4. 可以使用多个调试键

这种方法的缺点是:

  1. 您需要记住每次更新 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;
        }
    
    }
    
于 2011-08-12T16:22:06.023 回答
0

我设置了一个简单的 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>
于 2013-01-22T12:28:35.213 回答
0

在 Map V2 中,使用 Android Studio Gradle 工具可以轻松发送单独的密钥。我为此实现了一个简单的方法。请检查这里的链接。

于 2016-09-01T13:19:57.393 回答