Currently I'm creating an application that supports chatting between users using GCM, everything is working fine except that when i click on the message received via a notification, the chat activity opens with null data.
I've registered the GCM broadcast receiver in the manifest as follows:
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<!-- Receives the registration id. -->
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="xxx.xxx.xxx" />
</intent-filter>
</receiver>
And on the chat activity, I have something like this:
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle b = intent.getExtras();
String message = b.getString("message");
Log.i(TAG, " Received in Activity " + message + ", NAME = "
+ chattingToName + ", dev ID = " + chattingToDeviceID);
// this demo this is the same device
ChatPeople curChatObj = addToChat(chattingToName, message,
"Received");
addToDB(curChatObj); // adding to db
populateChatMessages();
}
};
I guess this part is not called since on the chat history is not updated with the received message.
Any idea guys?
Thanks in advance.
This is my GcmBroadcastReceiver
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
Bundle extras = intent.getExtras();
Intent i = new Intent("CHAT_MESSAGE_RECEIVED");
i.putExtra("message", extras.getString("message"));
context.sendBroadcast(i);
}
}
It looks that you are not handling the User Notification received from the chat app in the correct manner. Please take a look at this official Google Documentation that deals with the User Notification on GCM.
Also please take a look at this tutorial that has code for the chat application.
Hope that Helps!!
Related
Manifest.xml of receiving app.
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<receiver android:name=".DemoReceiver"
android:exported="true" android:enabled="true">
<intent-filter>
<action android:name="com.example.myparentapplication.demo"/>
</intent-filter>
</receiver>
Receiver declared in receiving app:
public class DemoReceiver extends BroadcastReceiver {
public DemoReceiver(){}
#Override
public void onReceive(Context context, Intent intent) {
Log.v(TAG, "Received");
String data = intent.getStringExtra("data");
Toast.makeText(context,"opening the intent data : " + data,Toast.LENGTH_LONG ).show();
}
}
Broadcast sent by broadcasting app:
Intent intent = new Intent("com.example.myparentapplication.demo");
intent.putExtra("data","job dispatched");
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.setComponent(new ComponentName(getApplicationContext().getPackageName(), "com.example.myparentapplication.DemoReceiver"));
sendBroadcast(intent);
This way I am using broadcast after upgrading my api to Android 'O', but I am not receiving any broadcast. where as in documentation it says that explicit broadcast are allow to register in manifest after Android Oreo. Please guide me appropriately that what is wrong here?
Note: Receiving app is a background app. so I can not register broadcast dynamically. I have tried almost all the solution from stack overflow but still it's not working.
intent.setComponent(new ComponentName(getApplicationContext().getPackageName(), "com.example.myparentapplication.DemoReceiver"));
getApplicationContext().getPackageName() will return the application ID of the sending app. Your ComponentName needs the application ID of the receiving app.
I am using android studio and i struck in implementing broadcast in my app so that it should trigger only one App and i'm using Localbroadcastmanager for registering and unregistering
Android Phone
APP1 APP2
My Modules
I have integrated MyModules with two apps installed in one Android phone.
When i send a message to APP1 from some other Android phone it receives message to APP1 But both APP1 and APP2 triggers the notification at a same time.
My BroadcastService.java
public static void sendNotificationBroadcast(Context context, Message message) {
Log.i(TAG, "Sending notification broadcast...");
Intent notificationIntent = new Intent();
notificationIntent.putExtra(MyConstants.MESSAGE_JSON_INTENT, GsonUtils.getJsonFromObject(message, Message.class));
notificationIntent.setAction("com.notification.send");
context.sendBroadcast(notificationIntent);
}
i'm setting my intent action "com.notification.send"
AndroidManifest.xml
<receiver android:name="com.notification.NotificationBroadcastReceiver" android:exported="false">
<intent-filter>
<action android:name="com.notification.send"/>
</intent-filter>
</receiver>
This is my NotificationBroadcastReceiver.java
public class NotificationBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "NotificationBroadcastReceiver";
private static String NOTIFICATION_ICON_METADATA = "com.notification.icon";
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Integer notificationIconId = Utils.getMetaDataValueForResources(context, NOTIFICATION_ICON_METADATA);
String messageJson = intent.getStringExtra(Constants.MESSAGE_JSON_INTENT);
Log.i(TAG, "Received broadcast, action: " + action + ", message: " + messageJson);
if (!TextUtils.isEmpty(messageJson)) {
final Message message = (Message) GsonUtils.getObjectFromJson(messageJson, Message.class);
final NotificationService notificationService =
new NotificationService(notificationIconId == null ? R.drawable.ic_launcher : notificationIconId, context, R.string.wearable_action_label, R.string.wearable_action_title, R.drawable.ic_action_send);
final Contact contact = new contactService(context).getContactById(message.getIds());
new Thread(new Runnable() {
#Override
public void run() {
notificationService.notifyUser(contact, message);
}
}).start();
}
}
}
both Apps are listening to same broadcast, How to solve this problem ?
Thanks in advance
i fixed this problem by using context.getPackageName() i have appended with my action
BroadcastService.java
intent.setAction(context.getPackageName()+".send");
AndroidManifest.xml
<intent-filter>
<action android:name="YOUR ANDROID APP PACKAGENAME.send"/>
</intent-filter>
It looks like you are using Google Cloud Messaging to push to the device. Make sure each app uses a different GCM sender id or channel.
If you want to limit the broadcast to originating app only set package on the intent:
intent.setPackage(BuildConfig.APPLICATION_ID);
http://developer.android.com/reference/android/content/Intent.html#setPackage(java.lang.String)
I'm using the following library to read the sms messages that have been sent from my default application. The problem that I'm having is that when the application is close the service is not working to save the message that i have send. Does anyone knows how i can start the service when a message has been sent from my device?
Library
https://github.com/tuenti/SmsRadar
UPDATE 1:
BroadcastReceiver class
public class Broadcast_Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("android.provider.Telephony.SMS_SENT")){
Intent service = new Intent(context, SMSService.class);
context.startService(service);
Log.d("Broadcast_Receiver", "message sent");
}
else if ((intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")))
{
Log.d("Broadcast_Receiver", "message received");
}
}
}
manifest
<receiver android:name=".APPServices.SMS.Broadcast_Receiver" android:enabled="true">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_SENT"/>
</intent-filter>
</receiver>
Thank you
You'll need to use a "Broadcast Reciever" for that
As the name suggests: broadcast receiver waits for an event to occur and when the event occurs , it receives that info, which was broadcast-ed by the event.
Here is a great tutorial which describes how to implement it step by step (A little long to type it here)
http://androidexample.com/Incomming_SMS_Broadcast_Receiver_-_Android_Example/index.php?view=article_discription&aid=62&aaid=87
I have created a GCM Intent service and the device is getting registered successfully and server successfully send the message. but device don't get any notifications.
Below the log i see,
10-29 18:26:09.599: V/GCMBroadcastReceiver(30775): onReceive: com.google.android.c2dm.intent.RECEIVE
10-29 18:26:09.599: V/GCMBroadcastReceiver(30775): GCM IntentService class: com.eye.hor.GCMIntentService
10-29 18:26:09.599: V/GCMBaseIntentService(30775): Acquiring wakelock
Below is the code for GCMBroadcastReceiver,
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i(context.getPackageName(), intent.getExtras().toString());
Log.d("brdR", "askd");
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(), GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
Below is the code for GCMIntentService,
public class GcmIntentService extends IntentService {
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
public GcmIntentService() {
super("GcmIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty()) { // has effect of unparcelling Bundle
/*
* Filter messages based on message type. Since it is likely that
* GCM will be extended in the future with new message types, just
* ignore any message types you're not interested in, or that you
* don't recognize.
*/
if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
// sendNotification("Send error: " + extras.toString());
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
// sendNotification("Deleted messages on server: " +
// extras.toString());
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
// This loop represents the service doing some work.
// for (int i = 0; i < 5; i++) {
// Log.d("", "Working... " + (i + 1) + "/5 # " +
// SystemClock.elapsedRealtime());
// try {
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// }
// }
Log.d("true", "Completed work # " + SystemClock.elapsedRealtime());
// Post notification of received message.
sendNotification(extras.getString("msg"), extras.getString("title"), extras.getString("id"));
Log.d("true", "Received: " + extras.toString());
}
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
// Put the message into a notification and post it.
// This is just one simple example of what you might choose to do with
// a GCM message.
private void sendNotification(String msg, String title, String id) {
mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
int notification_id = Integer.parseInt(id);
// PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new
// Intent(this, CommonUtils.class), 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.icon).setContentTitle(title)
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg)).setContentText(msg);
// mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(notification_id, mBuilder.build());
}
}
This is manifest,
<!-- GCM requires a Google account. -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Creates a custom permission so only this app can receive its messages. -->
<permission
android:name="com.eye.hor.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.eye.hor.permission.C2D_MESSAGE" />
<!-- This app has permission to register and receive data message. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- Permission to vibrate -->
<uses-permission android:name="android.permission.VIBRATE" />
Receiver Code in Manifest,
<receiver
android:name="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<!-- Receives the registration id. -->
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.eye.hor.service" />
</intent-filter>
</receiver>
<service android:name="com.eye.hor.service.GCMIntentService" />
My main package name is com.eye.hor but i placed GCMIntentService and GCMBroadcastReceiver java files in the com.eye.hor.service package. i already put log in these two classes but they not reach.
please help
Looks like you already know you have a problem with the package names :
The following looks for your service class in the wrong package :
ComponentName comp =
new ComponentName(context.getPackageName(), // this is the main package of
// your app - com.eye.hor
GcmIntentService.class.getName());
Change it to :
ComponentName comp =
new ComponentName(GcmIntentService.class.getPackage().getName(),
GcmIntentService.class.getName());
You should also change the category in your manifest to the main package :
<category android:name="com.eye.hor.service" />
to
<category android:name="com.eye.hor" />
<category android:name="com.eye.hor.service" />
This is not supposed to be the package your broadcastreceiver is in, this is the package defined in the google developers console.
I'm willing to bet in your google developers console you defined the package has com.eye.hor, in which case you would have to change this line to:
<category android:name="com.eye.hor" />
What is device on which you developed your app? On different devices there are exotic settings influence on background working, check such setting in your device ("autostart", "push notification" and other, they can called different on some devices like Xiamo, Huawei and other).
Are you sure that your push server uses correct "sender id" and "api key" parameters, which you can check in developer console?
Check that Google Play services installed correct.
I can register my android app with C2DM successfully using a <receiver> in my manifest. However, if I delete the <receiver> from the manifest and register my receiver using the method registerReceiver of the context, I receive a SERVICE_NOT_AVAILABLE error response. I have reproduced this behaviour in the emulator and in a real device.
Is dynamically registering a C2DM receiver possible?
This is the fragment of the manifest I deleted:
<receiver android:name=".service.C2DM.C2DMReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="mytestapp" />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="mytestapp" />
</intent-filter>
</receiver>
And here is the code:
public class C2DMReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String registration = intent.getStringExtra("registration_id");
if (intent.getStringExtra("error") != null) {
//TODO: Registration failed, should try again later.
Log.e("MyTestAppC2DM", "C2DM Error = " + intent.getStringExtra("error"));
} else if (intent.getStringExtra("unregistered") != null) {
Log.d("MyTestAppC2DM", "C2DM Unregistered");
} else if (registration != null) {
Log.d("MyTestAppC2DM","C2DM registration_id = " + registration);
} else {
Log.w("MyTestAppC2DM", "C2DM No registration_id");
}
}
public static void register(Context context){
/* BEGIN OF DYNAMIC REGISTER */
C2DMReceiver c2dmReceiver = new C2DMReceiver();
IntentFilter receiveIntentFilter = new IntentFilter();
receiveIntentFilter.addAction("com.google.android.c2dm.intent.RECEIVE");
receiveIntentFilter.addCategory("mytestapp");
context.registerReceiver(c2dmReceiver, receiveIntentFilter, "com.google.android.c2dm.permission.SEND", null);
IntentFilter registrationIntentFilter = new IntentFilter();
registrationIntentFilter.addAction("com.google.android.c2dm.intent.REGISTRATION");
registrationIntentFilter.addCategory("mytestapp");
context.registerReceiver(c2dmReceiver, registrationIntentFilter, "com.google.android.c2dm.permission.SEND", null);
/*END OF DYNAMIC REGISTER*/
Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
registrationIntent.putExtra("app", PendingIntent.getBroadcast(context, 0, new Intent(), 0));
registrationIntent.putExtra("sender", "mysender#gmail.com");
ComponentName service = context.startService(registrationIntent);
if(service!=null){
Log.d("MyTestAppC2DM","C2DM Registration sent");
}else{
Log.d("MyTestAppC2DM","C2DM Service not found");
}
}
}
You can register the receiver C2DMReceiver in manifest file, and dispatch the intent to real BroadcastReceiver to handle it.
When a broadcast is sent by the system it will start applications to handle the intent if they have a matching intent filter declared in the manifest. Due to the nature of C2DM it is not useful to have a Broadcast Receiver installed dynamically because your application might not be running when a C2DM message is received. If its not running it won't be started for a dynamically installed receiver.
It might make sense to receive the c2dm/gcm REGISTERED intent in a dynamically registered BroadcastReceiver in an Activity, but like the original author I've found that this isn't working (except for GCM on JB). Is there a reason for this ? I can't find this limitation in the docs anywhere.