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