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

The Art of Pushing

The Art of Pushing

A common component in common to a lot of adds is the capability to receive pushes and show notifications to the user. Although to many devs and product owners think it is trivial, it is a vital component which requires a lot of care to be done properly.

In this talk we will aim some common problems about push and notification management, and which implications have for the product and how to build a good UX around those.

Saúl Díaz

May 18, 2016
Tweet

More Decks by Saúl Díaz

Other Decks in Programming

Transcript

  1. It’s a trap! Parse documentation When a push notification is

    received, the “title” is displayed in the status bar and the “alert” is displayed alongside the “title” when the user expands the notification drawer. If you choose to subclass com.parse.ParsePushBroadcastReceiver, be sure to replace that name with your class' name in the registration. Mixpanel documentation Now you'll need to inform the OS to allow a service to run that will handle inbound notifications. Replace "YOUR_PACKAGE_NAME" with your own app's package name in the the following snippet of xml, and add them to your AndroidManifest.xml inside of your <application> tag: <receiver android:name= "com.mixpanel.android.mpmetrics.GCMRe ceiver">[...]
  2. A push does not necessarily becomes a notification. Use pushes

    to perform behind-the-scenes stuff. Actual phone receiving pushes with a dramatized effect ->
  3. Handling your pushes product-proof Identify Source Map info to POJO

    Identify Deeplink Convert Deeplink Build Notification Identify type “I heard this new push analytics system is so cool we should try it” “Happens we have this revolutionary new SEO deeplinks” “A dude in the GDG Hamburg told me to do this”
  4. Handling your pushes product-proof public void onMessageReceived(RemoteMessage message) { //

    Identify and Build a POJO to have a common “language” for notificationFactory NotificationData notificationData = notificationDataFactory.convert(message); // Convert Deeplink to a common format notificationData.updateDeeplink( deeplinkConverter.convert(notificationData.deeplink())); // Add to our notifications info data notificationsRepo.add(notificationData); // Identify the push type and Build the notification notificationManager.notify(EXAMPLE_APP_NOTIFICATION_ID, notificationFactory.build(notificationsRepo)); }
  5. You must JSON this high to have push-fun { "alert":

    "Jon Bovi just published his new album", "author": "jon_bovi", "type": "new_album", "url": "album://album/12345" }
  6. Y U NO BRAND? new NotificationCompat.Builder( this) .setContentTitle( getResources().getString(R.string. app_name))

    .setContentText( "Bon Jovi just published his new album") .setSmallIcon(R.drawable. ic_notification_icon) .setColor(getResources().getColor(R.color. colorPrimary)) .setTicker( "Bon Jovi just published his new album") .setLights(getResources().getColor(R.color. colorPrimary), 1000, 1000);
  7. STORYTELLING IS CAPITAL new NotificationCompat.Builder(this) .setContentTitle("Bon Jovi") .setContentText( "wants you

    to check his new album") .setSmallIcon(R.drawable.ic_notification_icon) .setLargeIcon(bonJoviAvatar)
  8. ELEGANT NOTIFICATIONS ACTIONS Intent intent = new Intent(this, NotificationActionHandlerService.class); intent.setAction(NotificationActionHandlerService.ACTION_NAVIGATE);

    intent.putExtra(NotificationActionHandlerService.EXTRA_ID, notificationData.getAuthor()); builder.addAction( new NotificationCompat.Action(R.drawable.action_ic_navigate, "Navigate to venue", PendingIntent.getService(this, NAVIGATE_VENUE_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)));
  9. THE MAKING OF Number of notifs? Identify Type Build Notification

    Is Nougat? Build Pre-N Coalesced Build Nougat Coalesced More than 1 Only 1 No Yes For N notifs
  10. THE MAKING OF void build(NotificationsRepository repository) { if (repository.count() ==

    1) { notificationManager.notify(0x1234, buildSingleNotification(this.notificationsRepo.getAll().get(0)); } else if (this.notificationsRepo.count() > 1) { buildCoalescedNotification(this.notificationsRepo.getAll()); } } void buildCoalescedNotification(List<NotificationData> notifs) { final NotificationCompat.Builder builder = buildBasicNotification("BeAuthentic", String.format("You have %s new notifications", notifs.size()) .setNumber(notifs.size())// This line is for 4.0, lol .setGroup("BeAuthentic") // These two lines are for Android Nougat compatibility .setGroupSummary(true); if (isAndroidN()) { groupAsAndroidN(notificationManager, notifs); } else { groupAsMarshmallowAndLower(builder, notifs); } notificationManager.notify(0x1234, builder.build()); }
  11. THE MAKING OF void groupAsAndroidN(NotificationManagerCompat notificationManager, List<NotificationData> notifs) { for

    (NotificationData notification : notifs) { final NotificationCompar.Builder builder = buildSingleNotification(notification); builder.setGroup("BeAuthentic"); notificationManager.notify(notification.getId(),builder.build() ); } } void groupAsMarshmallowAndLower(NotificationCompat.Builder builder, List<NotificationData> notifs) { final NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(builder) .setSummaryText(String.format("You have %s new notifications", notifs.size())); for (NotificationData data : notifs) { inboxStyle.addLine(new StringBuffer(data.title()) .append(" ") .append(data.text()) .toString()); } }
  12. LISTEN WHEN YOUR NOTIFICATIONS ARE DISMISSED! final Intent intent =

    new Intent(this, NotificationActionHandlerService. class); intent.setAction(NotificationActionHandlerService. DELETE_NOTIFICATIONS); builder.setDeleteIntent(PendingIntent. getService(this, DELETED_NOTIFS_CODE, intent, PendingIntent. FLAG_UPDATE_CURRENT));
  13. DON’T BE AFRAID TO GENERATE NOTIFICATIONS FROM THE CLIENT Chicisimo

    produces a 6 ~ 9% increase in adoption rate