• This repository has been archived on 06/Jun/2023
  • Stars
    star
    475
  • Rank 92,465 (Top 2 %)
  • Language
    Go
  • License
    MIT License
  • Created almost 9 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A push notification delivery engine for the new HTTP/2 APNS service.

Buford

Apple Push Notification (APN) Provider library for Go 1.6 and HTTP/2. Send remote notifications to iOS, macOS, tvOS and watchOS. Buford can also sign push packages for Safari notifications and Wallet passes.

Please see releases for updates.

GoDoc Build Status MIT codecov

Documentation

Buford uses Apple's new HTTP/2 Notification API that was announced at WWDC 2015 and released on December 17, 2015.

API documentation is available from GoDoc.

Also see Apple's Local and Remote Notification Programming Guide, especially the sections on the JSON payload and the Notification API.

Terminology

APN Apple Push Notification

Provider The Buford library is used to create a provider of push notifications.

Service Apple's push notification service that Buford communicates with.

Client An http.Client provides an HTTP/2 client to communicate with the APN Service.

Notification A payload, device token, and headers.

Device Token An identifier for an application on a given device.

Payload The JSON sent to a device.

Headers HTTP/2 headers are used to set priority and expiration.

Installation

This library requires Go 1.6.3 or better.

go get -u -d github.com/RobotsAndPencils/buford

Buford depends on several packages outside of the standard library, including the http2 package. Its certificate package depends on the pkcs12 and pushpackage depends on pkcs7. They can be retrieved or updated with:

go get -u golang.org/x/net/http2
go get -u golang.org/x/crypto/pkcs12
go get -u github.com/aai/gocrypto/pkcs7

I am still looking for feedback on the API so it may change. Please copy Buford and its dependencies into a vendor/ folder at the root of your project.

Examples

package main

import (
	"encoding/json"
	"fmt"

	"github.com/RobotsAndPencils/buford/certificate"
	"github.com/RobotsAndPencils/buford/payload"
	"github.com/RobotsAndPencils/buford/payload/badge"
	"github.com/RobotsAndPencils/buford/push"
)

// set these variables appropriately
const (
	filename = "/path/to/certificate.p12"
	password = ""
	host = push.Development
	deviceToken = "c2732227a1d8021cfaf781d71fb2f908c61f5861079a00954a5453f1d0281433"
)

func main() {
	// load a certificate and use it to connect to the APN service:
	cert, err := certificate.Load(filename, password)
	exitOnError(err)

	client, err := push.NewClient(cert)
	exitOnError(err)

	service := push.NewService(client, host)

	// construct a payload to send to the device:
	p := payload.APS{
		Alert: payload.Alert{Body: "Hello HTTP/2"},
		Badge: badge.New(42),
	}
	b, err := json.Marshal(p)
	exitOnError(err)

	// push the notification:
	id, err := service.Push(deviceToken, nil, b)
	exitOnError(err)

	fmt.Println("apns-id:", id)
}

See example/push for the complete listing.

Concurrent use

HTTP/2 can send multiple requests over a single connection, but service.Push waits for a response before returning. Instead, you can wrap a Service in a queue to handle responses independently, allowing you to send multiple notifications at once.

var wg sync.WaitGroup
queue := push.NewQueue(service, numWorkers)

// process responses (responses may be received in any order)
go func() {
	for resp := range queue.Responses {
		log.Println(resp)
		// done receiving and processing one response
		wg.Done()
	}
}()

// send the notifications
for i := 0; i < 100; i++ {
	// increment count of notifications sent and queue it
	wg.Add(1)
	queue.Push(deviceToken, nil, b)
}

// wait for all responses to be processed
wg.Wait()
// shutdown the channels and workers for the queue
queue.Close()

It's important to set up a goroutine to handle responses before sending any notifications, otherwise Push will block waiting for room to return a Response.

You can configure the number of workers used to send notifications concurrently, but be aware that a larger number isn't necessarily better, as Apple limits the number of concurrent streams. From the Apple Push Notification documentation:

"The APNs server allows multiple concurrent streams for each connection. The exact number of streams is based on server load, so do not assume a specific number of streams."

See example/concurrent/ for a complete listing.

Headers

You can specify an ID, expiration, priority, and other parameters via the Headers struct.

headers := &push.Headers{
	ID:          "922D9F1F-B82E-B337-EDC9-DB4FC8527676",
	Expiration:  time.Now().Add(time.Hour),
	LowPriority: true,
	Type:        push.Alert,
}

id, err := service.Push(deviceToken, headers, b)

If no ID is specified APNS will generate and return a unique ID. When an expiration is specified, APNS will store and retry sending the notification until that time, otherwise APNS will not store or retry the notification. LowPriority should always be set when sending a ContentAvailable payload.

Custom values

To add custom values to an APS payload, use the Map method as follows:

p := payload.APS{
	Alert: payload.Alert{Body: "Message received from Bob"},
}
pm := p.Map()
pm["acme2"] = []string{"bang", "whiz"}

b, err := json.Marshal(pm)
if err != nil {
	log.Fatal(b)
}

id, err := service.Push(deviceToken, nil, b)

Error responses

Errors from service.Push or queue.Response could be HTTP errors or an error response from Apple. To access the Reason and HTTP Status code, you must convert the error to a push.Error as follows:

if e, ok := err.(*push.Error); ok {
	switch e.Reason {
	case push.ErrBadDeviceToken:
		// handle error
	}
}

Website Push

Before you can send push notifications through Safari and the Notification Center, you must provide a push package, which is a signed zip file containing some JSON and icons.

Use pushpackage to write a zip to a http.ResponseWriter or to a file. It will create the manifest.json and signature files for you.

pkg := pushpackage.New(w)
pkg.EncodeJSON("website.json", website)
pkg.File("icon.iconset/[email protected]", "static/[email protected]")
// other icons... (required)
if err := pkg.Sign(cert, nil); err != nil {
	log.Fatal(err)
}

NOTE: The filenames added to the zip may contain forward slashes but not back slashes or drive letters.

See example/website/ and the Safari Push Notifications documentation.

Wallet (Passbook) Pass

A pass is a signed zip file with a .pkpass extension and a application/vnd.apple.pkpass MIME type. You can use pushpackage to write a .pkpass that contains a pass.json file.

See example/wallet/ and the Wallet Developer Guide.

Related Projects

  • apns2 Alternative HTTP/2 APN provider library (Go)
  • go-apns-server Mock APN server (Go)
  • gorush A push notification server (Go)
  • Push Encryption Web Push for Chrome and Firefox (Go)
  • apns A Go package to interface with the Apple Push Notification Service (Timehop)
  • apns Utilities for Apple Push Notification and Feedback Services
  • micromdm Mobile Device Management server (Go)
  • Lowdown (Ruby)
  • Apnotic (Ruby)
  • Pigeon (Elixir, iOS and Android)
  • APNSwift (Swift)

More Repositories

1

XcodesApp

The easiest way to install and switch between multiple versions of Xcode - with a mouse click.
Swift
4,603
star
2

xcodes

The best command-line tool to install and switch between multiple versions of Xcode.
Swift
2,382
star
3

RPSlidingMenu

A collection view menu in the style of UltraVisual.
Objective-C
864
star
4

go-saml

A just good enough SAML client library written in Go.
Go
131
star
5

objective-c-style-guide

Our Objective-C coding style guide. Fall in line!
101
star
6

RPBorderlessSegmentedControl

A replica of Xcode 5's toolbar segmented controls.
Objective-C
93
star
7

terraform-ecs-autoscaling

A terraform module for creating an AWS autoscaling group for ECS
HCL
70
star
8

RPClarity

A Swift 1.2 playground that shows a technique for blurring an image behind the characters (glyphs) of one or more UILabels
Swift
42
star
9

RPInstantAlpha

Easily allow users to remove the background from an image, just like in iWork
Objective-C
30
star
10

1password-action

Import logins, passwords and documents from your 1Password vaults to use in your GitHub Action workflows.
TypeScript
30
star
11

stencil-xclangspec

Xcode syntax highlighting for Stencil
Shell
26
star
12

marvin

Slack bot written in Go
Go
24
star
13

go-swaggerLite

Framework agnostic Swagger API description generator
Go
20
star
14

terrible

Transform Terraform state into Ansible inventories
Python
18
star
15

Astro

Astro is a library, built in Swift, used to hold common utility methods.
Swift
17
star
16

Scribble

A Photoshop script that automatically annotates your PSDs with font information
JavaScript
11
star
17

Jeff

Record your screen as a GIF and share it anywhere with Dropbox
Objective-C
11
star
18

ErrorHandling

An easy way to thoroughly handle errors in SwiftUI, with support for retry/recovery and sign out.
Swift
7
star
19

AsyncHTTPNetworkService

A Network layer for Swift using Concurrency
Swift
7
star
20

pencilcase

Objective-C
6
star
21

json-github-editor

Modify JSON files in a GitHub repo with this structured, client-side editor that you host
JavaScript
5
star
22

homebrew-made

Ruby
4
star
23

react-gantry

R&P's React Starter Kit
SCSS
4
star
24

ex-puppeteer-img

Elixir Package to use the puppeteer-img command line tool to make website screenshots.
Elixir
4
star
25

RPJSContext

JSContext++
JavaScript
3
star
26

pegboard

Pegboard sets up your tools.
Shell
3
star
27

RoboSchema

Easily convert SQL Schemas to Salesforce
JavaScript
3
star
28

react-robits

Reusable React Components
JavaScript
2
star
29

ElectricBarn

Basic template for stubbing network requests with the MITMProxy libraries
Python
2
star
30

VRadventure

A Virtual Reality Adventure
Swift
2
star
31

EmitterGenerator

EmitterGenerator
Objective-C
2
star
32

heroku-buildpack-freetds

Shell
1
star
33

go-httpsign

Go middleware for signing and verifying http requests
Go
1
star
34

CharlesTrustCertificateLibrary

Android library to trust user installed CA certificates (e.g. the Charles Root Certificate)
1
star
35

SourceryTemplates

Our latest Sourcery templates for Swift code generation
1
star
36

FastBit-iOS

C++
1
star
37

feedbackassistant.apple.com

Repository containing sample projects for feedbackassistant.apple.com (nΓ©e radar.apple.com)
Swift
1
star
38

Scythe

Scythe cuts your Harvest ⛏
Swift
1
star
39

MainThreadChecker

Simple example of iOS 11's new, Main Thread Checker
Swift
1
star
40

cache-money-client

Go Client for the Azure GitHub Actions caching service.
Go
1
star
41

ExtendedBrowser

Extended Browser for Android
Java
1
star
42

puppeteer-img

Command link tool to make webpage screenshot images using puppeteer
JavaScript
1
star