Jak otworzyć standardową aplikację Google Map z mojej aplikacji?

140

Gdy użytkownik naciśnie przycisk w mojej aplikacji, chciałbym otworzyć standardową aplikację Google Map i pokazać konkretną lokalizację. Jak mogę to zrobić? (bez użycia com.google.android.maps.MapView)

LA_
źródło

Odpowiedzi:

241

Powinieneś utworzyć Intentobiekt z geo-URI:

String uri = String.format(Locale.ENGLISH, "geo:%f,%f", latitude, longitude);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
context.startActivity(intent);

Jeśli chcesz podać adres, który trzeba zastosować inną formę geo-URI: geo:0,0?q=address.

źródło: https://developer.android.com/guide/components/intents-common.html#Maps

Michael
źródło
1
Dzięki, @Pixie! Jaki jest format szerokości i długości geograficznej? Jeśli zdam lat: 59.915494, lng: 30.409456, zwraca niewłaściwą pozycję.
LA_
2
Ok, znalazłem problem. String.format("geo:%f,%f", latitude, longitude)zwrócony ciąg przecinkami: geo:59,915494,30,409456.
LA_
20
To przenosi mnie do lokalizacji, ale nie umieszcza tam balonu. Bardzo chciałbym mieć balon, aby użytkownik mógł go kliknąć, aby uzyskać wskazówki itp.
Mike
5
Nie zadzieraj z String.format () dla prostej konkatenacji ciągów. Ta metoda jest przeznaczona tylko dla tekstu interfejsu użytkownika, dlatego reprezentacja kropki dziesiętnej może się różnić. Po prostu użyj operatora „+” lub StringBuilder: String uri = "geo:" + lastLocation.getLatitude () + "," + lastLocation.getLongitude ().
Agustí Sánchez
4
W przypadku wskazówek zamiar nawigacji jest teraz obsługiwany przez google.navigation: q = latitude, longitude: Uri gmmIntentUri = Uri.parse ("google.navigation: q =" + 12f "+", "+ 2f); Mapa intencjiIntent = new Intent (Intent.ACTION_VIEW, gmmIntentUri); mapIntent.setPackage ("com.google.android.apps.maps"); startActivity (mapIntent);
David Thompson,
106

Możesz też po prostu użyć http://maps.google.com/maps jako swojego identyfikatora URI

String uri = "http://maps.google.com/maps?saddr=" + sourceLatitude + "," + sourceLongitude + "&daddr=" + destinationLatitude + "," + destinationLongitude;
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(intent);

lub możesz upewnić się, że używana jest tylko aplikacja Mapy Google, co spowoduje zatrzymanie wyświetlania filtru intencji (okna dialogowego), używając

intent.setPackage("com.google.android.apps.maps");

tak:

String uri = "http://maps.google.com/maps?saddr=" + sourceLatitude + "," + sourceLongitude + "&daddr=" + destinationLatitude + "," + destinationLongitude;
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
intent.setPackage("com.google.android.apps.maps");
startActivity(intent);

lub możesz dodać etykiety do lokalizacji, dodając ciąg w nawiasach po każdym zestawie współrzędnych, na przykład:

String uri = "http://maps.google.com/maps?saddr=" + sourceLatitude + "," + sourceLongitude + "(" + "Home Sweet Home" + ")&daddr=" + destinationLatitude + "," + destinationLongitude + " (" + "Where the party is at" + ")";
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
intent.setPackage("com.google.android.apps.maps");
startActivity(intent);

Aby użyć bieżącej lokalizacji użytkownika jako punktu początkowego (niestety nie znalazłem sposobu na oznaczenie bieżącej lokalizacji), po prostu upuść saddrparametr w następujący sposób:

String uri = "http://maps.google.com/maps?daddr=" + destinationLatitude + "," + destinationLongitude + " (" + "Where the party is at" + ")";
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
intent.setPackage("com.google.android.apps.maps");
startActivity(intent);

Dla kompletności, jeśli użytkownik nie ma zainstalowanej aplikacji map, dobrym pomysłem będzie złapanie wyjątku ActivityNotFoundException, jak stwierdza @TonyQ, wtedy możemy rozpocząć aktywność ponownie bez ograniczeń aplikacji map, możemy być całkiem pewni że nigdy nie dojdziemy do Toast na końcu, ponieważ przeglądarka internetowa jest prawidłową aplikacją do uruchamiania tego schematu adresu URL.

        String uri = "http://maps.google.com/maps?daddr=" + 12f + "," + 2f + " (" + "Where the party is at" + ")";
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
        intent.setPackage("com.google.android.apps.maps");
        try
        {
            startActivity(intent);
        }
        catch(ActivityNotFoundException ex)
        {
            try
            {
                Intent unrestrictedIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
                startActivity(unrestrictedIntent);
            }
            catch(ActivityNotFoundException innerEx)
            {
                Toast.makeText(this, "Please install a maps application", Toast.LENGTH_LONG).show();
            }
        }

EDYTOWAĆ:

W przypadku wskazówek zamiar nawigacji jest teraz obsługiwany przez google.navigation

Uri navigationIntentUri = Uri.parse("google.navigation:q=" + 12f + "," + 2f);
Intent mapIntent = new Intent(Intent.ACTION_VIEW, navigationIntentUri);
mapIntent.setPackage("com.google.android.apps.maps");
startActivity(mapIntent);
David Thompson
źródło
java.util.IllegalFormatConversionException:% f nie może sformatować wyjątków argumentów java.lang.String arguments
Amitsharma
Opublikuj to, co zastąpiłeś pierwszą linią kodu przez [wiersz zaczynający się od String uri = string.format] Wygląda na to, że jednym z parametrów powinien być ciąg znaków, który powinien być zmiennoprzecinkowy
David Thompson
Hej, kiedy przekazuję etykietę Google Maps z szerokością i długością geograficzną, aplikacja map konwertuje etykietę na adresy. Czy możesz powiedzieć, jak rozwiązać ten problem?
Rohan Sharma,
41

Użycie formatu String pomoże, ale musisz uważać na ustawienia regionalne. W Niemczech liczba zmiennoprzecinkowa będzie oddzielona przecinkiem zamiast kropki.

Używając String.format("geo:%f,%f",5.1,2.1);lokalnego języka angielskiego, wynik będzie, "geo:5.1,2.1"ale z językiem niemieckim otrzymasz"geo:5,1,2,1"

Aby temu zapobiec, należy użyć języka angielskiego.

String uri = String.format(Locale.ENGLISH, "geo:%f,%f", latitude, longitude);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
context.startActivity(intent);

Aby ustawić etykietę dla punktu geograficznego, możesz rozszerzyć swój identyfikator geograficzny, używając:

!!! ale bądź ostrożny z tym geo-uri jest nadal rozwijany http://tools.ietf.org/html/draft-mayrhofer-geo-uri-00

String uri = String.format(Locale.ENGLISH, "geo:%f,%f?z=%d&q=%f,%f (%s)", 
                           latitude, longitude, zoom, latitude, longitude, label);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
context.startActivity(intent);
David Boho
źródło
możesz także użyć „& t = h” versus „& t = m” do wywoływania w trybie wyświetlania satelity lub warstwy mapy.
tony gil
1
Próbuję czegoś podobnego, z tym wyjątkiem, że dodaję zapytanie ze współrzędnymi, aby uzyskać balon. Mój kod wygląda dokładnie tak, jak Twój pierwszy przykład. Format URI formatuję przy użyciu języka angielskiego, ale kiedy używam go na moim urządzeniu ustawionym na język niemiecki, Mapy Google nadal zastępują kropki przecinkami, więc moje zapytanie nie działa. Kiedy ustawiłem lokalizację urządzenia na angielski (USA), na przykład działa idealnie. Co mogę zrobić? Wydaje się, że bez względu na to, które Mapy Google ponownie zmieniają ciąg zapytania.
kaolick,
6

Czasami, jeśli nie ma żadnej aplikacji skojarzonej z geo: protocal, możesz użyć try-catch, aby uzyskać ActivityNotFoundException do obsługi tego.

Dzieje się tak, gdy używasz jakiegoś emulatora, takiego jak androVM, który nie jest domyślnie zainstalowany na mapie Google.

TonyQ
źródło
6

Możesz także użyć poniższego fragmentu kodu, dzięki czemu istnienie map Google jest sprawdzane przed rozpoczęciem intencji.

Uri gmmIntentUri = Uri.parse(String.format(Locale.ENGLISH,"geo:%f,%f", latitude, longitude));
Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
mapIntent.setPackage("com.google.android.apps.maps");
if (mapIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(mapIntent);
}

Źródła: https://developers.google.com/maps/documentation/android-api/intents

Kerim Gökarslan
źródło
1

Aby przejść do lokalizacji Z PINem, użyj:

String uri = "http://maps.google.com/maps?q=loc:" + destinationLatitude + "," + destinationLongitude;
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
intent.setPackage("com.google.android.apps.maps");
startActivity(intent);

bez kodu PIN, użyj tego w uri:

 String uri = "geo:" + destinationLatitude + "," + destinationLongitude;
M. Usman Khan
źródło
0

Mam przykładową aplikację, w której przygotowuję intencję i po prostu przekazuję CITY_NAME w intencji do działania znacznika map, który ostatecznie oblicza długość i szerokość geograficzną przez Geocoder za pomocą CITY_NAME.

Poniżej znajduje się fragment kodu rozpoczynania działania znacznika map i kompletna aktywność MapsMarker.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    } else if (id == R.id.action_refresh) {
        Log.d(APP_TAG, "onOptionsItemSelected Refresh selected");
        new MainActivityFragment.FetchWeatherTask().execute(CITY, FORECAS_DAYS);
        return true;
    } else if (id == R.id.action_map) {
        Log.d(APP_TAG, "onOptionsItemSelected Map selected");
        Intent intent = new Intent(this, MapsMarkerActivity.class);
        intent.putExtra("CITY_NAME", CITY);
        startActivity(intent);
        return true;
    }

    return super.onOptionsItemSelected(item);
}

public class MapsMarkerActivity extends AppCompatActivity
        implements OnMapReadyCallback {

    private String cityName = "";

    private double longitude;

    private double latitude;

    static final int numberOptions = 10;

    String [] optionArray = new String[numberOptions];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Retrieve the content view that renders the map.
        setContentView(R.layout.activity_map);
        // Get the SupportMapFragment and request notification
        // when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);

        // Test whether geocoder is present on platform
        if(Geocoder.isPresent()){
            cityName = getIntent().getStringExtra("CITY_NAME");
            geocodeLocation(cityName);
        } else {
            String noGoGeo = "FAILURE: No Geocoder on this platform.";
            Toast.makeText(this, noGoGeo, Toast.LENGTH_LONG).show();
            return;
        }
    }

    /**
     * Manipulates the map when it's available.
     * The API invokes this callback when the map is ready to be used.
     * This is where we can add markers or lines, add listeners or move the camera. In this case,
     * we just add a marker near Sydney, Australia.
     * If Google Play services is not installed on the device, the user receives a prompt to install
     * Play services inside the SupportMapFragment. The API invokes this method after the user has
     * installed Google Play services and returned to the app.
     */
    @Override
    public void onMapReady(GoogleMap googleMap) {
        // Add a marker in Sydney, Australia,
        // and move the map's camera to the same location.
        LatLng sydney = new LatLng(latitude, longitude);
        // If cityName is not available then use
        // Default Location.
        String markerDisplay = "Default Location";
        if (cityName != null
                && cityName.length() > 0) {
            markerDisplay = "Marker in " + cityName;
        }
        googleMap.addMarker(new MarkerOptions().position(sydney)
                .title(markerDisplay));
        googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
    }

    /**
     * Method to geocode location passed as string (e.g., "Pentagon"), which
     * places the corresponding latitude and longitude in the variables lat and lon.
     *
     * @param placeName
     */
    private void geocodeLocation(String placeName){

        // Following adapted from Conder and Darcey, pp.321 ff.
        Geocoder gcoder = new Geocoder(this);

        // Note that the Geocoder uses synchronous network access, so in a serious application
        // it would be best to put it on a background thread to prevent blocking the main UI if network
        // access is slow. Here we are just giving an example of how to use it so, for simplicity, we
        // don't put it on a separate thread.  See the class RouteMapper in this package for an example
        // of making a network access on a background thread. Geocoding is implemented by a backend
        // that is not part of the core Android framework, so we use the static method
        // Geocoder.isPresent() to test for presence of the required backend on the given platform.

        try{
            List<Address> results = null;
            if(Geocoder.isPresent()){
                results = gcoder.getFromLocationName(placeName, numberOptions);
            } else {
                Log.i(MainActivity.APP_TAG, "No Geocoder found");
                return;
            }
            Iterator<Address> locations = results.iterator();
            String raw = "\nRaw String:\n";
            String country;
            int opCount = 0;
            while(locations.hasNext()){
                Address location = locations.next();
                if(opCount == 0 && location != null){
                    latitude = location.getLatitude();
                    longitude = location.getLongitude();
                }
                country = location.getCountryName();
                if(country == null) {
                    country = "";
                } else {
                    country =  ", " + country;
                }
                raw += location+"\n";
                optionArray[opCount] = location.getAddressLine(0)+", "
                        +location.getAddressLine(1)+country+"\n";
                opCount ++;
            }
            // Log the returned data
            Log.d(MainActivity.APP_TAG, raw);
            Log.d(MainActivity.APP_TAG, "\nOptions:\n");
            for(int i=0; i<opCount; i++){
                Log.i(MainActivity.APP_TAG, "("+(i+1)+") "+optionArray[i]);
            }
            Log.d(MainActivity.APP_TAG, "latitude=" + latitude + ";longitude=" + longitude);
        } catch (Exception e){
            Log.d(MainActivity.APP_TAG, "I/O Failure; do you have a network connection?",e);
        }
    }
}

Linki wygasają, więc wkleiłem cały kod powyżej, ale na wszelki wypadek, jeśli chcesz zobaczyć pełny kod, jest dostępny pod adresem : https://github.com/gosaliajigar/CSC519/tree/master/CSC519_HW4_89753

JRG
źródło
0

Jest to napisane w Kotlinie, otworzy aplikację map, jeśli zostanie znaleziona, umieści punkt i pozwoli Ci rozpocząć podróż:

  val gmmIntentUri = Uri.parse("http://maps.google.com/maps?daddr=" + adapter.getItemAt(position).latitud + "," + adapter.getItemAt(position).longitud)
        val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
        mapIntent.setPackage("com.google.android.apps.maps")
        if (mapIntent.resolveActivity(requireActivity().packageManager) != null) {
            startActivity(mapIntent)
        }

Zamień requireActivity()na Context.

Gastón Saillén
źródło