29

我遇到了一个奇怪的问题——我在我的应用程序中使用 GCM 已经很长时间了,而且一切正常。但是,在发布到 Google Play 之前,我将我的应用程序包名称从 更改为com.android.testappcom.android.recognition并且在此 GCM 停止工作之后。起初我遇到错误GCM sender id not set on constructor并通过覆盖修复它getSenderIds(Context context),但现在我无法获得注册 ID。以下是来自 logcat 的消息: 在此处输入图像描述

我怎样才能解决这个问题?当我切换到一个新包时,我将清单文件中的所有内容都更改为新包:

<receiver
        android:name="com.google.android.gcm.GCMBroadcastReceiver"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <category android:name="com.android.recognition" />
        </intent-filter>
    </receiver>

那么这背后的问题是什么?重命名应用程序包会导致这种情况还是有其他原因?

4

17 回答 17

43

问题得到了解答,就我而言,它稍微复杂一些。

  1. 检查您是否有有效的互联网连接
  2. 检查您的清单中是否具有 Internet 权限
  3. 确保包名称正确,如 Eran 所述
  4. 设备时间设置正确。即使一切都很完美,如果设备时钟设置不正确,它也会失败。

错误的时钟给我带来了问题。:)

于 2013-12-21T10:48:18.540 回答
33

SERVICE_NOT_AVAILABLE错误表示GCM Service当前不可用。等待一段时间后再试。

这种情况发生了很多次(根据我的经验),所以不用担心。


参见GCMConstantsGCM Lib 的类。

/**
     * The device can't read the response, or there was a 500/503 from the
     * server that can be retried later. The application should use exponential
     * back off and retry.
     */
    public static final String ERROR_SERVICE_NOT_AVAILABLE =
            "SERVICE_NOT_AVAILABLE";

有关更多调查handleRegistration(),请参阅GCMBaseIntentService

private void handleRegistration(final Context context, Intent intent) {
        String registrationId = intent.getStringExtra(EXTRA_REGISTRATION_ID);
        String error = intent.getStringExtra(EXTRA_ERROR);
        String unregistered = intent.getStringExtra(EXTRA_UNREGISTERED);
        Log.d(TAG, "handleRegistration: registrationId = " + registrationId +
                ", error = " + error + ", unregistered = " + unregistered);

        // registration succeeded
        if (registrationId != null) {
            GCMRegistrar.resetBackoff(context);
            GCMRegistrar.setRegistrationId(context, registrationId);
            onRegistered(context, registrationId);
            return;
        }

        // unregistration succeeded
        if (unregistered != null) {
            // Remember we are unregistered
            GCMRegistrar.resetBackoff(context);
            String oldRegistrationId =
                    GCMRegistrar.clearRegistrationId(context);
            onUnregistered(context, oldRegistrationId);
            return;
        }

        // last operation (registration or unregistration) returned an error;
        Log.d(TAG, "Registration error: " + error);
        // Registration failed
        if (ERROR_SERVICE_NOT_AVAILABLE.equals(error)) {
            boolean retry = onRecoverableError(context, error);
            if (retry) {
                int backoffTimeMs = GCMRegistrar.getBackoff(context);
                int nextAttempt = backoffTimeMs / 2 +
                        sRandom.nextInt(backoffTimeMs);
                Log.d(TAG, "Scheduling registration retry, backoff = " +
                        nextAttempt + " (" + backoffTimeMs + ")");
                Intent retryIntent =
                        new Intent(INTENT_FROM_GCM_LIBRARY_RETRY);
                retryIntent.putExtra(EXTRA_TOKEN, TOKEN);
                PendingIntent retryPendingIntent = PendingIntent
                        .getBroadcast(context, 0, retryIntent, 0);
                AlarmManager am = (AlarmManager)
                        context.getSystemService(Context.ALARM_SERVICE);
                am.set(AlarmManager.ELAPSED_REALTIME,
                        SystemClock.elapsedRealtime() + nextAttempt,
                        retryPendingIntent);
                // Next retry should wait longer.
                if (backoffTimeMs < MAX_BACKOFF_MS) {
                  GCMRegistrar.setBackoff(context, backoffTimeMs * 2);
                }
            } else {
                Log.d(TAG, "Not retrying failed operation");
            }
        } else {
            // Unrecoverable error, notify app
            onError(context, error);
        }
    }
于 2013-06-19T10:43:06.737 回答
22

SERVICE_NOT_AVAILABLE是 Google Cloud Messaging 最令人沮丧的问题之一。GoogleCloudMessaging.register(SENDER_ID)它是由注册设备以获取推送通知并返回注册 ID 的函数调用引发的异常。

  1. SERVICE_NOT_AVAILABLE 可能意味着用户的设备无法读取注册请求的响应或从服务器返回 500/503 错误代码。开发者没有办法修复这个错误,因为它在谷歌端,所以我们可以盲目地建议用户应该在几个小时内再试一次。
  2. SERVICE_NOT_AVAILABLE 可能在某些设备上发生,即使注册成功。这可以通过实现一个解决方法广播接收器来在调用失败时捕获令牌来解决。我实施了这个解决方法,它可能已经解决了一些用户的问题,但我仍然收到了许多其他 SERVICE_NOT_AVAILABLE 投诉。
  3. SERVICE_NOT_AVAILABLE 可能是由于设备上的 Google Play 服务库过时或缺失而发生的。在这种情况下,应用程序理论上可以通过打开相应的 Google Play 应用程序列表来通知用户更新 Google Play 服务。但是,应用程序不知道这就是抛出 SERVICE_NOT_AVAILABLE 的原因,因此它不能盲目地将用户重定向到 Google Play 上的 Google Play Services 应用程序页面。
  4. 当设备的时钟与网络不同步时,可能会出现 SERVICE_NOT_AVAILABLE。同样,开发人员无法知道这是确切的问题,因此我们可以盲目地建议用户检查他们的系统时钟同步,希望他们是极少数时钟不同步的人之一。
  5. SERVICE_NOT_AVAILABLE 可能会在 root 用户从他们的设备中删除环聊/GTalk 应用程序时发生(因为他们认为它是英国媒体报道软件)。GCM 由 Hangouts/GTalk 实现和处理,因此没有它就无法使用 GCM。
  6. 如果用户正在运行未安装 Google API 的设备(例如 Amazon Kindle),则可能会出现 SERVICE_NOT_AVAILABLE。此处无事可做,这些用户将永远不会收到来自您的应用的推送通知。

阅读更多: http ://eladnava.com/google-cloud-messaging-extremely-unreliable/

仅这些问题就足以让我开始寻找 GCM 替代品。我每天或两天都会在我的应用程序上获得 1 星评价,其中包含在抛出 SERVICE_NOT_AVAILABLE 时显示的错误消息的评论。我无法帮助这些用户,因为他们中的大多数人都因为无法控制的原因收到了它。

谷歌云消息传递的替代方案

Pushy ( https://pushy.me/ ) 是一个独立的推送通知网关,完全独立于 GCM。它维护自己的后台套接字连接,就像 GCM 一样,以接收推送通知。底层协议是 MQTT,一种极其轻量级的发布/订阅协议,占用的网络带宽和电池非常少。

Pushy 的一个巨大优势在于,用于发送推送通知(从服务器)和注册设备以获取推送通知的代码实际上在 GCM 和 Pushy 之间是可互换的。这使得在实施 GCM 之后切换到 Pushy 变得非常容易,并且因为它的不稳定性而不得不放弃它。

(全面披露:我为自己的项目创建了 Pushy,并意识到许多应用程序将从这样的服务中受益)

于 2015-04-08T09:30:09.060 回答
18

确保您在清单的权限部分更改了包名称:

<permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE"
    android:protectionLevel="signature" />
<uses-permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE" />

由于该部分中的包名称不正确,我遇到了类似的错误。

于 2013-06-19T12:44:33.133 回答
13

对我来说 - 设备时间不正确。我将设备设置更改为使用“自动日期和时间”,再试一次,一切正常。

干杯

于 2014-09-08T10:06:43.320 回答
3

我有同样的问题,但上述解决方案都没有解决我的问题。幸运的是,我最近解决了它,我想解释一下,跳跃它会帮助其他人:

就我而言,我在自定义应用程序类中注册了推送服务(在任何活动之前执行,我认为这是由于某些事情没有被正确初始化)。将其更改为主要活动解决了该问题。

public class MyCustomApp extends Application {

    @Override
    public void onCreate() {
         super.onCreate();
         PushService.register(this); //BAD IDEA, don't register pushes in Application Class
    }

}
于 2014-03-28T11:57:31.650 回答
3

我有一个类似的问题。在 google nexus (Android 4.4.2) 上运行良好,但在三星 Galaxy s3 (Android 4.1.2) 上运行良好。我在三星注册时获得了 SERVICE_NOT_AVAILABLE。原来三星的时间已经关闭。它没有设置为使用网络时间自动更新。一旦我修复了 GCM 就像一个魅力。谢谢 - 乌梅什

于 2014-04-16T13:23:14.413 回答
3

对我来说有连接问题。更改互联网连接解决了我的问题

于 2014-10-22T07:06:00.430 回答
3

对我来说,我通过在 Galaxy S4 上的数据使用选项中选中“限制后台数据”来关闭谷歌服务的“后台数据访问”。一旦我打开它,问题就在地窖网络上解决了。在 Wifi 上它工作正常。

于 2015-01-11T20:26:50.977 回答
3

就我而言,解决方案是根据https://snowdog.co/blog/dealing-with-service_not_available-google-cloud-messaging/在清单中添加一个新的意图过滤器操作 REGISTRATION

    <receiver
        android:name=".RemoteNotificationReceiver"
        android:permission="com.getset.getset.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.getset.getset.c2dm.intent.RECEIVE" />
            <action android:name="com.getset.getset.c2dm.intent.REGISTRATION" />
            <category android:name="com.getset.getset" />
        </intent-filter>
    </receiver>

我不得不承认,鉴于教程中缺少它,我很惊讶它的工作原理,但是将其取出肯定会将成功的注册 ID 变成异常。

注意:使用 Nexus 5 API 21 (Lollipop) 模拟器。

于 2015-01-21T13:59:49.510 回答
2

对我来说,问题是手机没有连接到互联网。我断开连接并连接到 Wi-Fi,并测试了与浏览器的连接并再次测试。像魅力一样工作:-)

于 2016-07-31T20:05:03.953 回答
0

我已经为谷歌服务关闭了“后台数据访问”。通过取消选中“数据使用”选项中的“限制后台数据”它对我有用!

于 2015-04-29T13:00:11.840 回答
0

对我来说,goolge 阻止了我的 IP!我不得不重置我的 DSL 连接以从池中获取新 IP,然后一切又恢复正常,我知道他们为什么阻止我,也许是因为尝试了许多应用程序?无论如何现在正在工作,我希望这对其他人有帮助:)

于 2015-05-11T05:43:17.663 回答
0

对我来说,SERVICE_NOT_AVAILABLE 问题出在我的应用程序项目中,因为接收器类。所以我在实现接收器后解决了如下问题。 <receiver android:name="receiver name" android:permission="com.google.android.c2dm.permission.SEND"> <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE"/> <action android:name="com.google.android.c2dm.intent.REGISTRATION"/> <category android:name="your package"/> </intent-filter> </receiver> 我希望这会对你有所帮助:-)。

于 2016-08-31T08:09:15.117 回答
0

我有一个 OnePlus2 在数据时无法接收推送。当我与 连接时logcat,我看到了很多这个错误,但不确定它是否相关。

我放弃了尝试找到与之对应的设置,只是将设备恢复出厂设置。运行 OxygenOS 的 OnePlus 设备在安装软件更新时有时会出现奇怪的配置错误,并且恢复出厂设置然后从 Google 备份恢复会使事情再次运行的速度比理解潜在问题所需的速度更快(并且可能是用户甚至没有解决根本问题的正确访问权限)。

于 2018-05-24T14:45:51.873 回答
0

就我而言,这是因为我的手机里面没有 SIM 卡。

我猜想拥有 sim 卡会在设备上设置自动时间,从而解决此问题。

于 2020-06-01T13:35:46.880 回答
-1

经过长时间的斗争,我设法解决了这个问题。确保 Google Play 服务应用程序是最新的,并且您的手机上没有禁用其后台同步。

于 2017-01-11T19:40:09.043 回答