开发C2DM Messaging应用程序。在那里,我命令使用C2DMBroadcastReceiver
,C2DMBaseReceiver
和C2DMMessaging
类接收注册ID。我将在我的包中C2DMReceiver
扩展C2DMBaseReceiver
。
这是我的代码段
C2DMMessaging.java
package com.google.android.c2dm;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.util.Log;
public class C2DMessaging {
public static final String EXTRA_SENDER = "sender";
public static final String EXTRA_APPLICATION_PENDING_INTENT = "app";
public static final String REQUEST_UNREGISTRATION_INTENT = "com.google.android.c2dm.intent.UNREGISTER";
public static final String REQUEST_REGISTRATION_INTENT = "com.google.android.c2dm.intent.REGISTER";
public static final String LAST_REGISTRATION_CHANGE = "last_registration_change";
public static final String BACKOFF = "backoff";
public static final String GSF_PACKAGE = "com.google.android.gsf";
// package
static final String PREFERENCE = "com.google.android.c2dm";
private static final long DEFAULT_BACKOFF = 30000;
/**
* Initiate c2d messaging registration for the current application
*/
public static void register(Context context,
String senderId) {
Intent registrationIntent = new Intent(REQUEST_REGISTRATION_INTENT);
registrationIntent.setPackage(GSF_PACKAGE);
registrationIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT,
PendingIntent.getBroadcast(context, 0, new Intent(), 0));
registrationIntent.putExtra(EXTRA_SENDER, senderId);
context.startService(registrationIntent);
Log.e("C2DM Services","Service Started");
}
/**
* Unregister the application. New messages will be blocked by server.
*/
public static void unregister(Context context) {
Intent regIntent = new Intent(REQUEST_UNREGISTRATION_INTENT);
regIntent.setPackage(GSF_PACKAGE);
regIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT, PendingIntent.getBroadcast(context,
0, new Intent(), 0));
context.startService(regIntent);
Log.e("C2DM Services","unregister");
}
/**
* Return the current registration id.
*
* If result is empty, the registration has failed.
*
* @return registration id, or empty string if the registration is not complete.
*/
public static String getRegistrationId(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
String registrationId = prefs.getString("dm_registration", "");
Log.e("C2DM Services","get registration id");
return registrationId;
}
public static long getLastRegistrationChange(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
Log.e("C2DM Services","getlastregchange");
return prefs.getLong(LAST_REGISTRATION_CHANGE, 0);
}
static long getBackoff(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
Log.e("C2DM Services","getbackoff");
return prefs.getLong(BACKOFF, DEFAULT_BACKOFF);
}
static void setBackoff(Context context, long backoff) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putLong(BACKOFF, backoff);
editor.commit();
Log.e("C2DM Services","setbackoff");
}
// package
static void clearRegistrationId(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putString("dm_registration", "");
editor.putLong(LAST_REGISTRATION_CHANGE, System.currentTimeMillis());
editor.commit();
Log.e("C2DM Services","clearregid");
}
// package
static void setRegistrationId(Context context, String registrationId) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putString("dm_registration", registrationId);
editor.commit();
Log.e("C2DM Services","setregid");
}
}
C2DMBroadcastReceiver.java
package com.google.android.c2dm;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class C2DMBroadcastReceiver extends BroadcastReceiver {
@Override
public final void onReceive(Context context, Intent intent) {
// To keep things in one place.
Log.e("C2DM Broadcast receiver","onReceive");
C2DMBaseReceiver.runIntentInService(context, intent);
setResult(Activity.RESULT_OK, null /* data */, null /* extra */);
}
}
清单文件
<permission android:name="com.sample.gt.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.sample.gt.permission.C2D_MESSAGE" />
<!-- Permissions -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<service android:name="com.sample.gt.c2dm.C2DMReceiver" />
<!--
Only C2DM servers can send messages for the app. If permission is not
set - any other app can generate it
-->
<receiver android:name="com.google.android.c2dm.C2DMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<!-- Receive the actual message -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.sample.gt.c2dm" />
</intent-filter>
<!-- Receive the registration id -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.sample.gt.c2dm" />
</intent-filter>
</receiver>
C2DMMessaging.java
public class C2DMessaging {
public static final String EXTRA_SENDER = "sender";
public static final String EXTRA_APPLICATION_PENDING_INTENT = "app";
public static final String REQUEST_UNREGISTRATION_INTENT = "com.google.android.c2dm.intent.UNREGISTER";
public static final String REQUEST_REGISTRATION_INTENT = "com.google.android.c2dm.intent.REGISTER";
public static final String LAST_REGISTRATION_CHANGE = "last_registration_change";
public static final String BACKOFF = "backoff";
public static final String GSF_PACKAGE = "com.google.android.gsf";
// package
static final String PREFERENCE = "com.google.android.c2dm";
private static final long DEFAULT_BACKOFF = 30000;
/**
* Initiate c2d messaging registration for the current application
*/
public static void register(Context context,
String senderId) {
Intent registrationIntent = new Intent(REQUEST_REGISTRATION_INTENT);
registrationIntent.setPackage(GSF_PACKAGE);
registrationIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT,
PendingIntent.getBroadcast(context, 0, new Intent(), 0));
registrationIntent.putExtra(EXTRA_SENDER, senderId);
context.startService(registrationIntent);
Log.e("C2DM Services","Service Started");
}
..........
}
现在我的问题是,
我通过传递上下文从我的活动中调用C2DMMessaging的注册,该服务是在C2DMMessaging中创建的,之后我没有收到 C2DMBroadcastReceiver的onReceive()
这是我从vogille.de获得的代码。如果我这样使用它,这工作正常,但是当我在我的应用程序中使用它时,这个问题就会出现。
我已经搜索了一些用谷歌搜索的内容,我发现manifest
文件中的问题可能。
我不知道我错在哪里。 有人可以提供帮助吗?
答案 0 :(得分:7)
由于一个不明原因,您的接收器类C2DMReceiver必须位于程序包的根目录中,该程序包在清单中声明为您的程序包名称。 这是我设法让这个工作的唯一方法...所以而不是:
service android:name="com.sample.gt.c2dm.C2DMReceiver"
尝试
service android:name=".C2DMReceiver"
这是我的清单摘录(权限除外)
<!--C2DM -->
<service android:name=".C2DMReceiver" />
<receiver android:name="com.google.android.c2dm.C2DMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<!-- Receive the actual message -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="my.package" />
</intent-filter>
<!-- Receive the registration id -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="my.package" />
</intent-filter>
</receiver>
答案 1 :(得分:4)
我感觉到你的痛苦,我努力让C2DM在其他网站中看到vogille.de。最终为我工作的是使用eclipse“App Engine Connected Android Project”创建的C2DM.jar文件(在File&gt; New&gt; Project&gt; Google下)。
注意:在撰写本文时,您必须安装该插件的测试版才能拥有此选项! http://code.google.com/eclipse/beta/docs/download.html
我的清单文件的相关部分:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
>
<permission
android:name="my_package_name.permission.C2D_MESSAGE"
android:protectionLevel="signature"
/>
<uses-permission android:name="my_package_name.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
...
>
<!-- Only C2DM servers can send messages for the app. If permission is not set - any other app can generate it -->
<receiver
android:name="com.google.android.c2dm.C2DMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND"
>
<!-- Receive the actual message -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="my_package_name" />
</intent-filter>
<!-- Receive the registration id -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="my_package_name" />
</intent-filter>
</receiver>
</application>
</manifest>
以下是我用来与C2DM服务进行交互的代码:
package my_package_name
import com.google.android.c2dm.C2DMBaseReceiver;
import com.google.android.c2dm.C2DMessaging;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
/**
* Receive C2DM state changes.
*
* Be careful: the various onX receivers may be called from a mysterious
* context -- in particular they cannot safely create new AsyncTask objects.
*/
public class C2DMReceiver extends C2DMBaseReceiver {
// GMail account associated with the C2DM application. Must agree with
// what the 3rd party server uses to authenticate with C2DM.
private static final String C2DM_SENDER = "my_email@gmail.com";
// -----------------------------------------------------------------
/**
* Ask this device to register for C2DM messaging. Will trigger
* onRegistered (or onError) when finished.
*/
public static void register(Context context) {
C2DMessaging.register(context, C2DM_SENDER);
}
/**
* Unregister this device from further C2DM messaging.
*/
public static void unregister(Context context) {
C2DMessaging.unregister(context);
}
// -----------------------------------------------------------------
public C2DMReceiver() {
super(C2DM_SENDER);
}
@Override
protected void onMessage(Context context, Intent intent) {
// Extras contains whatever your server put into the C2DM message.
final Bundle extras = intent.getExtras();
}
@Override
public void onError(Context context, String error_id) {
}
@Override
public void onRegistered(Context context, String registration_id) {
}
@Override
public void onUnregistered(Context context) {
}
}
生成的示例代码包括基于Java的AppEngine应用程序。我正在使用python,这是完成这篇文章的相关代码:
class C2dmAuthToken(db.Model):
"""Maintain an auth token used to talk to the C2DM service. There is at
most one of these records."""
role_email = db.StringProperty(indexed=False, default='my_email@gmail.com')
passwd = db.StringProperty(indexed=False, default='my_password')
token = db.TextProperty(indexed=False, default='')
class C2dmRegistration(db.Model):
"""Map from user to the C2DM registration id needed for the C2DM
service to send messages to the registered device."""
user_id = db.IntegerProperty(required=True)
registration_id = db.StringProperty(indexed=False)
class RegisterHandler(MyRequestHandler.MyRequestHandler):
def post(self):
# Parse arguments.
user_id = self.parseId('user_id')
registration_id = self.parseStr('registration_id')
# Create or update the device record.
record = C2dmRegistration.gql('WHERE user_id = :1', user_id).get()
if record == None:
record = C2dmRegistration(user_id=user_id)
record.registration_id = registration_id
record.put()
class UnregisterHandler(MyRequestHandler.MyRequestHandler):
def post(self):
# Parse arguments.
user_id = self.parseId('user_id')
# Unregister this device.
record = C2dmRegistration.gql('WHERE user_id = :1', user_id).get()
if record != None:
record.delete()
def getAuthToken():
"""Return an auth token associated with the role account. Login to
Google and store the auth token if needed."""
token_record = C2dmAuthToken.all().get()
if token_record == None:
token_record = C2dmAuthToken()
if len(token_record.token) > 0:
return token_record.token
form_fields = {
'accountType' : 'GOOGLE',
'Email' : token_record.role_email,
'Passwd' : token_record.passwd,
'service' : 'ac2dm',
'source' : 'my_source_name',
}
headers = {
'Content-Type' : 'application/x-www-form-urlencoded',
}
result = urlfetch.fetch(url='https://www.google.com/accounts/ClientLogin',
payload=urllib.urlencode(form_fields),
method=urlfetch.POST,
headers=headers)
if result.status_code != 200:
logging.warning('getAuthToken: client login http error %d' % result.status_code)
return None
for line in result.content.split('\n'):
if line.startswith('Auth='):
token_record.token = line[5:]
if len(token_record.token) == 0:
logging.warning('getAuthToken: no token')
return None
logging.info('getAuthToken allocated new token %s' % token_record.token)
token_record.put()
return token_record.token
def setAuthToken(token):
"""Update the auth token."""
token_record = C2dmAuthToken.all().get()
if token_record == None:
token_record = C2dmAuthToken()
token_record.token = token
token_record.put()
def sendMessage(dst_user_id, message):
"""Send a message to the dst user's device using C2DM."""
registration_record = C2dmRegistration.gql('WHERE user_id = :1', dst_user_id).get()
if registration_record == None:
logging.warning('SendMessage: no such dst_user_id %ld' % dst_user_id)
return False
# Use http and not https to avoid an invalid certificate error.
# Since the request originates inside google hopefully it is
# never snoop-able to the outside world, and does not contain
# critically secure info (such as the role password).
form_fields = {
'registration_id' : registration_record.registration_id,
'collapse_key' : '%d' % int(time.time() * 1000),
'data.message' : message,
}
headers = {
'Content-Type' : 'application/x-www-form-urlencoded',
'Authorization': 'GoogleLogin auth=%s' % getAuthToken(),
}
result = urlfetch.fetch(url='http://android.apis.google.com/c2dm/send',
payload=urllib.urlencode(form_fields),
method=urlfetch.POST,
headers=headers)
if result.status_code != 200:
logging.warning('sendMessage: http error %d' % result.status_code)
return None
if 'Update-Client-Auth' in result.headers:
logging.info('updating auth token')
setAuthToken(result.headers['Update-Client-Auth'])
return True
def main():
application = webapp.WSGIApplication([
('/c2dm/register', RegisterHandler),
('/c2dm/unregister', UnregisterHandler),
], debug=True)
wsgiref.handlers.CGIHandler().run(application)
if __name__ == '__main__':
main()
您的Android应用应该调用/ c2dm / register和/ c2dm / unregister方法来设置和清除设备c2dm令牌和后端。其他后端代码应调用sendMessage,要求Google将消息中继到设备。
此代码包含您的Gmail密码。我使用一次性gmail地址来满足我的c2dm需求,并通过直接数据存储区操作实际设置密码,而不是在代码中使用纯文本。即使有人知道更好的管理身份验证的方式,我也很乐意听到它。
我希望这有帮助!
答案 2 :(得分:3)
首先让我说你的IDE设置不是问题,这个过程甚至不需要服务器(现在)使用app引擎,这是在文件&gt;下添加Google选项的原因。新&gt;项目
Android设备联系谷歌C2DM服务器获取注册ID如果流程成功谷歌回复注册ID,以后您可以发送到您的服务器,现在我们将尝试让该过程工作并拥有在设备上注册ID,然后你可以处理它。
据我了解,您创建了一个Android项目,将他们在Chrome到手机示例中使用的Google课程,他们的教程中提供了vogella.de
在您的启动活动中执行此操作后,您调用了方法C2DMMessaging.register(this, "example@gmail.com);
这里有很多错误: 附:根据我的标准,这些是根据他们的可能性排序的,我也排除了一些似乎不适用于你提到的片段的案例。
由于是一个声誉低的用户,我无法发表评论