【问题标题】:Google Maps Android API v2 throws GooglePlayServicesNotAvailableException, out of date, SupportMapFragment.getMap() returns nullGoogle Maps Android API v2 抛出 GooglePlayServicesNotAvailableException,过期,SupportMapFragment.getMap() 返回 null
【发布时间】:2012-12-05 11:24:57
【问题描述】:

我正在尝试使用 Android 支持库将新的 Google Maps Android API v2 合并到应用程序中。 我经历了多次迭代,试图找到工作的地方,现在我放弃了,认为我应该在这里问。

我去了 API 控制台,创建了一个项目,启用了适用于 Android 的 Google Maps API v2,根据需要创建了一个调试 KEY 并将其粘贴到清单上。没有身份验证问题或类似问题。很确定我做对了。

在我的项目的libs 文件夹中,我放置了android-support-v4.jar(通过项目右键单击->Android->添加支持库...)。在 Eclipse 中,我执行了 File->Import->Android->Existing Android Code Into Workspace 并导入了最新的(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 在此之后再次为空。

然后我看到有一个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

这可能是罪魁祸首,但我没有找到解决办法。

在这一点上,我没有想法。我阅读了几个线程hereherehere,但没有一个建议能解决问题。对于后者,他们建议不包括项目依赖项,只包括 jar 文件。好吧,使用 google-play-services_lib/libs 文件夹中的 google-play-services.jar 或从该项目导出我自己的 jar 都不起作用。

顺便说一下,我是在实际设备(2.3.5 和 3.2 的平板电脑)上运行,而不是模拟器。

衷心感谢任何帮助。 :)

更新:

解决方案是下面的量子位。

至于导出库依赖项,一种不必处理它的简洁方法(在处理存储库时很痛苦)是使用FatJar 并导出google_play_services_lib 项目(我没有创建一个本地副本,因为当它更新时我不想重新导入),并将输出 fat jar 文件作为另一个 jar 文件包含在您的项目中。 注意:在选择要包含在 fat jar 中的 jar 文件时,我必须排除 annotations.jar 文件,因为它已经预先包含并且会导致重复错误。 现在我所要做的就是将google_play_services_rev_3.jar 包含在我项目的libs 文件夹中,然后就可以开始了。

【问题讨论】:

  • 由于这不是您的问题的答案,我将仅作为评论给出:当您不想做的不仅仅是基于 GPS/WLAN 的定位、显示地图、绘制到显示我建议使用 sourceforge.net/projects/libwlocate 的类 ouf 的地图。恕我直言,它们更容易处理并为多种地图类型提供支持。
  • 这个“google_play_services_rev_3.jar”应该是通用的,对任何项目和配置都一样,我想?感谢 FatJar 的提示,现在我的项目在 Jenkins CI 中使用此程序工作。
  • @JaakL 是的,它是通用的,您可以在任何项目中导入它。 :)

标签: android google-maps android-support-library google-play-services google-maps-android-api-2


【解决方案1】:

如该链接底部所述; 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();
    }

【讨论】:

    【解决方案2】:

    我在我的项目中遇到了同样的问题。解决方案非常简单,只需处理((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap(); 可以返回null 的可能性。如果您将处理null,则内置SupportMapFragment 将处理Google Play services out of date. 错误,并将向您显示用于更新Google Play 服务的地图本地化消息和按钮,就像@qubz 在示例项目中讲述的那样。

    示例代码:

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

    结果:

    作为文档悲伤

    只有在加载了底层地图系统并且片段中存在底层视图时,才能使用 getMap() 获取 GoogleMap。该类自动初始化地图系统和视图;但是,您无法保证它何时准​​备就绪,因为这取决于 Google Play 服务 APK 的可用性。如果 GoogleMap 不可用,getMap() 将返回 null。 SupportMapFragment

    【讨论】:

    • 有点困惑如何调用地图应用程序的更新,就像您提到“获取 Google Play 服务”的调用一样
    • @AbdulWahab 如果您将处理 ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();可以返回 null 谷歌播放服务库将显示 MapFragment 的更新屏幕
    • 嗯,我明白了,更新屏幕是来自谷歌播放服务 libraya 的本地调用,我在想,它 getMap() 返回 null 然后在自定义更新按钮上我必须解析什么意图去像我们这样更新页面:Intent viewIntent = new Intent("android.intent.action.VIEW", Uri.parse("stackoverflow.com/")); startActivity(viewIntent);
    • @AbdulWahab 这是一个解释如何手动调用播放服务更新developer.android.com/google/play-services/setup.html AND developer.android.com/reference/com/google/android/gms/common/…, android.app.Activity, int)
    • 感谢您的链接,@Lemberg
    【解决方案3】:

    从 Play 商店下载并安装最新的 Google Play services。由于某种原因,我无法通过搜索找到它。通过在文件夹 /extras/google/google_play_services/samples/maps 中运行 SDK 中的示例应用程序,我被提示安装升级,并被带到 Play 商店执行此操作。

    【讨论】:

    • 默认安装。这是一个商业(无根)HTC Flyer,根深蒂固的 HTC Desire S 安装了 gapps(并且有 Google play 服务)。
    • 您需要最新版本。您发布的错误是指默认的“出厂安装”版本。
    • 我刚刚在这里读到http://code.google.com/p/gmaps-api-issues/issues/detail?id=4627#c1,将新的 MapFragment 添加到活动页面将触发更新。如果您已经构建了应用程序,这可能比配置示例应用程序运行更容易。
    • 你我的朋友是救命稻草。由于某种原因,我禁用了不会自动更新 google play 服务的后台数据。启用后,它会自动更新并且一切正常(好吧,我没有看到地图,只有右下角的 +-,但这本身就是另一个问题)。不需要 Fragment 事务,也不需要 MapsInitializer。再次感谢!
    • 作为对访问者的一般参考,本页后半部分概述了 Google Play 服务 APK 安装场景以及如何处理这些场景。 http://developer.android.com/google/play-services/setup.html
    猜你喜欢
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 2014-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-13
    • 1970-01-01
    相关资源
    最近更新 更多