当我向设备发送通知时,该设备收到推送消息,但它收到“com.google.android.c2dm.intent.REGISTRATION” Intent ,而不是“com.google.android.c2dm.intent” 。收到”。 如果我尝试发送第二个通知,我会收到来自 Google 的“NotRegistered”错误。
设备注册正常(我猜),因为我获得了身份验证 token “APA91...-119 个字符-”。
这是我开始注册设备的代码:
Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
registrationIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0));
registrationIntent.putExtra("sender", "EMAIL");
startService(registrationIntent);
发件人(这是在 Android 设备中完成的):
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("https://www.google.com/accounts/ClientLogin");
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("Email", "SAME AS LOGIN"));
nameValuePairs.add(new BasicNameValuePair("Passwd", "****"));
nameValuePairs.add(new BasicNameValuePair("accountType", "HOSTED_OR_GOOGLE"));
nameValuePairs.add(new BasicNameValuePair("source","Google-cURL-Example"));
nameValuePairs.add(new BasicNameValuePair("service", "ac2dm"));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = client.execute(post);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
Log.e("C2DM", line);
if (line.startsWith("Auth=")) {
s = line.substring(5);//LOGIN TOKEN
Log.i("C2DM", "Token get: "+ s);
String auth_key = s; /* GETTING THE AUTH TOKEN FROM SERVER */
StringBuilder postDataBuilder = new StringBuilder();
postDataBuilder.append(PARAM_REGISTRATION_ID).append("=").append(auth_key);
postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=").append("0");
postDataBuilder.append("&").append("data.info").append("=").append(URLEncoder.encode("Invitar", UTF8));
URLEncoder.encode(telephonyManager.getDeviceId(), UTF8));
byte[] postData = postDataBuilder.toString().getBytes(UTF8);
URL url = new URL("https://android.clients.google.com/c2dm/send");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
conn.setRequestProperty("Content-Length",Integer.toString(postData.length));
conn.setRequestProperty("Authorization", "GoogleLogin auth="+ auth_key);
OutputStream out = conn.getOutputStream();
out.write(postData);
out.close();
int responseCode = conn.getResponseCode();
Log.e("C2DM", String.valueOf(responseCode));
// Validate the response code
if (responseCode == 401 || responseCode == 403) {
Log.e("C2DM", "Unauthorized - need token");
}
// Check for updated token header
String updatedAuthToken = conn.getHeaderField(UPDATE_CLIENT_AUTH);
if (updatedAuthToken != null && !auth_key.equals(updatedAuthToken)) {
Log.i("C2DM","Got updated auth token from datamessaging servers: "+ updatedAuthToken);
Editor edit = prefManager.edit();
edit.putString(AUTH, updatedAuthToken);
}
String responseLine = new BufferedReader(new InputStreamReader(conn.getInputStream())).readLine();
if (responseLine == null || responseLine.equals("")) {
Log.i("C2DM", "Got " + responseCode+ " response from Google AC2DM endpoint.");
throw new IOException("Got empty response from Google AC2DM endpoint.");
}
String[] responseParts = responseLine.split("=", 2);
if (responseParts.length != 2) {
Log.e("C2DM", "Invalid message from google: " + responseCode+ " " + responseLine);
throw new IOException("Invalid response from Google "+ responseCode + " " + responseLine);
}
if (responseParts[0].equals("id")) {
Log.i("C2DM", "Successfully sent data message to device: "+ responseLine);
retval = 1;
}
if (responseParts[0].equals("Error")) {
String err = responseParts[1];
Log.w("C2DM","Got error response from Google datamessaging endpoint: "+ err);
// No retry.
throw new IOException(err);
}
return sendMessage();
}
}
} catch (IOException e) {
e.printStackTrace();
}
我的收件人:
public void onReceive(Context context, Intent intent) {
Log.d("C2DM", "Intent recieved: "+intent.getAction());
if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
handleRegistration(context, intent);
} else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
handleMessage(context, intent);
}
}
private void handleRegistration(Context context, Intent intent) {
String registration = intent.getStringExtra("registration_id");
if (intent.getStringExtra("error") != null) {
// Registration failed, should try again later.
Log.d("C2DM", "registration failed");
String error = intent.getStringExtra("error");
if(error == "SERVICE_NOT_AVAILABLE"){
Log.d("c2dm", "SERVICE_NOT_AVAILABLE");
}else if(error == "ACCOUNT_MISSING"){
Log.d("c2dm", "ACCOUNT_MISSING");
}else if(error == "AUTHENTICATION_FAILED"){
Log.d("c2dm", "AUTHENTICATION_FAILED");
}else if(error == "TOO_MANY_REGISTRATIONS"){
Log.d("c2dm", "TOO_MANY_REGISTRATIONS");
}else if(error == "INVALID_SENDER"){
Log.d("c2dm", "INVALID_SENDER");
}else if(error == "PHONE_REGISTRATION_ERROR"){
Log.d("c2dm", "PHONE_REGISTRATION_ERROR");
}
} else if (intent.getStringExtra("unregistered") != null) {
//HERE IS WHERE ARRIVES THE SEND NOTIFICATION (NOT THE UNREGISTER NOTIFICATION)
Log.d("C2DM", "unregistered: "+intent.getStringExtra("unregistered"));
} else if (registration != null) {
Log.d("C2DM", registration);
/* SENDING THE AUTH TOKET TO SERVER */
}
}
我在设备上推送通知,因为如果我在服务器端推送通知,我总是会收到“InvalidRegistration”错误。
奇怪的是,我好像注册了,但是当我发送一条推送消息时,就像谷歌取消注册设备一样。
有什么想法/建议吗?
最佳答案
我遇到了同样的问题并解决了它。
这是错误的代码
<receiver android:name=".MyC2DMReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.package.myapp" />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.c2dm.permission.RECEIVE" />
<category android:name="com.package.myapp" />
</intent-filter>
</receiver>
我有写 Intent 而不是许可
com.google.android.c2dm.permission.RECEIVE => com.google.android.c2dm.intent.RECEIVE
然后它就正常工作了 所以RECEIVE的包名是错误的
正确的代码
<receiver android:name=".MyC2DMReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.package.myapp" />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.package.myapp" />
</intent-filter>
</receiver>
关于Android c2dm自动注销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6097980/
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty
我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功
我想知道是否可以通过自动创建数组来插入数组,如果数组不存在的话,就像在PHP中一样:$toto[]='titi';如果尚未定义$toto,它将创建数组并将“titi”压入。如果已经存在,它只会推送。在Ruby中我必须这样做:toto||=[]toto.push('titi')可以一行完成吗?因为如果我有一个循环,它会测试“||=”,除了第一次:Person.all.eachdo|person|toto||=[]#with1billionofperson,thislineisuseless999999999times...toto.push(person.name)你有更好的解决方案吗?
出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t
我正在使用devise,当用户更改密码时,网站会将他们注销。我在网上读到,添加sign_in可以解决问题但不起作用,并且当密码更改时用户会注销。这是我的代码if@user.errors[:base].empty?and@user.update_attributes(params[:user])sign_in(current_user,:bypass=>true)flash[:success]="Useraccounthasbeensuccessfullyupdated"redirect_toedit_user_path(params[:site_id],@user)elserender
文章目录1.自动驾驶实战:基于Paddle3D的点云障碍物检测1.1环境信息1.2准备点云数据1.3安装Paddle3D1.4模型训练1.5模型评估1.6模型导出1.7模型部署效果附录show_lidar_pred_on_image.py1.自动驾驶实战:基于Paddle3D的点云障碍物检测项目地址——自动驾驶实战:基于Paddle3D的点云障碍物检测课程地址——自动驾驶感知系统揭秘1.1环境信息硬件信息CPU:2核AI加速卡:v100总显存:16GB总内存:16GB总硬盘:100GB环境配置Python:3.7.4框架信息框架版本:PaddlePaddle2.4.0(项目默认框架版本为2.3
我不确定如何为我的搜索功能添加自动完成表单。"get"do%>nil%>我有一个具有自定义操作的Controllerdefquery@users=Search.user(params[:query])@article=Search.article(params[:query])end模型如下:defself.user(search)ifsearchUser.find(:all,:conditions=>['first_nameLIKE?',"%#{search}%"])elseUser.find(:all)endenddefself.article(search)ifsearchArt
我对自动测试的工作方式的印象(基于cucumbergithubwiki和其他在线内容)是它应该重新运行红色示例,直到它们通过。我的问题是它会重新运行规范文件中找到失败示例的所有示例,包括通过的示例。我不想浪费时间在修复失败示例的同时重新运行通过的示例。是否可以配置自动测试以便仅运行失败的示例? 最佳答案 您需要rspec-retrygem。以下是文档中有关如何实现它的一些示例:将它应用到覆盖整个测试套件的configureblock中...RSpec.configuredo|config|config.verbose_retry=t