API Google Android для Android v2 выбрасывает GooglePlayServicesNotAvailableException, устаревший, SupportMapFragment.getMap() возвращает null

Я пытаюсь включить новый API Android Google Maps v2 в приложение, используя библиотеку поддержки Android. Я прошел через много итераций, чтобы попытаться найти работу, и теперь я сдался и подумал, что я должен спросить здесь.

Я пошел в API-консоль, создал проект, включил Google Maps API v2 для Android, создал необходимый отладочный ключ и вставил его в манифест. Нет проблем с проверкой подлинности или что-то в этом роде. Совершенно верно, я сделал это правильно.

В моей папке libs я положил android-support-v4.jar (через проект правой кнопкой мыши → Android- > Добавить библиотеку поддержки...). В Eclipse я сделал File- > Import- > Android- > Существующий код Android в рабочей области и импортировал последнюю версию (rev 3) android-sdk/google/google_play_services/libproject/google-play-services_lib. Затем я добавил его как библиотеку зависимостей в свой проект (проект правой кнопкой мыши- > Свойства- > Android- > Добавить его как зависимость библиотеки внизу.

В моем манифесте я:

<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>

В моем mainview.xml у меня есть:

<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" />

Теперь на MainView.java у меня есть:

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
    }
}

Затем мне показалось, что мне, вероятно, нужно инициализировать фрагменты, поэтому я добавил в свой onCreate после настройки содержимого:

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

Тогда я сказал, может быть, это не SupportMapFragment, но я действительно должен ссылаться на фактический фрагмент, и в моем onResume я сделал:

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 после этого снова имеет значение null.

Затем я увидел, что есть класс MapsInitializer, поэтому я подумал, что, возможно, я должен сначала назвать это.

Итак, я добавил код перед тем, как получить фрагмент в приведенном выше коде:

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

При этом Logcat сообщил о предупреждении (строка 313 - 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)

В ходе моих попыток Logcat сообщит следующее предупреждение:

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

Это может быть/виновником, но я не нашел решения.

В этот момент у меня нет идей. Я прочитал несколько тем здесь, здесь, здесь, но ни одно из предложений не разрешило проблему. На последнем они предлагают не включать зависимость проекта и просто включать файл jar. Ну, это не сработало либо с помощью google-play-services.jar из папки google-play-services_lib/libs, либо экспортировало мою собственную банку из этого проекта.

Кстати, я запускаю фактическое устройство (2.3.5 и планшет с 3.2), а не эмулятор.

Любая помощь всем сердцем ценится.:)

UPDATE:

Решение ниже по кубиту.

При экспорте зависимостей библиотеки аккуратный способ не иметь дело с этим (что является болью при работе с репозиториями) заключается в использовании FatJar и экспортируйте проект google_play_services_lib (который я НЕ создавал локальную копию, потому что когда он обновляется, я не хочу повторно импортировать), и включайте в файл проекта файл с избыточным файлом в качестве другого файла jar, ПРИМЕЧАНИЕ. При выборе файлов jar для включения в жирную банку мне пришлось исключить файл annotations.jar, поскольку он уже был предварительно включен и вызывает ошибки для дублирования. Теперь все, что мне нужно сделать, это включить google_play_services_rev_3.jar в мою папку проекта libs, и мне хорошо идти.

Ответ 1

Загрузите и установите последний Google Play services из Play Маркета. По какой-то причине я не смог найти его, выполнив поиск. Запустив пример приложения из SDK в папке /extras/google/google_play_services/samples/maps, мне было предложено установить обновление и было отправлено в Play Store для этого.

Ответ 2

как описано в нижней части этой ссылки; http://developer.android.com/google/play-services/setup.html

и здесь приведен пример кода для правильной обработки этого файла;

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();
    }

Ответ 3

У меня была такая же проблема в моем проекте. Решение очень просто справиться с возможностью возврата ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap(); null. Если вы будете обрабатывать null, buid-in SupportMapFragment будет обрабатывать ошибку Google Play services out of date. и покажет вам установленное локализованное сообщение карты и кнопку для обновления Службы Google Play точно так же, как @Bbz расскажет в примерном проекте.

Код из образца:

@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"));
}

И результат:

enter image description here

Как документация печально

GoogleMap может быть получен только с помощью getMap(), когда загружена базовая система карт и существует базовый вид в фрагменте. Этот класс автоматически инициализирует систему карт и представление; однако вы не можете быть уверены, когда он будет готов, потому что это зависит от доступности APK сервисов Google Play. Если GoogleMap недоступен, getMap() вернет значение null. SupportMapFragment