- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我已遵循本教程 https://developers.google.com/cloud-messaging/ios/client在我的 iOS 应用程序上实现 GCM。我的应用服务器是用 Java 编写的谷歌应用引擎,我使用 gcm-server.jar https://github.com/google/gcm图书馆。我认为我的证书没问题,我可以注册、获取 token ,甚至可以接收我的应用服务器发送的消息内容。但是,当应用程序处于后台时,我不会收到任何通知提醒,只有当我单击应用程序图标以重新启动它时,我才会收到通知提醒。
我以为那是因为我只实现了 didReceiveRemoteNotification:
而不是 didReceiveRemoteNotification:fetchCompletionHandler:
所以我实现了它而不是第一个但是我没有收到通知而在后台,更糟糕的是,应用程序崩溃并显示类似“无法识别的选择器发送到实例 didReceiveRemoteNotification:”之类的内容,就像用户信息中出现问题一样。我确实在 xCode 中允许背景模式,就像它所需要的那样。这是我使用的代码:
AppDelegate ()
@property (nonatomic, strong) NSDictionary *registrationOptions;
@property (nonatomic, strong) GGLInstanceIDTokenHandler registrationHandler;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//-- Set Notification
[[GCMService sharedInstance] startWithConfig:[GCMConfig defaultConfig]];
if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)])
{
NSLog(@"Case iOS8");
// iOS 8 Notifications
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[application registerForRemoteNotifications];
}
else
{
NSLog(@"Case iOS7");
// iOS < 8 Notifications
[application registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)];
}
self.registrationHandler = ^(NSString *registrationToken, NSError *error){
if (registrationToken != nil) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:registrationToken forKey:TOKENGCM];
NSLog(@"Registration Token: %@", registrationToken);
//some code
} else {
NSLog(@"Registration to GCM failed with error: %@", error.localizedDescription);
}
};
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
[[GCMService sharedInstance] disconnect];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Connect to the GCM server to receive non-APNS notifications
[[GCMService sharedInstance] connectWithHandler:^(NSError *error) {
if (error) {
NSLog(@"Could not connect to GCM: %@", error.localizedDescription);
} else {
NSLog(@"Connected to GCM");
// ...
}
}];
}
- (void)applicationWillTerminate:(UIApplication *)application {
}
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// Start the GGLInstanceID shared instance with the default config and request a registration
// token to enable reception of notifications
[[GGLInstanceID sharedInstance] startWithConfig:[GGLInstanceIDConfig defaultConfig]];
self.registrationOptions = @{kGGLInstanceIDRegisterAPNSOption:deviceToken,
kGGLInstanceIDAPNSServerTypeSandboxOption:@NO};
[[GGLInstanceID sharedInstance] tokenWithAuthorizedEntity:SENDER_ID
scope:kGGLInstanceIDScopeGCM
options:self.registrationOptions
handler:self.registrationHandler];
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSLog(@"Error in registration. Error: %@", err);
}
- (void)onTokenRefresh {
// A rotation of the registration tokens is happening, so the app needs to request a new token.
NSLog(@"The GCM registration token needs to be changed.");
[[GGLInstanceID sharedInstance] tokenWithAuthorizedEntity:SENDER_ID
scope:kGGLInstanceIDScopeGCM
options:self.registrationOptions
handler:self.registrationHandler];
}
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(@"Notification received: %@", userInfo);//This does print the content of my message in the console if the app is in foreground
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive) {
NSString *cancelTitle = @"Close";
NSString *showTitle = @"Show";
NSString *message = [[userInfo valueForKey:@"aps"] valueForKey:@"alert"];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Some title"
message:message
delegate:self
cancelButtonTitle:cancelTitle
otherButtonTitles:showTitle, nil];
[alertView show];
}
else{
NSLog(@"Notification received while inactive");
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 99];
UIAlertView *BOOM = [[UIAlertView alloc] initWithTitle:@"BOOM"
message:@"app was INACTIVE"
delegate:self
cancelButtonTitle:@"a-ha!"
otherButtonTitles:nil];
[BOOM show];
NSLog(@"App was NOT ACTIVE");
[[NSNotificationCenter defaultCenter] postNotificationName:@"Notification!"
object:nil
userInfo:userInfo];
}
// This works only if the app started the GCM service
[[GCMService sharedInstance] appDidReceiveMessage:userInfo];
}
//Implement that causes unrecognized selector crash
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))handler {
NSLog(@"Notification received: %@", userInfo);
// This works only if the app started the GCM service
[[GCMService sharedInstance] appDidReceiveMessage:userInfo];
// Handle the received message
// Invoke the completion handler passing the appropriate UIBackgroundFetchResult value
// [START_EXCLUDE]
[[NSNotificationCenter defaultCenter] postNotificationName:@"notif"
object:nil
userInfo:userInfo];
handler(UIBackgroundFetchResultNoData);
// [END_EXCLUDE]
}
@end
有人能弄清楚我不在前台时收不到通知的原因吗?
编辑:服务器端用于发送 GCM 消息的 Java 代码:
public static MulticastResult sendViaGCM(String tag, String message, List<String> deviceIdsList) throws IOException {
Sender sender = new Sender(Constantes.API_KEY);
// This message object is a Google Cloud Messaging object
Message msg = new Message.Builder().addData("tag",tag).addData("message", message).build();
MulticastResult result = sender.send(msg, deviceIdsList, 5);
return result;
}
EDIT2: POST 请求的屏幕截图 http://image.noelshack.com/fichiers/2015/34/1440193492-gcm1.png http://image.noelshack.com/fichiers/2015/34/1440193502-gcm2.png
EDIT3:我现在从我的应用服务器发送的请求:
public static void sendGCMMessage(String tag, String message, List<String> deviceIdsList) {
String request = "https://gcm-http.googleapis.com/gcm/send";
try{
URL url = new URL(request);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
//conn.setInstanceFollowRedirects(false);
conn.setRequestMethod("POST");
//Les deux headers obligatoires:
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", "key=" + API_KEY);
//Construction du JSON:
JSONObject fullJSON = new JSONObject();
JSONObject data=new JSONObject();
JSONObject notification=new JSONObject();
data.put("tag", tag);
data.put("message", message);
notification.put("sound", "default");
notification.put("badge", "1");
notification.put("title", "default");
notification.put("body", message);
fullJSON.put("registration_ids", deviceIdsList);
fullJSON.put("notification", notification);
fullJSON.put("content_available", "true");
fullJSON.put("data", data);
//Phase finale:
OutputStreamWriter wr= new OutputStreamWriter(conn.getOutputStream());
wr.write(fullJSON.toString());
wr.flush();
wr.close();//pas obligatoire
//conn.setUseCaches(false);
}
catch(Exception e){
e.printStackTrace();
}
最佳答案
基于GCM documentation , 您可以设置 content_available
至 true
.
(在 iOS 上,使用此字段表示 APNS 负载中可用的内容。当发送通知或消息并将其设置为 true 时,不活动的客户端应用程序将被唤醒。在 Android 上,数据消息会唤醒默认情况下的应用程序。在 Chrome 上,目前不支持。)
content_available
对应苹果的content-available
,您可以在 this Apple Push Notification Service documentation 中找到.
此外,您应该使用 Notification playload , 用于向您的 iOS 应用程序发送消息,以便它可以在您的应用程序处于后台时显示横幅。
这是一个示例 HTTP 请求:
https://gcm-http.googleapis.com/gcm/send
Content-Type:application/json
Authorization:key=API_KEY
{
"to" : "REGISTRATION_TOKEN",
"notification" : {
"sound" : "default",
"badge" : "1",
"title" : "default",
"body" : "Test",
},
"content_available" : true,
}
The Java library只是一个示例,您可以向其中添加其他字段。例如,在 Message.java类,可以添加两个私有(private)变量,一个是private final Boolean contentAvailable
, 另一个是 private final Map<String, String> notification
.
您可以通过执行 curl -i -H "Content-Type:application/json" -H "Authorization:key=API_KEY" -X POST -d '{"to":"REGISTRATION_TOKEN", "notificaiton":{"sound":"default", "badge":"1", "title": "default", "body":"test",},"content_available":true}' https://android.googleapis.com/gcm/send
在终端中尝试 HTTP 请求,或在 Postman 中尝试.
已编辑:
如果您的应用程序被终止,并且您希望推送通知显示在您的设备中,您可以设置 high priority在您的 HTTP 请求正文中(请注意,与普通优先级消息相比,将您的消息设置为高优先级会更耗电)。
示例 HTTP 请求:
{
"to" : "REGISTRATION_TOKEN",
"notification" : {
"sound" : "default",
"badge" : "1",
"title" : "default",
"body" : "Test",
},
"content_available" : true,
"priority" : "normal",
}
关于java - 谷歌云消息 : don't receive alerts when iOS App is in background,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32134815/
如果数据是从另一台计算机(首先)“发送”的,我如何设置我的套接字例程以“发送”(首先)或(切换)“接收”? 谢谢 通用代码: -(void) TcpClient{ char buffer[12
我正在尝试在代码中使用 Java 8 方法引用。有四种类型的方法引用可用。 静态方法引用。 实例方法(绑定(bind)接收者)。 实例方法(未绑定(bind)接收者)。 构造函数引用。 使用静态方法引
我正在尝试在我的代码中使用 Java 8 方法引用。有四种类型的方法引用可用。 静态方法引用。 实例方法(绑定(bind)接收器)。 实例方法(UnBound 接收器)。 构造函数引用。 使用静态方法
这个问题在这里已经有了答案: X does not implement Y (... method has a pointer receiver) (4 个答案) 关闭 3 年前。 最近在研究Iri
我把这个问题/错误发布到 GIT 官方 channel ,但没有得到任何回应。希望这里有人可以帮助我。 当 receive.denyCurrentBranch 设置为 updateInstead 并且
我正在开发一个新的监控系统,该系统可以测量 Celery 队列吞吐量并在队列备份时帮助提醒团队。在我的工作过程中,我遇到了一些我不理解的奇怪行为(并且在 Celery 规范中没有详细记录)。 出于测试
我正在开发一个新的监控系统,该系统可以测量 Celery 队列吞吐量并在队列备份时帮助提醒团队。在我的工作过程中,我遇到了一些我不理解的奇怪行为(并且在 Celery 规范中没有详细记录)。 出于测试
这个问题在这里已经有了答案: What does this Google Play APK publish error message mean? (17 个答案) 关闭 3 年前。 我为我的应用程
我正在寻找一种解决方案来从我的 child “药物”中获取数据,并使用 ID 从“medication_plan”节点接收特定数据并将它们显示在 Recyclerview 中。 数据库结构: 目前我正
我正在构建 DNN 来预测对象是否存在于图像中。我的网络有两个隐藏层,最后一层看起来像这样: # Output layer W_fc2 = weight_variable([2048, 1])
我有一个模拟销售漏斗的 WF4 服务。它的工作原理是从“注册”接听电话开始。之后,有 10 个类似的阶段(每个阶段包含 2 个接收)。在当前阶段验证接收到的数据之前,您不能前进到一个阶段。但我不确定的
我有一个用 NSubstitute 伪造的对象,它有一个被调用两次的方法。我想验证该方法实际上已被调用两次(且仅调用两次)。我浏览了文档和谷歌,但没有运气。任何帮助,将不胜感激。谢谢。 最佳答案 NS
我在 Windows 上使用 D 编写了一个套接字服务器,现在我想将它移植到 Linux 上。这是代码摘要: /* * this.rawsocks - SocketSet * this.serve
我有一个在 AndroidManifest.xml 中定义了 Receiver 的应用程序,它似乎随机地被禁用,这导致应用程序强制关闭,直到重新安装应用程序。在发生这种情况之前,应用可能会在一天、一周
我正在尝试使用 android 注释库通过两种方式进行广播接收器,但 ide 无法识别此代码中的 @Receiver 或 @ReceiverAction import android.content.
我正在试验 Android 的 LiveData .我只是试图将大量通知推送给观察 LiveData 对象的观察者。我让一个线程在后台运行,在一个 while 循环中,我不断地通过 LiveData
当我运行以下代码时: [Test] public async Task Can_Test_Update() { var response = await _controller.UpdateA
查看 header 时,似乎第二台接收邮件的服务器直到最终 header 中报告的送达日期之后才转发它。 在 c9mailgw11.amadis.com,报告的时间是 22:47:49 -0800
我在这里搜索了几个问题都没有得到答案,所以我会根据我的具体情况询问。 真正简单的接收后 Hook ,它只是 curl 到 Redmine 以强制 Redmine 在提交时更新 repo 的 View
我目前正在尝试 Elixir。我对 Ruby 或函数式编程的经验很少,所以我不太熟悉语法。我在读Learn Elixir in Y minutes其中一个例子让我有点困惑。起初,指南显示了 case
我是一名优秀的程序员,十分优秀!