4. ● Firebase is the future
○ Acquired by Google in 2014
○ Has become Google’s mobile developer toolset
● Which should you use?
○ Existing GCM projects will still work
○ New projects must be created using Firebase
● What’s different?
○ Easier integration
○ All new features will be FCM only!
Google or Firebase Cloud Messaging?
13. ● NotificationCompat.Builder
○ Provides setters for each component of the notification
○ Can use anything exposed by it safely regardless of OS version
● NotificationManagerCompat
○ Posts built notifications using
notify(int id, Notification notification)
What to build and post with?
33. ● A group consists of:
○ A set of one or more individual notifications
○ A single summary notification
■ Made by calling setGroupSummary(true)
● Groups are keyed by unique strings that you choose
● Android will NOT group your notifications until:
○ A second notification is posted to a specific group
○ A summary notification is posted
● You cannot post a summary in the same notify() call as a
notification!
Grouping Notifications
35. Pre-N Devices See The Most
Recently Posted Summary Only!
Wear + N and up Devices See These
as a Group
Grouping Notification Example
id=1000
groupKey=”MyGroup”
isGroupSummary=false
text=”My first message”
id=1001
groupKey=”MyGroup”
isGroupSummary=false
text=”My second message”
id=1999
groupKey=”MyGroup”
isGroupSummary=true
text=”2 new messages”
id=1999
groupKey=”MyGroup”
isGroupSummary=true
text=”My first message”
37. ● Build using stored notifications you’ve seen before
○ SharedPref/DB recommended as mentioned earlier
● Order can matter!
○ For best results, post the summary first, then the individual
notification
● Summaries don’t require sound, but set it anyways
○ Wear devices use the summary sound/vibrate data in some cases
Group Summaries Continued
38. ● setAutoCancel(true) is almost always the right thing to do!
● Don’t forget to handle the user entering from the launcher icon or
recent app list!
Clearing Notifications
39. ● NotificationManager’s clear(id) can do two things:
○ Clear an individual notification by id
Clearing Notifications
id=1000
groupKey=”MyGroup”
isGroupSummary=false
text=”My first message”
id=1001
groupKey=”MyGroup”
isGroupSummary=false
text=”My second message”
id=1999
groupKey=”MyGroup”
isGroupSummary=true
text=”2 new messages”
clear(1000)
clear(1001)
○ Clear an entire group by using the group summary’s notification id
40. ● NotificationManager’s clear(id) can do two things:
○ Clear an individual notification by id
Clearing Notifications
id=1000
groupKey=”MyGroup”
isGroupSummary=false
text=”My first message”
id=1001
groupKey=”MyGroup”
isGroupSummary=false
text=”My second message”
id=1999
groupKey=”MyGroup”
isGroupSummary=true
text=”2 new messages”
clear(1999)
○ Clear an entire group by using the group summary’s notification id
41. ● If you want to nuke the site from orbit...
○ clearAll()
Clearing Notifications
43. // Remote input instance to fetch data from the user
RemoteInput remoteInput =
new RemoteInput.Builder(KEY_REPLY_TEXT)
.setLabel(replyLabelString)
.setChoices(/* string array */)
.build();
// Create the reply action and add the remote input
builder.addAction(
new NotificationCompat.Action.Builder(
replyDrawable, replyLabelString, pendingIntent)
.addRemoteInput(remoteInput)
.build());
------- Where you handle the pending intent ---------
RemoteInput.getResultsFromIntent(intent)
.getCharSequence(KEY_REPLY_TEXT);
Reply Action
44. // Remote input instance to fetch data from the user
RemoteInput remoteInput =
new RemoteInput.Builder(KEY_REPLY_TEXT)
.setLabel(replyLabelString)
.setChoices(/* string array */)
.build();
// Create the reply action and add the remote input
builder.addAction(
new NotificationCompat.Action.Builder(
replyDrawable, replyLabelString, pendingIntent)
.addRemoteInput(remoteInput)
.build());
------- Where you handle the pending intent ---------
RemoteInput.getResultsFromIntent(intent)
.getCharSequence(KEY_REPLY_TEXT);
Reply Action
45. // Remote input instance to fetch data from the user
RemoteInput remoteInput =
new RemoteInput.Builder(KEY_REPLY_TEXT)
.setLabel(replyLabelString)
.setChoices(/* string array */)
.build();
// Create the reply action and add the remote input
builder.addAction(
new NotificationCompat.Action.Builder(
replyDrawable, replyLabelString, pendingIntent)
.addRemoteInput(remoteInput)
.build());
------- Where you handle the pending intent ---------
RemoteInput.getResultsFromIntent(intent)
.getCharSequence(KEY_REPLY_TEXT);
Reply Action
46. // Remote input instance to fetch data from the user
RemoteInput remoteInput =
new RemoteInput.Builder(KEY_REPLY_TEXT)
.setLabel(replyLabelString)
.setChoices(/* string array */)
.build();
// Create the reply action and add the remote input
builder.addAction(
new NotificationCompat.Action.Builder(
replyDrawable, replyLabelString, pendingIntent)
.addRemoteInput(remoteInput)
.build());
------- Where you handle the pending intent ---------
RemoteInput.getResultsFromIntent(intent)
.getCharSequence(KEY_REPLY_TEXT);
Reply Action
47. // Remote input instance to fetch data from the user
RemoteInput remoteInput =
new RemoteInput.Builder(KEY_REPLY_TEXT)
.setLabel(replyLabelString)
.setChoices(/* string array */)
.build();
// Create the reply action and add the remote input
builder.addAction(
new NotificationCompat.Action.Builder(
replyDrawable, replyLabelString, pendingIntent)
.addRemoteInput(remoteInput)
.build());
------- Where you handle the pending intent ---------
RemoteInput.getResultsFromIntent(intent)
.getCharSequence(KEY_REPLY_TEXT);
Reply Action
48. // Remote input instance to fetch data from the user
RemoteInput remoteInput =
new RemoteInput.Builder(KEY_REPLY_TEXT)
.setLabel(replyLabelString)
.setChoices(/* string array */)
.build();
// Create the reply action and add the remote input
builder.addAction(
new NotificationCompat.Action.Builder(
replyDrawable, replyLabelString, pendingIntent)
.addRemoteInput(remoteInput)
.build());
------- Where you handle the pending intent ---------
RemoteInput.getResultsFromIntent(intent)
.getCharSequence(KEY_REPLY_TEXT);
Reply Action
49. // Remote input instance to fetch data from the user
RemoteInput remoteInput =
new RemoteInput.Builder(KEY_REPLY_TEXT)
.setLabel(replyLabelString)
.setChoices(/* string array */)
.build();
// Create the reply action and add the remote input
builder.addAction(
new NotificationCompat.Action.Builder(
replyDrawable, replyLabelString, pendingIntent)
.addRemoteInput(remoteInput)
.build());
------- Where you handle the pending intent ---------
RemoteInput.getResultsFromIntent(intent)
.getCharSequence(KEY_REPLY_TEXT);
Reply Action
50. // Remote input instance to fetch data from the user
RemoteInput remoteInput =
new RemoteInput.Builder(KEY_REPLY_TEXT)
.setLabel(replyLabelString)
.setChoices(/* string array */)
.build();
// Create the reply action and add the remote input
builder.addAction(
new NotificationCompat.Action.Builder(
replyDrawable, replyLabelString, pendingIntent)
.addRemoteInput(remoteInput)
.build());
------- Where you handle the pending intent ---------
RemoteInput.getResultsFromIntent(intent)
.getCharSequence(KEY_REPLY_TEXT);
Reply Action
51. // Remote input instance to fetch data from the user
RemoteInput remoteInput =
new RemoteInput.Builder(KEY_REPLY_TEXT)
.setLabel(replyLabelString)
.setChoices(/* string array */)
.build();
// Create the reply action and add the remote input
builder.addAction(
new NotificationCompat.Action.Builder(
replyDrawable, replyLabelString, pendingIntent)
.addRemoteInput(remoteInput)
.build());
------- Where you handle the pending intent ---------
RemoteInput.getResultsFromIntent(intent)
.getCharSequence(KEY_REPLY_TEXT);
Reply Action
52. // Remote input instance to fetch data from the user
RemoteInput remoteInput =
new RemoteInput.Builder(KEY_REPLY_TEXT)
.setLabel(replyLabelString)
.setChoices(/* string array */)
.build();
// Create the reply action and add the remote input
builder.addAction(
new NotificationCompat.Action.Builder(
replyDrawable, replyLabelString, pendingIntent)
.addRemoteInput(remoteInput)
.build());
------- Where you handle the pending intent ---------
RemoteInput.getResultsFromIntent(intent)
.getCharSequence(KEY_REPLY_TEXT);
Reply Action
54. Tracking Pushes
● Each push your server sends is assigned a message id from Google
"message_id":"0:1479505763653918%3a63b8c3f9fd7ecd"
● Information to record
○ FCM message id
○ Internal unique id from your backend for this particular push
● Record this information on server and device side to determine if
○ Push was sent and received
○ Push was sent but not received
○ Push was sent and received more than once (Google error)
○ Push was sent twice and received twice (Local push server error)
55. Build a Silent Test Push System
● Come up with a data payload that indicates this is a test push
data {
isTest: true
id: <server generated id>
}
● Have client ack this push via an API to your backend
● Allows easy silent testing of pushes to confirm FCM link is working