Genesis Vargas J

Desarrollando una app iOS y Android con Geolocalizacion (usando Google Maps) Parte 2

Comparte:

Hola amigos, en el post anterior les enseñé como crear nuestro proyecto en la consola de desarrolladores de Google par aobtener nuestra clave de API de Google Maps y desarrollamos la app iOS de geolocalización, en éste post continuaremos y desarrollaremos la app Android de geolocalización que muestre un mapa (de Google) y nos localice poniendo un marcador en nuestra ubicación actual.

Lo primero que hacemos es abrir Android Studio y creamos un nuevo proyecto al que llamaremos geolocalizacion (trabajaremos con Java como lenguaje de programación), el siguiente paso será escoger la plantilla de Mapas para que todo nos salga fácil, cuando el proyecto se haya creado automáticamente se nos abrirá el archivo google_maps_api.xml donde vamos a pegar nuestra API key que creamos en el post anterior.

Ahora revisamos tres archivos importantes: 1) build.gradle (Module: app): en éste archivo automáticamente Android Studio nos implemento el SDK de Google Maps con el siguiente comando:  compile 'com.google.android.gms:play-services-maps:10.2.6' pero ahora nos toca a nosotros agregar el comando para implementar la localización y agregamos debajo el siguiente comando: compile 'com.google.android.gms:play-services-location:10.2.6' Si te fijas bien estamos utilizando Google Play Services y su servicio de ubicación que particularmente pienso al igual que muchos fue de las grandes cosas que ha hecho Google en los últimos años, ya que si recuerdan bien, antes para hacer éste tipo de apps se utilizaba el API de localización de Android y éste tenia varios problemas graves como el consumo másivo de bateria y falta de precisión en la recepción de ubicaciones, puedes ver un review de este tema (en inglés) aquí.

El archivo build.gradle te debería quedar así:

 


apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.3"
    defaultConfig {
        applicationId "co.dstic.geolocalizacion"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.google.android.gms:play-services-maps:10.2.6'
    compile 'com.google.android.gms:play-services-location:10.2.6'
    testCompile 'junit:junit:4.12'
}

2) El archivo activity_main.xml automáticamente tiene un fragment de mapa de Google que nos creó Android Studio con el id: map.

3) El archivo MainActivity.java automáticamente tiene el codigo necesario para mostrar un mapa y un marcador en Sidney-Australia, como queremos que nuestra app nos geolocalice borraremos todo el código y nos debería quedar así:


package co.dstic.geolocalizacion;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.location.Location;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStatusCodes;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

public class MainActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks, LocationListener {

    private GoogleMap mMap;
    private LocationRequest locRequest;
    private static final String LOGTAG = "geolocalizacion";
    private static final int PETICION_PERMISO_LOCALIZACION = 101;
    private static final int PETICION_CONFIG_UBICACION = 201;
    private GoogleApiClient apiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        apiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this).addOnConnectionFailedListener(this).addApi(LocationServices.API).build();
        apiClient.connect();
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PETICION_PERMISO_LOCALIZACION);
        } else {
            enableLocationUpdates();
        }
    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.e(LOGTAG, "Se ha interrumpido la conexión con Google Play Services");
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        Log.e(LOGTAG, "Error grave al conectar con Google Play Services");
    }

    @Override
    public void onLocationChanged(Location location) {
        Log.i(LOGTAG, "Recibida nueva ubicación!");
        actualizarUbicacion(location);
        disableLocationUpdates();
    }

    private void actualizarUbicacion(Location location) {
        if (location != null) {
            LatLng coordenadas = new LatLng(location.getLatitude(), location.getLongitude());
            CameraUpdate miUbicacion = CameraUpdateFactory.newLatLngZoom(coordenadas, 17);
            mMap.moveCamera(miUbicacion);
            mMap.addMarker(new MarkerOptions().position(coordenadas).title("Mi ubicacion"));
        }
    }

    private void startLocationUpdates() {
        if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            //Ojo: estamos suponiendo que ya tenemos concedido el permiso.
            Log.i(LOGTAG, "Inicio de recepción de ubicaciones");
            LocationServices.FusedLocationApi.requestLocationUpdates(apiClient, locRequest, this);
        }
    }

    private void disableLocationUpdates() {
        LocationServices.FusedLocationApi.removeLocationUpdates(apiClient, this);
    }

    private void enableLocationUpdates() {
        locRequest = new LocationRequest();
        locRequest.setInterval(1000);
        locRequest.setFastestInterval(1000);
        locRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        LocationSettingsRequest locSettingsRequest = new LocationSettingsRequest.Builder().addLocationRequest(locRequest).build();
        PendingResult result = LocationServices.SettingsApi.checkLocationSettings(apiClient, locSettingsRequest);
        result.setResultCallback(new ResultCallback() {
            @Override
            public void onResult(LocationSettingsResult locationSettingsResult) {
                final Status status = locationSettingsResult.getStatus();
                switch (status.getStatusCode()) {
                    case LocationSettingsStatusCodes.SUCCESS:
                        Log.i(LOGTAG, "Configuración correcta");
                        startLocationUpdates();
                        break;
                    case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                        try {
                            Log.i(LOGTAG, "Se requiere actuación del usuario");
                            status.startResolutionForResult(MainActivity.this, PETICION_CONFIG_UBICACION);
                        } catch (IntentSender.SendIntentException e) {
                            Log.i(LOGTAG, "Error al intentar solucionar configuración de ubicación");
                        }
                        break;
                    case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                        Log.i(LOGTAG, "No se puede cumplir la configuración de ubicación necesaria");
                        break;
                }
            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == PETICION_PERMISO_LOCALIZACION) {
            if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                enableLocationUpdates();
            } else {
                Log.e(LOGTAG, "Permiso denegado");
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case PETICION_CONFIG_UBICACION:
                switch (resultCode) {
                    case Activity.RESULT_OK:
                        enableLocationUpdates();
                        break;
                    case Activity.RESULT_CANCELED:
                        Log.i(LOGTAG, "El usuario no ha realizado los cambios de configuración necesarios");
                        break;
                }
                break;
        }
    }
}

El activity ahora implementará los siguientes Callbacks: 1) GoogleApiClient.ConnectionCallbacks: éste tiene un método onConnected() que se llamará siempre que el dispositivo esté conectado y desconectado. 2) GoogleApiClient.OnConnectionFailedListener: éste tiene un método onConnectionFailed() que resulta en un intento fallido de conectar al cliente al servicio. 3) LocationListener: éste tiene un método onLocationChanged() que se llamará siempre que haya un cambio en la ubicación del dispositivo. Vamos a declarar variables para el mapa (GoogleMap), el apiclient de play services (GoogleApiClient) y el locationRequest para las actualizaciones de ubicación desde FusedLocationProviderApi. Desde ahora en el método onCreate referenciamos el fragment del mapa (id: map) y cargamos el mapa asíncronamente, en el método onMapReady() configuramos el apiClient de play services y nos conectamos, en el método onConnected() realizaremos una válidacion de permisos (desde Android 6.0 éste tema de los permisos cambió y ahora se validan a tráves del código ya que los usuarios pueden activar o desactivar éstas funciones en el menú de configuración) para saber si el usuario tiene activada la ubicación y nos concede el permiso para usarla.

Cuando éste se conceda se procederá a configurar el LocationRequest y naturalmente la recepción de ubicaciones, necesitaremos proporcionar ciertos parámetros como el intérvalo de milisegundos para consultar una nueva ubicación y la precisión que queremos para obtener la ubicación, cuando el resultado de este callback sea correcto empezamos a geolocalizar a tráves del método startLocationUpdates que a su vez llamará al siguiente código: LocationServices.FusedLocationApi.requestLocationUpdates(apiClient, locRequest, this) que es el encargado de la recepción de la última ubicación. Finalmente en éste punto se llama al método onLocationChanged y allí hacemos dos cosas: 1) llamámos el método actualizarUbicacion() que se encarga de recibir la localización y la convertimos en coordenadas para luego mover la cámara del mapa en esa ubicación y poner un marcador allí mismo. 2) detener el servicio de recpeción de ubicaciones (esto es opcional) con el método disableLocationUpdates() que a su vez llama el siguiente código: LocationServices.FusedLocationApi.removeLocationUpdates(apiClient, this);

** También agregamos los métodos onActivityResult() y onRequestPermissionsResult para saber cuando por primera vez el usuario entra en la app y ver el resultado de los posibles escenarios: 1) No tiene activada la ubicación, 2) Tiene activada la ubicación pero aún no ha dado el permiso, etc **

Ahora simplemente corremos nuestra aplicación y nos geolocalizará automáticamente.

Y de ésta manera ya hemos desarrollado una app Android en Java de geolocalización usando Google Maps.

Bueno eso es todo espero que les sirva mucho para aprender y practicar, les dejo una carpeta comprimida para que descarguen el ejemplo.

Si te gustan mis tutoriales no dudes en seguirme en mis redes sociales para estar al tanto y suscribirte a mi canal de youtube.

Comentarios


genesis vargas

Soy Genesis Vargas Jiménez, autor de éste blog. Me gusta desarrollar software en todas las plataformas (web, móvil y desktop) y compartir conocimiento para ayudar a muchas personas.

Desde el 2015 soy MVP Microsoft en Visual Studio y tecnologías de desarrollo, reconocimiento que me enorgullece mucho.

MVP Genesis Vargas J

A PHP Error was encountered

Severity: Core Warning

Message: Module 'timezonedb' already loaded

Filename: Unknown

Line Number: 0

Backtrace: