更新
已解决-感谢@MusiGenesis的坚持,我通过注册一个新的Google Mail帐户和一个新的C2DM帐户解决了这个问题.在更新了Web服务器和android应用中的相关凭据后,所有 *** 作都开始像魔术一样工作.
更新结束
我正在寻找有关发送推送通知时401未经授权错误的原因的明确列表,因此我可以尝试消除问题.
我有一个在C2DM中注册的Google电子邮件
我可以使用curl获得授权码
我的Android应用程序上有注册用户的身份验证令牌
使用2个身份验证令牌(刷新),从Web服务器发送推送通知请求时,我从Web服务器收到401未经授权的错误.
据我所知,我正在做我需要做的所有事情,因此我正在寻找自己可能缺少的东西.我搜寻了互联网,很多人似乎都遇到了同样的问题,但没有明确的答案.
任何帮助,不胜感激
更新
如下面的答案中所述,似乎需要第二阶段才能获得注册ID,该注册ID似乎与注册用户在androID应用上接收到的身份验证令牌不同.看过Jumpnote代码和这两个资源
http://www.vogella.de/articles/AndroidCloudToDeviceMessaging/article.html#implementation_mobileregistration
和
http://marakana.com/forums/android/general/272.html
除了auth令牌外,我看不到任何有关第二次注册电话以获取注册ID的信息.我显然缺少了一些东西,如果有人可以帮我说清楚,我将不胜感激.
**更新2 **
我的C2DM接收器看起来像这样
public class C2DMReceiver extends C2DMBaseReceiver { public C2DMReceiver() { super(REGISTERED_Google_MAIL_ADDRESS); } @OverrIDe public voID onRegistered(Context context, String registrationID) throws java.io.IOException { // The registrationID should be sent to your application server. Log.e("C2DM", "Registration ID arrived!"); Log.e("C2DM", registrationID); Intent webSeverReg = new Intent(this, RegService.class); startService(webServerReg); }; @OverrIDe protected voID onMessage(Context context, Intent intent) { Log.e("C2DM", "Message: Fantastic!!!"); // Extract the payload from the message Bundle extras = intent.getExtras(); if (extras != null) { System.out.println(extras.get("payload")); // Now do something smart based on the information } } @OverrIDe public voID one rror(Context context, String errorID) { Log.e("C2DM", "Error occured!!!"); }}
从Jumpnote应用中获取的C2DMBaseReceiver看起来像这样
/** * Base class for C2D message receiver. Includes constants for the * strings used in the protocol. */public abstract class C2DMBaseReceiver extends IntentService { private static final String C2DM_RETRY = "com.Google.androID.c2dm.intent.RETRY"; public static final String REGISTRATION_CALLBACK_INTENT = "com.Google.androID.c2dm.intent.REGISTRATION"; private static final String C2DM_INTENT = "com.Google.androID.c2dm.intent.RECEIVE"; // Logging tag private static final String TAG = "C2DM"; // Extras in the registration callback intents. public static final String EXTRA_UNREGISTERED = "unregistered"; public static final String EXTRA_ERROR = "error"; public static final String EXTRA_REGISTRATION_ID = "registration_ID"; public static final String ERR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE"; public static final String ERR_ACCOUNT_MISSING = "ACCOUNT_MISSING"; public static final String ERR_AUTHENTICATION_Failed = "AUTHENTICATION_Failed"; public static final String ERR_TOO_MANY_REGISTRATIONS = "TOO_MANY_REGISTRATIONS"; public static final String ERR_INVALID_ParaMETERS = "INVALID_ParaMETERS"; public static final String ERR_INVALID_SENDER = "INVALID_SENDER"; public static final String ERR_PHONE_REGISTRATION_ERROR = "PHONE_REGISTRATION_ERROR"; // wakelock private static final String WAKELOCK_KEY = "C2DM_liB"; private static PowerManager.WakeLock mWakeLock; private final String senderID; /** * The C2DMReceiver class must create a no-arg constructor and pass the * sender ID to be used for registration. */ public C2DMBaseReceiver(String senderID) { // senderID is used as base name for threads, etc. super(senderID); this.senderID = senderID; } /** * Called when a cloud message has been received. */ protected abstract voID onMessage(Context context, Intent intent); /** * Called on registration error. OverrIDe to provIDe better * error messages. * * This is called in the context of a Service - no dialog or UI. */ public abstract voID one rror(Context context, String errorID); /** * Called when a registration token has been received. */ public voID onRegistered(Context context, String registrationID) throws IOException { // registrationID will also be saved } /** * Called when the device has been unregistered. */ public voID onUnregistered(Context context) { } @OverrIDe public final voID onHandleIntent(Intent intent) { Log.d(TAG, "@@@@ - onHandleIntent Messaging request received"); try { Context context = getApplicationContext(); if (intent.getAction().equals(REGISTRATION_CALLBACK_INTENT)) { handleRegistration(context, intent); } else if (intent.getAction().equals(C2DM_INTENT)) { onMessage(context, intent); } else if (intent.getAction().equals(C2DM_RETRY)) { C2DMessaging.register(context, senderID); } } finally { // Release the power lock, so phone can get back to sleep. // The lock is reference counted by default, so multiple // messages are ok. // If the onMessage() needs to spawn a thread or do something else, // it should use it's own lock. mWakeLock.release(); } } /** * Called from the broadcast receiver. * Will process the received intent, call handleMessage(), registered(), etc. * in background threads, with a wake lock, while keePing the service * alive. */ static voID runIntentInService(Context context, Intent intent) { if (mWakeLock == null) { // This is called from broadcastReceiver, there is no init. PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); } mWakeLock.acquire(); // Use a naming convention, similar with how permissions and intents are // used. Alternatives are introspection or an ugly use of statics. String receiver = context.getPackagename() + ".C2DMReceiver"; intent.setClassname(context, receiver); context.startService(intent); } private voID handleRegistration(final Context context, Intent intent) { final String registrationID = intent.getStringExtra(EXTRA_REGISTRATION_ID); Log.d(TAG, "@@@@ - HandleRegistration Messaging request received"); String error = intent.getStringExtra(EXTRA_ERROR); String removed = intent.getStringExtra(EXTRA_UNREGISTERED); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "dmControl: registrationID = " + registrationID + ", error = " + error + ", removed = " + removed); } if (removed != null) { // Remember we are unregistered C2DMessaging.clearRegistrationID(context); onUnregistered(context); return; } else if (error != null) { // we are not registered, can try again C2DMessaging.clearRegistrationID(context); // Registration Failed Log.e(TAG, "Registration error " + error); one rror(context, error); if ("SERVICE_NOT_AVAILABLE".equals(error)) { long backoffTimeMs = C2DMessaging.getBackoff(context); Log.d(TAG, "Scheduling registration retry, backoff = " + backoffTimeMs); Intent retryIntent = new Intent(C2DM_RETRY); PendingIntent retryPIntent = PendingIntent.getbroadcast(context, 0 /*requestCode*/, retryIntent, 0 /*flags*/); AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); am.set(AlarmManager.ELAPSED_REALTIME, backoffTimeMs, retryPIntent); // Next retry should wait longer. backoffTimeMs *= 2; C2DMessaging.setBackoff(context, backoffTimeMs); } } else { try { onRegistered(context, registrationID); C2DMessaging.setRegistrationID(context, registrationID); } catch (IOException ex) { Log.e(TAG, "Registration error " + ex.getMessage()); } } }}
解决方法:
您说您“在我的androID应用中拥有来自注册用户的auth令牌”.您可能写错了,但是从字面上看,您的意思是您使用的是注册用户的auth令牌,而不是用户从C2DM服务器获得的注册ID.
编辑:您的客户端应用程序(在设备上运行)对C2DM使用3个步骤:1)调用C2DM服务器,传递客户端的gmail帐户ID和密码,取回auth令牌; 2)使用步骤1中的auth令牌再次调用C2DM服务器,获取注册ID(ASCII溢出的96-120个字符); 3)调用您的服务器应用,并传递在步骤2中获得的注册ID(而不是在步骤1中获得的auth令牌).
然后,当服务器应用程序想要向客户端推送内容时,它将调用C2DM服务器以获取身份验证令牌(传递用于注册C2DM服务器的电子邮件和密码,而不是客户端用户的电子邮件和密码) ,然后使用该auth令牌以及客户端的注册ID来执行推送.
编辑2:我在此处对客户端发生的情况的描述是错误的-客户端代码在任何时候均不涉及获取oauth令牌.所有这些东西都由AndroID OS本身处理.本教程:
http://www.vogella.de/articles/AndroidCloudToDeviceMessaging/article.html
很好地展示了C2DM的所有工作原理.
编辑3:我在C2DM上看到的最常见的错误来自文档中对“发件人的电子邮件”的使用.该术语指的是已“注册”用于C2DM的gmail帐户,而不是指AndroID用户的gmail帐户.您的网络服务器应用程序使用此gmail帐户(以及匹配的密码)从C2DM获取oauth令牌. AndroID客户端应用程序需要使用相同的帐户(没有匹配的密码,它不知道),以进行调用,该调用返回一个registrationID,然后将其发送到您的Web服务器.
总结以上是内存溢出为你收集整理的android-C2DM推送通知什么原因导致401未授权错误?全部内容,希望文章能够帮你解决android-C2DM推送通知什么原因导致401未授权错误?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)