Android:自动选择调试/发布地图 API 密钥?

发布于 2024-09-05 05:41:42 字数 433 浏览 2 评论 0原文

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


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

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

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

OBSOLETED: this old question refers to obsoleted Google Maps v1 API. When using v2 API, you can use multiple certificate fingerprints in one Google API Console entry. API Key is no longer stored in Manifest nor code.


Is it possible to automatically detect, which certificate was used for signing APK? I'd like to have both debug and release Maps certificates in application and pass valid one to MapView constructor.

With such setup I will not make mistake while releasing application - I'm using debug certificate on emulator and my device, then sign with release one before sending app to Market.

I was thinking about detecting my particular device or whether debugger is connected but it is not perfect. Maybe some file marking need for debug certificate? Is there any better way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

这个俗人 2024-09-12 05:41:42

SDK 工具,修订版 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

There is a new way to determine is it a debug build or release one in SDK Tools, Revision 17. An excerpt from new features overview:

Builds now generate a class called BuildConfig containing a DEBUG constant that is automatically set according to your build type. You can check the (BuildConfig.DEBUG) constant in your code to run debug-only functions.

So now you can simply write something like this:

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

UPDATE: I've encountered bug in ADT: sometimes BuildConfig.DEBUG is true after exporting application package. Description is here: http://code.google.com/p/android/issues/detail?id=27940

极致的悲 2024-09-12 05:41:42

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 布局不太美观):

在我的 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);
    }

Had the same hassle with the API key. Here's a full solution, based on the above link and example from Bijarni (which somehow didn't work for me), I use now this method:

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

You have to find out your debug signature's hashValue() once, just output sigs[i].hashCode().

Then, I didn't want to dynamically add the MapView, but rather use the xml file. You cannot set the api key attribute in the code and use an xml layout, so I use this simple method (though copying the xml layout isn't so beautiful):

In my 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);
    }
乱了心跳 2024-09-12 05:41:42

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

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

Much easier way to determine whether it is a debug build is by checking the debug flag on the application info than the signature hash.

public boolean isDebugBuild() throws Exception
{
   PackageManager pm = _context.getPackageManager();
   PackageInfo pi = pm.getPackageInfo(_context.getPackageName(), 0);

   return ((pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
}

Once debug build is found, either you can use different resource for showing map or create the mapview within the app and add to a layout.

    if(isDebugBuild())
    {
        _mapView = new MapView(this, getString(R.string.debugmapskey));
    }
    else
    {
        _mapView = new MapView(this, getString(R.string.releasemapskey));
    }
浮生面具三千个 2024-09-12 05:41:42

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

来源

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

All answers here seem outdated, if you are using android studio then gradle is the way to go

Use different keys in your build.gradle

android {
  .. .. ...
    buildTypes {
       debug {
          resValue "string", "google_maps_api_key", "[YOUR DEV KEY]"
       }
       release {
           resValue "string", "google_maps_api_key", "[YOUR PROD KEY]"
       }
    }
  }

And in your AndroidManifest.xml

<meta-data
        android:name="com.google.android.maps.v2.API_KEY"
        android:value="@string/google_maps_api_key"/>

source

And if you want to save some passwords for debug and release differently then you should follow this

深居我梦 2024-09-12 05:41:42

我通过将 API 密钥设置为存储在 local.properties 中的属性,解决了将 api 密钥错误集成到构建过程和源代码控制中的可怕问题。我必须将以下内容添加到 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 (它不能转到 < code>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 集成得很好(我不需要签入键)并且可以接受构建过程。

I have worked around the horrendous mis-integration of the api keys into the build process and source control by making it a property stored in local.properties. I had to add the following to 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>

Now, of course I had to create mapview.xml.tpl in my projects root (it can't go to res/layout because it will break the build process):

<?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@"
    />

During pre-compilation, the template is copied to the right place and @apiKey@ is replaced with the real key. Unfortunately I have not found a way to distinguish between debug and release builds in this phase, so to compile for release, I just add the release apiKey to the ant parameters:

ant -DmapsApiKey=.... release 

This approach integrates well with SCM (I do not need to check in the keys) and acceptably with the build process.

你的心境我的脸 2024-09-12 05:41:42

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

http://blog.cuttleworks.com/2011/02/android-开发-产品-构建/

If you're still interested I just blogged about another way to do this. With a simple change to the Android build script, you can switch the Map API key as well as all other required release changes. What I like about this is that nothing debug-related goes into the release, and you can keep the XML layouts just the way they were before.

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

倥絔 2024-09-12 05:41:42

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

I think that creating an entry in the Google API's console which includes both your release key and your debug key (both mapping to the same package) works great and is a much simpler way to not have to worry about whether you are debuging or compiling a release version.
The solution is outlined here

执着的年纪 2024-09-12 05:41:42

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

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

I've ended up with the special file on SD card - if present, use debug key; missing - use release one. And it works.

EDIT: see new accepted answer, it works better

生活了然无味 2024-09-12 05:41:42

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

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

这种方法的优点是:

  1. 您不需要编写 ant 目标(如果您使用 eclipse,则很好)
  2. 不会被错误地签入)
  3. 正确的发布密钥始终位于 map.xml 中(希望调试密钥 密钥始终用于发布版本
  4. 可以使用多个调试密钥

这种方法的缺点是:

  1. 您需要记住每次更新map.xml时更新map_dbg.xml

    public class MapViewActivity 扩展 MapActivity {
    
        @覆盖
        公共无效 onCreate(捆绑保存实例状态){
            super.onCreate(savedInstanceState);
            //
            // 将map.xml复制到map_dbg.xml并更新api密钥。 
            //
            int id = getLayoutId("map_dbg");
            如果(id==0)
                id = R.layout.map;
    
            设置内容视图(id);
        }
    
        int getLayoutId(字符串名称) {
            返回 isDebugBuild() ? getResources().getIdentifier(名称, "布局", getPackageName()) : 0;
        }
    
        公共布尔 isDebugBuild() 
        {
            布尔 dbg = false;
            尝试 {
                PackageManager pm = getPackageManager();
                PackageInfo pi = pm.getPackageInfo(getPackageName(), 0);
    
                dbg = ((pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
            } catch (异常 e) {
            }
            返回数据库;
        }
    
    }
    

I don't know if this helps anyone but I have merged some of the other suggestions here to produce the following MapViewActivity.

In this example R.layout.map_dbg is only used if this is a debug build and the file exists (add this file to your .gitignore).

The advantages of this approach are :

  1. you don't need to write an ant target (good if you use eclipse)
  2. the correct release key is always in map.xml (hopefully a debug key won't be checked in by mistake)
  3. the release key is always used for a release build
  4. multiple debug keys can be used

The disadvantages of this approach are :

  1. you need to remember to update map_dbg.xml every time map.xml is updated

    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;
        }
    
    }
    
过潦 2024-09-12 05:41:42

我设置了一个简单的 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>

I have setup a simple ant target that replaces the apikey with either a debug key or a release key. This is really simple and keeps the code free of unwanted logic.

<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>
讽刺将军 2024-09-12 05:41:42

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

In Map V2 Its easy to send seperate keys using Android Studio Gradle tool. I have implemented an easy way for that. please check the link here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文