【问题标题】:How can I mock a message sent from Google Cloud Messaging?如何模拟从 Google Cloud Messaging 发送的消息?
【发布时间】:2015-04-16 00:19:09
【问题描述】:
我正在使用 Google Cloud Messaging API 向 Android 设备发送推送通知。我已经实现了IntentService 和相应的逻辑来处理来自 GCM 服务器的通知。问题是 GCM 有时需要 15 分钟才能发送消息,这让调试变得非常痛苦。
我搜索了如何模拟 GCM,但没有找到任何适用于我的情况的解决方案。 我已经实现了第三方客户端服务器;问题是等待 GCM 将消息实际发送到 Android 设备。
Android 设备上的入口点是IntentService,它有一个钩子方法handleIntent(Intent)。似乎一种可能性是编写另一个向系统发送“欺骗”意图的程序,以便系统加载我的IntentService,其行为、外观和感觉就像真正的 GCM 意图。这样,我的应用程序就可以立即接收消息。
有没有人遇到过这个问题,或者有什么解决办法?
【问题讨论】:
标签:
android
google-app-engine
google-cloud-messaging
【解决方案1】:
如果你想模拟一些东西,但你不知道如何做到这一点,请使用以下方法。
- 使用您需要模拟的依赖项(intentservice)创建一个适配器类(CAdpapter)。
- 创建一些调用依赖关系的公共方法。
- 创建一个接口(IAdapater),并确保适配器类实现了该接口(只需将您在第 2 步中创建的方法放入该接口即可)。
- 确保需要与依赖项(如 IntentService 所述)对话的类不直接执行此操作,而是与 IAdapter 的实例对话。
- 编写一个实现 IAdapter (MockAdapter) 的模拟类。如果您不喜欢这样,请使用模拟框架。
类现在可以通过适配器与 IntentService 或 Mock 对话。一个解决方案可以是创建自己的类来与您需要模拟的依赖关系进行对话。
模拟可能很难。 Mock 需要实现与普通类相同的接口。但是,如果这个类有一个巨大的接口或根本没有接口,那么它可能是一个问题(这些只是示例)。编写自己的类来调用您需要模拟的类可能是一种解决方案
【解决方案2】:
我使用Postman 来伪造通知。
你需要标题:
// Please note that the authorization header's KEY is actually "key=<your GCM API key>"
Authorization: key=<your GCM API key>
Content-Type: application/json
然后发布到https://android.googleapis.com/gcm/send(这是针对 Android 的,我假设现在某个地方也有 iOS 设备,因为 Google 也支持 iOS 设备)。
你的身体必须是这样的:
{
"registration_ids":["<Your device registration token from GCM>"],
"data": {
"message" : "your message here"
}
}
我假设(但我尚未确认):
- 您可以在registration_ids上做一个逗号分隔的列表
-
您可以将其他字段放入该“数据”json;任何可以通过 Bundle 传递的东西。这是基于此代码有效的事实:
public class PushNotificationListenerService extends GcmListenerService {
private static final String TAG = "NotificationListener";
/**
* Called when message is received.
*
* @param from SenderID of the sender.
* @param data Data bundle containing message data as key/value pairs.
* For Set of keys use data.keySet().
*/
// [START receive_message]
@Override
public void onMessageReceived(String from, Bundle data) {
// Pay attention to this line of code; this indicates
// that you could have ANY key-value pair passed in
// as long as it's capable of being serialized into a Bundle object
String message = data.getString("message");
Log.d(TAG, "From: " + from);
Log.d(TAG, "Message: " + message);
/**
* In some cases it may be useful to show a notification
* indicating to the user that a message was received.
*/
sendNotification(message);
//TODO any of your own logic to handle the notification
}
// [END receive_message]
/**
* Create and show a simple notification containing the received GCM
* message.
*
* @param message GCM message received.
*/
private void sendNotification(String message) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0
/* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri =
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new
NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_favorite_white_shadow_36dp)
.setContentTitle("GCM Message")
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}