apns2

repository·main·Indexed 41 days ago

https://github.com/andrewbarba/apns2

A Node.js client for Apple's Push Notification Service (APNS) using the HTTP/2 protocol and JSON Web Tokens (JWT) for authentication. Version 12.2.0 supports sending basic, advanced, and silent notifications, batch processing via sendMany(), and detailed error handling based on APNS response reasons. It provides built-in support for both production and sandbox environments.

Tokens
5.7K
Snippets
19
Records
21
Agent score
51%

What's inside apns2

  1. Create an ApnsClient using a signing key

    main

    To connect to Apple's Push Notification Service, instantiate ApnsClient with a signing key (JWT-based authentication). You must provide your Apple Team ID, Key ID, and the contents of your .p8 auth key file.

    import { ApnsClient } from 'apns2'
    import fs from 'fs'
    
    const client = new ApnsClient({
      team: `TFLP87PW54`,
      keyId: `123ABC456`,
      signingKey: fs.readFileSync(`${__dirname}/path/to/auth.p8`),
      defaultTopic: `com.tablelist.Tablelist`,
      requestTimeout: 0, // optional, Default: 0 (without timeout)
      keepAlive: true, // optional, Default: 5000
    })
  2. Configure APNS environments (Production vs Sandbox)

    main

    The ApnsClient connects to the production server by default. To switch to the development/sandbox environment, you must specify the host in the configuration object.

    • Production (Default): api.push.apple.com
    • Sandbox: api.sandbox.push.apple.com
    // Production
    const client = new ApnsClient({
      host: 'api.push.apple.com',
      // ... other options
    })
    
    // Sandbox
    const client = new ApnsClient({
      host: 'api.sandbox.push.apple.com',
      // ... other options
    })
  3. Configure the ApnsClient

    main

    To use the ApnsClient, instantiate it with an ApnsOptions object. This object requires your Apple Developer credentials and allows you to specify the environment (host) and connection behavior.

    Configuration Options

    KeyTypeDescription
    teamstringYour Apple Developer Team ID.
    signingKeystring | Buffer | PrivateKeyYour APNs private key.
    keyIdstringThe Key ID associated with your signing key.
    defaultTopicstring (optional)The default apns-topic used if not specified in a notification.
    hostHost | string (optional)The APNS host. Defaults to Host.production. Use Host.development for sandbox.
    requestTimeoutnumber (optional)Timeout for requests in milliseconds.
    keepAliveboolean (optional)Enables HTTP/2 connection pooling and background pings. Defaults to true.

    Available Hosts

    Use the Host object to select the environment:

    • Host.production: api.push.apple.com
    • Host.development: api.sandbox.push.apple.com
    import { ApnsClient, Host } from 'apns2';
    
    const client = new ApnsClient({
      team: 'YOUR_TEAM_ID',
      signingKey: 'YOUR_PRIVATE_KEY_CONTENT',
      keyId: 'YOUR_KEY_ID',
      host: Host.development, // Use sandbox for testing
      keepAlive: true
    });
  4. Handle APNS errors

    main

    Errors in apns2 correspond to APNS Table 4. You can handle errors in two ways:

    1. Try/Catch: Wrap client.send() calls in a try/catch block to catch errors returned by the promise.
    2. Event Listeners: Attach listeners to the client using the Errors object to react to specific error types (like badDeviceToken) or all errors via Errors.error.

    Error objects include reason, statusCode, and the original notification object.

    import { Errors } from 'apns2'
    
    // Listen for a specific error (e.g., to clean up invalid tokens)
    client.on(Errors.badDeviceToken, (err) => {
      console.error(err.reason, err.statusCode, err.notification.deviceToken)
    })
    
    // Listen for any error
    client.on(Errors.error, (err) => {
      console.error(err.reason, err.statusCode, err.notification.deviceToken)
    })
  5. Send basic and advanced notifications

    main

    Use the Notification class to construct push notifications. You can send simple alerts or use the aps property for complete control over the payload structure.

    Basic Alert: Pass a device token and an options object containing an alert string.

    Advanced Payload: For full control, pass an aps object to the constructor to match Apple's APNS Payload Options.

    Options include:

    • alert: The message text.
    • badge: The number to display on the app icon.
    • data: Custom JSON payload.
    • aps: The full APNS dictionary.
    import { Notification } from 'apns2'
    
    // Basic notification
    const bn = new Notification(deviceToken, { alert: 'Hello, World' })
    await client.send(bn)
    
    // Notification with badge and custom data
    const bnWithData = new Notification(deviceToken, {
      alert: 'Hello, World',
      badge: 4,
      data: {
        userId: 'user_123'
      }
    })
    await client.send(bnWithData)
    
    // Advanced control via aps
    const advanced = new Notification(deviceToken, {
      aps: { ... }
    })
    await client.send(advanced)
  6. Send silent notifications

    main

    To wake up an app in the background without showing a visible alert, use the SilentNotification class.

    Important: Apple recommends that no options other than the content-available flag be sent in order for a notification to truly be silent. Consequently, the SilentNotification constructor does not accept any additional options.

    import { SilentNotification } from 'apns2'
    
    const sn = new SilentNotification(deviceToken)
    
    try {
      await client.send(sn)
    } catch (err) {
      console.error(err.reason)
    }
  7. Send multiple notifications concurrently

    main

    Use the client.sendMany() method to send an array of Notification objects at once.

    import { Notification } from 'apns2'
    
    const notifications = [
      new Notification(deviceToken1, { alert: 'Hello, World' }),
      new Notification(deviceToken2, { alert: 'Hello, World' })
    ]
    
    try {
      await client.sendMany(notifications)
    } catch (err) {
      console.error(err.reason)
    }
  8. Generate APNs payload with buildApnsOptions()

    main

    The buildApnsOptions() method on a Notification instance converts the user-friendly NotificationOptions into a valid ApnsPayload. This payload structure is what is actually sent to the APNs gateway. Custom keys provided in the data option are merged into the root of the resulting payload, while standard options are nested under the aps key.

    const notification = new Notification('TOKEN', {
      alert: 'Hello',
      badge: 5,
      data: { customKey: 'customValue' }
    });
    
    const payload = notification.buildApnsOptions();
    // Resulting payload structure:
    // {
    //   "aps": {
    //     "alert": "Hello",
    //     "badge": 5
    //   },
    //   "customKey": "customValue"
    // }
  9. Send silent notifications with SilentNotification

    main

    Use the SilentNotification class to send background notifications that trigger app updates without showing an alert to the user. This class automatically configures the notification with contentAvailable: true, type: PushType.background, and priority: Priority.throttled.

    To instantiate, provide the deviceToken and an optional options object. The options object allows you to override any NotificationOptions except for type, alert, priority, and contentAvailable (which are fixed for silent notifications).

    import { SilentNotification } from './notifications/silent-notification.js';
    
    const silentNotification = new SilentNotification("DEVICE_TOKEN", {
      // You can pass other NotificationOptions here, but cannot override 
      // type, alert, priority, or contentAvailable
    });
  10. Handle APNS errors and events

    main

    The ApnsClient extends EventEmitter. When a notification fails to send, the client throws an ApnsError and emits events based on the error reason.

    Error Events

    You can listen for specific error reasons or a generic error event:

    • client.on(error.reason, (error) => ...): Emits an event for a specific error reason (e.g., Errors.expiredProviderToken).
    • client.on(Errors.error, (error) => ...): Emits a generic event for any ApnsError.

    Error Structure

    An ApnsError contains:

    • statusCode: The HTTP status code returned by Apple.
    • notification: The Notification object that failed to send.
    • response: The parsed JSON response from the APNS server (ApnsResponseError).
  11. Import apns2 core modules

    main

    The apns2 package exports its primary functionality through a single entrypoint. You can import the client, error classes, and notification types directly from the package root.

    Key modules available via the entrypoint include:

    • Core client and configuration logic (from ./apns.js)
    • Error definitions (from ./errors.js)
    • Standard notification structures (from ./notifications/notification.js)
    • Silent notification structures (from ./notifications/silent-notification.js)
    import {
      ApnsClient,
      Notification,
      SilentNotification,
      ApnsError
    } from 'apns2';
  12. Clean up ApnsClient resources

    main

    To prevent memory leaks and ensure connections are closed properly, you should clean up the client when it is no longer needed.

    • close(): Closes the underlying connection pool and stops the background ping interval.
    • destroy(err?): Destroys the client and the connection pool. Use this if you need to signal an error during shutdown.
    await client.close();
    // OR
    await client.destroy();