apnsclient Package

Apple Push Notification service client. Only public API is documented here to limit visual clutter. Refer to the sources if you want to extend this library. Check Getting Started for usage examples.

apnsclient Package

class apnsclient.transport.Session(pool='apnsclient.backends.stdio', connect_timeout=10, write_buffer_size=2048, write_timeout=20, read_buffer_size=2048, read_timeout=20, read_tail_timeout=3, **pool_options)

The front-end to the underlying connection pool. The purpose of this class is to hide the transport implementation that is being used for networking. Default implementation uses built-in python sockets and select for asynchronous IO.

Arguments:
  • pool (str, type or object): networking layer implementation.
  • connect_timeout (float): timeout for new connections.
  • write_buffer_size (int): chunk size for sending the message.
  • write_timeout (float): maximum time to send single chunk in seconds.
  • read_buffer_size (int): feedback buffer size for reading.
  • read_timeout (float): timeout for reading single feedback block.
  • read_tail_timeout (float): timeout for reading status frame after message is sent.
  • pool_options (kwargs): passed as-is to the pool class on instantiation.
get_connection(address='push_sanbox', certificate=None, **cert_params)

Obtain cached connection to APNs.

Session caches connection descriptors, that remain open after use. Caching saves SSL handshaking time. Handshaking is lazy, it will be performed on first message send.

You can provide APNs address as (hostname, port) tuple or as one of the strings:

  • push_sanbox – ("gateway.sandbox.push.apple.com", 2195), the default.
  • push_production – ("gateway.push.apple.com", 2195)
  • feedback_sandbox – ("feedback.sandbox.push.apple.com", 2196)
  • feedback_production – ("feedback.push.apple.com", 2196)
Arguments:
  • address (str or tuple): target address.
  • certificate (BaseCertificate): provider’s certificate instance.
  • cert_params (kwargs): BaseCertificate arguments, used if certificate instance is not given.
new_connection(address='feedback_sandbox', certificate=None, **cert_params)

Obtain new connection to APNs. This method will not re-use existing connection from the pool. The connection will be closed after use.

Unlike get_connection() this method does not cache the connection. Use it to fetch feedback from APNs and then close when you are done.

Arguments:
  • address (str or tuple): target address.
  • certificate (BaseCertificate): provider’s certificate instance.
  • cert_params (kwargs): BaseCertificate arguments, used if certificate instance is not given.
outdate(delta)

Close open unused connections in the pool that are left untouched for more than delta time.

You may call this method in a separate thread or run it in some periodic task. If you don’t, then all connections will remain open until session is shut down. It might be an issue if you care about your open server connections.

Arguments:delta (timedelta): maximum age of unused connection.
shutdown()

Shutdown all connections in the pool. This method does will not close connections being use at the calling time.

class apnsclient.apns.APNs(connection)

APNs client.

Arguments:
  • connection (Connection): the connection to talk to.
feedback()

Fetch feedback from APNs.

The method returns generator of (token, datetime) pairs, denoting the timestamp when APNs has detected the device token is not available anymore, probably because application was uninstalled. You have to stop sending notifications to that device token unless it has been re-registered since reported timestamp.

Unlike sending the message, you should fetch the feedback using non-cached connection. Once whole feedback has been read, this method will automatically close the connection.

Note

If the client fails to connect to APNs, probably because your network is down, then this method will raise the related exception. However, if connection is successfully established, but later on the IO fails, then this method will simply stop iterating. The rest of the failed tokens will be delivered during the next feedback session.

Example:

session = Session()
# get non-cached connection, free from possible garbage
con = session.new_connection("feedback_production", cert_string=db_certificate)
service = APNs(con)
try:
    # on any IO failure after successfull connection this generator
    # will simply stop iterating. you will pick the rest of the tokens
    # during next feedback session.
    for token, when in service.feedback():
        # every time a devices sends you a token, you should store
        # {token: given_token, last_update: datetime.datetime.now()}
        last_update = get_last_update_of_token(token)

        if last_update < when:
            # the token wasn't updated after the failure has
            # been reported, so the token is invalid and you should
            # stop sending messages to it.
            remove_token(token)
except:
    print "Check your network, I could not connect to APNs"
Returns:generator over (binary, datetime)
send(message)

Send the message.

The method will block until the whole message is sent. The method returns Result object, which you can examine for possible errors and retry attempts.

Note

If the client fails to connect to APNs, probably because your network is down, then this method will raise the related exception. However, if connection is successfully established, but later on the IO fails, then this method will prepare a retry message with the rest of the failed tokens.

Example:

# if you use cached connections, then store this session instance
# somewhere global, such that it will not be garbage collected
# after message is sent.
session = Session()
# get a cached connection, avoiding unnecessary SSL handshake
con = session.get_connection("push_production", cert_string=db_certificate)
message = Message(["token 1", "token 2"], alert="Message")
service = APNs(con)
try:
    result = service.send(message)
except:
    print "Check your network, I could not connect to APNs"
else:
    for token, (reason, explanation) in result.failed.items():
        delete_token(token) # stop using that token

    for reason, explanation in result.errors:
        pass # handle generic errors

    if result.needs_retry():
        # extract failed tokens as new message
        message = message.retry()
        # re-schedule task with the new message after some delay
Returns:Result object with operation results.
class apnsclient.apns.Message(tokens, alert=None, badge=None, sound=None, content_available=None, expiry=None, payload=None, priority=10, extra=None, **extra_kwargs)

The push notification to one or more device tokens.

Read more about the payload.

Note

In order to stay future compatible this class doesn’t transform provided arguments in any way. It is your responsibility to provide correct values and ensure the payload does not exceed the limit of 256 bytes. You can also generate whole payload yourself and provide it via payload argument. The payload will be parsed to init default fields like alert and badge. However if parsing fails, then these standard fields will become unavailable. If raw payload is provided, then other data fields like alert or sound are not allowed.

Arguments:
  • tokens (str or list): set of device tokens where to the message will be sent.

  • alert (str or dict): the message; read APNs manual for recognized dict keys.

  • badge (int or str): badge number over the application icon or special value such as “increment”.

  • sound (str): sound file to play on arrival.

  • content_available (int): set to 1 to indicate new content is available.

  • expiry (int, datetime or timedelta): timestamp when message will expire.

  • payload (dict or str): JSON-compatible dictionary with the

    complete message payload. If supplied, it is given instead of all the other, more specific parameters.

  • priority (int): priority of the message, defaults to 10

  • extra (dict): extra payload key-value pairs.

  • extra_kwargs (kwargs): extra payload key-value paris, will be merged with extra.

__getstate__()

Returns dict with __init__ arguments.

If you use pickle, then simply pickle/unpickle the message object. If you use something else, like JSON, then:

# obtain state dict from message
state = message.__getstate__()
# send/store the state
# recover state and restore message
message_copy = Message(**state)

Note

The message keeps expiry internally as a timestamp (integer). So, if values of all other arguments are JSON serializable, then the returned state must be JSON serializable. If you get TypeError when you instantiate Message from JSON recovered state, then make sure the keys are str, not unicode.

Returns:kwargs for Message constructor.
tokens

List target device tokens.

class apnsclient.apns.Result(message, failure=None)

Result of send operation.

errors

Returns list of (reason, explanation) pairs denoting severe errors, not related to failed tokens. The reason is an integer code as described in APNs tutorial.

The following codes are considered to be errors:
  • (1, "Processing error")
  • (3, "Missing topic")
  • (4, "Missing payload")
  • (6, "Invalid topic size")
  • (7, "Invalid payload size")
  • (None, "Unknown"), usually some kind of IO failure.
failed

Reports failed tokens as {token : (reason, explanation)} mapping.

Current APNs protocols bails out on first failed device token, so the returned dict will contain at most 1 entry. Future extensions may upgrade to multiple failures in a batch. The reason is the integer code as described in APNs tutorial.

The following codes are considered to be token failures:
  • (2, "Missing device token")
  • (5, "Invalid token size")
  • (8, "Invalid token")
needs_retry()

Returns True if there are tokens that should be retried.

Note

In most cases if needs_retry is true, then the reason of incomplete batch is to be found in errors and failed properties. However, Apple added recently a special code 10 - Shutdown, which indicates server went into a maintenance mode before the batch completed. This response is not really an error, so the before mentioned properties will be empty, while needs_retry will be true.

retry()

Returns Message with device tokens that can be retried.

Current APNs protocol bails out on first failure, so any device token after the failure should be retried. If failure was related to the token, then it will appear in failed set and will be in most cases skipped by the retry message.