Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Set Course for Notifications… Engage! (DevFest DC)

Eric Fung
September 24, 2016

Set Course for Notifications… Engage! (DevFest DC)

With only a minimum of coding, Firebase provides your Android app with simple push notifications and collects analytics to measure user engagement. However, if you need to customize the notifications or their behavior, you need to implement everything yourself. For a recent Android news app I developed, I wanted to use push messaging to inform users when new articles were published. This talk will describe how I used three Firebase tools (Notifications, Cloud Messaging, and Analytics) to implement custom notifications and analytics to track their performance.

This was presented at DevFest DC on 2016-09-24. It is a revised version of the one I presented in Toronto.

Video: https://www.youtube.com/watch?v=N31imAjtuAQ

Eric Fung

September 24, 2016
Tweet

More Decks by Eric Fung

Other Decks in Programming

Transcript

  1. Set Course
    for Notifications…
    Engage!
    Eric Fung @gnufmuffin
    DevFest DC ● 2016-09-24

    View full-size slide

  2. Entrepreneur's Digest

    View full-size slide

  3. Let's Try Firebase!

    View full-size slide

  4. Let's Try Firebase!

    View full-size slide

  5. Cloud Messaging
    vs
    Notifications

    View full-size slide

  6. Cloud
    Messaging
    → Reliably delivers messages
    → Optional application server
    → Multiplatform client SDKs

    View full-size slide

  7. Notifications
    → Graphical console for
    re-engagement
    → No coding required
    → Built-in analytics

    View full-size slide

  8. Android Integration
    compile "com.google.firebase:firebase-messaging:${FB_VERSION}"

    View full-size slide

  9. What You Get
    → Manifest permissions
    → Registration token
    → Broadcast receiver
    → Display in notification area
    → Topic subscription
    → Analytics

    View full-size slide

  10. Notifications Console

    View full-size slide

  11. Funnel Analysis

    View full-size slide

  12. Wow, amazing!

    View full-size slide

  13. What About…
    → Different notification style?
    → Grouping and summary?
    → Not showing until background sync happens?
    → Analytics and reporting?

    View full-size slide

  14. Let's
    Dig
    Deeper

    View full-size slide

  15. Notification Messages
    {
    "to" : "/topics/email_marketing",
    "notification" : {
    "body" : "How to Grow a Business with Email Marketing",
    "title" : "New article available",
    }
    }
    → Predefined keys
    → Shown automatically if app backgrounded
    → Console only sends this type

    View full-size slide

  16. Data Messages
    {
    "to" : "/topics/email_marketing",
    "data" : {
    "item_id" : 14142135,
    "article_title" : "How to Grow a Business with Email Marketing"
    }
    }
    → Freeform keys and values
    → App decides what to do on receive
    → Console cannot send this kind

    View full-size slide

  17. Notification vs Data Messages

    View full-size slide

  18. Sending Data Messages
    → Must use FCM
    → Handle everything in onMessageReceived
    → No more analytics
    → Or funnel analysis

    View full-size slide

  19. The Best of Both Worlds?
    → Custom Notifications
    → Analytics + Reporting

    View full-size slide

  20. Styling
    &
    Grouping
    Notifications

    View full-size slide

  21. Styling & Grouping Notifications

    View full-size slide

  22. Grouping Notifications
    private static final String GROUP_NEW_ARTICLE = "new_article";
    new NotificationCompat.Builder(context)
    .setContentTitle(title[0])
    .setGroup(GROUP_NEW_ARTICLE) // ⾢⾢⾢⾢⾢

    new NotificationCompat.Builder(context)
    .setContentTitle(title[1])
    .setGroup(GROUP_NEW_ARTICLE) // ⾢⾢⾢⾢⾢

    View full-size slide

  23. Summary Notification
    new NotificationCompat.Builder(context)
    .setContentTitle(n + " new articles")
    .setStyle(inboxStyle)
    .setGroup(GROUP_NEW_ARTICLE) // ⾢⾢⾢⾢⾢
    .setGroupSummary(true) // ⾢⾢⾢⾢⾢

    View full-size slide

  24. Stacked Notifications in Wear

    View full-size slide

  25. Bundled Notifications in Nougat

    View full-size slide

  26. Notifications As Pings

    View full-size slide

  27. When Not To Show
    → During "Do Not Disturb" time
    → Push data needs further processing
    → Send-to-sync messages

    View full-size slide

  28. Being a Good App Citizen
    → Push messages are delivered very quickly
    → Consider server when client syncs
    → Stagger start time of sync
    → Minimize power usage

    View full-size slide

  29. Scheduling Background Sync
    https://developer.android.com/topic/performance/
    scheduling.html
    → JobScheduler (API 21)
    → Firebase JobDispatcher?
    → GCMNetworkManager

    View full-size slide

  30. Jobs in GCMNetworkManager
    → Specify network and scheduling requirements
    → Scheduler tries to batch and defer as long as
    possible

    View full-size slide

  31. build.gradle
    compile "com.google.android.gms:play-services-gcm:${PLAY_VERSION}"

    View full-size slide

  32. AndroidManifest.xml
    android:name=".notifications.MyFirebaseMessagingService"
    android:exported="false">




    → onMessageReceived is called in this service

    View full-size slide

  33. MyFirebaseMessagingService.java
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
    Map data = remoteMessage.getData();
    long articleId = parseIdFromData(data);
    // TBD: Remember we have a pending notification
    scheduleArticleFetch(rng.nextInt(SYNC_MIN) + 1, SYNC_MAX);
    }

    View full-size slide

  34. scheduleArticleFetch(min, max)
    OneoffTask task = new OneoffTask.Builder()
    .setService(MyGcmTaskService.class)
    .setRequiredNetwork(Task.NETWORK_STATE_CONNECTED)
    .setExecutionWindow(min, max)
    .build();
    gcmNetworkManager.schedule(task);

    View full-size slide

  35. AndroidManifest.xml
    android:name=".service.MyGcmTaskService"
    android:exported="true"
    android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">




    → Background job will run in this service

    View full-size slide

  36. MyGcmTaskService.java
    @Override
    public int onRunTask(TaskParams taskParams) {
    Bundle extras = taskParams.getExtras();
    apiService.fetchLatest(…);
    // TBD: Alert observers that sync has completed,
    // then showing any notifications that were pending
    }

    View full-size slide

  37. Events
    → Automatically collected events are reserved
    → Need to define your own names

    View full-size slide

  38. Detect Foreground or Background
    Ordered Broadcast
    https://commonsware.com/blog/2010/08/11/activity-
    notification-ordered-broadcast.html
    Application and ActivityLifecycleCallbacks
    http://www.developerphil.com/no-you-can-not-override-the-
    home-button-but-you-dont-have-to/

    View full-size slide

  39. notif_receive, notif_foreground
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
    boolean isBackground =
    ((MyApp)getApplication()).isBackground();
    firebaseAnalytics.logEvent(isBackground
    ? "notif_receive"
    : "notif_foreground",
    params);

    }

    View full-size slide

  40. notif_receive, notif_foreground
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
    // TBD: Extract any extra data and record in event, e.g. item ID
    boolean isBackground =
    ((MyApp)getApplication()).isBackground();
    firebaseAnalytics.logEvent(isBackground
    ? "notif_receive"
    : "notif_foreground",
    params);

    }

    View full-size slide

  41. Opening Notification
    Intent serviceIntent = new Intent(NotificationActionService.ACTION_TAPPED,
    null, context, NotificationActionService.class);

    Intent intent = PendingIntent.getService(context.getApplicationContext(),
    REQUEST_CODE_TAPPED,
    serviceIntent,
    PendingIntent.FLAG_UPDATE_CURRENT);
    NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
    .setContentIntent(intent)

    View full-size slide

  42. NotificationActionService.java
    public class NotificationActionService extends IntentService {
    @Override
    protected void onHandleIntent(Intent intent) {
    switch (intent.getAction()) {
    case ACTION_TAPPED:
    firebaseAnalytics.logEvent("notif_open", params);
    case ACTION_DISMISSED:
    firebaseAnalytics.logEvent("notif_dismiss", params);
    }
    }
    }

    View full-size slide

  43. Code Snippets
    https://goo.gl/50tRcm

    View full-size slide

  44. Analytics Limitations
    → Can't filter analytics by event parameters ✳
    → Need parameters for per-notification funnel
    analysis
    → Parameters can be specified in Audiences

    View full-size slide

  45. Audiences
    → Segment user base by combining events,
    parameters and properties

    View full-size slide

  46. !
    Segment by Item ID
    → Users who received a notification AND,
    → Opened the notification, OR, dismissed it

    View full-size slide

  47. Define Funnel
    → Then, view funnel with audience filter

    View full-size slide

  48. Funnel Analysis

    View full-size slide

  49. Beyond Analytics
    → Filtering on event parameters is a popular feature
    request
    → Can stream raw events + parameters into
    BigQuery

    View full-size slide

  50. Application
    Server

    View full-size slide

  51. Topic Messaging
    → Useful if you don't need to address individually
    → Topics don't have to be pre-defined
    → For simple messaging, subscribe all clients to one
    topic
    firebase.subscribeToTopic("all_new_articles");

    View full-size slide

  52. Sending Notifications to FCM
    → Don't need to integrate into your backend
    → Anything that can send an HTTP request
    → Example using cURL in the Gist
    → Shell script useful for debugging

    View full-size slide

  53. Learning
    https://github.com/firebase/quickstart-android
    https://github.com/googlesamples/android-ActiveNotifications
    Firebase YouTube channel
    Firebase Blog

    View full-size slide

  54. Support
    Stack Overflow, Google Group, Report Bug/Feature Request
    https://firebase.google.com/support/
    Status Page
    https://status.firebase.google.com/
    Firebase Slack
    https://firebase-community.appspot.com/

    View full-size slide

  55. Takeaway
    → Firebase Notifications gives you a basic
    implementation
    → For more complex needs, get to know FCM
    → For me, no reduction in lines of code
    → Lot of manual work to produce analytics

    View full-size slide

  56. Let's have some questions!
    Email [email protected]
    Work www.shopify.com
    Blog code.gnufmuffin.com
    Code github.com/efung
    Social @gnufmuffin
    Slides speakerdeck.com/efung

    View full-size slide