18

Sto cercando di incorporare la nuova API di Google Maps per Android v2 in un'applicazione che utilizza la libreria di supporto Android. Ho attraversato molte iterazioni per cercare di ottenere un posto dove lavorare e ora ho rinunciato e ho pensato di dover chiedere qui.Google Maps API Android v2 genera GooglePlayServicesNotAvailableException, obsoleto, SupportMapFragment.getMap() restituisce null

Sono passato alla console API, ho creato un progetto, ho abilitato l'API di Google Maps v2 per Android, creato un debug KEY come richiesto e incollato sul manifest. Nessun problema di autenticazione o qualcosa del genere. Abbastanza sicuro di aver fatto bene.

Nella cartella libs del mio progetto ho inserito android-support-v4.jar (tramite il progetto tasto destro del mouse-> Android-> Aggiungi libreria di supporto ...). In Eclipse ho fatto File-> Importa-> Android-> Codice Android esistente in Workspace e importato l'ultimo (rev 3) di android-sdk/google/google_play_services/libproject/google-play-services_lib. Poi ho aggiunto come una libreria di dipendenza al mio progetto (progetto-destra click-> Proprietà-> Android-> Aggiungi come dipendenza libreria sul fondo

Nel mio manifesto ho:.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...> 
    <permission 
     android:name="myapp.permission.MAPS_RECEIVE" 
     android:protectionLevel="signature"/> 

    <All the uses-permission required like INTERNET, ACCESS_NETWORK_STATE, WRITE_EXTERNAL_STORAGE, FINE AND COARSE LOCATION, etc> 
    <uses-permission android:name="myapp.permission.MAPS_RECEIVE"/> 
    <uses-feature android:glEsVersion="0x00020000" android:required="true"/> 
    <application ...> 
     ... 
     <uses-library android:name="com.google.android.maps" /> 
     <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AI..."/> 
    </application> 

Nel mio mainview.xml ho:

<fragment 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/map" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    class="com.google.android.gms.maps.SupportMapFragment" /> 

Ora in MainView.java ho:

import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentActivity; 
import android.support.v4.app.FragmentManager; 
import android.support.v4.app.FragmentTransaction; 
import com.google.android.gms.maps.GoogleMap; 
import com.google.android.gms.maps.SupportMapFragment; 

public class MainView extends FragmentActivity ... { 
    private GoogleMap mMap; 

    @Override 
    protected void onResume() { 
     ... 
     Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.map); 
     SupportMapFragment mapFragment = (SupportMapFragment)fragment; 
     mMap = mapFragment.getMap(); 
     //PROBLEM: mMap is null here even though mapFragment is not 
    } 
} 

Poi ho tho effettuato l 'acquisto probabilmente ho bisogno di inizializzare i frammenti così ho aggiunto nella mia onCreate dopo aver impostato la visualizzazione del contenuto:

//Fragments 
FragmentManager manager = getSupportFragmentManager(); 
FragmentTransaction transaction = manager.beginTransaction(); 
transaction.add(R.id.map, SupportMapFragment.newInstance()); 
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); 
transaction.commit(); 

Allora ho detto, forse non è SupportMapFragment ma io in realtà dovrebbe fare riferimento al frammento reale, e nella mia onResume I fatto:

Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.map); 
SupportMapFragment mapFragment = (SupportMapFragment)fragment; 

//Fragments 
FragmentManager manager = getSupportFragmentManager(); 
FragmentTransaction transaction = manager.beginTransaction(); 
transaction.add(R.id.map, mapFragment); 
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); 
transaction.commit(); 

mMap = mapFragment.getMap(); 

mMap è nuovamente nullo dopo questo.

Poi ho visto che c'è una classe MapsInitializer, quindi ho pensato che forse dovrei chiamarla prima.

Così ho aggiunto il codice prima di ottenere il frammento di codice di cui sopra:

try { 
    MapsInitializer.initialize(this); 
} catch (GooglePlayServicesNotAvailableException e) { 
    e.printStackTrace(); 
} 

Con questa Logcat riportato l'avvertimento (linea 313 è il MapsInitializer.initialize(this)):

com.google.android.gms.common.GooglePlayServicesNotAvailableException 
    at com.google.android.gms.internal.n.c(Unknown Source) 
    at com.google.android.gms.internal.n.a(Unknown Source) 
    at com.google.android.gms.maps.MapsInitializer.initialize(Unknown Source) 
    at myapp.activities.MainView.inflateSelectedViewAndSetData(MainView.java:313) 
    at myapp.activities.MainView.onClick(MainView.java:642) 
    at android.view.View.performClick(View.java:3153) 
    at android.view.View$PerformClick.run(View.java:12148) 
    at android.os.Handler.handleCallback(Handler.java:587) 
    at android.os.Handler.dispatchMessage(Handler.java:92) 
    at android.os.Looper.loop(Looper.java:152) 
    at android.app.ActivityThread.main(ActivityThread.java:4615) 
    at java.lang.reflect.Method.invokeNative(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:491) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599) 
    at dalvik.system.NativeStart.main(Native Method) 

Durante i miei tentativi Logcat segnalerebbe il seguente avviso:

Google Play services out of date. Requires 2010100 but found 1013 

Questo potrebbe essere a/il colpevole ma non ho trovato soluzione.

A questo punto sono fuori di idee. Ho letto diverse discussioni here, here, here ma nessuno dei suggerimenti ha risolto il problema. Su quest'ultimo suggeriscono di non includere la dipendenza del progetto e di includere solo il file jar. Bene, non ha funzionato né usando google-play-services.jar dalla cartella google-play-services_lib/libs né esportando il mio barattolo da quel progetto.

A proposito, sto utilizzando un dispositivo reale (2.3.5 e un tablet con 3.2), non l'emulatore.

Qualsiasi aiuto apprezzato di tutto cuore. :)

UPDATE:

La soluzione è appresso con qubit.

Per quanto esportare la dipendenza biblioteca, un modo pulito per non avere a che fare con esso (che è un dolore quando si tratta di repository) è quello di utilizzare FatJar ed esportare il progetto google_play_services_lib (che non ho creato una copia locale da perché quando si aggiorna non voglio reimportare) e includere il file jar di output fat nel tuo progetto come un altro file jar. NOTA: quando ho scelto i file jar da includere nel contenitore di grassi, ho dovuto escludere il file annotations.jar poiché era già pre-incluso e causava errori di duplicazione. Ora tutto quello che devo fare è includere lo google_play_services_rev_3.jar nella cartella libs del mio progetto e sono a posto.

+0

Poiché questa non è una risposta al tuo problema, la darò solo come commento: quando non vuoi fare più di localizzazione basata su GPS/WLAN, mostrando mappe, disegnando in mappe mostrate raccomandiamo di usare le classi ouf di http://sourceforge.net/projects/libwlocate/. IMHO sono molto più facili da gestire e forniscono supporto per diversi tipi di mappe. – Elmi

+0

Questo "google_play_services_rev_3.jar" dovrebbe essere generico, lo stesso vale per qualsiasi progetto e configurazione, suppongo?Grazie per il suggerimento di FatJar, ho ottenuto il mio progetto lavorando in Jenkins CI con questa procedura. – JaakL

+0

@JaakL Sì, è generico e puoi importarlo su qualsiasi progetto. :) – iliask

risposta

5

Scaricare e installare l'ultimo Google Play services dal Play Store. Per qualche motivo, non sono riuscito a trovarlo cercando. Eseguendo l'app di esempio dall'SDK nella cartella /extras/google/google_play_services/samples/maps, è stato richiesto di installare l'aggiornamento ed è stato portato sul Play Store per farlo.

+0

Sono installati di default. È un HTC Flyer commerciale (non rootato) e l'HTC Desire S con root ha installato gapps (e i servizi di gioco di Google sono lì). – iliask

+1

È necessaria l'ultima versione. L'errore che hai postato si riferisce alla versione predefinita "installata in fabbrica". – qubz

+2

Ho appena letto qui [http://code.google.com/p/gmaps-api-issues/issues/detail?id=4627#c1](http://code.google.com/p/gmaps- api-issues/issues/detail? id = 4627 # c1) che aggiungendo il nuovo MapFragment a una pagina attiva attiverà l'aggiornamento. Questo potrebbe essere più semplice della configurazione dell'app di esempio da eseguire se hai già creato un'app. – qubz

15

come descritto nella parte inferiore di tale collegamento; http://developer.android.com/google/play-services/setup.html

e qui viene fornito un codice di esempio per gestirlo correttamente;

int checkGooglePlayServices = GooglePlayServicesUtil.isGooglePlayServicesAvailable(mContext); 
    if (checkGooglePlayServices != ConnectionResult.SUCCESS) { 
    // google play services is missing!!!! 
    /* Returns status code indicating whether there was an error. 
    Can be one of following in ConnectionResult: SUCCESS, SERVICE_MISSING, SERVICE_VERSION_UPDATE_REQUIRED, SERVICE_DISABLED, SERVICE_INVALID. 
    */ 
     GooglePlayServicesUtil.getErrorDialog(checkGooglePlayServices, mActivity, 1122).show(); 
    } 
6

Ho avuto lo stesso problema nel mio progetto. La soluzione è molto semplice, basta gestire la possibilità che ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap(); possa restituire null. Se gestirai null l'SupportMapFragment in entrata gestirà l'errore Google Play services out of date. e mostrerà l'istante di messaggio localizzato sulla mappa e il pulsante per l'aggiornamento del servizio Google Play proprio come quello che @qubz sta raccontando nel progetto di esempio.

Codice da campione:

@Override 
protected void onResume() { 
    super.onResume(); 
    setUpMapIfNeeded(); 
} 

/** 
* Sets up the map if it is possible to do so (i.e., the Google Play services APK is correctly 
* installed) and the map has not already been instantiated.. This will ensure that we only ever 
* call {@link #setUpMap()} once when {@link #mMap} is not null. 
* <p> 
* If it isn't installed {@link SupportMapFragment} (and 
* {@link com.google.android.gms.maps.MapView MapView}) will show a prompt for the user to 
* install/update the Google Play services APK on their device. 
* <p> 
* A user can return to this FragmentActivity after following the prompt and correctly 
* installing/updating/enabling the Google Play services. Since the FragmentActivity may not have been 
* completely destroyed during this process (it is likely that it would only be stopped or 
* paused), {@link #onCreate(Bundle)} may not be called again so we should call this method in 
* {@link #onResume()} to guarantee that it will be called. 
*/ 
private void setUpMapIfNeeded() { 
    // Do a null check to confirm that we have not already instantiated the map. 
    if (mMap == null) { 
     // Try to obtain the map from the SupportMapFragment. 
     mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)) 
       .getMap(); 
     // Check if we were successful in obtaining the map. 
     if (mMap != null) { 
      setUpMap(); 
     } 
    } 
} 

/** 
* This is where we can add markers or lines, add listeners or move the camera. In this case, we 
* just add a marker near Africa. 
* <p> 
* This should only be called once and when we are sure that {@link #mMap} is not null. 
*/ 
private void setUpMap() { 
    mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker")); 
} 

E risultato:

enter image description here

Come documentazione triste

Un GoogleMap può essere acquisita solo con getMap() quando il mappe sottostanti il sistema è caricato e la vista sottostante nel frammento esiste. Questa classe inizializza automaticamente il sistema di mappe e la vista; tuttavia, non è possibile garantire quando sarà pronto poiché dipende dalla disponibilità dell'APK dei servizi di Google Play. Se un GoogleMap non è disponibile, getMap() restituirà null. SupportMapFragment

+0

leggermente confuso come chiamare l'aggiornamento per l'applicazione mappa, come menzionando quella chiamata "Ottieni servizio Google Play" –

+0

@AbdulWahab se gestirai la possibilità che ((SupportMapFragment) getSupportFragmentManager(). findFragmentById (R.id.map)). getMap(); può restituire null la libreria del servizio di riproduzione di google mostrerà la schermata di aggiornamento insted di MapFragment – Lemberg

+0

hmmm, ho capito, la schermata di aggiornamento è chiamata nativa da google play service libraya, stavo pensando, getMap() restituisce null poi su un aggiornamento personalizzato pulsante quale intento devo analizzare per andare alla pagina di aggiornamento come abbiamo: Intent viewIntent = nuovo Intento ("android.intent.action.VIEW", Uri.parse ("http://www.stackoverflow.com/ ")); startActivity (viewIntent); –

Problemi correlati