Google Play 서비스의 Fused Location Provider를 이용한 현재위치 측위

안드로이드에서 LocationManager를 이용해서 현재위치를 측위할 때 개발자가 직접 기능을 구현하기 때문에 측위 방법의 선택과 그에 대한 고려사항이 많아 복잡하고 어려웠습니다. 이번 블로그에서는 이런 문제를 해결할수 있는 FusedLocationProvider API와 Google Play 서비스에 대하여 간단히 소개하도록 하겠습니다.

 

1. iOS의 위치측위 방법 (CLLocationManager)
//헤더파일 설정 (.h)#import@interface PhotoViewController : UIViewController <CLLocationManagerDelegate>{

CLLocationManager *locationManager;

………………………………

}

@property (nonatomic, strong) CLLocationManager *locationManager;

 

 

//소스파일 설정 (.m)

locationManager = [[CLLocationManager alloc]init];// 초기화

locationManager.delegate = self;// delegate 연결

locationManager.desiredAccuracy = kCLLocationAccuracyBest;// 정확도 최고로 설정

[locationManager startUpdatingLocation];// 현재 위치 업데이트

NSLog(@”%f”,locationManager.location.coordinate.latitude);// latitude

NSLog(@”%f”,locationManager.location.coordinate.longitude);// longitude

iOS는 CLLocationManager를 통해 측위요청하면 CLLocationManager에서 설정하는 정확도 레벨에 근거해 GPS, Wi-FI, CellTower 순으로 측위하여 측위된 결과를 CLLocationManagerDelegate를 통해 CLLocationManager에 전달됩니다. 사용자는 해당정보를 CLLocation을 통해 확인할 수 있습니다. iOS는 OS단과 해당 API가 해당 서비스에 대한 모든 처리를 담당하고 있기 때문에 개발자는 간단하게 API를 호출하여 현재 위치를 측위할 수 있습니다.

 

2. 안드로이드 위치측위 방법 (LocationManager)
//AndroidManifest.xml<!– 위치측위에 사용한 Provider 권한 설정. –><uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” />

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

 

 

//안드로이드 Activity Class

private LocationManager locationManager;

private boolean gps_enabled = false;

private boolean network_enabled = false;

 

@Override

public voidonCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

 

locationManager = (LocationManager)this.getSystemService(Context.LOCATION_SERVICE);

gps_enabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);//GPS 이용가능 여부

network_enabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);//Network 이용가능 여부

if(!gps_enabled && !network_enabled){

Log.d(“LocationManagerTest”,“nothing is enabled”)//모두 사용 불가

return;

}

 

if((gps_enabled)//GPS를 이용한 측위요청

locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);// 현재 위치 업데이트

 

if((network_enabled)//Network를 이용한 측위요청

locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);// 현재 위치 업데이트

}

 

LocationListener locationListenerGps = new LocationListener() {

public void onLocationChanged(Location location) {

double x =location.getLatitude();

double y = location.getLongitude();

locationManager.removeUpdates(this);

locationManager.removeUpdates(locationListenerNetwork);

 

Log.d(“LocationManagerTest”,“gps enabled”+x + “\n” + y, duration)

}

 

public void onProviderDisabled(String provider) {

}

 

public void onProviderEnabled(String provider) {

}

 

public void onStatusChanged(String provider, int status, Bundle extras) {

}

};

 

LocationListener locationListenerNetwork = new LocationListener() {

public void onLocationChanged(Location location) {

double x = location.getLatitude();

double y = location.getLongitude();

locationManager.removeUpdates.removeUpdates(this);

locationManager.removeUpdates.removeUpdates(locationListenerGps);

Log.d(“LocationManagerTest”,“network enabled”+x + “\n” + y, duration)

}

 

public void onProviderDisabled(String provider) {

}

 

public void onProviderEnabled(String provider) {

}

 

public void onStatusChanged(String provider, int status, Bundle extras) {

}

};

Android는 GPS, Network 중에서 개발자가 측위할 방법를 직접 선택하고 구현해야 합나디. Wi-Fi를 통한 위치 확인은 Manifest를 통해 권한 설절(ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION)을 설정한 경우에 따라 위치 측위가 가능합니다. LocationManager를 통해 측위요청을 할때 GPS, Network 중 이용가능한 Provider를 검색하고, Provider 정보와 함께 요청하면 등록한 LocationListener를 통해 측위된 결과를 확인할 수 있습니다. 위의 소스는 사용가능한 Provider정보를 통해 GPS, Wi-Fi, CellTower 중 하나만을 선택하여 측위하였지만 iOS와 같이 순차적으로 선택하여 각각의 위치를 획득, 비교하여 해당결과 전달하게 되면다면 여러조건에 대하여 고려해야할 부분이 발생하고 정확한 결과를 위해 보정(getBestprovider, isBetterLocation, PassiveProvider)이 필요하기 때문에 아마 위의 소스보다 더 복잡할 것입니다.

 

3. Fused Location Provider를 이용한 위치 측위

Fused Location Provider는 Google I/O 2013에서 기존의 LocationManager를 개선한 위치측위 기술입니다. Fused Location Provider의 특징은 저전력으로 위치측위의 정확도를 향상시켰고, 기존보다 간편하게 API 호출하여 위치를 측위할 수 있도록 개선되었습니다. Fused Location Provider는 Google Play 서비스를 통해 API형태로 사용할 수 있습니다.

play-services-diagram

Google Play 서비스는 구글에서 제공하는 다양한 서비스들을 손쉽게 사용할 수 있도록 제공하는 클라이언트 라이브러리입니다. 구글 플레이 스토어를 통한 자동 플랫폼 업데이트를 지원하기 때문에 OS버전이나, 통신사 버전에 따른 디바이스 지원에 대한 걱정없이 구글이 제공하는 최신의 기능을 쉽게 빠르게 사용할 수 있습니다.

google_play_service_install

 

Google Play 서비스 라이브러리는 Android-SDK의 “./extras/google/google_play_services” 폴더에 라이브러리 프로젝트, 문서. Sample 정보가 저장되어 있습니다. 만약 해당폴더가 없다면 Eclipse의 Android SDK Manager를 통해 다운로드 받을 수 있습니다. Google Play 서비스 라이브러리는 Android Project로 제공되기는 때문에 Eclipse의 Import Project를 통해 “./extras/google/google_play_services/libproject” 위치의 Android Project를 Import 합니다. Import된 Project Properties의 Android 속성 중 Library 항목에서 “is Library”를 체크하여 project의 속성을 Library로 설정합니다. 마지막으로 나의 Project Properties에서 Android 속성의 Library 항목에 Import한 Google Play 서비스 Project를 Add하면 Google Play 서비스를 사용하기 위한 설정이 완료됩니다.

 

설정이 완료되었다면 Google Play 서비스를 통해 Fused Location Provider API를 호출해 보도록 하겠습니다. Google Play 서비스를 통해 구글에서 제공하는 다양한 API를 호출하기 위해서는 Google Client를 통해 접근승인을 받은 후 API를 사용할 수 있습니다. Google Clinet를 이용한 접근승인 요청 내용은 아래와 같이 작성할 수 있습니다.

//Google Play 서비스 접근승인 요청public GoogleApiClient.Builder setGoogleServiceBuilder(){

//Google Api Client 생성

GoogleApiClient.Builder mGoogleApiClientBuilder = new GoogleApiClient.Builder(this.activity);

mGoogleApiClientBuilder.addApi(LocationServices.API);//Fused Location Provider API 사용요청

 

//Google Client Connection Callback 클래스

CallbackConnectedGoogleService callbackConnectedGoogleService = new CallbackConnectedGoogleService(this);

mGoogleApiClientBuilder.addConnectionCallbacks(callbackConnectedGoogleService);

mGoogleApiClientBuilder.addOnConnectionFailedListener(callbackConnectedGoogleService);

 

GoogleApiClient mGoogleApiClient = mGoogleApiClientBuilder.build();

mGoogleApiClient.connect();

 

return mGoogleApiClientBuilder;

}

 

 

//Google Play 서비스 접근승인 응답

class CallbackConnectedGoogleService implements ConnectionCallbacks, OnConnectionFailedListener{

 

private String LOG_TAG = “CallbackGooglePlacesService”;

private GoogleServiceControl googleServiceControl;

 

public CallbackConnectedGoogleService(GoogleServiceControl googleServiceControl){

this.googleServiceControl = googleServiceControl;

}

 

@Override

public void onConnectionFailed(ConnectionResult result) {

// TODO Auto-generated method stub

Log.d(LOG_TAG, “GoogleService onConnectionSuspended”);

Log.d(LOG_TAG, “Connected Failed : “ + result.getErrorCode());

}

 

@Override

public void onConnected(Bundle connectionHint) {

// TODO Auto-generated method stub

Log.d(LOG_TAG, “GoogleService onConnected”);

Log.d(LOG_TAG, “Connected Success”);

}

 

@Override

public void onConnectionSuspended(int cause) {

// TODO Auto-generated method stub

Log.d(LOG_TAG, “GoogleService onConnectionSuspended”);

Log.d(LOG_TAG, “Suspended cause : “ + cause);

}

}

 

 

GoogleApiClient ClassGoogleApiClient.Builderd에 접근요청과 관련된 다양한 속성을 설정한 후 생성되는 클래스로서 connect() 함수를 통해 접근승인을 요청을 할 수 있습니다. 그리고 GoogleApiClient.Builderd Class의 addApi()함수에는 접근요청할 API의 정보를 설정합니다. Fused Location Provider API를 사용하기 위해 addApi() 함수에 LocationServices.API를 설정하였습니다. connect() 함수를 호출하면 접근승인 요청을 전달하게 되고 리스너로 등록한 CallbackConnectedGoogleService Class로 전달됩니다. ConnectionCallbacks, OnConnectionFailedListener interface을 통해 override한 onConnected(), onConnectionSuspended(), onConnectionFailed()를 통해 각 응답 상태에 따라 결과를 받아서 처리할 수 있습니다. 이와같은 접근승인 요청은 몇개의 API를 사용하더라도 앱에서 한번만 수행하면 됩니다. Drive, Place 등과 같은 다른 서비스를 이용한다면 addApi()함수를 이용해서 원하는 서비스만 추가하면 됩니다.

(Android Develop – Google Play Services)

 

//Fused Location Provider API 호출public void getLastKnownLocation(GoogleApiClient mGoogleApiClient){Location mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);

Log.d(“Fused Location Provider API : Latitude”, mLastLocation.getLatitude());

Log.d(“Fused Location Provider API : Longitude”, mLastLocation.getLongitude());

Log.d(“Fused Location Provider API : Accuracy”, mLastLocation.getAccuracy());

}

접근승인 요청이 성공하면 Fused Location Provider API에 대한 LocationServices Class를 사용할 수 있다. Connection을 요청했던 GoogleApiClient Class의 Instance로 하여 getLastKnownLocation() 함수를 호출하면 현재위치를 측위한 결과값을 Location Class로 받을 수 있다. LocationManager를 이용해서 현재위치를 측위하는 로직에 비해 매우 간소해 진걸 확인할 수 있습니다. getLastKnownLocation()이외에도 측위에 대한 다양한 함수는 Android Develop Reference에서 확인할 수 있습니다.

 

응답받은 결과를 지도에 출력해서 WPS 방식의 Geolocation API와 LocationManager(GPS)와 비교해보면 아래와 같습니다. 아래 위치는 실내에서 측위를 했을때의 결과입니다. Geolocation API은 실내에서도 정확도가 높은 반면 LocationManger에서는 GPS Provider를 이용해서 약간 정확도가 떨어지는 결과를 보여주고 있습니다. 마지막으로 Fused Location Provider API는 Geolocation API와 같이 정확도 높은 결과를 보여주고 있습니다.

result

Google Play 서비스의 Fused Location Provider API을 이용해서 현재위치 측위를 간단히 소개하였습니다. Fused Location Provider API는 복잡한 계산이나 세부적인 요소들을 구글의 서비스에서 알아서 처리해주기 때문에 LocationManager에 비해 복잡한 구현없이 정확도 높은 결과를 위치를 측위할 수 있었습니다. 그리고 본문에서 간단히 소개한 Google Play 서비스는 구글에서 제공하는 다양한 서비스를 통합관리되고 있기 때문에 LocationService 이외에도 다양한 서비스들을 간편한 API 형태로 제공하고 있기 때문에 기회가 된다면 참고해 보는것도 많은 도움이 될것 같습니다.

 

 

참고자료 :

– Android Develop – Google Play Services : https://developer.android.com/google/play-services/index.html

– Android Develop – Google Play Services Reference : https://developer.android.com/google/play-services/index.html