如何修复Google Cloud Messaging注册错误:SERVICE_NOT_AVAILABLE?

时间:2013-06-19 10:32:57

标签: java android push-notification google-cloud-messaging

我遇到了一个奇怪的问题 - 我在我的应用程序中使用GCM已经有很长一段时间了,一切都运行得很好。但是,在发布到Google Play之前,我将应用程序包名称从com.android.testapp更改为com.android.recognition,此后GCM停止了工作。起初我得到错误GCM sender id not set on constructor并通过覆盖getSenderIds(Context context)修复它,但现在我无法获得注册ID。以下是来自logcat的消息: enter image description here

我该如何解决这个问题?当我切换到新包时,我将清单文件中的所有内容更改为新包:

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

那背后的问题是什么?可以重命名应用程序包导致这个还是有另一个原因?

17 个答案:

答案 0 :(得分:42)

问题得到解答,在我的情况下,它稍微复杂一点。

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

答案 1 :(得分:32)

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

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


请参阅GCM Lib的GCMConstants类。

/**
     * 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);
        }
    }

答案 2 :(得分:18)

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

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

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

答案 3 :(得分:18)

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

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

    仅这些问题足以让我开始寻找GCM替代品。我会每天或每两天对我的应用程序进行1星评价,并在评论中包含抛出SERVICE_NOT_AVAILABLE时显示的错误消息。我没有办法帮助这些用户,因为他们中的大多数人都是出于他们无法控制的原因而接收这些用户。

    Google Cloud Messaging的替代方案

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

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

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

答案 4 :(得分:13)

对我来说 - 设备时间不正确。我更改了设备设置以使用“自动日期和时间”,再次尝试并且一切都很好。

干杯

答案 5 :(得分:3)

就我而言,解决方案是根据https://snowdog.co/blog/dealing-with-service_not_available-google-cloud-messaging/

向清单添加新的intent-filter操作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(棒棒糖)模拟器。

答案 6 :(得分:3)

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

答案 7 :(得分:3)

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

答案 8 :(得分:3)

我有类似的问题。在google nexus(Android 4.4.2)上工作得很好,但在三星galaxy s3(Android 4.1.2)上却没有。 我在三星注册时获得了SERVICE_NOT_AVAILABLE。事实证明三星的时间已经过去了。它未设置为使用网络时间自动更新。一旦我修复了GCM就像一个魅力。谢谢 - Umesh

答案 9 :(得分:3)

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

在我的情况下,我在自定义应用程序类中注册了推送服务(在任何活动之前执行,我认为是由于某些事情尚未被初始化)。将其更改为主要活动解决了问题。

public class MyCustomApp extends Application {

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

}

答案 10 :(得分:2)

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

答案 11 :(得分:0)

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

答案 12 :(得分:0)

对我来说goolge阻止了我的IP!我不得不重置我的DSL conn从池中获取一个新的IP,一切都恢复了,idk为什么他们阻止我,也许是为了尝试很多应用程序?无论如何现在正在工作,我希望这有助于其他人:)

答案 13 :(得分: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> 我希望这会对你有所帮助:-)。

答案 14 :(得分:0)

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

我放弃了尝试找到与之对应的设置,并且刚刚恢复出厂设置。运行OxygenOS的OnePlus设备有时会在安装软件更新时出现奇怪的配置错误,并且恢复出厂设置,然后从Google备份恢复,使得恢复工作的速度比理解底层问题要快得多(并且可能是用户甚至没有正确访问以解决潜在问题。)

答案 15 :(得分:0)

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

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

答案 16 :(得分:-1)

经过长时间的努力,我设法解决了这个问题。 确保Google Play服务应用是最新的,并且未在手机上禁用其后台同步。