因为Google Maps的API版本更新,之前的一些教程都是关于旧版本V1的,虽然Google说继续提供服务,但是不再提供API Key的申请。
而新的V2版本貌似改动还挺大。也没搜到国内有什么系统介绍的博客文章之类的(书肯定是来不及那么新了)。
断断续续折腾了大概半个月,因为对Android也不是特别熟悉,所以碰到这样那样的问题。
终于在昨天看见模拟器上跑的地图了。太感人了。
下面就主要说说要成功做成这一件事的流程吧。
一些相关的链接:
Google Maps Android API V1的介绍:
https://developers.google.com/maps/documentation/android/v1/mapkey?hl=zh-CN
Google Maps Android API v2的初步介绍:
https://developers.google.com/maps/documentation/android/
Introduction
https://developers.google.com/maps/documentation/android/intro
Getting Started
(本部分参考https://developers.google.com/maps/documentation/android/start)
1.首先安装Google Play services SDK
Google Maps Android API是作为这个SDK的一部分发行的。
这个安装是通过Android SDK Manager进行,配置好之后的Eclipse上面应该有Android SDK Manager的图标,一般的SDK版本安装和更新都在这里进行。
安装和更新Extras下的Google Play services即可。
2.获取API key
获取Maps API key需要两样东西:应用的signing certificate和它的package name。
获取这个key之后,把它加在应用程序的AndroidManifest.xml文件里即可。
为应用获取一个key还是需要好几个步骤的,下面详细说明:
获取数字证书(digital certificate)信息
数字证书有Debug和Release两种,下面主要说Debug的。
要获取一个叫做SHA-1 fingerprint的东西,作为数字证书的一个简短代表。
这个指纹(fingerprint)是通过一个哈希算法得到的字符串,为了得到你的证书的SHA-1 fingerprint,首先要找到你的debug keystore 文件,文件名叫debug.keystore。
默认情况下它和虚拟机AVD存放在一起,win7下的路径是:C:\Users\your_user_name\.android\,也可以通过Eclipse中的Windows > Prefs > Android > Build来查看这个路径。
然后,在cmd命令行里运行下列命令:
keytool -list -v -keystore "C:\Users\your_user_name\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android
就显示一大堆东西,其中就有证书指纹:
SHA1那一行就包含了证书的SHA-1 fingerprint,是二十段用冒号割开的数字段,每段是两个十六进制的数。
在Google APIs Console上创建API Project
在Google APIs Console上创建项目,并且注册Maps API。
首先,去这个网址:https://code.google.com/apis/console/
用Gmail的账户登录,如果是第一次的话,需要创建项目,默认情况会创建一个叫做API Project的项目。
点击左边的Services,会在中间看到很多的APIs和Services,找到Google Maps Android API v2,然后把它设置成on,需要接受一些服务条款。
获得API Key
在左边的导航条中选择API Access。
在出来的页面中选择Create New Android Key...就可以生成key了:
然后在对话框中填入:SHA-1 指纹, 分号隔开,然后是应用的 package name.然后就会生成一个Key。
比如:
3.把API Key加入应用程序
首先,建立虚拟设备AVD和应用程序。
关于AVD,官方文档并没详细介绍,我后面会有说明。
建立好应用程序,注意包名应该和申请key时候的包名一致。
之后修改AndroidManifest.xml文件:
3.1.在<application>元素中加入子标签
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="your_api_key"/>
其中your_api_key置换成自己申请的API Key。
3.2.加入一些许可信息
<permission android:name="com.example.mapdemo.permission.MAPS_RECEIVE" android:protectionLevel="signature"/> <uses-permission android:name="com.example.mapdemo.permission.MAPS_RECEIVE"/>
其中com.example.mapdemo换成自己的包名。
4. AndroidManifest.xml中的其他具体设置
许可设置
<uses-permission> 作为<manifest> 的子元素,需要加入下列一些:
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
OpenGL ES V2特性支持
同样也是作为<manifest> 的子元素。
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
5.加上地图
首先布局文件:
<?xml version="1.0" encoding="utf-8"?> <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.MapFragment"/>
然后在MainActivity.java:
package com.example.mapdemo; import android.app.Activity; import android.os.Bundle; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } }
遇到的问题和解决的方法
程序编译错误,显示找不到一些类
如图:
解决这个问题,首先需要把Google Play services的类库加载进来:
在Eclipse里面选择:File > Import > Android > Existing Android Code Into Workspace然后点击Next.
之后Browse..., 找到路径下的<android-sdk-folder>/extras/google/google_play_services/libproject/google-play-services_lib, 然后选择Finish。
第二步是添加对这个库的引用:
在自己的项目上右键,选Properties,左边选Android,然后在下面的Library里面Add刚才的google-play-services_lib。
之后程序就应该能运行了。
接着你可能会碰到下面的问题:
这里导入的 google-play-services_lib可能不成功
导入
安装完以后你就能用的吗?不行。你必须导入“Google Play services”库到在你的工作文件夹。点击菜单“File -> import...”,在import对话框中选择“Existing Android Code Into Workspace”,在下一步指定已安装“Google Play services”库的路径(在Android SDK安装目录下\android-sdk\extras\google\google_play_services\libproject\google-play-services_lib)于是你就看到下面的界面状态。记得必须选中”Copy projects into workspace“,否则在以后的开发中会遇到问题。 然后,你可以将“Google Play services”库加入你需要的工程中。打开工程的属性对话框
在左侧选择“Android”属性,点击右下方“Add”按钮,可以选择添加在当前工作区目录中所有有效的库项目。完成上述步骤,你就可以选择添加“goole-play-services_lib”了。
可用性检查
如同 Google Play 服务简介中说的,Google Play 通过Google Play 商店应用为Android2.2以上的用户提供服务更新。但更新可能无法立即满足所有用户,要列出所有Android设备厂商的名字会越来越难:-)。重点: 由于难于预料每个设备的状况,在访问Google Play服务特性以前,你必须在应用中检测一个兼容的Google Play服务APK是否有效。对大部分应用,最好的时机是在主活动(MainActivity)的onResume()
函数。
在用户设备上的Google Play服务APK一般有四种状况。
- Google Play Store 应用的当前版本已经安装, 最近的 Google Play 服务APK 也已经被下载。
- Google Play Store 应用的当前版本已经安装, 但最近的 Google Play 服务APK还没有被下载。
- 有一个旧的 Google Play Store应用, 它不会主动下载Google Play 服务更新。
- Google Play 服务APK无效或者处于关闭状态,一般这是由于用户过去卸载或关闭了它。.
第一种情况是成功状态,一般都是这种情况。但另外三种情况仍然会出现在某些用户的设备上。Google Play 服务客户端库有工具函数来判断当前的 Google Play 服务 APK 是否足以支持你正使用的客户库版本。如果不支持,客户库将让用户去 Google Play Store 来下载Google Play 服务APK.的当前版本。
注意: 搜索Google Play Store是找不到Google Play 服务 APK的。客户库发现设备没有Google Play 服务 APK或其不兼容时,将提供一个Google Play Store的深度链接。
它依赖于你在应用中选择的合适位置。例如,如果是你的应用需要 Google Play 服务,你可能需要在程序第一次启动时做这件事。另一方面,要是Google Play服务对你的应用知识一个可选部分,你可以在用户进入相关功能前进行检查。
- 用
isGooglePlayServicesAvailable()
函数可以查询设备上Google Play 服务APK的状态,它返回结果码。 - 如果结果码是
SUCCESS
, 那Google Play 服务APK是新的,你需要的功能可以正常进行。 - 如果结果码是
SERVICE_MISSING
,SERVICE_VERSION_UPDATE_REQUIRED
或SERVICE_DISABLED
,那调用getErrorDialog()
以向用户显示错误消息,它将允许用户从Google Play Store下载APK或在系统设置界面打开相应功能。
- int errorCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this.getActivity()); // 因为我的代码在Fragment里,所以用getActivity(),要是你的代码在 Activiy中,用this就好
- if( ConnectionResult.SUCCESS != errorCode )
- {
- GooglePlayServicesUtil.getErrorDialog(errorCode, this.getActivity(), 0).show();
- }
署名要求
如果您使用谷歌地图的Android API,在应用程序中,你必须将谷歌Play服务署名文本作为你应用的“法律声明”内容的一部分。谷歌服务署名文本可以通过调用
GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo
获得。
例程代码
例程代码和谷歌服务SDK捆绑在一起。首先你必须按前面步骤添加库项目google-play-services_lib
。然后你通过类似过程将例程代码加入你的工作目录。
- 选择 File > Import > Android > Existing Android Code Into Workspace 并点击 Next。
- 选择Browse...,输入
<android-sdk-folder>/extras/google/google_play_services/samples/maps
, 点击Finish。 - 选择Project > Properties,选择 Java Build Path, 找到 Libraries。
- 选择Add External Jars包含以下 jar文件,点击OK:
<android-sdk-folder>/extras/android/compatibility/v4/android-support-v4.jar
- 添加自己的 Google Maps Android API 密钥。
- 选择 Run > Run 来测试例程。
程序运行成功,但是显示This app won't run unless you update Google Play services.
如图:
有传言说V2不能在AVD上运行,可能Google还会对此问题进行更新。
经过搜索,这个问题已经在Stackoverflow上被讨论过了,链接:http://stackoverflow.com/questions/13691943/this-app-wont-run-unless-you-update-google-play-services-via-bazaar
所以看来在AVD上运行的问题已经被解决了。
解决的方法就是在AVD上安装两个包(Google Play Store和Google Play services):vending.apk和gms.apk,(给一个网盘链接:http://pan.baidu.com/share/link?shareid=190602&uk=2701745266)
并且AVD就选择普通的API 16就行,不需要是Google APIs。我选的是Android4.1 API16.
安装时把那两个包放在当前目录,用命令行安装:
之后运行程序,就出地图了:
补充说明
因为MapFragment只在API 12及之后的版本才有,所以对于之前的版本需要使用Support Library来进行辅助。
如果minSdkVersion设置为12以前的,就需要使用Support Library。
需要更改的地方是:布局文件中,把MapFragment改为SupportMapFragment。
MainActivity继承自FragmentActivity而不是Activity。(需要import android.support.v4.app.FragmentActivity;)
附上完整代码
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.maptest" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" /> <uses-feature android:glEsVersion="0x00020000" android:required="true"/> <permission android:name="com.example.maptest.permission.MAPS_RECEIVE" android:protectionLevel="signature"/> <uses-permission android:name="com.example.maptest.permission.MAPS_RECEIVE"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/title_activity_main" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyAJRV7Rd_dlxnr8FYhQN3pEBUYFkhZWWpI"/> </application> </manifest>
package com.example.maptest; import android.os.Bundle; import android.support.v4.app.FragmentActivity; public class MainActivity extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
布局文件:
<?xml version="1.0" encoding="utf-8"?> <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.SupportMapFragment"/>