步驟一:

GoogleMap環境準備。

Android系統默認並不支持調用Google Map,爲正常調用Google Map服務,需要先進行如下準備工作。

1)獲取Map API Key

單擊Eclipse主菜單:Window —>Preferences —> 單擊左側「Android」—> Build —> 彈出如圖1所示。

151221371.jpg

圖1查看Android模擬器的Keystore

2)上圖中顯示的便是模擬器的keystore的存儲位置,接下來應用程序需要根據該keystore來生成Google API的Key。

3)用JDK提供的keytool工具爲Android keystore生成認證指紋,啓動命令行窗口輸入如下命令:

keytool –list –keystore <Android keystore的存儲位置>

其中<Android keystore的存儲位置>要替換成圖1中Androidkeystore的存儲位置,如:Keytool -list -keystore "D:\Program Files\android-sdks \.android\debug.keystore"。

151229821.jpg

圖2指紋

注:默認**庫口令是:android

就會得到MD5的指紋,記錄下此記錄:二十段用冒號割開的數字段,每段是兩個十六進制的數(圖2中紅色刪除線下的部分)

4)在Google APIs Console上創建項目,並且註冊Maps API。

首先,去這個網址:https://code.google.com/apis/console/

注:本文對申請API Key V2的說明是基於google developer console(上面的網址)網站舊版本的說明,現在已更新了,如果要返回舊版本可在打開網址後,選擇舊版本。

170530461.jpg

用Gmail的賬戶登錄,如果是第一次的話,需要創建項目,默認情況會創建一個叫做APIProject的項目。

登陸之後出現頁面(如圖3所示):

151243437.jpg

圖3創建APIProject工程

單擊「Createproject...」後到達頁面(如圖4所示):

151250852.jpg

圖4 服務頁面

點擊左邊的Services,會在中間看到很多的APIs和Services,找到GoogleMaps Android API v2,然後把它設置成on,需要接受一些服務條款,如圖5所示。

151253977.jpg

圖5 開啓的服務頁面

之後跳轉到頁面,如圖6所示:

151255544.jpg

圖6 同意條款

勾選同意條款,單擊接受按鈕。

5)獲得API Key

在左邊的導航條中選擇API Access(如圖7)。


151257162.jpg

圖7 導航欄

在出來的頁面中選擇Create New Android Key...就可以生成key了(如圖8所示)

151305346.jpg

圖8 生成Key

然後在對話框中填入:SHA-1 指紋,分號隔開,然後是應用的 package name.然後就會生成一個Key,如圖9所示。151308140.jpg9 生成自己的Key操作圖

最後生成的API Key如圖10所示:

151310143.jpg

10 生成的API Key

步驟二:

把API Key加入應用程序。

1)首先,新建Android應用程序。創建應用程序時,注意包名應該和申請key時候的包名一致。

   2)之後修改AndroidManifest.xml文件,在<application>元素中加入子標籤

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

注:其中your_api_key置換成自己申請的API Key。

在該文件中加入一些許可信息,允許必要的權限。

<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換成自己的包名。

步驟三:


AndroidManifest.xml文件中的其他的選項設置。

1)許可設置

<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_GSERVICE S"/>
<uses-permission
    android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission
    android:name="android.permission.ACCESS_FINE_LOCATION"/>

2)OpenGL ES V2特性支持(作爲<manifest> 的子元素)

<uses-feature
android:glEsVersion="0x00020000"
android:required="true"/>

步驟


在佈局文件中加上地圖。

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

遇到的問題和解決的方法。

程序編譯錯誤,顯示找不到一些類,如圖11所示。

151312459.jpg

11 錯誤提示信息


解決這個問題,首先需要把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,如圖12所示。

151316157.jpg

12 引用類庫步驟圖

之後運行程序就應該出來地圖了。運行過程中,有可能會碰到下面的問題:程序運行成功,但是顯示This app won't run unlessyou update Google Play services,如圖13所示。需要點擊Update,按照提示操作。

151318656.jpg

13 提示界面

   之後運行程序,就出地圖了,如14所示。151321922.jpg

圖14 運行結果圖

注:

因爲MapFragment只在API 12及之後的版本纔有,所以對於之前的版本需要使用Support Library來進行輔助。

如果minSdkVersion設置爲12以前的,就需要使用Support Library

需要更改的地方是:佈局文件中,把MapFragment改爲SupportMapFragment。

   MainActivity繼承自FragmentActivity而不是Activity。(需要import android.support.v4. app.FragmentActivity;)。

步驟


新建工程GoogleMapTest,包名爲com.example.googlemaptest,將一張名爲pos.png的圖片導入到drawable目錄下,用於標註當前的位置。項目中Activity的名字爲MainActivity.java,對應的佈局文件名字爲activity_main.xml,佈局文件中包括2個輸入框,用於接收用戶輸入的經緯度信息,有1個按鈕,用於根據用戶輸入的經緯度定位具體位置;有兩個單選按鈕,分別顯示普通地圖和衛星地圖;有1個地圖組件。該工程目錄結構及佈局文件界面如圖15所示:

151215166.jpg

15 工程目錄結構圖

步驟


   編輯地圖組件對應的佈局文件googlemap.xml,主要代碼如下。

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.MapFragment"
map:cameraBearing="45"
map:cameraTargetLat="25.033611"
map:cameraTargetLng="121.565000"
map:cameraTilt="0"
map:cameraZoom="13"
map:uiCompass="true"
map:mapType="normal"
map:uiRotateGestures="true"
map:uiScrollGestures="true"
map:uiTiltGestures="true"
map:uiZoomControls="false"
map:uiZoomGestures="true" />

注:此文件中,class屬性以下的幾行代碼,是用於設置地圖的一些屬性,這部分內容不是必須的,可以根據自己的需要進行設置,也可以都不設置,而在Activity中使用代碼進行設置。

當在XML文件中加入這些map屬性的設置時,必須要添加命名空間:xmlns:map="http://schemas.android.com/apk/res-auto",並且該XML文件中不能再加入其它的組件,例如編輯框,甚至不能爲其添加容器,例如LinearLayout。如果設置了這些屬性,並且還想添加其它組件,就需要將該XML文件作爲主XML佈局文件的一部分,通過<include>標籤包含在主佈局文件中。具體方法稍後具體說明。

   如果不在XML文件中設置這些map屬性的話,該XML文件可以不添加命名空間,並且可以在此文件中添加其它的組件。

步驟

編寫主佈局文件:activity_main.xml,採用線性佈局並將上面的地圖組件對應的XML文件(googlemap.xml)包含進來。

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
    android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="定位"
android:textSize="15sp" />
<LinearLayout
    android:id="@+id/location"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal" >
<!-- 定義輸入經度值的文本框 -->
<EditText
        android:id="@+id/edt_lng"
    android:layout_width="wrap_content"
android:layout_height="wrap_content"
        android:ems="6"
            android:hint="經度"
android:textSize="20sp" />
<!-- 定義輸入緯度值的文本框 -->
<EditText
android:id="@+id/edt_lat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:ems="6"
android:hint="緯度"
android:textSize="20sp" />
<Button
android:id="@+id/btn_loc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="定位"
android:textSize="15sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/mapsChoice"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<!-- 定義選擇地圖類型的單選按鈕 -->
<RadioGroup
    android:id="@+id/rg_mapType"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal" >
<RadioButton
android:id="@+id/rb_nomal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="普通視圖" />
 <RadioButton
android:id="@+id/rb_satellite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="衛星視圖" />
</RadioGroup>
</LinearLayout>
</LinearLayout>
<include android:id="@+id/googleMap"
layout="@layout/googlemap" />

步驟

編寫Activity文件,MainActivity.java

聲明各組件及必要的類。

//定義界面上的可視化組件
private Button btn_loc;
private EditText edt_lng, edt_lat;
private RadioGroup rg_mapType;
GoogleMap mMap;
private CameraPosition cameraPosition;
private MarkerOptions markerOpt;
//定義LocationManager對象
private LocationManager locManager;
private Location location;
private String bestProvider;

   在onCreate()方法中獲取各組件,並給按鈕註冊事件監聽器,實現地理位置的實時定位。

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//獲取用戶界面的組件
findViews();
//創建LocationManager對象,並獲取Provider
initProvider();
//取得地圖組件
mMap = ((MapFragment)getFragmentManager()
.findFragmentById(R.id.mapView)).getMap();
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
//更新位置信息
updateToNewLocation(location);
//給按鈕添加監聽器
btn_loc.setOnClickListener(new MapClickedListener());
//爲RadioGroup的選中狀態改變添加監聽器
rg_mapType.setOnCheckedChangeListener(new ChangeMapTypeListener());
// 設置監聽器,自動更新的最小時間爲間隔N秒(1秒爲1*1000,這樣寫主要爲了方便)或最小位移變化超過N
locManager.requestLocationUpdates(bestProvider,  3 * 1000, 8
, new LocationListener() {       
//當Provider的狀態改變時
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
// 當GPS LocationProvider可用時,更新位置
location = locManager.getLastKnownLocation(provider);
}
@Override
public void onProviderDisabled(String provider) {
updateToNewLocation(null);
}
@Override
public void onLocationChanged(Location location) {
// 當GPS定位信息發生改變時,更新位置
        updateToNewLocation(location);
}
});
}
private void initProvider() {
//創建LocationManager對象
locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// List all providers:
List<String> providers = locManager.getAllProviders();
Criteria criteria = new Criteria();
bestProvider = locManager.getBestProvider(criteria, false);
location = locManager.getLastKnownLocation(bestProvider);
System.out.println("經度:"+location.getLatitude()+"緯度:" + location.getLongitude());
}
//獲取用戶界面組件
private void findViews() {
//獲取界面上的兩個按鈕
btn_loc = (Button) findViewById(R.id.btn_loc);
//獲取界面上的兩個文本框
edt_lng = (EditText) findViewById(R.id.edt_lng);
edt_lat = (EditText) findViewById(R.id.edt_lat);
//獲得RadioGroup
rg_mapType = (RadioGroup) findViewById(R.id.rg_mapType);
}

實現各個事件監聽器類。

//定位按鈕的點擊事件監聽器
private class MapClickedListener implements OnClickListener{
//根據用戶輸入經緯度定位
@Override
public void onClick(View v) {            
        //獲取用戶輸入的經緯度
        String lng = edt_lng.getText().toString().trim();
        String lat = edt_lat.getEditableText().toString().trim();
        if(lng.equals("") || lat.equals("")){
        Toast.makeText(getApplicationContext(), "請輸入有效的經緯度信息!
", Toast.LENGTH_LONG).show();
            location = locManager.getLastKnownLocation(bestProvider);
            updateToNewLocation(location);
}else{
        location.setLongitude(Double.parseDouble(lng));
        location.setLatitude(Double.parseDouble(lat));
        //調用方法更新地圖定位信息
        updateToNewLocation(location);
}
}
}
private class ChangeMapTypeListener implements OnCheckedChangeListener{
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch(checkedId){       
        case R.id.rb_nomal://如果勾選的是"正常視圖"的單選按鈕
                mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
                break;
            case R.id.rb_satellite://如果勾選的是"衛星視圖"的單選按鈕
                mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
                break;
        }
}
}

實現更新位置信息的方法。

private void updateToNewLocation(Location location){
mMap.clear();
//Marker1
markerOpt = new MarkerOptions();
double dLong = 114.51500;
double dLat = 38.042000;
if(location != null){
    //獲取經度
    dLong = location.getLongitude();
    //獲取緯度
    dLat = location.getLatitude();
}
markerOpt.position(new LatLng(dLat, dLong));
    markerOpt.draggable(false);
    markerOpt.visible(true);
    markerOpt.anchor(0.5f, 0.5f);//設爲圖片中心
    markerOpt.icon(BitmapDescriptorFactory.fromResource(R.drawable.pos));
    mMap.addMarker(markerOpt);
    //將攝影機移動到指定的地理位置
    cameraPosition = new CameraPosition.Builder()
            .target(new LatLng(dLat, dLong))
            .zoom(15) // 縮放比例
            .bearing(0) // Sets the orientation of the camera to east
            .tilt(30)  // Sets the tilt of the camera to 30 degrees
            .build();// Creates a CameraPosition from the builder
mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}

步驟

編輯AndroidManifest.xml,需要添加必要的權限及所申請的API Key

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   …  >
    <uses-sdk
       … />
    <!—下面的權限中,com.example.googlemaptest 要換成你的工程文件的包名-->
    <permission android:name="com.example.googlemaptest.permission.MAPS_RECEIVE"
        android:protectionLevel="signature"/>
<uses-permission
android:name="com.example.googlemaptest.permission.MAPS_RECEIVE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission
android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<!—下面的兩條權限在API V2中是不要求的,但是在開發過程中建議添加 -->
    <uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true"/>
    <application
        … >
        <activity
            android:name="com.example.googlemaptest.MainActivity"
…
        </activity>
        <meta-data android:name="com.google.android.maps.v2.API_KEY"
<!—下面的屬性值要求添加你申請的API Key值-->
            android:value="你申請的API Key值 " />
        <uses-library android:required="true"
                android:name="com.google.android.maps" />
    </application>
</manifest>

步驟

運行改項目,測試定位功能。

   注:由於本項目提取歷史定位數據,所以首次使用,在沒有歷史數據的情況下會閃退,這是因爲第一次獲取GPS的時候沒有歷史數據,location = locManager.getLastKnownLocation(provider)這條語句獲取不到歷史數據造成的,常見的解決辦法有如下幾種:

   1. 循環獲取定位數據,直到獲取到經緯度爲止。該方法的缺點是獲取不到數據時會進入死循環。

while(location  == null){
    lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 30000, 1, new LocListener()); 
}

   2. 優先採用NETWORK_PROVIDER,該Provider比GPS_PROVIDER的穩定性好。

   3. 讀取定位數據之前,先讓程序獲取定位數據,給程序預留一定的時間,因爲定位數據不一定一次性獲取成功,這和位置、手機軟硬件有關。

   4. 偷懶的方法是使用其他的軟件如百度地圖,首先獲取到定位數據,有歷史數據了以後再運行該程序。

   5. 在程序中給定初始化的經緯度數據。


附錄:

新版本中對於已申請的API Key可以服務於多個包,直接添加就可以了。

新版本的谷歌開發網左側的列表中,點擊APIs & auth下的APIs,會顯示所開啓的服務。

左側的列表如下圖所示

173100165.jpg

點擊Credentials列表可申請新的API Key,如下圖示。

173322787.jpg

點擊「CREATE NEW KEY」可申請新的Key,點擊「Edit allowed Android applications」可編輯已有的API Key,也可使用已有Key,支持更多的服務,如下圖所示。

173611287.jpg

   直接在框中添加Key所支持的包名即可,需要注意的是,Key與包名之間要命「;」隔開。之後點擊「Update」按鈕。


到此結束,希望對大家有幫助。

以上純屬個人觀點,供新手交流學習。歡迎高手及大神批評指正。