Use Apple Push Notification Service through Java
Asked Answered
C

7

8

Am trying to implement a Java program which sends an Apple Push Notification to an iPhone client app... Found the following library: Java APNs

Provider code:

Created the following code (from Javapns) to use in my app:

try {
    PayLoad payLoad = new PayLoad();

    payLoad.addAlert("My alert message");
    payLoad.addBadge(45);
    payLoad.addSound("default");

    PushNotificationManager pushManager = PushNotificationManager.getInstance();
    pushManager.addDevice("iPhone", "f4201f5d8278fe39545349d0868a24a3b60ed732");
    log.warn("Initializing connectiong with APNS...");

    // Connect to APNs
    pushManager.initializeConnection(HOST, PORT, 
                                 "/etc/Certificates.p12", "password", 
    SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);

    Device client = pushManager.getDevice("Lambo");

    // Send Push
    log.warn("Sending push notification...");
    PushNotificationManager.getInstance().sendNotification(client, payLoad);
 }
 catch (Exception e) {
    throw new ApnsPushNotificationException("Unable to send push " + e);
 }

When I run this app (as you can see through the Log4j statements) there's no exceptions which occur:

  WARN  [MyCode] Initializing connectiong with APNS...
  WARN  [MyCode] Sending push notification...

But my client app doesn't receive any notifications!

IDPP Registration Process:

Also, did the following on the iPhone Developer Program Portal (IDPP):

  • Created the APNS based SSL Certificate and Keys

  • Created and installed the provisioning profile

  • Installed the SSL Certificate and Key on the server.

Have read over the Apple Push Notification Service Guide several times and noticed a few things:

(1) On page 15, it states that the device token is not the same as the device UDID (which I am currently incorrectly passing in as the second parameter inside the PushNotificationManager.addDevice() method (see above)).

On page 17, it states:

"APNs generates a device token using information contained in the unique device certificate. The device token contains an identifier of the device. It then encrypts the device token with a token key and returns it to the device. The device returns the device token to the requesting application as an NSData object. The application then must deliver the device token to its provider in either binary or hexidecimal format."

iPhone OS Client Implementation

(2) After reading pages 33 - 34, I discovered that I didn't include the Objective-C code to have the app register with APNs.

Am not an Objective-C developer, so is this where I can recover the device code or do I have to get it from the certificate?

Where do I obtain the device token (sorry, someone else wrote the Objective-C client app and I am a Java Developer)?

Question(s):

(1) With the exception of not knowing where to get the device token and the mobile client code registration, is there anything else that I have not looked over or missed?

(2) Am I using the Javapns library the right way?

Thank you for taking the time to read this...

Creuse answered 31/8, 2009 at 4:48 Comment(1)
Is DeviceID and Device token same ?Tweezers
P
8

Just a little tip, in order to convert your received token into a format suitable for registration with javapns, this code will do the trick:

- (NSString *)convertTokenToDeviceID:(NSData *)token {
NSMutableString *deviceID = [NSMutableString string];

// iterate through the bytes and convert to hex
unsigned char *ptr = (unsigned char *)[token bytes];

for (NSInteger i=0; i < 32; ++i) {
    [deviceID appendString:[NSString stringWithFormat:@"%02x", ptr[i]]];
}

return deviceID;

}

Prithee answered 9/10, 2009 at 14:19 Comment(1)
is this still needed with the most recent version of java-apns?Dissonancy
C
19

As a shameful self-advertising, I encourage to use java-apns library. Your code will look like:

ApnsService service =
     APNS.newService()
     .withCert("/etc/Certificates.p12", "password")
     .withSandboxDestination() // or .withProductionDestination()
     .build();

String payload =
    APNS.newPayload()
    .alertBody("My alert message")
    .badge(45)
    .sound("default")
    .build();

String deviceToken = "f4201f5d8278fe39545349d0868a24a3b60ed732";

log.warn("Sending push notification...");
service.push(deviceToken, payload);
Clegg answered 25/11, 2009 at 21:42 Comment(7)
With the caveat that his deviceToken is wrong, too, right? That looks like a [[UIDevice currentDevice] uniqueIdentifier], but the java apns class wants the binary device token converted to a 64 character hex string.Amadus
Ok, great. I was able to get the exact code you pasted above working, so long as I replaced deviceToken with the full 64 char hex string generated by code similar to ZaBlanc's. Great library, by the way!Amadus
@Nate. Thanks, please join the google group and influence the library evolution.Clegg
hi.i checked with this ..but the default sound is not working in this case.Kurd
@notnoop, The above code is fine for single payload push to one or more device. If we need to do this repeatedly based on the web service call, creating the apnsservice each and every time won't be good. Is there a way to keep this connection open as long as possible? I don't see any open or close of connection. when does it happen exactly. Please guide me.Malcommalcontent
How we will come to know that Push Notification being sent successfully through APNS API? As GCM gives success or failure message. Does APNS provide same for ioS?Jubbah
@Clegg how to send apns-push-type header attribute? for iOS 13 we need to send this header ref: onesignal.com/blog/….Purport
P
8

Just a little tip, in order to convert your received token into a format suitable for registration with javapns, this code will do the trick:

- (NSString *)convertTokenToDeviceID:(NSData *)token {
NSMutableString *deviceID = [NSMutableString string];

// iterate through the bytes and convert to hex
unsigned char *ptr = (unsigned char *)[token bytes];

for (NSInteger i=0; i < 32; ++i) {
    [deviceID appendString:[NSString stringWithFormat:@"%02x", ptr[i]]];
}

return deviceID;

}

Prithee answered 9/10, 2009 at 14:19 Comment(1)
is this still needed with the most recent version of java-apns?Dissonancy
T
2

I tried this and I keep getting hanged when sending the notification, and nothing gets sent.

The issue stems from the following function:

         public void sendNotification(Device device, PayLoad payload) 

It seems that the bufferedreader has NULL

           BufferedReader in = 
           new BufferedReader(new InputStreamReader(this.socket.getInputStream() ) );

So when this portion of the code gets hit it just hangs there in endless loop

  logger.debug( "In: [" + in.readLine() + "]" );

This output is [null]

So then right after then the loops get executed:

      while ( ! this.socket.isInputShutdown() ) {
          while( in.ready() ) {
              logger.debug("ready now");
              logger.debug(in.readLine());
              System.out.println( this.socket.getInputStream().read() );
          }
      }

The code enters the first while loop and waits for the BufferedReader in to be ready and just keeps waiting..... ad that is your hanging

Theodor answered 25/7, 2011 at 0:0 Comment(1)
Can you please guide me if i can use this libarary to send apns-push-type header for APNS payload, which is required in iOS13? My question: #61278508Purport
C
1
  1. Your Java code looks solid! However, don't forget to close the connection, through PushNotificationManager.closeConnection(). It's important to cleanup after yourself.

    As a side comment, I notice that you are adding the device 'iPhone' but querying for 'Lambo' afterwards. This is an indication of a bug.

  2. The device token shown in the code is incorrect. Device tokens, currently, as 32-bit long value, which gets hexed into 64 characters. I assume that the server is failing silently when pushing the notification to invalid token!

  3. The only way to get the device token is from the app itself. As provided by the Push Notification guide suggests, the iPhone app needs to register for notification upon launch. In the application:didRegisterForRemoteNotificationsWithDeviceToken:, the iPhone needs to send the device token to your java provider server. (For debugging purposes, you can just NSLog the device token and use it; it never changes across runs).

    I would recommend that you create a server in your java provider server to receive device tokens. Set up a ServerSocket to receive connections from the iPhone and their device token (and any additional info you need) and insert the tokens in the database.

Clegg answered 31/8, 2009 at 14:14 Comment(1)
Can you please guide me if i can use this libarary to send apns-push-type header for APNS payload, which is required in iOS13? My question: #61278508Purport
E
1

Regarding the comment for notnoop here:

If you are landing on this post in 2022, you'll find that the java-apns library doesn't work since 2021. Instead they recommend using pushy library.

I have tried this one just by following their example in the README file and it works really well. They have added examples for both authorisation types: by certificate or by token.

Elwaine answered 17/10, 2022 at 13:33 Comment(0)
C
0

You seem to be missing the token

pushManager.addDevice("iPhone", "f4201f5d8278fe39545349d0868a24a3b60ed732");

Takes id and token check:

https://github.com/o-sam-o/javapns/blob/master/src/javapns/notification/PushNotificationManager.java#L501

The only way to get a token is from the iphone app. A valid token looks something like this: 1d2d6f34 c5028bca c50df5f9 1992c912 ce7deae8 3bbe7da5 447f6a68 cfecdc0e

Corpuz answered 31/8, 2009 at 5:3 Comment(1)
I updated the link to github.com/o-sam-o/javapns/blob/master/src/javapns/notification/…Corpuz
I
0

JavaPNS was recently updated to 2.0, and fixed ALL reported issues up to the release date. It does fix the issue you are describing, and using the library is MUCH simpler than it ever was (you can push a notification with a single line of code now).

Isoniazid answered 10/10, 2011 at 22:29 Comment(3)
Could you please paste code to support your answer ? Here in my case I not getting any error also notifications are not going. Please helpTweezers
Here it is: Push.alert("Hello World!", "keystore.p12", "keystore_password", false, "Your token"); Everything is pretty well documented in the project's wiki on Google Code. There are basic and advanced code examples.Isoniazid
@Syslvain P. Can you please guide me if i can use this libarary to send apns-push-type header for APNS payload, which is required in iOS13? My question: #61278508Purport

© 2022 - 2024 — McMap. All rights reserved.