2014년 2월 4일 화요일

android - Google Location Services API

기존에는 위치기반 서비스를 위해 android.location API를 사용했으나 이제 Google Play Services에서 제공하는 Google Location Services API를 사용하길 권장한다.

이는 저전력과 최상의 위치정보 획득/유지 등 파워풀한 기능을 제공한다.

참고) 구글에서는 개발자가 Google Play Service에서 제공하는 API를 최우선으로 사용하길 권장한다.
Android API는 OS version에 종속적이고 이는 제조사에서 디바이스에 OS 업그레이드를 제공하는 시점에서야 새로이 추가된 API를 사용할 수 있기에 제조사에따라, 단말에 따라 신규 API 사용이 제한되기 때문이다.
이를 해결하기 위해 구글의 핵심 API들을 Google Play Service에 통합해나가고 있다.
이로 인해 구글은 제조사의 OS 업그레이드에 영향을 받지않고 새로운 서비스나 기능을 보다 빠르게 사용자들에게 제공할 수 있게되었다.
(Android 2.2이상에서 Google Play Service는 Play Store를 통해 자동 업데이트된다)


Location API 사용을 위한 사전준비

1. Google Play Services 설치
해당 API를 사용하기 위해서는 먼저 Google Play Services Library를 설정하여야 한다.

 1) SDK Manager 실행

 2) Google Play Services SDK 설치
  - Android 2.2에서는 Google Play Services for Froyo를 설치
  - android 2.3 이상에서는  Google Play Services SDK 4.0.30 이상 버전을 설치

 3) Google API 설치
  - emulator에서 테스트 하기 위해선 Android 4.2.2 이상의 Google API를 설치해야 함

 4) 라이브러리 프로젝트로 아래 경로의 프로젝트를 임포트 한다.
 <android-sdk>/extras/google/google_play_services/libproject/google-play-services_lib/


2. 프로젝트에 적용

 1) 자신의 프로젝트에서 사용하려면 임포트한 Google Play Services Library Project를 추가

 2) manifest 파일의 <application> 태그에 아래 설정을 추가한다.
<meta-data android:name="com.google.android.gms.version"
           android:value="@integer/google_play_services_version" />

 3) proguard를 사용하고 있다면 아래 설정을 proguard 설정파일에 추가한다.
-keep class * extends java.util.ListResourceBundle {
    protected Object[][] getContents();
}
-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
    public static final *** NULL;
}
-keepnames @com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class * {
    @com.google.android.gms.common.annotation.KeepName *;
}
-keepnames class * implements android.os.Parcelable {
    public static final ** CREATOR;
}

참고 URL) http://developer.android.com/google/play-services/setup.html


Google Location API 사용하기

1. 최근 위치 가져오기
Location Service는 현재 위치를 자동으로 관리하며 Location permission에 따라 정확도가 결정된다

 1) Location permission 지정
  - ACCESS_COARSE_LOCATION은 도시의 블럭단위 정도의 정확도를 갖는다.
  - ACCESS_FINE_LOCATION은 보다 정확한 위치정보를 획득할 수 있으며 ACCESS_COARSE_LOCATION과 함께 사용한다.
  - 사용하고자 하는 Location permission을 manifest 파일에 추가한다.

 2) Google Play Services 체크
  필요한 Google Play Services 버전이 설치되어 있는지 체크하고 설치가 필요한 경우 설치를 유도하게 한다.

 3) LocationClient를 이용한 최근 위치 획득
  - ConnectionCallbacks과 OnConnectionFailedListener 콜백을 정의한다.
  - LocationClient를 Activity의 onCreat()에서 생성하고 onStart()에서 연결하고 onStop()에서 연결을 끊는다.
  - getLastLocation() 함수로 최근 위치를 획득한다.

비고) Google Location API를 사용하면 위와 같이 간단히 최근 위치를 획득할 수 있으나 android.location API를 사용하면 Criteria로 정확도를 선택하고 LocationManager로 최적의 Provider를 선택하고(실패시 대응코드 적용도 필요) 얻어진 Provider의 결과에 따라(GPS_PRIVIDER, NETWORK_PROVIDER, PASSIVE_PROVIDER) 가장 적합환 위치정보를 획득하는 시나리오를 구성하여야 한다.


2. 위치 갱신정보 획득
 위에 언급한 1번 최근 가져오기와 동일한 구성하에 아래 항목을 추가한다.

 1) LocationListener 콜백 정의
   위치정보가 갱신되면 Location정보를 콜백

 2) 위치정보 갱신 요청
  - GooglePlayServicesClient.ConnectionCallbacks의 onConnected()메소드로 연결이 성공한 경우 위치정보 갱신을 요청
  - 갱신정보는 LocationRequest를 사용하며 중요 파라미터들은 다음과 같다.

  • setPriority() : 전력소모와 정확도중 우선순위를 두는 정도에따른 설정값
    • PRIORITY_HIGH_ACCURACY : 배터리소모를 고려하지 않고 정확도 최우선
    • PRIORITY_LOW_POWER : 도시정도의 정확도로 저전력 고려
    • PRIORITY_NO_POWER : 추가적인 배터리 소모없이 위치정보 획득
    • PRIORITY_BALANCED_POWER_ACCURACY : 도시의 블럭정도의 정확도
  • setInterval() : 업데이트 되길 바라는 주기(milliseconds), 다른 어플에서 설정한 setInterval()값에 영향을 받는다.
  • setFastInterval() : 명확한 업데이트 주기(milliseconds), 자신의 어플에서 위치정보 획득 후 처리하는 로직의 시간비용값보다 커야한다.
  • setSmallestDisplacement() : 위치정보 갱신의 최소 거리(m, 미터), 해당 거리이상 위치가 변경되어야 갱신함

  - requestLocationUpdates() 메소드로 위치정보 갱신 요청
  - removeLocationUpdates() 메소드로 우치정보 갱신 요청 취소


3. 위치정보의 주소 얻기
  - android.location API 사용
  - Geocoder 클래스의 getFromLocation() 메소드를 사용하여 Address 컬랙션 획득


4. Geofence(가상경계) 생성과 모니터
  - Geofence를 모니터링 하려면 ACCESS_FINE_LOCATION 권한을 필요로 한다.
  - 위도, 경도, 반경을 지정하여 Geofence를 생성하고 이에 얼마나 근접한지 들어갔는지 나갔는지 등을 모니터할 수 있다.
  - Geofence에 만료시간을 지정하여 만료처리 할 수 있다.
  - Geofence는 유니크한 ID를 가지며 이를 통해 해지 할 수 있다.

위에 언급한 1번 최근 가져오기와 동일한 구성하에 아래 항목을 추가한다.

 1) manifest 파일에 ACCESS_FINE_LOCATION 권한을 추가한다.

 2) Geofence를 Geofence.Builder로 생성한다.
  - setCircularRegion() : latitude, longitude, radius로 가상경계 설정
  - setExpirationDuration() : 가상경계 만료시간 설정(millisecond)
  - setLoiteringDelay() : 가상경계에 들어갔는지 나갔는지 판단할때 지연시간(millisecond)
  - setRequestId() : 가상경계의 유니크한 ID 문자열
  - setTransitionTypes() : 가상경계의 이동 행위

  • GEOFENCE_TRANSITION_DWELL : 가상경계에 들어가 지정된 시간 이상 머무를때
  • GEOFENCE_TRANSITION_ENTER : 가상경계에 들어갔을때
  • GEOFENCE_TRANSITION_EXIT : 가상경계에서 나왔을때

 3) OnAddGeofencesResultListener 정의

 4) LocationClient의 addGeofences() 메소드로 Geofence를 등록한다.
  Activity, Broadcast, Service 등의 형태로 생성된 PendingIntent에 의해 Intent에 행위정보가 전달된다.

 5) LocationClient의 removeGeofences() 메소드로 Geofence를 해지한다.


5. 사용자의 현재 행위 인지
 걷는중, 운전중, 서있기등 사용자의 현재 행위를 인지

 1) ACTIVITY_RECOGNITION 권한 추가
  ACCESS_COARSE_LOCATION이나 ACCESS_FINE_LOCATION 권한을 필요로 하지 않는다.

 2) Google Play Services 체크

 3) ActivityRecognitionClient를 Activity의 onCreate()에서 생성

 4) onStart()에서 연결하고 onStop()에서 연결끊기

 5) ActivityRecognitionClient가 연결이 성공하여 ConnectionCallback에서 onConnntected()가 호출되면 requestActivityUpdates() 메소드로 행위 인식 요청
  -  Activity, Broadcast, Service 등의 형태로 생성된 PendingIntent에 의해 Intent에 행위정보가 전달된다.
  - IntentService를 이용하는것이 효화적이다.

 6) ActivityRecognitionResult로 intent로 전달된 행위정보를 처리


6. Mock Location을 이용한 테스팅
 - 위치정보를 바꾸기 위해 실제로 이동하거나 할 필요없이 Mock Location을 이용하여 테스트가 가능하다.
 - Location Service를 Mock Mode로 설정하고 Mock 데이터를 전달하면 Location Service는 Mock Data를 처리한다.
 - 별도의 앱에서 Mock 데이터를 전송할 수 있으며 이는 실제 앱에 테스트 코드를 삽입하지 않아도 되기에 보다 좋은 방법이다.

 Mock Data Provider 앱 구현

 1) ACCESS_MOCK_LOCATION 퍼미션 추가
  - Mock location을 전송하려면 ACCESS_MOCK_LOCATION 퍼미션이 필요함

 2) LocationClient에 setMockMode() 메소드로 모드 설정

 3) Mock location sending...

참고 URL) http://developer.android.com/tools/device.html#setting-up