- Notifications
You must be signed in to change notification settings - Fork36
A simple C Library for interact with the Apple Push Notification Service (APNs)
License
adobkin/libcapn
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
libcapn is a C Library to interact with theApple Push Notification Service (APNs for short) using simple and intuitive API.With the library you can easily send push notifications to iOS and OS X (>= 10.8) devices.
Version 2.0 isn't compatible with 1.0
Requirements
- CMake >= 2.8.5
- Clang 3 and later or GCC 4.6 and later
- make
Build instructions
$ git clone https://github.com/adobkin/libcapn.git$ git submodule update --init$ mkdir build$cd build$ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr ../$ make$ sudo make install
Requirements
Build instructions
Download the latest source archive fromGitHub and extract it somewhere on your disk, e.g.
C:\libcapn
Open command console (Win-R ==> "cmd" => Enter)
Go to the libcapn directory and run
win_build\build.bat
cd C:\libcapnwin_build\build.bat
First, initialize the library by callingapn_library_init()
. This function must be called at least once before any calls to otherlibcapn
functions. Becauseapn_library_init()
is not thread-safe, you must not call it while any other thread in the program is running.
The reason is thatapn_library_init()
calls initialization functions of SSL library that are not thread-safe.
Create a new apncontext
and specify the path to a certificate file and the path to a private key file usingapn_set_certificate()
.If the private key is password protected, pass it as well, otherwise passNULL
. The Certificate and the private key must be in PEM format.An alternative way is to use a .p12 file instead of a certificate and a private key. Useapn_set_pkcs12_file()
to specify the path to a .p12 file .If a .p12 file is specified, certificate and private key will be ignored.
apn_ctx_t*ctx=apn_init();if(!ctx) {// error}// Uses certificate and private key (in PEM format)apn_set_certificate(ctx,"push_test.pem","push_test_key.pem","12345678");// Uses .p12 fileapn_set_pkcs12_file(ctx,"push_test.p12","123");
By default the library uses production environment to interact with Apple Push Notification Service (APNs). Callapn_set_mode()
passingAPN_MODE_SANDBOX
touse sandbox environment.
Certificate and private key (or .p12 file) must conform to the specified mode, otherwise the notifications will not betransported to the device.
apn_set_mode(ctx,APN_MODE_SANDBOX);
To specify behavior callapn_set_behavior()
. Function takes one or more bit flags as a parameter:
apn_set_behavior(apn_ctx,APN_OPTION_RECONNECT |APN_OPTION_LOG_STDERR);
Available flags:
APN_OPTION_RECONNECT
- Automatically establish new connection when connection is dropped.APN_OPTION_LOG_STDERR
- Print log messages to standard error
For logging specify log level and pointer to callback-function usingapn_set_log_level()
andapn_set_log_callback()
:
voidlogfunc(apn_log_levellevel,constchar*constmessage,uint32_tlen) {printf("======> %s\n",message);}apn_set_log_level(ctx,APN_LOG_LEVEL_INFO |APN_LOG_LEVEL_ERROR |APN_LOG_LEVEL_DEBUG);apn_set_log_callback(ctx,logfunc);
To establishes connection to the APNs, callingapn_connect()
:
if(APN_ERROR==apn_connect(ctx)) {printf("Could not connected to Apple Push Notification Service: %s (errno: %d)\n",apn_error_string(errno),errno);// error}
Every remote notification includes a payload. The payload contains information about how the system should alertthe user as well as any custom data you provide.
To create a payload you need to useapn_payload_init()
; to set general properties of the payload, useapn_payload_set_*()
functions. You can also specifycustom properties usingapn_payload_add_custom_property_*()
functions:
apn_payload_t*payload=apn_payload_init();if(!payload) {printf("Unable to init payload: %s (%d)\n",apn_error_string(errno),errno);// error}apn_payload_set_badge(payload,10);apn_payload_set_body(payload,"Test Push Message");// Custom propertyapn_payload_add_custom_property_integer(payload,"custom_property_integer",100);...
In iOS 8 and later, the maximum size allowed for a payload is 2 kilobytes; prior to iOS 8and in OS X, the maximum payload size is 256 bytes. APNs rejects any notification that exceeds this limit.
A payload may contain thecontent-available
property. If this property is set to a value of 1, it lets the remote notification act as a “silent”notification. When a silent notification arrives, iOS wakes up your app in the background so that you can get new data from your server or do backgroundinformation processing. Users aren’t told about the new or changed information that results from a silent notification.
By default the library uses default priority to notifications. Callapn_payload_set_priority()
, passingAPN_NOTIFICATION_PRIORITY_HIGH
to use high priority:
apn_payload_set_priority(payload,APN_NOTIFICATION_PRIORITY_HIGH);
When you set high priority, notifications are sent immediately to devices. The notification must trigger an alert, sound, or badgeon the device. It is an error to use this priority for a push that contains only thecontent-available
key. When you set default priority, notifications are sent at a time thatconserves power on the device receiving them.
Next, create array of tokens and add the device tokens as either a hexadecimal string to array:
apn_array_t*tokens=apn_array_init(2,NULL,NULL);if(tokens) {apn_array_insert(tokens,"XXXXXXXX");apn_array_insert(tokens,"YYYYYYYY");apn_array_insert(tokens,"ZZZZZZZZ");}
Each push environment will issue a different token(s) for the same device or computer. The device token(s) for productionis different from the development one. If you are using a production mode, you must use a production token(s) and vice versa
To send notification to devices callapn_send()
, passingcontext
,payload
, array of devicetokens
and pointer to a invalid tokens array. The array should be freed - callapn_array_free()
:
apn_array_t*invalid_tokens=NULL;if(APN_ERROR==apn_send(ctx,payload,tokens,&invalid_tokens)) {printf("Could not sent push: %s (errno: %d)\n",apn_error_string(errno),errno)}else {if (invalid_tokens) {printf,"Invalid tokens:\n");uint32_ti=0;for (;i<apn_array_count(invalid_tokens);i++) {printf(" %u. %s\n",i,apn_array_item_at_index(invalid_tokens,i)); }apn_array_free(invalid_tokens); }}
The APNs drops the connection if it receives an invalid token. You'll need to reconnect and send notification to token(s)following it, again.
If flagAPN_OPTION_RECONNECT
is specified, theapn_send()
automatically establishes new connection to APNs when connection is dropped
Advanced, you can take invalid token, just specify a pointer to callback-function usingapn_set_invalid_token_callback
:
voidinvalid_token(constchar*consttoken,uint32_tindex) {printf("======> Invalid token: %s (index: %d)\n",token,index);}...apn_ctx_t*ctx= ...apn_set_invalid_token_callback(ctx,invalid_token);
The callback function will be called for each invalid token. Function has the following prototype:
void (*invalid_token_callback)(constchar*consttoken,uint32_tindex)
#include<stdio.h>#include<string.h>#include<errno.h>#include<assert.h>#include<capn/apn.h>void__apn_logging(apn_log_levelslevel,constchar*constmessage,uint32_tlen) {printf("======> %s\n",message);}void__apn_invalid_token(constchar*consttoken,uint32_tindex) {printf("======> Invalid token: %s (index: %d)\n",token,index);}intmain() {apn_payload_t*payload=NULL;apn_ctx_t*ctx=NULL;time_ttime_now=0;char*invalid_token=NULL;assert(apn_library_init()==APN_SUCCESS);time(&time_now);if(NULL== (ctx=apn_init())) {printf("Unable to init context: %d\n",errno);apn_library_free();return-1; }apn_set_pkcs12_file(ctx,"push_test.p12","12345678");apn_set_mode(ctx,APN_MODE_SANDBOX);//APN_MODE_PRODUCTION or APN_MODE_SANDBOXapn_set_behavior(ctx,APN_OPTION_RECONNECT);apn_set_log_level(ctx,APN_LOG_LEVEL_INFO |APN_LOG_LEVEL_ERROR |APN_LOG_LEVEL_DEBUG);apn_set_log_callback(ctx,__apn_logging);apn_set_invalid_token_callback(ctx,__apn_invalid_token);if(NULL== (payload=apn_payload_init())) {printf("Unable to init payload: %d\n",errno);apn_free(ctx);apn_library_free();return-1; }apn_payload_set_badge(payload,10);// Icon badgeapn_payload_set_body(payload,"Test Push Message");// Notification textapn_payload_set_expiry(payload,time_now+3600);// Expiresapn_payload_set_priority(payload,APN_NOTIFICATION_PRIORITY_HIGH);// Notification priorityapn_payload_add_custom_property_integer(payload,"custom_property_integer",100);// Custom propertyapn_array_t*tokens=apn_array_init(2,NULL,NULL);if(!tokens) {apn_free(ctx);apn_payload_free(payload);apn_library_free();return-1; }apn_array_insert(tokens,"XXXXXXXX");apn_array_insert(tokens,"YYYYYYYY");apn_array_insert(tokens,"ZZZZZZZZ");if(APN_ERROR==apn_connect(ctx)) {printf("Could not connect to Apple Push Notification Service: %s (errno: %d)\n",apn_error_string(errno),errno);apn_free(ctx);apn_payload_free(payload);apn_array_free(tokens);apn_library_free();return-1; }apn_array_t*invalid_tokens=NULL;intret=0;if (APN_ERROR==apn_send(ctx,payload,tokens,&invalid_tokens)) {printf("Could not send push: %s (errno: %d)\n",apn_error_string(errno),errno);ret=-1; }else {printf("Notification was successfully sent to %u device(s)\n",apn_array_count(tokens)- ((invalid_tokens) ?apn_array_count(invalid_tokens) :0));if (invalid_tokens) {printf("Invalid tokens:\n");uint32_ti=0;for (;i<apn_array_count(invalid_tokens);i++) {printf(" %u. %s\n",i,apn_array_item_at_index(invalid_tokens,i)); }apn_array_free(invalid_tokens); } }apn_free(ctx);apn_payload_free(payload);apn_array_free(tokens);apn_library_free();returnret;}
apn-pusher - simple command line tool to send push notifications to iOS and OS X devices:
apn-pusher -c ./test_push.p12 -p -d -m'Test' -t 1D2EE2B3A38689E0D43E6608FEDEFCA534BBAC6AD6930BFDA6F5CD72A808832B:1D2EE2B3A38689E0D43E6608FEDEFCA534BBAC6AD6930BFDA6F5CD72A808832A
apn-pusher -c ./test_push.p12 -p -d -m'Test' -T ./tokens.txt -v
Options:
Usage: apn-pusher [OPTION] -h Print this message andexit -c Path to .p12 file (required) -p Passphrasefor .p12 file. Will be asked from the tty -d Use sandbox mode -m Body of the alert to sendin notification -a Indicates content available -b Badge number toset with notification -s Name of a sound filein the app bundle -i Name of an image filein the app bundle -y Category name of notification -t Tokens, separated with':' (required) -T Path to file with tokens -v Make the operation more talkative
About
A simple C Library for interact with the Apple Push Notification Service (APNs)