Android:自动选择调试/发布Maps api密钥?

时间:2010-06-12 19:16:59

标签: android google-maps debugging key android-mapview

OBSOLETED:这个旧问题是指过时的Google Maps v1 API。使用v2 API时,您可以在一个Google API Console条目中使用多个证书指纹。 API密钥不再存储在Manifest或代码中。


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

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

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

11 个答案:

答案 0 :(得分:45)

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

  

Builds现在生成一个名为 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

答案 1 :(得分:26)

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

答案 2 :(得分: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);
}

找到调试版本后,您可以使用不同的资源显示地图或在应用程序中创建mapview并添加到布局中。

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

答案 3 :(得分: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(我不需要检查密钥)很好地集成,并且可以接受构建过程。

答案 4 :(得分:3)

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

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

答案 5 :(得分:3)

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

答案 6 :(得分:2)

这里的所有答案看起来都过时了,如果你使用的是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

答案 7 :(得分:1)

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

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

答案 8 :(得分:1)

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

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

这种方法的优点是:

  1. 你不需要写一个蚂蚁目标(如果你使用eclipse就很好)
  2. 正确的发布密钥始终在map.xml中(希望不会错误地检入调试密钥)
  3. 发布密钥始终用于发布版本
  4. 可以使用多个调试密钥
  5. 这种方法的缺点是:

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

答案 9 :(得分: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>

答案 10 :(得分:0)

在Map V2中使用Android Studio Gradle工具轻松发送单独的密钥。我已经实现了一个简单的方法。请查看链接here