I want to send a notification to the user when a task is assigned (i.e on a button click). When a task is assigned to the user I change some values in my server(i.e i'm performing a post method) I would like to know how to achieve this.
I have reached till registering the user when he logs in to my app & i'm storing users token id into my server I have also gone through google developers guide and have registered my app and obtained senderid and serverapikey. I will post the code till where I have reached please help me on how to proceed further.
LoginActivity
private void checkUserRegistrationToken() {
String url = URLMap.getGcmtokenUrl("gcmtoken_url");
employeeId = LoggedInUserStore.getLoggedInEmployeeId(getApplicationContext());
companyId = LoggedInUserStore.getLoggedInCompanyId(getApplicationContext());
url = url.replace("{eid}", employeeId).replace("{cid}", companyId);
final StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jObj = new JSONObject(response);
tokenId = jObj.getString("TokenId");
if (tokenId.equals("null")) {
registerInBackground();
}
} catch (JSONException e) {
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
System.out.println("Error===" + error.toString());
}
});
request.setRetryPolicy(new VolleyRetryPolicy().getRetryPolicy());
RequestQueue queue = ((VolleyRequestQueue) getApplication()).getRequestQueue();
queue.add(request);
}
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcmObj == null) {
gcmObj = GoogleCloudMessaging.getInstance(LoginActivity.this);
}
tokenId = gcmObj.register(String.valueOf(R.string.gcm_defaultSenderId));
msg = "Registration ID:" + tokenId;
if (new ServiceManager(getApplicationContext()).isNetworkAvailable() && checkPlayServices()) {
String storeUrl = URLMap.getGcmtokenPostUrl();
employeeId = LoggedInUserStore.getLoggedInEmployeeId(getApplicationContext());
companyId = LoggedInUserStore.getLoggedInCompanyId(getApplicationContext());
HashMap<String, String> map = new HashMap<String, String>();
map.put("EmployeeId", employeeId);
map.put("CompanyId", companyId);
map.put("TokenId", tokenId);
JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, storeUrl, new JSONObject(map), new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.i(TAG, "Token has been posted in server!");
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.i(TAG, "Error posting token into server!!");
}
});
request.setRetryPolicy(new VolleyRetryPolicy().getRetryPolicy());
RequestQueue queue = ((VolleyRequestQueue) getApplication()).getRequestQueue();
queue.add(request);
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Token Mesage=" + msg);
return msg;
}
#Override
protected void onPostExecute(String s) {
}
}.execute();
}
As you can see that I'm storing token id of user into my server.
Now I have also created a GcmBroadcastReceiver class
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ComponentName comp = new ComponentName(context.getPackageName(),
NotificationService.class.getName());
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
and I have also created a NotificationService class which has on MessageReceived method
public class NotificationService extends GcmListenerService {
public static final int notifyID = 9001;
public static final String appname = "FM Ninja";
NotificationCompat.Builder builder;
public NotificationService() {
// super("GcmIntentService");
}
#Override
public void onMessageReceived(String from, Bundle data) {
Intent resultIntent = null;
PendingIntent resultPendingIntent;
resultIntent = new Intent(this, HomeActivity.class);
resultPendingIntent = PendingIntent.getActivity(this, 0,
resultIntent, PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder mNotifyBuilder;
NotificationManager mNotificationManager;
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotifyBuilder = new NotificationCompat.Builder(this)
.setContentTitle("title")
.setTicker("New Message !")
.setContentText("first message please")
.setSmallIcon(R.mipmap.cms_launch_icon);
// Set pending intent
mNotifyBuilder.setContentIntent(resultPendingIntent);
// Set Vibrate, Sound and Light
int defaults = 0;
defaults = defaults | Notification.DEFAULT_LIGHTS;
defaults = defaults | Notification.DEFAULT_VIBRATE;
defaults = defaults | Notification.DEFAULT_SOUND;
mNotifyBuilder.setDefaults(defaults);
mNotifyBuilder.setAutoCancel(true);
// Post a notification
mNotificationManager.notify(notifyID, mNotifyBuilder.build());
}
}
The problem is even after adding permission in Manifeast when a call is made from server onMessageReceived is never getting executed Please help me.
I will also post manifeast file
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--GCM Permissions-->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.google.android.c2dm.permission.SEND"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<permission android:name="com.six30labs.cms.permission.C2D_MESSAGE"
android:protectionLevel="signature"/>
<uses-permission android:name="com.six30labs.cms.permission.C2D_MESSAGE" />
<application
android:name="com.six30labs.cms.general.VolleyRequestQueue"
android:allowBackup="true"
android:icon="#mipmap/cms_launch_icon"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".SplashScreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<activity android:name=".LoginActivity" />
<activity android:name=".ForgotPassword" />
<activity android:name=".NoInternet" />
<activity android:name=".HomeActivity"/>
<activity android:name=".ComplaintDetailsSupervisor" />
<activity android:name=".ComplaintDetailsEmployee" />
<activity android:name=".NavBarProfile" />
<activity android:name=".ComplaintDetailsWorker" />
<activity android:name=".AssignedDetailSupervisor" />
<activity android:name=".AcceptedComplaintDetailsWorker" />
<activity android:name=".VerifyDetailSupervisor"/>
<activity android:name=".ManagerComplaintListActivity"/>
<!--<service android:name="com.six30labs.cms.storage.RegistrationIntentService"
android:exported="false"/>-->
<receiver
android:name="com.six30labs.cms.general.GcmBroadcastReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.six30labs.cms"/>
</intent-filter>
</receiver>
<!-- Register Service -->
<service android:name="com.six30labs.cms.general.NotificationService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
</application>
Server side script
public class GCMNotification
{
private CMSEntities db = new CMSEntities();
static string gcmid = "AIzaSyB7HSIF1RIvkyCnpP6KtYiy6wQ-s6YBscY";
public void AssignEmpNotification(string employeeid)
{
long id = Convert.ToInt64(employeeid);
PushBroker pushBroker = new PushBroker();
pushBroker.RegisterGcmService(new GcmPushChannelSettings(gcmid));
pushBroker.QueueNotification(new GcmNotification().ForDeviceRegistrationId("APA91bGElkVodLyubuMM90TEnfUMab0Fs6JudsjXcgIUrTrT8Zk3GezKYWc9w2gGs6pzLLq_nPSZCXU30M5iYKdRJcKZnkafWuwhnihZQ88vcwUrKhiQn6eWSqGrLCeHFblVT09IR7jy")
.WithJson(#"{""message"":""Hi Hello" + "wsfdasd" + #""",""title"":""title" + "vendorBids" + #""",""Bidsid"":""" + "1" + #""",""Eventdate"":""" + "2/2/2016" + #""",""vendorname"":""" + "name" + #"""}"));
pushBroker.StopAllServices();
}
}
The server needs to send http post request
to "https://android.googleapis.com/gcm/send" along with list of
registration ids and message as body data.
The body data is a combination of :
a. registration ids (which is a list of array)
b. message
The header is a combination of :
a. Content-Type
b. Authorization (key:project id)
List regIds = new ArrayList();
//add regIds to this list : regIds.add("value");
JSONObject data = new JSONObject ();
data.put("registration_ids", regIds);
data.put("Message", "Hello");
ApiKey is the value we received during project created in google store.
Map headers = new HashMap();
headers.put("Content-Type", "application/json");
header.put("Authorization","key=ApiKey");
After sending http post request. The google gcm server will send
the message to all users whose registration id is mentioned in http
request.
The android mobile will receive a notification from gcm server as response
which will be handled by GCMBroadcastReceiver.
Now NotificationService class will be invoked which will extent
IntentService.
In this class ,
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty() &&
GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
showNotification(intent.getStringExtra("Message"));
}
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
This method is calling "showNotification" method which has a string
parameter.
Use this message and show in notification using NotificationManager.
Hope this helps :)
Start logging the response that the server is getting after sending the notification payload to google servers. If there is a problem with the device token, you will get a detailed error like "Not Registered".
If the there is no problem in token, google server will respond you with success and message id.
Once you are assured that there is no problem with the device token, then we can think about the issues in the device code.
Other probable issue I can think of is that the SHA hash that you have added in the google developer console is not matching with the SHA hash of the keystore that you have signed the app with.
Add the SHA hash of debug.keystore as well as the production signing keystore.
Related
I am trying to add notifications to my Android app using GCM. I started out by following this
tutorial and using this example project as a reference.
I followed all the steps and created all needed classes and services, but I am still not receiving any notifications.
I'm checking for Google Play Services and seem to register my device successfully on my server. I added the google-services.json file to my project and added all permissions and libraries to the project.
What is going wrong?
Did I forget anything? Do I still need to do something? I'm very confused at this point.
AndroidManifest
Permissions
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<permission android:name="com.manager_android.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
<uses-permission android:name="com.manager_android.permission.C2D_MESSAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Receiver and services
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
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="com.manager_android" />
<!--here-->
</intent-filter>
</receiver>
<service
android:name=".Activities.GcmIntentService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service
android:name=".Activities.TokenRefreshListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID"/>
</intent-filter>
</service>
<service android:name=".Activities.RegistrationService"
android:exported="false">
</service>
Added to app build.gradle
compile 'com.google.android.gms:play-services-gcm:11.0.4'
apply plugin: 'com.google.gms.google-services'
Added to project build.gradle
classpath 'com.google.gms:google-services:3.1.0'
RegistrationService
public class RegistrationService extends IntentService {
public RegistrationService() {
super("");
}
private final String TAG = "RegistrationInfo";
#Override
protected void onHandleIntent(#Nullable Intent intent) {
registerDevice();
}
private void registerDevice() {
InstanceID myID = InstanceID.getInstance(getApplicationContext());
String registratonToken = "";
try {
registratonToken = myID.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
log.d("Registration Token", registratonToken);
Map<String, String> params = new HashMap<>();
params.put("user_id", registratonToken);
params.put("platform", "GCM");
SaveSharedPreference.setToken(getApplicationContext(), registratonToken);
//Register token on server
Communication.post(getString(R.string.register_device_url), new RequestParams(params), new AsyncHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
Log.i(TAG, "Registration was successful");
}
#Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
Log.i(TAG, "Registration failed.");
}
});
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "Couldn't register device", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
TokenRefreshListenerService
public class TokenRefreshListenerService extends InstanceIDListenerService {
#Override
public void onTokenRefresh() {
Intent i = new Intent(this, RegistrationService.class);
startService(i);
}
}
GCMIntentService
public class GcmIntentService extends GcmListenerService {
private int testId = 1234;
#Override
public void onMessageReceived(String from, Bundle data) {
String message = data.getString("message");
sendNotification(message);
}
private void sendNotification(String message) {
Intent intent = new Intent(this, MainScreenActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), testId, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.logo)
.setContentTitle("GCM Message")
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)
.setWhen(System.currentTimeMillis());
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(testId, notificationBuilder.build());
}
}
I start the RegistrationService as a service when the user logs in to register the device.
This documentation can help you understand about notifications.
A notification is a message you display to the user outside of your
app's normal UI. When you tell the system to issue a notification, it
first appears as an icon in the notification area. To see the details
of the notification, the user opens the notification drawer. Both the
notification area and the notification drawer are system-controlled
areas that the user can view at any time.
It also provides sample codes on every topic that you will tackle.
For GCM, you can refer to this documentation.
Google Cloud Messaging (GCM) is a free service that enables developers
to send messages between servers and client apps. This includes
downstream messages from servers to client apps, and upstream messages
from client apps to servers.
It will help you understand about the concept of GCM. Also it provides sample to start with.
I have trouble in getting refreshed token in firebase. I have gone through documentation and followed the steps fro android exactly. In my log I find firebase connection as successful. Not sure why I am not getting the instance token. I am in initial stage and trying to get the token in logcat.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.project.application"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<application
android:allowBackup="false"
android:icon="#drawable/icon"
android:label="#string/app_name" >
<activity
android:name=".ProjectName"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:icon="#drawable/icon"
android:label="#string/app_name"
android:theme="#android:style/Theme.Light.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
</activity>
<service
android:name=".MyInstanceIDListenerService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service
android:name=".MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
</application>
</manifest>
public class MyInstanceIDListenerService extends FirebaseInstanceIdService{
private static final String TAG = "MyFirebaseIIDService";
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
sendRegistrationToServer(refreshedToken);
}
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// TODO(developer): Handle FCM messages here.
Log.d(TAG, "From: " + remoteMessage.getFrom());
String messageBody = null;
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
}
if (remoteMessage.getNotification() != null) {
messageBody = remoteMessage.getNotification().getBody();
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
}
sendNotification(messageBody);
}
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, SplashActivity.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_stat_ic_notification)
.setContentTitle("FCM Message")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
The onTokenRefresh() method doesn't trigger the first time an app Is installed. It is only triggered by specific scenarios.
To get your token, you have to call FirebaseInstanceId.getInstance().getToken() at the start of your app (like in onCreate or something).
From the github project of FCM here
The documentation onTokenRefresh() reads :
Called if InstanceID token is updated. This may occur if the security of the previous token had been compromised. Note that this is called when the InstanceID token is initially generated so this is where you would retrieve the token.
You have to Clear Cache of you app or reinstall it in order to call this method.
fix your permission
<permission android:name="${applicationId}.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
Make sure you have correct google-service.json.
Note: token only generate once. try to clean app data to get new token
EDIT:
Or you can do iteration to get token manually in your Activity/Fragment class
FirebaseInstanceId iid = FirebaseInstanceId.getInstance();
String token = iid.getToken();
while(token == null){
iid = FirebaseInstanceId.getInstance();
token = iid.getToken();
}
Logger.info("TOKEN","==>"+token);
The onNewToken callback fires whenever a new token is generated.
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the InstanceID token
* is initially generated so this is where you would retrieve the token.
*/
#Override
public void onNewToken(String token) {
Log.d(TAG, "Refreshed token: " + token);
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// Instance ID token to your app server.
sendRegistrationToServer(token);
}
To get your token, you have to call call FirebaseInstanceId.getInstance().getInstanceId()
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(#NonNull Task<InstanceIdResult> task) {
if (!task.isSuccessful()) {
Log.w(TAG, "getInstanceId failed", task.getException());
return;
}
// Get new Instance ID token
String token = task.getResult().getToken();
// Log and toast
String msg = getString(R.string.msg_token_fmt, token);
Log.d(TAG, msg);
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
});
Try deleting the google-services.json file and re-adding it.
I'm new to android. In my app, I didn't receive notification when the app is closed. If it is running it received. I tried all the way but still I didn't get the solution. Please find what I make wrong
Here my code:
Manifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.google.android.c2dm.permission.REGISTER" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<permission android:name="com.h2o.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.h2o.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver
android:name="com.h2o.ExternalReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<action android:name="com.google.android.c2dm.intent.REGISTER" />
<category android:name="com.google.android.gcm.demo.app" />
</intent-filter>
</receiver>
<service
android:name="com.h2o.MessageReceivingService"
android:label="com.h2o.MessageReceivingService" >
<intent-filter>
<action android:name="com.h2o.ExternalReceiver" />
<category android:name="com.h2o"/>
</intent-filter>
</service>
Receiver:
public class ExternalReceiver extends WakefulBroadcastReceiver {
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),MessageReceivingService.class.getName());
startWakefulService(context,(intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
Service:
public class MessageReceivingService extends Service{
private GoogleCloudMessaging gcm;
public static SharedPreferences savedValues;
public static void sendToApp(Bundle extras, Context context){
Intent newIntent = new Intent();
newIntent.setClass(context, AndroidMobilePushApp.class);
newIntent.putExtras(extras);
newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(newIntent);
}
public void onCreate(){
super.onCreate();
final String preferences = getString(R.string.preferences);
savedValues = getSharedPreferences(preferences, Context.MODE_PRIVATE);
gcm = GoogleCloudMessaging.getInstance(getBaseContext());
SharedPreferences savedValues = PreferenceManager.getDefaultSharedPreferences(this);
if(savedValues.getBoolean(getString(R.string.first_launch), true)){
register();
SharedPreferences.Editor editor = savedValues.edit();
editor.putBoolean(getString(R.string.first_launch), false);
editor.commit();
}
if(savedValuess.getBoolean(getString(R.string.first_launch), true)){
// Let AndroidMobilePushApp know we have just initialized and there may be stored messages
sendToApp(new Bundle(), this);
}
}
protected static void saveToLog(Bundle extras, Context context){
SharedPreferences.Editor editor=savedValues.edit();
String numOfMissedMessages = context.getString(R.string.num_of_missed_messages);
int linesOfMessageCount = 0;
for(String key : extras.keySet()){
String line = String.format("%s=%s", key, extras.getString(key));
editor.putString("MessageLine" + linesOfMessageCount, line);
linesOfMessageCount++;
}
editor.putInt(context.getString(R.string.lines_of_message_count), linesOfMessageCount);
editor.putInt(context.getString(R.string.lines_of_message_count), linesOfMessageCount);
editor.putInt(numOfMissedMessages, savedValues.getInt(numOfMissedMessages, 0) + 1);
editor.commit();
postNotification(new Intent(context, AndroidMobilePushApp.class), context);
}
protected static void postNotification(Intent intentAction, Context context){
final NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intentAction, Notification.DEFAULT_LIGHTS | Notification.FLAG_AUTO_CANCEL);
final Notification notification = new NotificationCompat.Builder(context).setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Message Received!")
.setContentText("")
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.getNotification();
mNotificationManager.notify(R.string.notification_number, notification);
}
private void register() {
new AsyncTask(){
protected Object doInBackground(final Object... params) {
String token;
try {
token = gcm.register(getString(R.string.project_number));
Log.i("registrationId", token);
}
catch (IOException e) {
Log.i("Registration Error", e.getMessage());
}
return true;
}
}.execute(null, null, null);
}
public IBinder onBind(Intent arg0) {
return null;
}
}
Thanks in advance!
To be able to receive notifications when your application is closed, you have to register a service listener with the following permission
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
See the documentation for more details
https://developer.android.com/reference/android/service/notification/NotificationListenerService.html
you need to define your broadcast receiver in manifest like this:
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.google.android.gcm.demo.app" />
</intent-filter>
and in the broadcast receiver class add the following codes:
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);
}}
there is some problem with wakeful broadcast receiver, read this
Confusion about WakefulBroadcastReceiver
For best practice it is recommended that you should use Firebase cloud messaging (FCM) instead of GCM.
I followed the documentation of google to implement push notifications.
When the app is open works fine, but when I close the app does not receive notifications.
Here is the code:
Manifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="it.bsdsoftware.cnabologna.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<permission
android:name="it.bsdsoftware.cnabologna.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version"/>
<application>
...
<service android:name=".notifiche.RegistrationIntentService"
android:exported="false" >
</service>
<service android:name=".notifiche.MyGcmListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service android:name=".notifiche.MyInstanceIDListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<receiver android:name=".notifiche.GcmBroadcastReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.GCM_RECEIVED_ACTION"/>
<category android:name="it.bsdsoftware.cnabologna" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
</intent-filter>
</receiver>
</application>
RegistrationIntentService.java
public class RegistrationIntentService extends IntentService {
private static final String TAG = "RegIntentService";
public RegistrationIntentService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
try {
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.notifiche_push_sender_id), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
Log.i(TAG, "GCM Registration Token: " + token);
sendRegistrationToServer(token);
} catch (Exception e) {
Log.d(TAG, "Failed to complete token refresh", e);
}
}
private void sendRegistrationToServer(String token) {
OperazioneInvioToken op = new OperazioneInvioToken(token);
WebServiceTask ws = new WebServiceTask(op, this, false);
ws.execute();
}
}
MyGcmListenerService.java
public class MyGcmListenerService extends GcmListenerService {
private static final String TAG = "MyGcmListenerService";
#Override
public void onMessageReceived(String from, Bundle data) {
Bundle notification = data.getBundle("notification");
String title = "";
String message = "";
if(notification!=null){
title = notification.getString("title");
message = notification.getString("body");
}
NotificationUtility.showNotification(title, message);
NotificationUtility.setBadge(1);
}
}
MyInstanceIDListenerService.java
public class MyInstanceIDListenerService extends InstanceIDListenerService {
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. This call is initiated by the
* InstanceID provider.
*/
#Override
public void onTokenRefresh() {
// Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
}
GcmBroadcastReceiver.java
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(), MyGcmListenerService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
When the app is open onMessageReceived of GcmListenerService class is called but when the app is closed is not called.
What did I do wrong?
Thanks
I resolved by updating the play service from com.google.android.gms:play-services:8.3.0 to com.google.android.gms:play-services:8.4.0
I've used the quickblox chat sample and it worked fine, But I wanted to use push notifications in it.. So I followed some tutorials and read the sample and just done like it.. But when I push notification from QuickBlox Admin Panel: Messages no thing happens in my application.. No Logs, No Notifications.. No Thing..!
I'm sure that the project number and api key are correct..
Here's the manifest :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.quickblox.sample.chat"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="19" />
<permission
android:name="com.quickblox.sample.chat.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.quickblox.sample.chat.permission.C2D_MESSAGE" />
<!-- 5. Add the following permissions: -->
<!-- App receives GCM messages. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- GCM connects to Google Services. -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 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" />
<!-- Access to device info -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".ApplicationSingleton"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".ui.activities.SplashActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="#string/app_name"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.activities.NewDialogActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="portrait" />
<activity
android:name="com.quickblox.sample.chat.DialogsActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="portrait" />
<activity
android:name=".ui.activities.ChatActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" />
<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="com.quickblox.sample.chat" />
</intent-filter>
</receiver>
<!-- 2. Add the following intent service: -->
<service android:name=".GCMIntentService" />
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
</application>
</manifest>
GcmBroadcastReceiver :
package com.quickblox.sample.chat;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.WakefulBroadcastReceiver;
import android.util.Log;
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.
Log.d("Login", "Receiver - Received Message!");
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
GCMIntentService :
package com.quickblox.sample.chat;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.WakefulBroadcastReceiver;
import android.util.Log;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import com.quickblox.sample.chat.definitions.Consts;
public class GCMIntentService extends IntentService {
public static final int NOTIFICATION_ID = 1;
private static final String TAG = GCMIntentService.class.getSimpleName();
private NotificationManager notificationManager;
public GCMIntentService() {
super(Consts.GCM_INTENT_SERVICE);
}
#Override
protected void onHandleIntent(Intent intent) {
Log.i(TAG, "new push");
Bundle extras = intent.getExtras();
GoogleCloudMessaging googleCloudMessaging = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = googleCloudMessaging.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)) {
processNotification(Consts.GCM_SEND_ERROR, extras);
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_DELETED.equals(messageType)) {
processNotification(Consts.GCM_DELETED_MESSAGE, extras);
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_MESSAGE.equals(messageType)) {
// Post notification of received message.
processNotification(Consts.GCM_RECEIVED, extras);
Log.i(TAG, "Received: " + extras.toString());
}
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
WakefulBroadcastReceiver.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 processNotification(String type, Bundle extras) {
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
final String messageValue = extras.getString("message");
Intent intent = new Intent(this, DialogsActivity.class);
intent.putExtra(Consts.EXTRA_MESSAGE, messageValue);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
intent, 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(Consts.GCM_NOTIFICATION)
.setStyle(
new NotificationCompat.BigTextStyle()
.bigText(messageValue))
.setContentText(messageValue);
mBuilder.setContentIntent(contentIntent);
notificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
}
I have the following code for registration in activity :
gcm = GoogleCloudMessaging.getInstance(this);
regId = getRegisterationId(this);
Log.d("Login", "ID: " + regId);
if (regId.isEmpty()) {
new Thread(new Runnable() {
#Override
public void run() {
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(DialogsActivity.this);
}
regId = gcm.register(Consts.PROJECT_NUMBER);
Log.d("Login", "Registered! ID: " + regId);
runOnUiThread(new Runnable() {
#Override
public void run() {
subscribeToPushNotifications(regId);
}
});
} catch (Exception e) {
Log.d("Login", "Reg e: " + e);
}
}
}).start();
} else {
Log.d("Login", "Already Exist");
subscribeToPushNotifications(regId);
} gcm = GoogleCloudMessaging.getInstance(this);
regId = getRegisterationId(this);
Log.d("Login", "ID: " + regId);
if (regId.isEmpty()) {
new Thread(new Runnable() {
#Override
public void run() {
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(DialogsActivity.this);
}
regId = gcm.register(Consts.PROJECT_NUMBER);
Log.d("Login", "Registered! ID: " + regId);
runOnUiThread(new Runnable() {
#Override
public void run() {
subscribeToPushNotifications(regId);
}
});
} catch (Exception e) {
Log.d("Login", "Reg e: " + e);
}
}
}).start();
} else {
Log.d("Login", "Already Exist");
subscribeToPushNotifications(regId);
}
public void subscribeToPushNotifications(String regId) {
String deviceId = ((TelephonyManager) getBaseContext()
.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
QBMessages.subscribeToPushNotificationsTask(regId, deviceId,
QBEnvironment.DEVELOPMENT,
new QBEntityCallbackImpl<ArrayList<QBSubscription>>() {
#Override
public void onSuccess(ArrayList<QBSubscription> result,
Bundle params) {
Log.d("Login", "Successfully Registered");
}
#Override
public void onError(List<String> errors) {
Log.d("Login", "e : " + errors);
}
});
}
private String getRegisterationId(Context context) {
SharedPreferences prefs = getGCMPreferences(context);
String registerationId = prefs.getString(PROPERTY_REG_ID, "");
if (registerationId.isEmpty()) {
Log.d("Login", "Not registered!");
return "";
}
return registerationId;
}
private SharedPreferences getGCMPreferences(Context context) {
return getSharedPreferences(DialogsActivity.class.getSimpleName(),
Context.MODE_PRIVATE);
}
private void storeRegisterationId(Context context, String regId) {
final SharedPreferences prefs = getGCMPreferences(context);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(PROPERTY_REG_ID, regId);
editor.commit();
}
And I get that registration done successfully.. :S
I've been searching for the solution for 2 days now :/ Any help will be appreciated.. Thanks.
I don't have enough reputation to comment, so I am putting this as a possible answer -
I have been working through the same for the last couple of days, and here are a couple of things to check:
When you set up the GCM API key, did you set any IPs? You should leave this blank to accept all.
When you say the registration is done successfully, do you mean you get the onSuccess Log message from subscribeToPushNotificationsTask? Check your device id; I was getting null for deviceId from:
String deviceId = ((TelephonyManager)getBaseContext().getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
So instead I had to use
String deviceId = Secure.getString(this.getContentResolver(), Secure.ANDROID_ID);
What options were you selecting in the Quickblox Admin Panel > Messages? Be sure you are selecting "GCM (Android Push)" under the channel option.
Lastly, make sure you are using all production or all development for your environments (QBEnvironment.DEVELOPMENT). I somehow ended up with a mix, and switched them all to production now.
My push notifications are now working, so perhaps I can help out more if you have specific questions.