After researching languages and choosing Go to implement a push provider for
OmniFocus, we needed to get started writing code. Apple has set out the
interface for a provider in the chapter “Provider Communication with Apple Push
Notification
Service;”
our task then became to write a server that could speak in the binary format
APNs expected.

Every notification delivered to Apple is built of a series of items. Each
item details one part of the notification, such as its JSON payload or metadata
like its priority or expiration date. Items have a common format: each begins
with one byte giving the item type, then two bytes giving its total length. All
the actual information in the item follows that three-byte “header.”

This is pretty straightforward to represent in Go: we just need a struct whose
layout matches the expected format of an item. Let’s write one now:

type Item struct {
ID byte
dataLength uint16
data []byte
}

From this basic definition, we can represent all the different kinds of item
that might appear in an APNs notification. Since the data in an item is stored
in its encoded (byte slice) form, we can also write this item to a binary buffer
for transmission to Apple very easily:

We can also take advantage of Go’s iota
construct inside constant declarations
to define names for each kind of item that Apple documents. Since the items are
1-indexed, we simply define the first as 1 + iota and let the language go from
there:

While some items are a little more complex than this one-liner, in general,
creating any single item is simply a matter of parsing its data into a byte
slice and returning one of these structs. We can then begin composing these
items into larger pieces of data for more convenient use.

The next step is to build an entire frame for transmission to Apple. A frame
is simply a list of items, all serialized next to each other and wrapped with a
few more bytes’ worth of header data. We can take a similar approach for
building frames as we did for items: create a struct that contains a slice of
Item structs, then implement a Bytes() function for that struct that
recursively encodes all the contained Items and adds the required header data.

Strictly speaking, this is all our push provider needs to start sending
notifications! We can construct frames full of items, serialize them, and send
them to Apple. However, we’ll probably want a little more metadata internally to
help our notifications along. At the very least, we’ll need to know the bundle
ID associated with each notification – since the connection we establish to
APNs is specific to one app’s bundle ID, and we’re providing push services for
multiple apps, we’ll need a way to distinguish between different notifications
so we know which connection to use.

To handle this, we wrap up our Frame in one more top-level struct: the
Notification. All this struct does is provide information that our provider
tracks internally – it doesn’t send anything extra to Apple. We define it as:

This last field is a little quirky: it maps strings to interface{}, which is
Go’s “anything” type. With this field, the provider yields a bit to Objective-C
– we can attach any extra bits of data that we want internally in this
UserInfo map, then pull them back out later. We’ll see an example of how this
is used in a future post.

At this point, we’re ready to start talking to Apple! We have representations of
all the different pieces of data that the APNs binary interface expects, at
least for sending notifications. In the next post, we’ll explore how the push
provider connects to the APNs gateway.