I know these methods are deprecated, but since the new GCM API seems to be buggy, I am reverting to these methods until a stable version is pushed by Google.
We are declaring this receiver inside the 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.myApp" />
</intent-filter>
</receiver>
<service android:name=".GCMIntentService" />
And we have the onMessage() method inside the GCMIntentService class.
#Override
protected void onMessage(Context context, Intent intent)
{
Log.i(TAG, "Received message");
String message = intent.getExtras().getString("msg");
}
1. However, upon receiving a message this method is never called. Why
?
Moreover, the example I follow uses the following.
registerReceiver(mHandleMessageReceiver, new IntentFilter("intent_filter_string"));
associated with the following class.
private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
String newMessage = intent.getExtras().getString("data");
}
};
which gets unregistered inside the onPause.
Why do we need to create this Broadcast Receiver?
Can't we do this in the manifest ?
Isn't this already covered by the onMessage() inside the GCMIntentService class ?
What role does the Pending Intent String play ?
Answers are appreciated.
Why do we need to create this Broadcast Receiver?
In some cases you might be interested in updating the UI if the app is running.
So you create a broadcast receiver at runtime and unregister it when the app
goes into background.
Can't we do this in the manifest?
Yes, you can do it in manifest too.
Isn't this already covered by the onMessage() inside the GCMIntentService class?
GCMIntentService extends GCMBaseIntentService. So any message coming from gcm,
will first be recieved in the onMessage of the GCMIntentService.
Its upto you to decide how you handle the message.
You can create a notification or send a broadcast to your custom broadcast
receivers and update the UI when the app is running.
What role does the Pending Intent play ?
According to the docs
A PendingIntent itself is simply a reference to a token maintained by the system
describing the original data used to retrieve it. This means that, even if its
owning application's process is killed, the PendingIntent itself will remain
usable from other processes that have been given it.
Did you registered your app/device combination to your GCm project? You have to do that first in the onRegistered Method. And did you add all necessary permissions? Google says you dont have to add the Custom Permissions above android 4.0 but my apps never worked without'em.
If you're looking for an easier way to work with GCM I recommend apiOmat: http://www.apiomat.com I know its Backend as a Service. But if your app is small you don't have to pay anything and it's much easier with it.
Related
I tried to wrap my head around Android BroadcastReceiver but with no success. I'm trying to implement something simple:
Listen to an incoming SMS
Check if the number is saved
If it is saved do something
So far I registered / created the BroadcastReceiver and I'm able to catch the incoming messages. I did this in the following way:
public class SmsReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){
//do things
}
}
}
I registered the receiver in the Manifest file in the following way:
<receiver
android:name=".SmsReceiver"
android:permission="android.permission.BROADCAST_SMS"
android:exported="true">
<intent-filter android:priority="2147483647" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Everything fine until now.
But, and here is the big BUT: I also created a class called 'UserManager' with a few basic tasks, for example: adding a new user, deleting a user, checking if the user exists, etc.
I store the users in a HashMap (phoneNumber, Name).
My questions are:
How can I pass an Object to my BroadcastReceiver? ( I want to be able to access the HashMap from the "UserManager" class)
I found a lot of topics regarding BroadcastReceivers. Some of them said that there are a couple ways of declaring a broadcast receiver. For example you could do it the way I did ( declaring it in Manifest), or you could do something more uhm... context based? Like declaring it BroadcastReceiver br = new MyBroadcastReceiver() and registering intentFilters to it. What is the difference? Which one should I use?
Is there something called "good practice"? What should I pay attention to? Do you know any material which explains clearly the different ways of using a broadcastReceiver?
You can use dependency injection. Or just hold reference to a class in you Application, that can be accessed by getApplicationContext
Difference is - for receivers declared in manifest you can receiver messages even if you app is in destroyed state. If you broadcast receiver is created manually, well, you must create it before message will be delivered. Also Android forces some restriction on receivers declared in manifest.
I have followed the Android GCM Client tutorial from Implementing GCM Client and the code from here. Also I am using the new process with the help of GoogleCloudMessaging.register(PROJECT_ID) to register devices.
The notifications seem to work fine and the ids stored on the server are also consistent.
The problem arises when the app is idle for a long time. The app stops getting any notifications, until it is opened again, after which it starts getting new notifications again (the previous ones are lost though).
Is this a common thing, or am I the only one facing the problem?
Here's some code for better insight:
the manifest file:
<receiver
android:name="GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="myPackage" />
</intent-filter>
</receiver>
<service android:name="GcmIntentServiceNew" />
GcmBroadcastReceiver.java
#Override
public void onReceive(Context context, Intent intent) {
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentServiceNew.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
And finally the GcmIntentServiceNew.java
public class GcmIntentServiceNew extends IntentService {
#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
if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
//
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
//
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
// Custom code here
}
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
}
Edit (No Solution yet)
I tested this a lot and can confirm now that the notifications stop after some time. I've been testing 10-15 notifications after an interval for 5-10 mins, could this be the reason of the notifications stopping?
The only solution that I see is going back to GCMRegistrar which is not ideal or reliable either.
The problem was with a library called Localytics, which was also handling Push notifications. Nothing related to GCM setup.
The app may be ended by the system if idle too long, but the example registers a GcmBroadcastReceiver that is started/invoked by the system whenever a GCM message arrives. That receiver in turn starts a Service which will then create the notification.
This pattern also works if the app is not running - actually, the system launches the app, resp. the broadcast receiver as part of the app, if necessary. If that is not the case with your app, you did something wrong.
Check your manifest file to see if the broadcast receiver and the service are specified correctly.
EDIT : Telling by your manifest file, I think you didn't provide the correct names for the broadcast receiver and the service. You have to provide either the fully qualified class name here (e.g com.example.GcmBroadcastReceiver) or you can leave the package name part of your app out but then you'd have at least to provide .GcmBroadcastReceiver (mind the leading dot!).
I'm working on an app where it has it's own DB and will be syncing with the backend via GCM, I'm thinking of using background service but I'm not sure if this is the right way to think about it, so, I would really appreciate if you can tell me the below is correct or not, if not can you please state what I need to do in steps or how should think about it? no code is required.
When the app has no running/active activity, assume that GCM has a payload and no need to contact the backend,
1. Backend had new data and sent it with GCM
2. Background service received it and updated the DB
When the app is currently running
1. Backend had new data and sent it with GCM
2. Background service received it and updated the DB and notifydatasetchanged
3. Data on activity will be changed as the source has changed(e.g listview update it's items)
In general your idea is ok. But you don't need to have always running background Service. Just create WakefulBroadcastReceiver and add it into your Manifest:
<receiver
android:name=".receivers.GCMReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.your.package" />
</intent-filter>
</receiver>
Receiver could look like this:
public class GCMReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ComponentName comp = new ComponentName(context.getPackageName(), GCMService.class.getName());
startWakefulService(context, (intent.setComponent(comp)));
}
}
This receiver launches your Service(GCMService).
I am trying to register a BroadcastReceiver programmatically to receive android.intent.action.MEDIA_MOUNTED. However, the onReceive() method never gets triggered. The same BroadcastReceiver class I created works fine if I register is statically in the app's manifest file.
Why is this the case? Is there a way to troubleshoot this? I need to register dynamically because my BroadcastReceiver class contains members that I want a service to query later on. If I catch this Intent statically then I have no easy way of querying these members because I believe the instance of BroadcastReceiver gets deleted as soon as onReceive() finishes. Is this correct? I am pretty sure this is the case considering the Android documentation has the following to say about this:
If this BroadcastReceiver was launched through a tag, then the object is no longer alive after returning from this function.
UPDATE 1:
Here is my dynamic registration code:
if (externalStorageListener == null)
{
Log.d(TAG, "creating externalStorageListener...");
IntentFilter filterExternalStorage = new IntentFilter();
filterExternalStorage.addAction(Intent.ACTION_MEDIA_MOUNTED);
filterExternalStorage.addDataScheme("file");
filterExternalStorage.setPriority(Integer.MAX_VALUE);
externalStorageListener = new ExternalStorageBroadcastReceiver();
registerReceiver(externalStorageListener, filterExternalStorage);
}
Here is the intent filter in my manifest that actually works:
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<data android:scheme="file"/>
</intent-filter>
Occasionally, to receive android.intent.action.MEDIA_MOUNTED with dynamically created BroadcastReceiver one is to have android.permission.MOUNT_UNMOUNT_FILESYSTEMS defined in manifest:
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
android.intent.action.MEDIA_MOUNTED action can be handled by privileged system application only. That action can not be received by 3rd party applications
May be when you create receiver dynamically your intent filter is different compared to when it is created through the <receiver/> tag? Could you show us both your manifest part and the code part?
Also, instead of storing data in receiver's fields, you could consider other options:
A content provider
Shared preferences
A singleton object
In that case there will be no difference between statically and dynamically created receivers.
EDIT: Based on the provided code, the problem is probably in priority setting:
Applications must use a value that is larger than SYSTEM_LOW_PRIORITY and smaller than SYSTEM_HIGH_PRIORITY .
SYSTEM_HIGH_PRIORITY = 1000
I have a background service which has a receiver for connectivity change which only seems to be received if the activity is active.
#Override
public void onCreate() {
mContext = this;
IntentFilter connectivityChangeFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
registerReceiver(receiver, connectivityChangeFilter);
I've set it up in the manifest as follows:
<service
android:name="com.myservice.TimeService"
android:label="com.myservice.TimeService" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</service>
I have another receiver for boot completed which works ok, which is registered as a receiver in the manifest (unlike this one).
Is the intent filter not enough to run a broadcast? I would want the receiver to call a method on the service so it needs to be able to access methods of the service but I don't think receivers can bind to services.
-- Update
In a nutshell, I want to know if I can statically declare a receiver that interacts with a service. Dynamic declaration works only if the app is active.
Use android sticky intent
A normal broadcast Intent is not available anymore after is was send and processed by the system. If you use the sendStickyBroadcast(Intent) method, the Intent is sticky, meaning the Intent you are sending stays around after the broadcast is complete.
example code here: