Grails 3 Send Push Notification to iOS Apps using APNS

by Didin J. on Aug 10, 2017 Grails 3 Send Push Notification to iOS Apps using APNS

Tutorial about how to send push notification to iOS apps directly using APNS (Apple Push Notification Service).

In this tutorial, we will explain about how to send the push notification to iOS apps directly using APNS (Apple Push Notification Service). A few years ago we still using an APNs plugin for send push notification to iOS apps. Now, that's plugin not working with Grails 3. The base 'notnoop.apns' Java plugin also not working for today's APNs HTTP2 protocol.

By the way, there's another Java plugin for APNs that support new APNs HTTP2 protocol. It is relayrides/pushy Java APNs library which support Apple's HTTP/2-based APNs protocol and supports both TLS and token-based authentication. It's not the only Java APNs library that supports HTTP2 protocol, but this time when I try this library and it is easy to implement with Grails 3.

There are some requirements for this tutorial, please complete it before starting.

- Apple Push Service Certificate for Development and Production (OS X is required)
- JDK 8
- Grails 3 SDK
- IDE or Text Editor
- Terminal or Command Line


1. Create PKCS12 (.p12) Certificate File

This time, we are not covering how to create or setup Apple Push Notification Certificate. For that, you can refer to this tutorial. So, we assume you have to get the Apple Push Notification certificate both development and production and exist in Keychain Access app in the OS X. Next, we have to export that certificate as PKCS12 (.p12) file.

Open Keychain Access app on OS X.

Grails 3 Send Push Notification to iOS Apps using APNS - Keychain Access

Expand the Apple Push Service certificate that wanna to export then push Ctrl+Mouse button on the Key then choose 'Export'.

Grails 3 Send Push Notification to iOS Apps using APNS - Export to PKCS .p12

Save as ".p12" file then give it a password. Remember or write the password on a notepad, because it will use in Grails 3 application.


2. Create New Grails 3 Application

As usual, we always do a tutorial from scratch. That means starting from creating new Grails 3 application. We assume all above requirements already installed and accessible in the terminal or command line. Next, open the terminal or command line then type this command.

grails create-app grails3-apns

Go to the newly created Grails 3 project folder.

cd grails3-apns

Enter Grails 3 interactive console by type this command.

grails

In this interactive console type this command to run the app.

run-app

You must see this page when open your browser then points to this address 'localhost:8080'.

Grails 3 Send Push Notification to iOS Apps using APNS - Grails 3 Homepage

Stop the app by type this command in the Grails 3 interactive console.

stop-app


3. Add Pushy Dependencies and Create APNs Service

Back to the point, add required dependencies for sending the push notification to APNs and create a service for using in Grails 3 application. First, add 'com.turo.pushy' Java APNs library as a dependency. To do that, open and edit 'build.gradle' file on the root of Grails 3 project folder then adds this dependency inside dependencies body.

compile "com.turo:pushy:0.10.1"

Compile the Grails project on Grails interactive console.

compile

Still, on Grails 3 interactive console, type this command for create new Grails service.

create-service Apns

Open and edit "grails-app/services/grails3/apns/ApnsService.groovy" file then add this imports.

import com.turo.pushy.apns.*;
import com.turo.pushy.apns.util.*;
import io.netty.util.concurrent.Future;

import java.io.File;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutionException;

Next, add this method inside the class body.

def sendPushNotification(String message, List tokenList) {
  final ApnsClient apnsClient = new ApnsClientBuilder()
  .setClientCredentials(new File("/path/YOURPUSHCERTIFICATE.p12"), "gewr")
  .build();

  apnsClient.setMetricsListener(new NoopMetricsListener());

  final Future<Void> connectFuture = apnsClient.connect(ApnsClient.PRODUCTION_APNS_HOST);
  connectFuture.await();

  final SimpleApnsPushNotification pushNotification;

  tokenList.each { String token ->
    final ApnsPayloadBuilder payloadBuilder = new ApnsPayloadBuilder();
    payloadBuilder.setAlertBody(message);

    final String payload = payloadBuilder.buildWithDefaultMaximumLength();
    final String tkn = TokenUtil.sanitizeTokenString(token);

    pushNotification = new SimpleApnsPushNotification(tkn, "com.greateasternlife.womensrun", payload);
  }

  final Future<PushNotificationResponse<SimpleApnsPushNotification>> sendNotificationFuture =
          apnsClient.sendNotification(pushNotification);

  try {
      final PushNotificationResponse<SimpleApnsPushNotification> pushNotificationResponse =
              sendNotificationFuture.get();

      if (pushNotificationResponse.isAccepted()) {

      } else {
          System.out.println("Notification rejected by the APNs gateway: " +
                  pushNotificationResponse.getRejectionReason());

          if (pushNotificationResponse.getTokenInvalidationTimestamp() != null) {

          }
      }
  } catch (final ExecutionException e) {
      System.err.println("Failed to send push notification.");
      e.printStackTrace();

      if (e.getCause() instanceof ClientNotConnectedException) {
          apnsClient.getReconnectionFuture().await();
      }
  }

  final Future<Void> disconnectFuture = apnsClient.disconnect();
  disconnectFuture.await();
}

Change "/path/YOURPUSHCERTIFICATE.p12" on the first line of a method to your full path of Apple Push Service certificate file. And also match the second lines of method "ApnsClient.PRODUCTION_APNS_HOST" as the environment that you use (DEVELOPMENT_APNS_HOST = for the development environment). Also, "com.xxxxx" on below line to be your iOS App bundle ID.

pushNotification = new SimpleApnsPushNotification(tkn, "com.xxxxxx", payload);


4. Create Controller and View for Test Sending Notification

For test sending push notification, just create new controller and view. On Grails 3 interactive console type this command.

create-controller PushNotification

Open and edit "grails-app/controllers/grails3/apns/PushNotificationController.groovy" file then replace all codes with this.

package grails3.apns

class PushNotificationController {

  def apnsService

  def index() { }

  def sendNotification() {
    if(params.token&&params.message) {
      applePushNotificationService.sendPushNotification(params.message,params.token)

      flash.message = "Push notification sent"
      redirect action:"index"
    } else {
      flash.message = "No token or message found"
      redirect action:"index"
    }
  }
}

Now, create file "index.gsp" on the folder "grails-app/views/pushNotification". Replace all HTML tags with this.

<!doctype html>
<html>
<head>
    <meta name="layout" content="main"/>
    <title>APNs Sender</title>

    <asset:link rel="icon" href="favicon.ico" type="image/x-ico" />
</head>
<body>
    <div id="content" role="main">
        <section class="row colset-2-its">
            <h1>Send Push Notification</h1>
            <g:if test="${flash.message}">
              <div class="message" role="alert">
                ${flash.message}
              </div>
            </g:if>
            <g:form action="sendNotification">
              <fieldset>
                <div class="fieldcontain">
                  <label for="regid">APNs Token</label>
                  <g:textField name="token" />
                </div>
                <div class="fieldcontain">
                  <label for="body">Message Body</label>
                  <g:textField name="message" />
                </div>
              </fieldset>
              <fieldset>
                <div class="buttons">
                  <g:submitButton class="save" name="submit" value="Send" />
                </div>
              </fieldset>
            </g:form>
        </section>
    </div>
</body>
</html>

That it's, now you can run the Grails 3 application then click on the "grails3.apns.PushNotificationController" hyperlink on the bottom of home page. Fill the required fields then click "send" button. If there's no error, you will receive the push notification on your iPhone from Grails 3 server.

You can find the full source code on our GitHub.

Thanks