Google API V2申請及Google Map簡單應用例子
步驟一:
GoogleMap環境準備。
Android系統預設並不支援呼叫Google Map,為正常呼叫Google Map服務,需要先進行如下準備工作。
1)獲取Map API Key
單擊Eclipse主選單:Window —>Preferences —> 單擊左側“Android”—> Build —> 彈出如圖1所示。
圖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"。
圖2指紋
注:預設金鑰庫口令是:android
就會得到MD5的指紋,記錄下此記錄:二十段用冒號割開的數字段,每段是兩個十六進位制的數(圖2中紅色刪除線下的部分)。
4)在Google APIs Console上建立專案,並且註冊Maps API。
首先,去這個網址:https://code.google.com/apis/console/
注:本文對申請API Key V2的說明是基於google developer console(上面的網址)網站舊版本的說明,現在已更新了,如果要返回舊版本可在開啟網址後,選擇舊版本。
用Gmail的賬戶登入,如果是第一次的話,需要建立專案,預設情況會建立一個叫做APIProject的專案。
登陸之後出現頁面(如圖3所示):
圖3建立APIProject工程
單擊“Createproject...”後到達頁面(如圖4所示):
圖4 服務頁面
點選左邊的Services,會在中間看到很多的APIs和Services,找到GoogleMaps Android API v2,然後把它設定成on,需要接受一些服務條款,如圖5所示。
圖5 開啟的服務頁面
之後跳轉到頁面,如圖6所示:
圖6 同意條款
勾選同意條款,單擊接受按鈕。
5)獲得API Key
在左邊的導航條中選擇API Access(如圖7)。
圖7 導航欄
在出來的頁面中選擇Create New Android Key...就可以生成key了(如圖8所示)。
圖8 生成Key
然後在對話方塊中填入:SHA-1 指紋,分號隔開,然後是應用的 package name.然後就會生成一個Key,如圖9所示。圖9 生成自己的Key操作圖
最後生成的API Key如圖10所示:
圖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所示。
圖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所示。
圖12 引用類庫步驟圖
之後執行程式就應該出來地圖了。執行過程中,有可能會碰到下面的問題:程式執行成功,但是顯示This app won't run unlessyou update Google Play services,如圖13所示。需要點選Update,按照提示操作。
圖13 提示介面
圖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所示:
圖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,會顯示所開啟的服務。
左側的列表如下圖所示
點選Credentials列表可申請新的API Key,如下圖示。
點選“CREATE NEW KEY”可申請新的Key,點選“Edit allowed Android applications”可編輯已有的API Key,也可使用已有Key,支援更多的服務,如下圖所示。
直接在框中新增Key所支援的包名即可,需要注意的是,Key與包名之間要命“;”隔開。之後點選“Update”按鈕。
到此結束,希望對大家有幫助。
以上純屬個人觀點,供新手交流學習。歡迎高手及大神批評指正。
轉載於:https://blog.51cto.com/weiweili/1342861