83
Android Google Maps 建建建建建建 建建建 建建建 2012/4 V1 2012/8 V2 2013/5 V3 V4 Android 建建建建建建建建建

Android Google Maps

Embed Size (px)

DESCRIPTION

Android 智慧型手機程式設計. Android Google Maps. 建國科技大學 資管系 饒瑞佶 2012/4 V1 2012/8 V2 2013/5 V3 V4. Google Maps. Reference : https://developers.google.com/maps/documentation/android/start#creating_an_api_project. 取得 Google Map API. Step1: 先進入 JDK 目錄. Google Maps. 透過 keytool.exe 建立認證指紋 SHA1 - PowerPoint PPT Presentation

Citation preview

Page 1: Android Google Maps

Android Google Maps

建國科技大學 資管系饒瑞佶

2012/4 V12012/8 V2

2013/5 V3 V4

Android 智慧型手機程式設計

Page 2: Android Google Maps

Google Maps

• 取得 Google Map API

Step1: 先進入 JDK 目錄

Reference :https://developers.google.com/maps/documentation/android/start#creating_an_api_project

Page 3: Android Google Maps

Google Maps

• 透過 keytool.exe 建立認證指紋 SHA1• 需要 debug_keystore 路徑

Page 4: Android Google Maps

新版 IDE 已經列出 SHA1 碼不過好像不太能用

下一步驟用

Page 5: Android Google Maps

重做一次認證

• 輸入• keytool -list -v -keystore "C:\Documents and

Settings\Administrator\.android\debug.keystore“

• 預設密碼是 android

來自 Eclipse 內的 default keystore

Page 6: Android Google Maps

Google Maps

• 產生認證指紋

要的是 SHA1 編碼

Page 7: Android Google Maps

Google Maps• 進入 Google Map API Key 申請頁面• http://code.google.com/intl/zh-Tw/android/add-ons/google-

apis/maps-api-signup.html ( 不再使用 )

輸入認證指紋碼

目前不用

Page 8: Android Google Maps

Google Maps Android API Version 1 開發法已經停用

• http://cheng-min-i-taiwan.blogspot.tw/2013/04/google-maps-android-api-v2-android.html

• 新版 API 需要配合 Google Play Services

Page 9: Android Google Maps

進入申請頁面

需要登入 Google

• https://developers.google.com/maps/documentation/javascript/tutorial#api_key

Page 10: Android Google Maps

Google Maps

• 進入 Google Map API Key 申請頁面

Reference :這裡有做法https://developers.google.com/maps/documentation/android/start#creating_an_api_project

Page 11: Android Google Maps
Page 12: Android Google Maps

API Access

Page 13: Android Google Maps

使用 SHA1 與 package Name

Page 14: Android Google Maps

result

Page 15: Android Google Maps

使用 API Key

Page 16: Android Google Maps

首先將 API key 加入 AndroidManifest.xml

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

Page 17: Android Google Maps

加入使用權限

Page 18: Android Google Maps

加入使用權限到 AndroidManifest.xml

<permission android:name="ctu.rcjao.helloandroid.permission.MAPS_RECEIVE“ android:protectionLevel="signature"/><uses-permission android:name="ctu.rcjao.helloandroid.permission.MAPS_RECEIVE"/>

改成自己的package name

改成自己的package name

Page 19: Android Google Maps

加入使用權限到 AndroidManifest.xml

Page 20: Android Google Maps

Use permission

<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"/><!-- The following two permissions are not required to use     Google Maps Android API v2, but are recommended. --><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

Page 21: Android Google Maps

再加入 use-feature

Page 22: Android Google Maps

uses-feature

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

Page 23: Android Google Maps

最後加入地圖

Page 24: Android Google Maps

Xml 檔案

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

加入下列 code

Page 25: Android Google Maps

JAVA 程式

public class Map extends FragmentActivity {

@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.map);}}

Page 26: Android Google Maps

執行

結果不能跑,有錯誤!

Page 27: Android Google Maps

打開 SDK 中的 SDK Manager ,找到 Extras 並安裝 Android Support Library 及 Google Play Services 兩個項目

Page 28: Android Google Maps

匯入 Google Play Services 函式庫File > Import > Android > Existing Android Code Into Workspace

路徑:android-sdk\extras\google\google_play_services\libproject\google-play-services_lib

Page 29: Android Google Maps

匯入完成

Page 30: Android Google Maps

專案要加入這個 library

Page 31: Android Google Maps

還有要開 google Maps Android API v2

不是這個喔!

Page 32: Android Google Maps

執行• 需要實體手機• 過程中可能需要更新 Google Play

Page 33: Android Google Maps

Google Maps

實體手機

Page 34: Android Google Maps

發佈到 AVD2.2

Page 35: Android Google Maps

有了,但是還是不行!換個版本 4.0.3

Page 36: Android Google Maps

使用 SDK 4.0.3

AVD 設定

Page 37: Android Google Maps

設定模擬器顯示地圖• 首先在模擬器中安裝 Google Play Service• 修改 System 目錄之檔案權限,允許寫入權限

– adb shell mount -o remount,rw -t yaffs2 /dev/block/mtdblock0 /system

– adb shell chmod 777 /system/app• adb push GoogleLoginService.apk /system/app/• adb push GoogleServicesFramework.apk /system/app/• adb push Phonesky.apk /system/app/

Page 38: Android Google Maps

• adb install Maps_6.12.0.apk • adb install

com.google.android.gms-3.apk

漫長的等待… .

Google Play Service要夠新

Page 39: Android Google Maps

如果出現要 update Google Play Service !

Page 40: Android Google Maps

通常是失敗,因為不支援線上更新

下載新的 APK 重裝就可以了

Page 41: Android Google Maps

result

Page 42: Android Google Maps

在 Google Maps 上加標示• SDK 至少要 4.0@SuppressLint("NewApi")public class Main extends FragmentActivity { // 要顯示的座標 static final LatLng CTU = new LatLng(24.06660656734983, 120.54975986480713); private GoogleMap map;

@SuppressLint("NewApi") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 取得地圖物件 map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap(); // 建立紅色氣球標示 Marker mk = map.addMarker(new MarkerOptions().position(CTU).title("建國科技大學 ").snippet("資管系 ")); // 設定縮放大小是 16 ,且將標示點放在正中央 map.moveCamera(CameraUpdateFactory.newLatLngZoom(CTU, 16)); }}

如果更早的 SDK 也要可以用 map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();

Page 43: Android Google Maps

result

Page 44: Android Google Maps

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" >

<fragment android:layout_weight="1" android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.SupportMapFragment"/> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_weight="0" > <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=" 地圖 " /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=" 衛星 " /> </LinearLayout></LinearLayout>

修改 UI 的 xml

加入這段來切換地圖種類

原地圖設定 layout_weight

Page 45: Android Google Maps

result

Page 46: Android Google Maps

Button btn_normalview=(Button)findViewById(R.id.button1);Button btn_satellitetview=(Button)findViewById(R.id.button2);btn_normalview.setOnClickListener(new Button.OnClickListener(){ public void onClick(View arg0) { map.setMapType(GoogleMap.MAP_TYPE_NORMAL); // 顯示地圖模式 }}); btn_satellitetview.setOnClickListener(new Button.OnClickListener(){ public void onClick(View arg0) { map.setMapType(GoogleMap.MAP_TYPE_SATELLITE); // 顯示衛星模式 } });

Oncreate 中加入下列 code

Page 47: Android Google Maps
Page 48: Android Google Maps

地址轉座標功能將下列 code 加入 UI (fragment 前 )

<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:layout_weight="0" > <EditText android:id="@+id/editText1" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" > <requestFocus /> </EditText> <Button android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=" 顯示 " /> <TextView android:id="@+id/textview1" android:text="" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout>

Page 49: Android Google Maps

地址轉座標功能Button btn_address_to_geo=(Button)findViewById(R.id.button3);btn_address_to_geo.setOnClickListener(new Button.OnClickListener(){ public void onClick(View arg0) { try { EditText inputaddress=(EditText)findViewById(R.id.editText1); tv1=(TextView)findViewById(R.id.textview1); Geocoder geocoder = new Geocoder(Main.this, Locale.getDefault()); List<Address> geoResults = geocoder.getFromLocationName(inputaddress.getText().toString(), 5); while (geoResults.size()==0) { geoResults = geocoder.getFromLocationName(inputaddress.getText().toString(), 5); } if (geoResults.size()>0) { Address addr = geoResults.get(0); Double latitude = addr.getLatitude() * 1E6; Double longitude = addr.getLongitude() * 1E6; tv1.setText(latitude + "/" + longitude); } } catch (Exception e) { tv1.setText(" 轉換失敗 "); } }});

Page 50: Android Google Maps

result

實機 模擬器

Page 51: Android Google Maps

建立 showlocation 方法

// 顯示座標點private void showloaction(double d,double e,String title, String snip){ LatLng CTU = new LatLng(d, e); // 取得地圖物件 map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap(); // 建立紅色氣球標示 Marker mk = map.addMarker(new MarkerOptions().position(CTU).title(title).snippet(snip)); // 設定縮放大小是 16 ,且將標示點放在正中央 map.moveCamera(CameraUpdateFactory.newLatLngZoom(CTU, 16));}

Page 52: Android Google Maps

呼叫 showlocation 方法

Page 53: Android Google Maps

呼叫 showlocation 方法 Button btn_address_to_geo=(Button)findViewById(R.id.button3); btn_address_to_geo.setOnClickListener(new Button.OnClickListener() { public void onClick(View arg0) { try { EditText inputaddress=(EditText)findViewById(R.id.editText1); tv1=(TextView)findViewById(R.id.textview1); Geocoder geocoder = new Geocoder(Main.this, Locale.getDefault()); List<Address> geoResults = geocoder.getFromLocationName(inputaddress.getText().toString(), 5); while (geoResults.size()==0) { geoResults = geocoder.getFromLocationName(inputaddress.getText().toString(), 5); } if (geoResults.size()>0) { Address addr = geoResults.get(0); Double latitude = addr.getLatitude() * 1E6; Double longitude = addr.getLongitude() * 1E6; tv1.setText(latitude + "/" + longitude); showloaction((double)(addr.getLatitude()), (double)(addr.getLongitude()),inputaddress.getText().toString(),""); } } catch (Exception e) { tv1.setText(" 轉換失敗 "); } } });

Page 54: Android Google Maps

AVD 多數執行有問題,最好使用手機測試

輸入地址

轉換地址成座標

座標

顯示座標點

Page 55: Android Google Maps

不用註冊 Google Maps API 也可以使用 Intent

Page 56: Android Google Maps

public class MapIntent extends Activity {

@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Uri uri=Uri.parse("geo:24.06660656734983,120.54975986480713"); Intent it=new Intent(Intent.ACTION_VIEW,uri); startActivity(it);}}

顯示 Google Maps 地圖

Page 57: Android Google Maps

利用 Intent 玩 Google Maps

Page 58: Android Google Maps

Google Maps street view

– Uri uri=Uri.parse("google.streetview:cbll=46.813812,-71.207378&cbp=1,99.56,,1,-5.27&mz=21");

只支援美加地區

AVD 是看不到的!

Page 59: Android Google Maps
Page 60: Android Google Maps

更多 Google Maps

• 路徑規劃

Uri uri = Uri.parse("http://maps.google.com/maps? f=d&saddr=startLat%20startLng&daddr=endLat%20endLng&hl=en"); Intent it = new Intent(Intent.ACTION_VIEW, uri); startActivity(it);

//where startLat, startLng, endLat, endLng are a long with 6 decimals like: 50.123456

Page 61: Android Google Maps

整合 GPS

Page 62: Android Google Maps

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/textview1" android:text="" android:layout_width="wrap_content" android:layout_height="wrap_content"/><fragment android:layout_weight="1" android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.SupportMapFragment"/></LinearLayout>

加入對應的 xml

Page 63: Android Google Maps

AndroidManiFest.xml

• 需要開放以下權限– <uses-permission

android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>

– <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>

Page 64: Android Google Maps

偵測是否開啟 GPS

// 如果沒有開啟 GPS--------------------- mLocationManager=(LocationManager)

(this.getSystemService(Context.LOCATION_SERVICE));

if(mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)){

}else{ // 到系統開啟 GPS 與 WIFI 服務的畫面 startActivity(new

Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); }//-------------------- 如果沒有開啟 GPS

private LocationManager mLocationManager;

Page 65: Android Google Maps

Android GPS 運作方式• 使用 LocationManager :判定是否有提供定位服務 ( 硬體 GPS 或 WIFI)

• 建立 LocationProvider ,設定定位參數,並同時透過 LocationManager 取得座標 ( 硬體軟體, GPS 或是 WiFi)

• 設定 LocationManager 的 Listener 事件,偵測事件的改變

• MapController 負責控制 Google Maps

Page 66: Android Google Maps

GPS 訊號抓取主體

沒有 GPS時觸發

GPS訊號擷取主體

宣告

Page 67: Android Google Maps

mLocationManager =(LocationManager)(this.getSystemService(Context.LOCATION_SERVICE)); if(mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)){ }else{ // 到達系統開啟 GPS 與 WIFI 服務的畫面 startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); } //-------------------- 如果沒有開啟 GPS /* Provider 初始化 */ getLocationPrivider(); /* 設定事件的 Listener */ mLocationManager.requestLocationUpdates(mLocationPrivider, 2000, 0, mLocationListener); if(mLocation!=null) //第一次顯示 { // 取得速度 double speed=mLocation.getSpeed()/1000*60*60; //原單位是 m/s double altitude = mLocation.getAltitude(); tv_show_gps.setText("緯度: " + formatgeo(mLocation.getLatitude()) + " 經度: " + formatgeo(mLocation.getLongitude()) + " 海拔: " + altitude + " m 速度: " + formatspeed(speed) + "km/h"); }

啟動 GPS

如果沒有啟動使用 GPS服務,將跳至設定畫面

要求 GPS提供服務設定 GPS監聽服務

如果有 GPS訊號,顯示到畫面上

TextView tv_show_gps;private ProgressDialog MyDialog;private String mLocationPrivider="";private Location mLocation;

宣告物件

補充說明

Page 68: Android Google Maps

tv_show_gps=(TextView)findViewById(R.id.textview1); createCancelProgressDialog(" 定位中 "," 定位中 .. 請稍待! "," 取消 "); try{ // 如果沒有開啟 GPS---------------------mLocationManager =(LocationManager)(this.getSystemService(Context.LOCATION_SERVICE)); if(mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)){ }else{ // 到系統開啟 GPS 與 WIFI 服務的畫面 startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); } //-------------------- 如果沒有開啟 GPS mLocationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE); // Provider 初始化 getLocationPrivider(); // 設定 GPS 的 Listener mLocationManager.requestLocationUpdates(mLocationPrivider, 2000, 0, mLocationListener); if(mLocation!=null) //第一次顯示 { // 取得速度 double speed=mLocation.getSpeed()/1000*60*60; //原單位是m/s double altitude = mLocation.getAltitude(); tv_show_gps.setText("緯度: " + formatgeo(mLocation.getLatitude()) + " 經度: " + formatgeo(mLocation.getLongitude()) + " 海拔: " + altitude + " m 速度: " + formatspeed(speed) + "km/h"); }

Page 69: Android Google Maps

}catch(Exception e){ new AlertDialog.Builder(GPS.this) .setTitle(" 系統訊息 ") .setMessage("無法取得 GPS 座標 ") .setPositiveButton("確認 ",new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub MyDialog.dismiss(); } }) .show(); }

Page 70: Android Google Maps

// 取得 LocationProviderpublic void getLocationPrivider(){ Criteria mCriteria01 = new Criteria(); mCriteria01.setAccuracy(Criteria.ACCURACY_FINE); mCriteria01.setAltitudeRequired(true); //需要高度 mCriteria01.setBearingRequired(false); mCriteria01.setCostAllowed(true); mCriteria01.setPowerRequirement(Criteria.POWER_LOW); mLocationPrivider = mLocationManager.getBestProvider(mCriteria01, true); mLocation = mLocationManager.getLastKnownLocation(mLocationPrivider);}

Page 71: Android Google Maps

// 偵測位置改變public final LocationListener mLocationListener = new LocationListener(){ public void onLocationChanged(Location location) { // 取得速度 double speed=location.getSpeed()/1000*60*60; //原單位是m/s double altitude = location.getAltitude(); tv_show_gps.setText("緯度: " + formatgeo(location.getLatitude()) + " 經度: " + formatgeo(location.getLongitude()) + " 海拔: " + altitude + " m 速度: " + formatspeed(speed) + "km/h"); MyDialog.dismiss(); // 結束進度 } public void onProviderDisabled(String provider) { } public void onProviderEnabled(String provider) { } public void onStatusChanged(String provider,int status,Bundle extras) { }};//-----------------偵測位置改變

Page 72: Android Google Maps

// format GPS 座標的方法 public String formatgeo(double num){NumberFormat formatter = new DecimalFormat("###.####");String s=formatter.format(num);return s;}

// format speed 的方法 public String formatspeed(double num){NumberFormat formatter = new DecimalFormat("###.##");String s=formatter.format(num);return s;}

Page 73: Android Google Maps

// 產生定位中視窗 private void createCancelProgressDialog(String title, String message, String buttonText) { MyDialog = new ProgressDialog(this); MyDialog.setTitle(title); MyDialog.setMessage(message); MyDialog.setButton(buttonText, new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int which){ // Use either finish() or return() to either close the activity or just the dialog android.os.Process.killProcess(android.os.Process.myPid()); HelloGPSActivity.this.finish(); return; } }); MyDialog.show(); // 顯示進度 }

// 按 BACK按鍵時關閉程式@Overridepublic void onBackPressed() { android.os.Process.killProcess(android.os.Process.myPid()); HelloGPSActivity.this.finish(); }

Page 74: Android Google Maps

透過 ddms 送出模擬 GPS 座標到AVD

需要<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>

Page 75: Android Google Maps
Page 76: Android Google Maps

取得 GPS 訊號後,將其顯示到Google Maps 上

Page 77: Android Google Maps

結合前面的 showloaction 方法• 在 onLocationChanged 中加入呼叫

記得加入地圖private GoogleMap map;

Page 78: Android Google Maps

稍微修改 showloaction 方法

移除前一個氣球

Page 79: Android Google Maps

result

Page 80: Android Google Maps

控制旋轉不觸發 oncreate

• AndroidMainfast.xml 中設定允許改變:– <uses-permission

android:name="android.permission.CHANGE_CONFIGURATION" />

• AndroidMainfast.xml 中對要攔截旋轉事件的Activity 加入屬性:– android:configChanges="orientation"

Page 81: Android Google Maps

畫路徑-從現在的範例修改LatLng p1; // 出發點LatLng p2; // 結束點

if(mLocation!=null) //第一次顯示{ // 取得速度 double speed=mLocation.getSpeed()/1000*60*60; //原單位是 m/s double altitude = mLocation.getAltitude(); p1 = new LatLng(mLocation.getLatitude(), mLocation.getLongitude()); tv_show_gps.setText(“緯度:” + formatgeo(mLocation.getLatitude()) + " 經度: " + formatgeo(mLocation.getLongitude()) + " 海拔: " + altitude + " m 速度: " + formatspeed(speed) + "km/h");}

加入成全域

加入第一個點

Page 82: Android Google Maps

public void onLocationChanged(Location location){ // 取得速度 double speed=location.getSpeed()/1000*60*60; //原單位是 m/s double altitude = location.getAltitude(); tv_show_gps.setText("緯度: " + formatgeo(location.getLatitude()) + " 經度: " + formatgeo(location.getLongitude()) + " 海拔: " + altitude + " m 速度: " + formatspeed(speed) + "km/h"); p2 = new LatLng(location.getLatitude(), location.getLongitude()); showloaction((double)(location.getLatitude()), (double)(location.getLongitude()),"目前 GPS座標點 ",""); p1=p2; MyDialog.dismiss(); // 結束進度 }

取得結束點畫線

將結束點變成出發點

Page 83: Android Google Maps

// 顯示座標點private void showloaction(double d,double e,String title, String snip){ LatLng CTU = new LatLng(d, e); // 取得地圖物件 map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap(); // 建立紅色氣球標示 if(mk != null) mk.remove(); mk = map.addMarker(new MarkerOptions().position(CTU).title(title).snippet(snip)); // 設定縮放大小是 16 ,且將標示點放在正中央 //map.moveCamera(CameraUpdateFactory.newLatLngZoom(CTU, 16)); PolylineOptions line=new PolylineOptions().add(p1,p2).width(5).color(Color.BLUE); map.addPolyline(line); map.moveCamera(CameraUpdateFactory.newLatLngZoom(p2, 16));}

加入畫線