66 Commits

Author SHA1 Message Date
Leo Vandriel c91a8e08c4 Merge pull request #62 from ClementPadovani/hotfix/make_plain_text_great_again
Removed all notions of rich text and disabled “smart” additions
2018-01-26 12:52:31 -08:00
Clément Padovani 6a8a48dfd9 Removed all notions of rich text and disabled “smart” additions 2017-12-30 20:50:11 +01:00
Leo 5b46a5c6de add certificate type to description 2017-04-26 11:06:32 -07:00
Leo a854649e09 bump version 2017-04-25 15:27:20 -07:00
Leo 36de866909 update changelog 2017-04-25 15:27:14 -07:00
Leo Vandriel 9371147fd1 Add support for new certificate type (passes) 2017-04-25 13:59:17 -07:00
Leonard van Driel 60288f8454 Merge pull request #49 from ClementPadovani/hotfix/rich_text_copy_paste
Disabled rich text.
2017-04-04 10:07:37 -07:00
Clément Padovani 5b4a2e5e94 Disabled rich text. 2017-04-01 13:07:33 +02:00
Leo Vandriel 2d1b534f4d fix app name in menu, issue #47 2017-03-20 11:43:42 -07:00
Leo Vandriel 26d42ca585 add docs pushing to macOS (issue by dylib) 2017-03-13 15:22:49 -07:00
Leo Vandriel 900b107dc0 bump version 2017-01-16 12:53:03 -08:00
Leo Vandriel 65738cad39 add support for ssl handshake internal error 2017-01-16 12:43:47 -08:00
Leo Vandriel ff5768048c add detection for p12 without password 2017-01-16 12:24:29 -08:00
Leonard van Driel 9b6770afe1 Merge pull request #35 from JanC/fix_umbrella_header
Fixed missing umbrella header
2016-12-04 11:29:20 -08:00
Jan Chaloupecky b4c0e1e72b Fixed missing umbrella header 2016-11-09 16:32:56 +01:00
Leo Vandriel 5bab81d099 add firewall info in readme 2016-09-26 09:16:50 -07:00
Leo Vandriel 3622125a62 bump version 2016-09-19 11:21:28 -07:00
Leo Vandriel 4850bfbb38 update touch project 2016-09-19 10:56:35 -07:00
Leo Vandriel 9dd461a972 add support for unknown certificate error 2016-09-19 10:55:14 -07:00
Leo Vandriel 0469f7ae05 update changelog
\ 2016-09-19 10:40:40 -07:00
Leonard van Driel fc18d96ff4 Merge pull request #24 from DanielFontes/master
Add support for WatchKit certificates
2016-09-19 10:38:25 -07:00
Leonard van Driel bd5d2e80f5 Merge pull request #25 from ReadmeCritic/master
Update README URLs based on HTTP redirects
2016-08-23 11:05:43 -07:00
ReadmeCritic bdbeb1be5f Update README URLs based on HTTP redirects 2016-08-08 08:40:57 -07:00
Daniel Fontes d0868e486c Add support for WatchKit certificates 2016-08-05 15:22:09 +02:00
Leo Vandriel 766aee9700 bump version 2016-07-19 16:12:41 -07:00
Leonard van Driel 8c4e208eda Merge pull request #23 from zats/master
Update readme
2016-07-18 15:52:35 -07:00
Sash Zats 9325a4ac64 Update README.md 2016-07-18 15:10:42 -07:00
Sash Zats bee2611e60 Update README.md 2016-07-18 15:09:39 -07:00
Leonard van Driel e638a42547 Merge pull request #22 from zats/master
Extract OS X and iOS frameworks to allow modularity
2016-07-18 14:52:28 -07:00
Sash Zats a8c6176b04 Add shared schemes 2016-07-17 16:22:08 -07:00
Sash Zats b5d1acba22 Extract functionality into corresponding frameworks 2016-07-17 16:17:10 -07:00
Leo Vandriel 7474d4fba4 bump version 2016-04-27 13:52:13 -07:00
Leo Vandriel 9570efd717 remove mac enum from touch target 2016-04-27 13:52:00 -07:00
Leo Vandriel 671c168e56 bump version 2016-01-07 16:08:55 -08:00
Leo Vandriel dd354b9629 fix token cache on connection 2016-01-07 15:41:03 -08:00
Leo Vandriel a8cd4e598d add deprecated methods 2016-01-07 15:30:31 -08:00
Leo Vandriel 2458c41eb6 Merge branch '666tos-master' 2016-01-07 15:27:50 -08:00
Leo Vandriel a4215b3f06 Merge branch 'master' of https://github.com/666tos/NWPusher into 666tos-master
# Conflicts:
#	Classes/NWSecTools.m
2016-01-07 15:27:30 -08:00
Leo Vandriel 0078f3d9fe bump version 2015-12-20 16:32:54 -08:00
Leo Vandriel 57be4eecd9 add void cert support 2015-12-20 16:30:24 -08:00
Leo Vandriel 504ab4d111 add errSSLClosedAbort (-9806) error with SSL handshake 2015-12-20 16:09:11 -08:00
Leo Vandriel 4f83e4ae03 Merge branch 'omarkj-omarkj-support-web-push' 2015-12-19 20:26:46 -08:00
Leo Vandriel fee9e1ba80 Merge branch 'omarkj-support-web-push' of https://github.com/omarkj/NWPusher into omarkj-omarkj-support-web-push
# Conflicts:
#	Classes/NWSecTools.m
2015-12-19 20:26:18 -08:00
Leo Vandriel d4af68951f update project settings 2015-12-19 19:57:43 -08:00
Leo Vandriel 49ca3dd04a add simplified certificate handling 2015-12-19 19:57:09 -08:00
Ómar Kjartan Yasin 8ce6167bf2 Add support for Web Push
Safari can setup Web Push notifications. Those
differ from both Mac Push Notification and iOS
notifications in that they are configured and
prompted from Safari - and are managed by Safari.

I have created a few certificates using the online
console as development, but Apple doesn’t seem to
support the Sandbox for Web Push.
2015-10-19 17:03:25 -07:00
Leo Vandriel 97b9f54d60 add dark wake error 2015-05-13 18:00:27 +02:00
Nikita Ivaniushchenko 4bf0730f90 fixed reconnection to server 2015-03-03 10:09:48 +01:00
Nikita Ivaniushchenko 1d88d5284d Added possibility to use VoIP certificates used for PushKit.
Added possiblity to switch server on-the-fly (necessary for VoIP pushes).
2015-02-23 17:29:45 +01:00
Leo Vandriel f1fc60312a bump version 2015-01-22 15:57:58 -08:00
Leo Vandriel 911d456b2d add expiration date to certificate listing 2015-01-22 15:55:36 -08:00
Leo Vandriel 6bf99f4906 add error reason to error info dict 2015-01-15 17:47:46 -08:00
Leo Vandriel 95e1e2c90d fix string format argument int 2015-01-15 11:46:26 -08:00
Leo Vandriel 7e623e8ece bump version 2015-01-15 11:41:45 -08:00
Leo Vandriel d92a31d302 add underlying error reason code 2015-01-15 11:38:52 -08:00
Leo Vandriel f6b9ff9905 bump version 2015-01-14 15:30:24 -08:00
Leo Vandriel db1795aa38 add additional ssl handshake error codes 2015-01-14 15:24:22 -08:00
Leo Vandriel 4671c607ff add cocoadocs link 2014-11-12 11:54:34 +01:00
Leo Vandriel db26eef28a update docs 2014-11-09 23:02:27 +01:00
Leo Vandriel 03ed94c746 update images 2014-10-29 15:14:37 -07:00
Leo Vandriel a47eef9bed bump version 2014-10-29 14:33:26 -07:00
Leo Vandriel 60fc2d62b9 add icon 2014-10-29 11:40:54 -07:00
Leo Vandriel bb1e33479e fix layout issues 2014-10-28 22:24:53 -07:00
Leo Vandriel 11beb0ad7f remove knwsuccess 2014-10-28 20:16:13 -07:00
Leo Vandriel 3d464c937a tweak ssl connection handshake retry 2014-10-28 20:12:55 -07:00
Leo Vandriel 7151d861c9 remove deprecated syntax 2014-10-28 20:06:16 -07:00
30 changed files with 1528 additions and 508 deletions
+54
View File
@@ -3,6 +3,60 @@ Change Log
### master (unreleased)
* add certificate type to description
### 0.7.5 (2017-04-25)
* Add support for new certificate type (passes)
* Fix rich text (#49)
* Fix app name (#47)
* Update docs pushing to macOS
### 0.7.4 (2017-01-16)
* Add support for handshake error (internal error)
* Add detection of p12 without password
### 0.7.3 (2016-09-19)
* Add support for Watch Kit certificates (DanielFontes)
* Add support for handshake error (certificate unknown)
### 0.7.2 (2016-07-19)
* Added support for Carthage, thanks to @zats
### 0.7.1 (2016-04-27)
* Remove Mac enum from Touch target
### 0.7.0 (2016-01-07)
* Add support for simplified certificates (pull request by 666tos)
### 0.6.4 (2015-12-20)
* Add support for new certificate types (web, simplified, voip)
* Add support for handshake errors (dark wake and closed abort)
### 0.6.3 (2015-01-22)
* Add certificate expiration date to listing
* Add expiration and revocation error message
### 0.6.2 (2015-01-15)
* Add underlying error reason code
### 0.6.1 (2015-01-14)
* Add SSL handshake error codes
### 0.6.0 (2014-10-30)
* Remove kNWSuccess
* Remove deprecated
### 0.5.4 (2014-10-28)
* Deprecate fetching
+10 -15
View File
@@ -17,13 +17,11 @@
@protocol NWHubDelegate <NSObject>
/** The notification failed during or after pushing. */
- (void)notification:(NWNotification *)notification didFailWithError:(NSError *)error;
@optional
- (void)notification:(NWNotification *)notification didFailWithResult:(NWError)result; // TODO: deprecated, remove from 0.6.0
@end
/** Helper on top of `NWPusher` that hides the details of pushing and reading.
This class provides a more convenient way of pushing notifications to the APNS server. It deals with the trouble of assigning a unique identifier to every notification and the handling of error responses from the server. It hides the latency that comes with transmitting the pushes, allowing you to simply push your notifications and getting notified of errors through the delegate. If this feels over-abstracted, then definitely check out the `NWPusher` class, which will give you full control.
This class provides a more convenient way of pushing notifications to the APNs. It deals with the trouble of assigning a unique identifier to every notification and the handling of error responses from the server. It hides the latency that comes with transmitting the pushes, allowing you to simply push your notifications and getting notified of errors through the delegate. If this feels over-abstracted, then definitely check out the `NWPusher` class, which will give you full control.
There are two set of methods for pushing notifications: the easy and the pros. The former will just do the pushing and reconnect if the connection breaks. This is your low-worry solution, provided that you call `readFailed` every so often (seconds) to handle error data from the server. The latter will give you a little more control and a little more responsibility.
*/
@@ -55,18 +53,18 @@
- (instancetype)initWithPusher:(NWPusher *)pusher delegate:(id<NWHubDelegate>)delegate;
/** Create, connect and returns an instance with delegate and identity. */
+ (instancetype)connectWithDelegate:(id<NWHubDelegate>)delegate identity:(NWIdentityRef)identity error:(NSError **)error;
+ (instancetype)connectWithDelegate:(id<NWHubDelegate>)delegate identity:(NWIdentityRef)identity environment:(NWEnvironment)environment error:(NSError **)error;
/** Create, connect and returns an instance with delegate and identity. */
+ (instancetype)connectWithDelegate:(id<NWHubDelegate>)delegate PKCS12Data:(NSData *)data password:(NSString *)password error:(NSError **)error;
+ (instancetype)connectWithDelegate:(id<NWHubDelegate>)delegate PKCS12Data:(NSData *)data password:(NSString *)password environment:(NWEnvironment)environment error:(NSError **)error;
/** @name Connecting */
/** Connect the pusher using the identity to setup the SSL connection. */
- (BOOL)connectWithIdentity:(NWIdentityRef)identity error:(NSError **)error;
- (BOOL)connectWithIdentity:(NWIdentityRef)identity environment:(NWEnvironment)environment error:(NSError **)error;
/** Connect the pusher using the PKCS #12 data to setup the SSL connection. */
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError **)error;
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password environment:(NWEnvironment)environment error:(NSError **)error;
/** Reconnect with the server, to recover from a closed or defect connection. */
- (BOOL)reconnectWithError:(NSError **)error;
@@ -123,7 +121,7 @@
/** Read the response from the server and reconnect if anything failed.
If the APNS server finds something wrong with a notification, it will write back the identifier and error code. As this involves transmission to and from the server, it takes just a little while to get this failure info. This method should therefore be invoked a little (say a second) after pushing to see if anything was wrong. On a slow connection this might take longer than the interval between push messages, in which case the reported notification was *not* the last one sent.
If the APNs finds something wrong with a notification, it will write back the identifier and error code. As this involves transmission to and from the server, it takes just a little while to get this failure info. This method should therefore be invoked a little (say a second) after pushing to see if anything was wrong. On a slow connection this might take longer than the interval between push messages, in which case the reported notification was *not* the last one sent.
From the server we only get the notification identifier and the error message. This method translates this back into the original notification by keeping track of all notifications sent in the past 30 seconds. If somehow the original notification cannot be found, it will assign `NSNull`.
@@ -147,12 +145,9 @@
// deprecated
- (NWError)connectWithIdentity:(NWIdentityRef)identity __deprecated;
- (NWError)connectWithPKCS12Data:(NSData *)data password:(NSString *)password __deprecated;
- (NWError)reconnect __deprecated;
- (NSUInteger)pushNotifications:(NSArray *)notifications autoReconnect:(BOOL)reconnect __deprecated;
- (NSUInteger)flushFailed __deprecated;
- (NSUInteger)fetchFailed __deprecated;
- (BOOL)fetchFailed:(BOOL *)failed autoReconnect:(BOOL)reconnect error:(NSError **)error __deprecated;
+ (instancetype)connectWithDelegate:(id<NWHubDelegate>)delegate identity:(NWIdentityRef)identity error:(NSError **)error __deprecated;
+ (instancetype)connectWithDelegate:(id<NWHubDelegate>)delegate PKCS12Data:(NSData *)data password:(NSString *)password error:(NSError **)error __deprecated;
- (BOOL)connectWithIdentity:(NWIdentityRef)identity error:(NSError **)error __deprecated;
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError **)error __deprecated;
@end
+16 -44
View File
@@ -42,14 +42,14 @@
#pragma mark - Connecting
- (BOOL)connectWithIdentity:(NWIdentityRef)identity error:(NSError *__autoreleasing *)error
- (BOOL)connectWithIdentity:(NWIdentityRef)identity environment:(NWEnvironment)environment error:(NSError *__autoreleasing *)error
{
return [_pusher connectWithIdentity:identity error:error];
return [_pusher connectWithIdentity:identity environment:environment error:error];
}
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError *__autoreleasing *)error
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password environment:(NWEnvironment)environment error:(NSError *__autoreleasing *)error
{
return [_pusher connectWithPKCS12Data:data password:password error:error];
return [_pusher connectWithPKCS12Data:data password:password environment:environment error:error];
}
- (BOOL)reconnectWithError:(NSError *__autoreleasing *)error
@@ -62,16 +62,16 @@
[_pusher disconnect];
}
+ (instancetype)connectWithDelegate:(id<NWHubDelegate>)delegate identity:(NWIdentityRef)identity error:(NSError *__autoreleasing *)error
+ (instancetype)connectWithDelegate:(id<NWHubDelegate>)delegate identity:(NWIdentityRef)identity environment:(NWEnvironment)environment error:(NSError *__autoreleasing *)error
{
NWHub *hub = [[NWHub alloc] initWithDelegate:delegate];
return identity && [hub connectWithIdentity:identity error:error] ? hub : nil;
return identity && [hub connectWithIdentity:identity environment:environment error:error] ? hub : nil;
}
+ (instancetype)connectWithDelegate:(id<NWHubDelegate>)delegate PKCS12Data:(NSData *)data password:(NSString *)password error:(NSError *__autoreleasing *)error
+ (instancetype)connectWithDelegate:(id<NWHubDelegate>)delegate PKCS12Data:(NSData *)data password:(NSString *)password environment:(NWEnvironment)environment error:(NSError *__autoreleasing *)error
{
NWHub *hub = [[NWHub alloc] initWithDelegate:delegate];
return data && [hub connectWithPKCS12Data:data password:password error:error] ? hub : nil;
return data && [hub connectWithPKCS12Data:data password:password environment:environment error:error] ? hub : nil;
}
#pragma mark - Pushing without NSError
@@ -123,9 +123,6 @@
BOOL pushed = [_pusher pushNotification:notification type:_type error:&e];
if (!pushed) {
if (error) *error = e;
if ([_delegate respondsToSelector:@selector(notification:didFailWithResult:)]) {
[_delegate notification:notification didFailWithResult:e.code];
}
if ([_delegate respondsToSelector:@selector(notification:didFailWithError:)]) {
[_delegate notification:notification didFailWithError:e];
}
@@ -188,9 +185,6 @@
if (apnError) {
NWNotification *n = _notificationForIdentifier[@(identifier)][0];
if (notification) *notification = n ?: (NWNotification *)NSNull.null;
if ([_delegate respondsToSelector:@selector(notification:didFailWithResult:)]) {
[_delegate notification:n didFailWithResult:apnError.code];
}
if ([_delegate respondsToSelector:@selector(notification:didFailWithError:)]) {
[_delegate notification:n didFailWithError:apnError];
}
@@ -213,46 +207,24 @@
#pragma mark - Deprecated
- (NWError)connectWithIdentity:(NWIdentityRef)identity
- (BOOL)connectWithIdentity:(NWIdentityRef)identity error:(NSError *__autoreleasing *)error
{
NSError *error = nil;
return [self connectWithIdentity:identity error:&error] ? kNWSuccess : error.code;
return [self connectWithIdentity:identity environment:NWEnvironmentAuto error:error];
}
- (NWError)connectWithPKCS12Data:(NSData *)data password:(NSString *)password
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError *__autoreleasing *)error
{
NSError *error = nil;
return [self connectWithPKCS12Data:data password:password error:&error] ? kNWSuccess : error.code;
return [self connectWithPKCS12Data:data password:password environment:NWEnvironmentAuto error:error];
}
- (NWError)reconnect
+ (instancetype)connectWithDelegate:(id<NWHubDelegate>)delegate identity:(NWIdentityRef)identity error:(NSError *__autoreleasing *)error
{
NSError *error = nil;
return [self reconnectWithError:&error] ? kNWSuccess : error.code;
return [self connectWithDelegate:delegate identity:identity environment:NWEnvironmentAuto error:error];
}
- (NSUInteger)pushNotifications:(NSArray *)notifications autoReconnect:(BOOL)reconnect
+ (instancetype)connectWithDelegate:(id<NWHubDelegate>)delegate PKCS12Data:(NSData *)data password:(NSString *)password error:(NSError *__autoreleasing *)error
{
NSAssert(reconnect, @"autoReconnect == false is ignored");
return [self pushNotifications:notifications];
}
- (NSUInteger)flushFailed
{
return [self readFailed];
}
- (NSUInteger)fetchFailed
{
return [self readFailed];
}
- (BOOL)fetchFailed:(BOOL *)failed autoReconnect:(BOOL)reconnect error:(NSError *__autoreleasing *)error
{
NWNotification *n = nil;
BOOL r = [self readFailed:&n autoReconnect:reconnect error:error];
if (failed) *failed = !!n;
return r;
return [self connectWithDelegate:delegate identity:data environment:NWEnvironmentAuto error:error];
}
@end
+10 -11
View File
@@ -10,9 +10,9 @@
@class NWSSLConnection;
/** Reads tokens and dates from the APNS Feedback Service.
/** Reads tokens and dates from the APNs feedback service.
The Feedback Service is a separate server that provides a list of all device tokens that it tried to deliver a notification to, but was unable to. This usually indicates that this device no longer has the app installed. This way, the Feedback Service provides reliable way of finding out who uninstalled the app, which can be fed back into your database.
The feedback service is a separate server that provides a list of all device tokens that it tried to deliver a notification to, but was unable to. This usually indicates that this device no longer has the app installed. This way, the feedback service provides reliable way of finding out who uninstalled the app, which can be fed back into your database.
Apple recommends reading from the service once a day. After a device token has been read, it will not be returned again until the next failed delivery. In practice: connect once a day, read all device tokens, and update your own database accordingly.
@@ -27,18 +27,18 @@
/** @name Initialization */
/** Setup connection with feedback service based on identity. */
+ (instancetype)connectWithIdentity:(NWIdentityRef)identity error:(NSError **)error;
+ (instancetype)connectWithIdentity:(NWIdentityRef)identity environment:(NWEnvironment)environment error:(NSError **)error;
/** Setup connection with feedback service based on PKCS #12 data. */
+ (instancetype)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError **)error;
+ (instancetype)connectWithPKCS12Data:(NSData *)data password:(NSString *)password environment:(NWEnvironment)environment error:(NSError **)error;
/** @name Connecting */
/** Connect with feedback service based on identity. */
- (BOOL)connectWithIdentity:(NWIdentityRef)identity error:(NSError **)error;
- (BOOL)connectWithIdentity:(NWIdentityRef)identity environment:(NWEnvironment)environment error:(NSError **)error;
/** Connect with feedback service based on PKCS #12 data. */
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError **)error;
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password environment:(NWEnvironment)environment error:(NSError **)error;
/** Disconnect from feedback service. The server will automatically drop the connection after all feedback data has been read. */
- (void)disconnect;
@@ -56,10 +56,9 @@
// deprecated
- (NWError)connectWithIdentity:(NWIdentityRef)identity __deprecated;
- (NWError)connectWithPKCS12Data:(NSData *)data password:(NSString *)password __deprecated;
- (NWError)readTokenData:(NSData **)token date:(NSDate **)date __deprecated;
- (NWError)readToken:(NSString **)token date:(NSDate **)date __deprecated;
- (NWError)readTokenDatePairs:(NSArray **)pairs max:(NSUInteger)max __deprecated;
+ (instancetype)connectWithIdentity:(NWIdentityRef)identity error:(NSError **)error __deprecated;
+ (instancetype)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError **)error __deprecated;
- (BOOL)connectWithIdentity:(NWIdentityRef)identity error:(NSError **)error __deprecated;
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError **)error __deprecated;
@end
+19 -30
View File
@@ -20,10 +20,11 @@ static NSUInteger const NWTokenMaxSize = 32;
#pragma mark - Connecting
- (BOOL)connectWithIdentity:(NWIdentityRef)identity error:(NSError *__autoreleasing *)error
- (BOOL)connectWithIdentity:(NWIdentityRef)identity environment:(NWEnvironment)environment error:(NSError *__autoreleasing *)error
{
if (_connection) [_connection disconnect]; _connection = nil;
NSString *host = [NWSecTools isSandboxIdentity:identity] ? NWSandboxPushHost : NWPushHost;
if (environment == NWEnvironmentAuto) environment = [NWSecTools environmentForIdentity:identity];
NSString *host = (environment == NWEnvironmentSandbox) ? NWSandboxPushHost : NWPushHost;
NWSSLConnection *connection = [[NWSSLConnection alloc] initWithHost:host port:NWPushPort identity:identity];
BOOL connected = [connection connectWithError:error];
if (!connected) {
@@ -33,13 +34,13 @@ static NSUInteger const NWTokenMaxSize = 32;
return YES;
}
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError *__autoreleasing *)error
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password environment:(NWEnvironment)environment error:(NSError *__autoreleasing *)error
{
NWIdentityRef identity = [NWSecTools identityWithPKCS12Data:data password:password error:error];
if (!identity) {
return NO;
}
return [self connectWithIdentity:identity error:error];
return [self connectWithIdentity:identity environment:environment error:error];
}
- (void)disconnect
@@ -47,16 +48,16 @@ static NSUInteger const NWTokenMaxSize = 32;
[_connection disconnect]; _connection = nil;
}
+ (instancetype)connectWithIdentity:(NWIdentityRef)identity error:(NSError *__autoreleasing *)error
+ (instancetype)connectWithIdentity:(NWIdentityRef)identity environment:(NWEnvironment)environment error:(NSError *__autoreleasing *)error
{
NWPushFeedback *feedback = [[NWPushFeedback alloc] init];
return identity && [feedback connectWithIdentity:identity error:error] ? feedback : nil;
return identity && [feedback connectWithIdentity:identity environment:environment error:error] ? feedback : nil;
}
+ (instancetype)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError *__autoreleasing *)error
+ (instancetype)connectWithPKCS12Data:(NSData *)data password:(NSString *)password environment:(NWEnvironment)environment error:(NSError *__autoreleasing *)error
{
NWPushFeedback *feedback = [[NWPushFeedback alloc] init];
return data && [feedback connectWithPKCS12Data:data password:password error:error] ? feedback : nil;
return data && [feedback connectWithPKCS12Data:data password:password environment:environment error:error] ? feedback : nil;
}
@@ -73,7 +74,7 @@ static NSUInteger const NWTokenMaxSize = 32;
return read;
}
if (length != data.length) {
return [NWErrorUtil noWithErrorCode:kNWErrorFeedbackLength error:error];
return [NWErrorUtil noWithErrorCode:kNWErrorFeedbackLength reason:length error:error];
}
uint32_t time = 0;
[data getBytes:&time range:NSMakeRange(0, 4)];
@@ -82,7 +83,7 @@ static NSUInteger const NWTokenMaxSize = 32;
[data getBytes:&l range:NSMakeRange(4, 2)];
NSUInteger tokenLength = htons(l);
if (tokenLength != NWTokenMaxSize) {
return [NWErrorUtil noWithErrorCode:kNWErrorFeedbackTokenLength error:error];
return [NWErrorUtil noWithErrorCode:kNWErrorFeedbackTokenLength reason:tokenLength error:error];
}
*token = [data subdataWithRange:NSMakeRange(6, length - 6)];
return YES;
@@ -124,36 +125,24 @@ static NSUInteger const NWTokenMaxSize = 32;
#pragma mark - Deprecated
- (NWError)connectWithIdentity:(NWIdentityRef)identity
- (BOOL)connectWithIdentity:(NWIdentityRef)identity error:(NSError *__autoreleasing *)error
{
NSError *error = nil;
return [self connectWithIdentity:identity error:&error] ? kNWSuccess : error.code;
return [self connectWithIdentity:identity environment:NWEnvironmentAuto error:error];
}
- (NWError)connectWithPKCS12Data:(NSData *)data password:(NSString *)password
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError *__autoreleasing *)error
{
NSError *error = nil;
return [self connectWithPKCS12Data:data password:password error:&error] ? kNWSuccess : error.code;
return [self connectWithPKCS12Data:data password:password environment:NWEnvironmentAuto error:error];
}
- (NWError)readTokenData:(NSData **)token date:(NSDate **)date
+ (instancetype)connectWithIdentity:(NWIdentityRef)identity error:(NSError *__autoreleasing *)error
{
NSError *error = nil;
return [self readTokenData:token date:date error:&error] ? kNWSuccess : error.code;
return [self connectWithIdentity:identity environment:NWEnvironmentAuto error:error];
}
- (NWError)readToken:(NSString **)token date:(NSDate **)date
+ (instancetype)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError *__autoreleasing *)error
{
NSError *error = nil;
return [self readToken:token date:date error:&error] ? kNWSuccess : error.code;
}
- (NWError)readTokenDatePairs:(NSArray **)pairs max:(NSUInteger)max
{
NSError *error = nil;
NSArray *p = [self readTokenDatePairsWithMax:max error:&error];
if (pairs) *pairs = p;
return p ? kNWSuccess : error.code;
return [self connectWithPKCS12Data:data password:password environment:NWEnvironmentAuto error:error];
}
@end
+12 -16
View File
@@ -10,9 +10,9 @@
@class NWNotification, NWSSLConnection;
/** Serializes notification objects and pushes them to the APNS.
/** Serializes notification objects and pushes them to the APNs.
This is the heart of the framework. As the (inconvenient) name suggest, it's also one of the first classes that was added to the framework. This class provides a straightforward interface to the APNS server, including connecting, pushing to and reading from the server.
This is the heart of the framework. As the (inconvenient) name suggest, it's also one of the first classes that was added to the framework. This class provides a straightforward interface to the APNs, including connecting, pushing to and reading from the server.
Connecting is done based on an identity or PKCS #12 data. The identity is an instance of `SecIdentityRef` and contains a certificate and private key. The PKCS #12 data can be deserialized into such an identity. One can reconnect or disconnect at any time, and should if the connection has been dropped by the server. The latter can happen quite easily, for example when there is something wrong with the device token or payload of the notification.
@@ -32,18 +32,18 @@
/** @name Initialization */
/** Creates, connects and returns a pusher object based on the provided identity. */
+ (instancetype)connectWithIdentity:(NWIdentityRef)identity error:(NSError **)error;
+ (instancetype)connectWithIdentity:(NWIdentityRef)identity environment:(NWEnvironment)environment error:(NSError **)error;
/** Creates, connects and returns a pusher object based on the PKCS #12 data. */
+ (instancetype)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError **)error;
+ (instancetype)connectWithPKCS12Data:(NSData *)data password:(NSString *)password environment:(NWEnvironment)environment error:(NSError **)error;
/** @name Connecting */
/** Connect with the APNS server using the identity. */
- (BOOL)connectWithIdentity:(NWIdentityRef)identity error:(NSError **)error;
/** Connect with the APNs using the identity. */
- (BOOL)connectWithIdentity:(NWIdentityRef)identity environment:(NWEnvironment)environment error:(NSError **)error;
/** Connect with the APNS server using the identity from PKCS #12 data. */
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError **)error;
/** Connect with the APNs using the identity from PKCS #12 data. */
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password environment:(NWEnvironment)environment error:(NSError **)error;
/** Reconnect using the same identity, disconnects if necessary. */
- (BOOL)reconnectWithError:(NSError **)error;
@@ -69,13 +69,9 @@
// deprecated
- (NWError)connectWithIdentity:(NWIdentityRef)identity __deprecated;
- (NWError)connectWithPKCS12Data:(NSData *)data password:(NSString *)password __deprecated;
- (NWError)reconnect __deprecated;
- (NWError)pushPayload:(NSString *)payload token:(NSString *)token identifier:(NSUInteger)identifier __deprecated;
- (NWError)pushNotification:(NWNotification *)notification type:(NWNotificationType)type __deprecated;
- (NWError)fetchFailedIdentifier:(NSUInteger *)identifier apnError:(NWError *)apnError __deprecated;
- (BOOL)fetchFailedIdentifier:(NSUInteger *)identifier apnError:(NSError **)apnError error:(NSError **)error __deprecated;
- (NSArray *)fetchFailedIdentifierErrorPairsWithMax:(NSUInteger)max error:(NSError **)error __deprecated;
+ (instancetype)connectWithIdentity:(NWIdentityRef)identity error:(NSError **)error __deprecated;
+ (instancetype)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError **)error __deprecated;
- (BOOL)connectWithIdentity:(NWIdentityRef)identity error:(NSError **)error __deprecated;
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError **)error __deprecated;
@end
+20 -48
View File
@@ -19,10 +19,11 @@ static NSUInteger const NWPushPort = 2195;
#pragma mark - Connecting
- (BOOL)connectWithIdentity:(NWIdentityRef)identity error:(NSError *__autoreleasing *)error
- (BOOL)connectWithIdentity:(NWIdentityRef)identity environment:(NWEnvironment)environment error:(NSError *__autoreleasing *)error
{
if (_connection) [_connection disconnect]; _connection = nil;
NSString *host = [NWSecTools isSandboxIdentity:identity] ? NWSandboxPushHost : NWPushHost;
if (environment == NWEnvironmentAuto) environment = [NWSecTools environmentForIdentity:identity];
NSString *host = (environment == NWEnvironmentSandbox) ? NWSandboxPushHost : NWPushHost;
NWSSLConnection *connection = [[NWSSLConnection alloc] initWithHost:host port:NWPushPort identity:identity];
BOOL connected = [connection connectWithError:error];
if (!connected) {
@@ -32,13 +33,13 @@ static NSUInteger const NWPushPort = 2195;
return YES;
}
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError *__autoreleasing *)error
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password environment:(NWEnvironment)environment error:(NSError *__autoreleasing *)error
{
NWIdentityRef identity = [NWSecTools identityWithPKCS12Data:data password:password error:error];
if (!identity) {
return NO;
}
return [self connectWithIdentity:identity error:error];
return [self connectWithIdentity:identity environment:environment error:error];
}
- (BOOL)reconnectWithError:(NSError *__autoreleasing *)error
@@ -54,16 +55,16 @@ static NSUInteger const NWPushPort = 2195;
[_connection disconnect]; _connection = nil;
}
+ (instancetype)connectWithIdentity:(NWIdentityRef)identity error:(NSError *__autoreleasing *)error
+ (instancetype)connectWithIdentity:(NWIdentityRef)identity environment:(NWEnvironment)environment error:(NSError *__autoreleasing *)error
{
NWPusher *pusher = [[NWPusher alloc] init];
return identity && [pusher connectWithIdentity:identity error:error] ? pusher : nil;
return identity && [pusher connectWithIdentity:identity environment:environment error:error] ? pusher : nil;
}
+ (instancetype)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError *__autoreleasing *)error
+ (instancetype)connectWithPKCS12Data:(NSData *)data password:(NSString *)password environment:(NWEnvironment)environment error:(NSError *__autoreleasing *)error
{
NWPusher *pusher = [[NWPusher alloc] init];
return data && [pusher connectWithPKCS12Data:data password:password error:error] ? pusher : nil;
return data && [pusher connectWithPKCS12Data:data password:password environment:environment error:error] ? pusher : nil;
}
#pragma mark - Pushing payload
@@ -82,7 +83,7 @@ static NSUInteger const NWPushPort = 2195;
return written;
}
if (length != data.length) {
return [NWErrorUtil noWithErrorCode:kNWErrorPushWriteFail error:error];
return [NWErrorUtil noWithErrorCode:kNWErrorPushWriteFail reason:length error:error];
}
return YES;
}
@@ -101,7 +102,7 @@ static NSUInteger const NWPushPort = 2195;
uint8_t command = 0;
[data getBytes:&command range:NSMakeRange(0, 1)];
if (command != 8) {
return [NWErrorUtil noWithErrorCode:kNWErrorPushResponseCommand error:error];
return [NWErrorUtil noWithErrorCode:kNWErrorPushResponseCommand reason:command error:error];
}
uint8_t status = 0;
[data getBytes:&status range:NSMakeRange(1, 1)];
@@ -118,7 +119,7 @@ static NSUInteger const NWPushPort = 2195;
case 7: [NWErrorUtil noWithErrorCode:kNWErrorAPNInvalidPayloadSize error:apnError]; break;
case 8: [NWErrorUtil noWithErrorCode:kNWErrorAPNInvalidTokenContent error:apnError]; break;
case 10: [NWErrorUtil noWithErrorCode:kNWErrorAPNShutdown error:apnError]; break;
default: [NWErrorUtil noWithErrorCode:kNWErrorAPNUnknownErrorCode error:apnError]; break;
default: [NWErrorUtil noWithErrorCode:kNWErrorAPNUnknownErrorCode reason:status error:apnError]; break;
}
return YES;
}
@@ -143,53 +144,24 @@ static NSUInteger const NWPushPort = 2195;
#pragma mark - Deprecated
- (NWError)connectWithIdentity:(NWIdentityRef)identity
- (BOOL)connectWithIdentity:(NWIdentityRef)identity error:(NSError *__autoreleasing *)error
{
NSError *error = nil;
return [self connectWithIdentity:identity error:&error] ? kNWSuccess : error.code;
return [self connectWithIdentity:identity environment:NWEnvironmentAuto error:error];
}
- (NWError)connectWithPKCS12Data:(NSData *)data password:(NSString *)password
- (BOOL)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError *__autoreleasing *)error
{
NSError *error = nil;
return [self connectWithPKCS12Data:data password:password error:&error] ? kNWSuccess : error.code;
return [self connectWithPKCS12Data:data password:password environment:NWEnvironmentAuto error:error];
}
- (NWError)reconnect
+ (instancetype)connectWithIdentity:(NWIdentityRef)identity error:(NSError *__autoreleasing *)error
{
NSError *error = nil;
return [self reconnectWithError:&error] ? kNWSuccess : error.code;
return [self connectWithIdentity:identity environment:NWEnvironmentAuto error:error];
}
- (NWError)pushPayload:(NSString *)payload token:(NSString *)token identifier:(NSUInteger)identifier
+ (instancetype)connectWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError *__autoreleasing *)error
{
NSError *error = nil;
return [self pushPayload:payload token:token identifier:identifier error:&error] ? kNWSuccess : error.code;
}
- (NWError)pushNotification:(NWNotification *)notification type:(NWNotificationType)type
{
NSError *error = nil;
return [self pushNotification:notification type:type error:&error] ? kNWSuccess : error.code;
}
- (NWError)fetchFailedIdentifier:(NSUInteger *)identifier apnError:(NWError *)apnErrorCode
{
NSError *error = nil;
NSError *apnError = nil;
BOOL read = [self readFailedIdentifier:identifier apnError:&apnError error:&error];
if (apnErrorCode && apnError) *apnErrorCode = apnError.code;
return read ? kNWSuccess : error.code;
}
- (BOOL)fetchFailedIdentifier:(NSUInteger *)identifier apnError:(NSError *__autoreleasing *)apnError error:(NSError *__autoreleasing *)error
{
return [self readFailedIdentifier:identifier apnError:apnError error:error];
}
- (NSArray *)fetchFailedIdentifierErrorPairsWithMax:(NSUInteger)max error:(NSError *__autoreleasing *)error
{
return [self readFailedIdentifierErrorPairsWithMax:max error:error];
return [self connectWithPKCS12Data:data password:password environment:NWEnvironmentAuto error:error];
}
@end
+1 -7
View File
@@ -9,7 +9,7 @@
#import <Foundation/Foundation.h>
/** An SSL (TLS) connection to the APNS server.
/** An SSL (TLS) connection to the APNs.
This class is basically an Objective-C wrapper around `SSLContextRef` and `SSLConnectionRef`, which are part of the native Secure Transport framework. This class provides a generic interface for SSL (TLS) connections, independent of NWPusher.
@@ -54,10 +54,4 @@
/** Write length number of bytes from data object. */
- (BOOL)write:(NSData *)data length:(NSUInteger *)length error:(NSError **)error;
// deprecated
- (NWError)connect __deprecated;
- (NWError)read:(NSMutableData *)data length:(NSUInteger *)length __deprecated;
- (NWError)write:(NSData *)data length:(NSUInteger *)length __deprecated;
@end
+27 -32
View File
@@ -8,6 +8,7 @@
#import "NWSSLConnection.h"
#include <netdb.h>
#define NWSSL_HANDSHAKE_TRY_COUNT 1 << 26
OSStatus NWSSLRead(SSLConnectionRef connection, void *data, size_t *length);
OSStatus NWSSLWrite(SSLConnectionRef connection, const void *data, size_t *length);
@@ -67,7 +68,7 @@ OSStatus NWSSLWrite(SSLConnectionRef connection, const void *data, size_t *lengt
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
return [NWErrorUtil noWithErrorCode:kNWErrorSocketCreate error:error];
return [NWErrorUtil noWithErrorCode:kNWErrorSocketCreate reason:sock error:error];
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
@@ -82,15 +83,15 @@ OSStatus NWSSLWrite(SSLConnectionRef connection, const void *data, size_t *lengt
addr.sin_family = AF_INET;
int conn = connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
if (conn < 0) {
return [NWErrorUtil noWithErrorCode:kNWErrorSocketConnect error:error];
return [NWErrorUtil noWithErrorCode:kNWErrorSocketConnect reason:conn error:error];
}
int cntl = fcntl(sock, F_SETFL, O_NONBLOCK);
if (cntl < 0) {
return [NWErrorUtil noWithErrorCode:kNWErrorSocketFileControl error:error];
return [NWErrorUtil noWithErrorCode:kNWErrorSocketFileControl reason:cntl error:error];
}
int set = 1, sopt = setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
if (sopt < 0) {
return [NWErrorUtil noWithErrorCode:kNWErrorSocketOptions error:error];
return [NWErrorUtil noWithErrorCode:kNWErrorSocketOptions reason:sopt error:error];
}
_socket = sock;
return YES;
@@ -104,19 +105,19 @@ OSStatus NWSSLWrite(SSLConnectionRef connection, const void *data, size_t *lengt
}
OSStatus setio = SSLSetIOFuncs(context, NWSSLRead, NWSSLWrite);
if (setio != errSecSuccess) {
return [NWErrorUtil noWithErrorCode:kNWErrorSSLIOFuncs error:error];
return [NWErrorUtil noWithErrorCode:kNWErrorSSLIOFuncs reason:setio error:error];
}
OSStatus setconn = SSLSetConnection(context, (SSLConnectionRef)(NSInteger)_socket);
if (setconn != errSecSuccess) {
return [NWErrorUtil noWithErrorCode:kNWErrorSSLConnection error:error];
return [NWErrorUtil noWithErrorCode:kNWErrorSSLConnection reason:setconn error:error];
}
OSStatus setpeer = SSLSetPeerDomainName(context, _host.UTF8String, strlen(_host.UTF8String));
if (setpeer != errSecSuccess) {
return [NWErrorUtil noWithErrorCode:kNWErrorSSLPeerDomainName error:error];
return [NWErrorUtil noWithErrorCode:kNWErrorSSLPeerDomainName reason:setpeer error:error];
}
OSStatus setcert = SSLSetCertificate(context, (__bridge CFArrayRef)@[_identity]);
if (setcert != errSecSuccess) {
return [NWErrorUtil noWithErrorCode:kNWErrorSSLCertificate error:error];
return [NWErrorUtil noWithErrorCode:kNWErrorSSLCertificate reason:setcert error:error];
}
_context = context;
return YES;
@@ -125,7 +126,7 @@ OSStatus NWSSLWrite(SSLConnectionRef connection, const void *data, size_t *lengt
- (BOOL)handshakeSSLWithError:(NSError *__autoreleasing *)error
{
OSStatus status = errSSLWouldBlock;
for (NSUInteger i = 0; i < 1 << 26 && status == errSSLWouldBlock; i++) { // 26? works.
for (NSUInteger i = 0; i < NWSSL_HANDSHAKE_TRY_COUNT && status == errSSLWouldBlock; i++) {
status = SSLHandshake(_context);
}
switch (status) {
@@ -133,8 +134,22 @@ OSStatus NWSSLWrite(SSLConnectionRef connection, const void *data, size_t *lengt
case errSSLWouldBlock: return [NWErrorUtil noWithErrorCode:kNWErrorSSLHandshakeTimeout error:error];
case errSecIO: return [NWErrorUtil noWithErrorCode:kNWErrorSSLDroppedByServer error:error];
case errSecAuthFailed: return [NWErrorUtil noWithErrorCode:kNWErrorSSLAuthFailed error:error];
case errSSLUnknownRootCert: return [NWErrorUtil noWithErrorCode:kNWErrorSSLHandshakeUnknownRootCert error:error];
case errSSLNoRootCert: return [NWErrorUtil noWithErrorCode:kNWErrorSSLHandshakeNoRootCert error:error];
case errSSLCertExpired: return [NWErrorUtil noWithErrorCode:kNWErrorSSLHandshakeCertExpired error:error];
case errSSLXCertChainInvalid: return [NWErrorUtil noWithErrorCode:kNWErrorSSLHandshakeXCertChainInvalid error:error];
case errSSLClientCertRequested: return [NWErrorUtil noWithErrorCode:kNWErrorSSLHandshakeClientCertRequested error:error];
case errSSLServerAuthCompleted: return [NWErrorUtil noWithErrorCode:kNWErrorSSLHandshakeServerAuthCompleted error:error];
case errSSLPeerCertExpired: return [NWErrorUtil noWithErrorCode:kNWErrorSSLHandshakePeerCertExpired error:error];
case errSSLPeerCertRevoked: return [NWErrorUtil noWithErrorCode:kNWErrorSSLHandshakePeerCertRevoked error:error];
case errSSLPeerCertUnknown: return [NWErrorUtil noWithErrorCode:kNWErrorSSLHandshakePeerCertUnknown error:error];
case errSSLInternal: return [NWErrorUtil noWithErrorCode:kNWErrorSSLHandshakeInternalError error:error];
#if !TARGET_OS_IPHONE
case errSecInDarkWake: return [NWErrorUtil noWithErrorCode:kNWErrorSSLInDarkWake error:error];
#endif
case errSSLClosedAbort: return [NWErrorUtil noWithErrorCode:kNWErrorSSLHandshakeClosedAbort error:error];
}
return [NWErrorUtil noWithErrorCode:kNWErrorSSLHandshakeFail error:error];
return [NWErrorUtil noWithErrorCode:kNWErrorSSLHandshakeFail reason:status error:error];
}
- (void)disconnect
@@ -159,7 +174,7 @@ OSStatus NWSSLWrite(SSLConnectionRef connection, const void *data, size_t *lengt
case errSSLClosedAbort: return [NWErrorUtil noWithErrorCode:kNWErrorReadClosedAbort error:error];
case errSSLClosedGraceful: return [NWErrorUtil noWithErrorCode:kNWErrorReadClosedGraceful error:error];
}
return [NWErrorUtil noWithErrorCode:kNWErrorReadFail error:error];
return [NWErrorUtil noWithErrorCode:kNWErrorReadFail reason:status error:error];
}
- (BOOL)write:(NSData *)data length:(NSUInteger *)length error:(NSError *__autoreleasing *)error
@@ -175,27 +190,7 @@ OSStatus NWSSLWrite(SSLConnectionRef connection, const void *data, size_t *lengt
case errSSLClosedAbort: return [NWErrorUtil noWithErrorCode:kNWErrorWriteClosedAbort error:error];
case errSSLClosedGraceful: return [NWErrorUtil noWithErrorCode:kNWErrorWriteClosedGraceful error:error];
}
return [NWErrorUtil noWithErrorCode:kNWErrorWriteFail error:error];
}
#pragma mark - Deprecated
- (NWError)connect
{
NSError *error = nil;
return [self connectWithError:&error] ? kNWSuccess : error.code;
}
- (NWError)read:(NSMutableData *)data length:(NSUInteger *)length
{
NSError *error = nil;
return [self read:data length:length error:&error] ? kNWSuccess : error.code;
}
- (NWError)write:(NSData *)data length:(NSUInteger *)length
{
NSError *error = nil;
return [self write:data length:length error:&error] ? kNWSuccess : error.code;
return [NWErrorUtil noWithErrorCode:kNWErrorWriteFail reason:status error:error];
}
@end
+20 -14
View File
@@ -43,31 +43,37 @@
/** @name Inspection */
/** Extracts the type and summary string. */
+ (NWCertType)typeWithCertificate:(NWCertificateRef)certificate summary:(NSString **)summary;
/** Extracts the summary string. */
+ (NSString *)summaryWithCertificate:(NWCertificateRef)certificate;
/** Tells if the identity is for pushing to the Development (sandbox) server. */
+ (BOOL)isSandboxIdentity:(NWIdentityRef)identity;
/** Tells what environment options can be used with this identity (Development(sandbox)/Production server or both). */
+ (NWEnvironmentOptions)environmentOptionsForIdentity:(NWIdentityRef)identity;
/** Tells if the certificate is for pushing to the Development (sandbox) server. */
+ (BOOL)isSandboxCertificate:(NWCertificateRef)certificate;
/** Tells what environment options can be used with this certificate (Development(sandbox)/Production server or both). */
+ (NWEnvironmentOptions)environmentOptionsForCertificate:(NWCertificateRef)certificate;
/** Tells if the certificate can be used for connecting with APNS. */
/** Tells if the certificate can be used for connecting with APNs. */
+ (BOOL)isPushCertificate:(NWCertificateRef)certificate;
/** Composes a dictionary describing the characteristics of the identity. */
+ (NSDictionary *)inspectIdentity:(NWIdentityRef)identity;
// deprecated
+ (NWError)identityWithPKCS12Data:(NSData *)pkcs12 password:(NSString *)password identity:(NWIdentityRef *)identity __deprecated;
+ (NWError)identitiesWithPKCS12Data:(NSData *)pkcs12 password:(NSString *)password identities:(NSArray **)identities __deprecated;
+ (NWError)keychainCertificates:(NSArray **)certificates __deprecated;
+ (NWError)certificateWithIdentity:(NWIdentityRef)identity certificate:(NWCertificateRef *)certificate __deprecated;
+ (NWError)keyWithIdentity:(NWIdentityRef)identity key:(NWKeyRef *)key __deprecated;
#if !TARGET_OS_IPHONE
+ (NWError)keychainIdentityWithCertificate:(NWCertificateRef)certificate identity:(NWIdentityRef *)identity __deprecated;
/** Extracts the expiration date. */
+ (NSDate *)expirationWithCertificate:(NWCertificateRef)certificate;
/** Extracts given properties of certificate, see `SecCertificateOIDs.h`, use `nil` to get all. */
+ (NSDictionary *)valuesWithCertificate:(NWCertificateRef)certificate keys:(NSArray *)keys error:(NSError **)error;
#endif
// deprecated
+ (BOOL)isSandboxIdentity:(NWIdentityRef)identity __deprecated;
+ (BOOL)isSandboxCertificate:(NWCertificateRef)certificate __deprecated;
+ (NWEnvironment)environmentForIdentity:(NWIdentityRef)identity;
+ (NWEnvironment)environmentForCertificate:(NWCertificateRef)certificate;
@end
+75 -67
View File
@@ -7,23 +7,6 @@
#import "NWSecTools.h"
/** Types of push certificates. */
typedef NS_ENUM(NSInteger, NWCertType) {
/** None. */
kNWCertTypeNone = 0,
/** iOS Development. */
kNWCertTypeIOSDevelopment = 1,
/** iOS Production. */
kNWCertTypeIOSProduction = 2,
/** OS X Development. */
kNWCertTypeMacDevelopment = 3,
/** OS X Production. */
kNWCertTypeMacProduction = 4,
/** Unknown. */
kNWCertTypeUnknown = 5,
};
@implementation NWSecTools
#pragma mark - Initialization
@@ -38,7 +21,7 @@ typedef NS_ENUM(NSInteger, NWCertType) {
return [NWErrorUtil nilWithErrorCode:kNWErrorPKCS12NoItems error:error];
}
if (identities.count > 1) {
return [NWErrorUtil nilWithErrorCode:kNWErrorPKCS12MultipleItems error:error];
return [NWErrorUtil nilWithErrorCode:kNWErrorPKCS12MultipleItems reason:identities.count error:error];
}
return identities.lastObject;
}
@@ -111,25 +94,33 @@ typedef NS_ENUM(NSInteger, NWCertType) {
return result;
}
+ (BOOL)isSandboxIdentity:(NWIdentityRef)identity
+ (NWEnvironmentOptions)environmentOptionsForIdentity:(NWIdentityRef)identity
{
NWCertificateRef certificate = [self certificateWithIdentity:identity error:nil];
return [self isSandboxCertificate:certificate];
return [self environmentOptionsForCertificate:certificate];
}
+ (BOOL)isSandboxCertificate:(NWCertificateRef)certificate
+ (NWEnvironmentOptions)environmentOptionsForCertificate:(NWCertificateRef)certificate
{
switch ([self typeWithCertificate:certificate summary:nil]) {
case kNWCertTypeIOSDevelopment:
case kNWCertTypeMacDevelopment:
return YES;
return NWEnvironmentOptionSandbox;
case kNWCertTypeIOSProduction:
case kNWCertTypeMacProduction:
return NWEnvironmentOptionProduction;
case kNWCertTypeSimplified:
case kNWCertTypeWebProduction:
case kNWCertTypeVoIPServices:
case kNWCertTypeWatchKitServices:
case kNWCertTypePasses:
return NWEnvironmentOptionAny;
case kNWCertTypeNone:
case kNWCertTypeUnknown:
break;
}
return NO;
return NWEnvironmentOptionNone;
}
+ (BOOL)isPushCertificate:(NWCertificateRef)certificate
@@ -139,6 +130,11 @@ typedef NS_ENUM(NSInteger, NWCertType) {
case kNWCertTypeMacDevelopment:
case kNWCertTypeIOSProduction:
case kNWCertTypeMacProduction:
case kNWCertTypeSimplified:
case kNWCertTypeWebProduction:
case kNWCertTypeVoIPServices:
case kNWCertTypeWatchKitServices:
case kNWCertTypePasses:
return YES;
case kNWCertTypeNone:
case kNWCertTypeUnknown:
@@ -154,6 +150,11 @@ typedef NS_ENUM(NSInteger, NWCertType) {
case kNWCertTypeIOSProduction: return @"Apple Production IOS Push Services: ";
case kNWCertTypeMacDevelopment: return @"Apple Development Mac Push Services: ";
case kNWCertTypeMacProduction: return @"Apple Production Mac Push Services: ";
case kNWCertTypeSimplified: return @"Apple Push Services: ";
case kNWCertTypeWebProduction: return @"Website Push ID: ";
case kNWCertTypeVoIPServices: return @"VoIP Services: ";
case kNWCertTypeWatchKitServices: return @"WatchKit Services: ";
case kNWCertTypePasses: return @"Pass Type ID: ";
case kNWCertTypeNone:
case kNWCertTypeUnknown:
break;
@@ -208,7 +209,7 @@ typedef NS_ENUM(NSInteger, NWCertType) {
OSStatus status = identity ? SecIdentityCopyCertificate((__bridge SecIdentityRef)identity, &cert) : errSecParam;
NWCertificateRef certificate = CFBridgingRelease(cert);
if (status != errSecSuccess || !cert) {
return [NWErrorUtil nilWithErrorCode:kNWErrorIdentityCopyCertificate error:error];
return [NWErrorUtil nilWithErrorCode:kNWErrorIdentityCopyCertificate reason:status error:error];
}
return certificate;
}
@@ -219,14 +220,14 @@ typedef NS_ENUM(NSInteger, NWCertType) {
OSStatus status = identity ? SecIdentityCopyPrivateKey((__bridge SecIdentityRef)identity, &k) : errSecParam;
NWKeyRef key = CFBridgingRelease(k);
if (status != errSecSuccess || !k) {
return [NWErrorUtil nilWithErrorCode:kNWErrorIdentityCopyPrivateKey error:error];
return [NWErrorUtil nilWithErrorCode:kNWErrorIdentityCopyPrivateKey reason:status error:error];
}
return key;
}
+ (NSArray *)allIdentitiesWithPKCS12Data:(NSData *)data password:(NSString *)password error:(NSError *__autoreleasing *)error
{
NSDictionary *options = @{(__bridge id)kSecImportExportPassphrase: password};
NSDictionary *options = password ? @{(__bridge id)kSecImportExportPassphrase: password} : @{};
CFArrayRef items = NULL;
OSStatus status = data ? SecPKCS12Import((__bridge CFDataRef)data, (__bridge CFDictionaryRef)options, &items) : errSecParam;
NSArray *dicts = CFBridgingRelease(items);
@@ -236,9 +237,10 @@ typedef NS_ENUM(NSInteger, NWCertType) {
case errSecAuthFailed: return [NWErrorUtil nilWithErrorCode:kNWErrorPKCS12AuthFailed error:error];
#if !TARGET_OS_IPHONE
case errSecPkcs12VerifyFailure: return [NWErrorUtil nilWithErrorCode:kNWErrorPKCS12Password error:error];
case errSecPassphraseRequired: return [NWErrorUtil nilWithErrorCode:kNWErrorPKCS12PasswordRequired error:error];
#endif
}
return [NWErrorUtil nilWithErrorCode:kNWErrorPKCS12Import error:error];
return [NWErrorUtil nilWithErrorCode:kNWErrorPKCS12Import reason:status error:error];
}
return dicts;
}
@@ -251,7 +253,7 @@ typedef NS_ENUM(NSInteger, NWCertType) {
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)options, (CFTypeRef *)&certs);
NSArray *certificates = CFBridgingRelease(certs);
if (status != errSecSuccess || !certs) {
return [NWErrorUtil nilWithErrorCode:kNWErrorKeychainCopyMatching error:error];
return [NWErrorUtil nilWithErrorCode:kNWErrorKeychainCopyMatching reason:status error:error];
}
return certificates;
}
@@ -266,62 +268,68 @@ typedef NS_ENUM(NSInteger, NWCertType) {
switch (status) {
case errSecItemNotFound: return [NWErrorUtil nilWithErrorCode:kNWErrorKeychainItemNotFound error:error];
}
return [NWErrorUtil nilWithErrorCode:kNWErrorKeychainCreateIdentity error:error];
return [NWErrorUtil nilWithErrorCode:kNWErrorKeychainCreateIdentity reason:status error:error];
}
return identity;
}
+ (NSDate *)expirationWithCertificate:(NWCertificateRef)certificate
{
return [self valueWithCertificate:certificate key:(__bridge id)kSecOIDInvalidityDate];
}
+ (id)valueWithCertificate:(NWCertificateRef)certificate key:(id)key
{
return [self valuesWithCertificate:certificate keys:@[key] error:nil][key][(__bridge id)kSecPropertyKeyValue];
}
+ (NSDictionary *)valuesWithCertificate:(NWCertificateRef)certificate keys:(NSArray *)keys error:(NSError **)error
{
CFErrorRef e = NULL;
NSDictionary *result = CFBridgingRelease(SecCertificateCopyValues((__bridge SecCertificateRef)certificate, (__bridge CFArrayRef)keys, &e));
if (error) *error = CFBridgingRelease(e);
return result;
}
#endif
#pragma mark - Deprecated
+ (NWError)identityWithPKCS12Data:(NSData *)pkcs12 password:(NSString *)password identity:(NWIdentityRef *)identity
+ (BOOL)isSandboxIdentity:(NWIdentityRef)identity
{
NSError *error = nil;
NWIdentityRef i = [self identityWithPKCS12Data:pkcs12 password:password error:&error];
if (identity) *identity = i;
return i ? kNWSuccess : error.code;
return [self environmentForIdentity:identity] == NWEnvironmentSandbox;
}
+ (NWError)identitiesWithPKCS12Data:(NSData *)pkcs12 password:(NSString *)password identities:(NSArray **)identities
+ (BOOL)isSandboxCertificate:(NWCertificateRef)certificate
{
NSError *error = nil;
NSArray * i = [self identitiesWithPKCS12Data:pkcs12 password:password error:&error];
if (identities) *identities = i;
return i ? kNWSuccess : error.code;
return [self environmentForCertificate:certificate] == NWEnvironmentSandbox;
}
+ (NWError)keychainCertificates:(NSArray **)certificates
+ (NWEnvironment)environmentForIdentity:(NWIdentityRef)identity
{
NSError *error = nil;
NSArray *c = [self keychainCertificatesWithError:&error];
if (certificates) *certificates = c;
return c ? kNWSuccess : error.code;
NWCertificateRef certificate = [self certificateWithIdentity:identity error:nil];
return [self environmentForCertificate:certificate];
}
+ (NWError)certificateWithIdentity:(NWIdentityRef)identity certificate:(NWCertificateRef *)certificate
+ (NWEnvironment)environmentForCertificate:(NWCertificateRef)certificate
{
NSError *error = nil;
NWCertificateRef c = [self certificateWithIdentity:identity error:&error];
if (certificate) *certificate = c;
return c ? kNWSuccess : error.code;
switch ([self typeWithCertificate:certificate summary:nil]) {
case kNWCertTypeIOSDevelopment:
case kNWCertTypeMacDevelopment:
return NWEnvironmentSandbox;
case kNWCertTypeIOSProduction:
case kNWCertTypeMacProduction:
return NWEnvironmentProduction;
case kNWCertTypeSimplified:
case kNWCertTypeWebProduction:
case kNWCertTypeVoIPServices:
case kNWCertTypeWatchKitServices:
case kNWCertTypePasses:
case kNWCertTypeNone:
case kNWCertTypeUnknown:
break;
}
return NWEnvironmentNone;
}
+ (NWError)keyWithIdentity:(NWIdentityRef)identity key:(NWKeyRef *)key
{
NSError *error = nil;
NWKeyRef k = [self keyWithIdentity:identity error:&error];
if (key) *key = k;
return k ? kNWSuccess : error.code;
}
#if !TARGET_OS_IPHONE
+ (NWError)keychainIdentityWithCertificate:(NWCertificateRef)certificate identity:(NWIdentityRef *)identity;
{
NSError *error = nil;
NWIdentityRef i = [self keychainIdentityWithCertificate:certificate error:&error];
if (identity) *identity = i;
return i ? kNWSuccess : error.code;
}
#endif
@end
+81 -10
View File
@@ -7,16 +7,42 @@
#import <Foundation/Foundation.h>
/** The current and past data formats supported by APNS. */
/** The current and past data formats supported by APNs. For more information see Apple documentation under 'Legacy Information'. */
typedef NS_ENUM(NSInteger, NWNotificationType) {
/** The oldest format, simply concatenates the device token and payload. */
/** The 'Simple Notification Format'. The oldest format, simply concatenates the device token and payload. */
kNWNotificationType0 = 0,
/** Similar to the previous format, but includes and identifier and expiration date. */
/** The 'Enhanced Notification Format'. Similar to the previous format, but includes and identifier and expiration date. */
kNWNotificationType1 = 1,
/** A new, more extensible format that allows for attributes like priority. */
/** The 'Binary Interface and Notification Format'. The latest, more extensible format that allows for attributes like priority. */
kNWNotificationType2 = 2,
};
/** Types of push certificates. */
typedef NS_ENUM(NSInteger, NWCertType) {
/** None. */
kNWCertTypeNone = 0,
/** iOS Development. */
kNWCertTypeIOSDevelopment = 1,
/** iOS Production. */
kNWCertTypeIOSProduction = 2,
/** OS X Development. */
kNWCertTypeMacDevelopment = 3,
/** OS X Production. */
kNWCertTypeMacProduction = 4,
/** Simplified Certificate Handling. */
kNWCertTypeSimplified = 5,
/** Web Push Production. */
kNWCertTypeWebProduction = 6,
/** VoIP Services. */
kNWCertTypeVoIPServices = 7,
/** WatchKit Services. */
kNWCertTypeWatchKitServices = 8,
/** Pass Type ID. */
kNWCertTypePasses = 9,
/** Unknown. */
kNWCertTypeUnknown = 10,
};
/** An ARC-friendly replacement of SecIdentityRef. */
typedef id NWIdentityRef;
@@ -30,8 +56,6 @@ typedef id NWKeyRef;
typedef NS_ENUM(NSInteger, NWError) {
/** No error, that's odd. */
kNWErrorNone = 0,
/** Deprecated in favor of `kNWErrorNone`, removed in 0.7.0 */
kNWSuccess = 0,
/** APN processing error. */
kNWErrorAPNProcessing = -1,
@@ -95,6 +119,30 @@ typedef NS_ENUM(NSInteger, NWError) {
kNWErrorSSLAuthFailed = -208,
/** SSL handshake failed. */
kNWErrorSSLHandshakeFail = -209,
/** SSL handshake root not a known anchor. */
kNWErrorSSLHandshakeUnknownRootCert = -223,
/** SSL handshake chain not verifiable to root. */
kNWErrorSSLHandshakeNoRootCert = -224,
/** SSL handshake expired certificates. */
kNWErrorSSLHandshakeCertExpired = -225,
/** SSL handshake invalid certificate chain. */
kNWErrorSSLHandshakeXCertChainInvalid = -226,
/** SSL handshake expecting client cert. */
kNWErrorSSLHandshakeClientCertRequested = -227,
/** SSL handshake auth interrupted. */
kNWErrorSSLHandshakeServerAuthCompleted = -228,
/** SSL handshake certificate expired. */
kNWErrorSSLHandshakePeerCertExpired = -229,
/** SSL handshake certificate revoked. */
kNWErrorSSLHandshakePeerCertRevoked = -230,
/** SSL handshake certificate unknown. */
kNWErrorSSLHandshakePeerCertUnknown = -233,
/** SSL handshake internal error. */
kNWErrorSSLHandshakeInternalError = -234,
/** SSL handshake in dark wake. */
kNWErrorSSLInDarkWake = -231,
/** SSL handshake connection closed via error. */
kNWErrorSSLHandshakeClosedAbort = -232,
/** SSL handshake timeout. */
kNWErrorSSLHandshakeTimeout = -218,
@@ -131,6 +179,8 @@ typedef NS_ENUM(NSInteger, NWError) {
kNWErrorPKCS12AuthFailed = -312,
/** PKCS12 data wrong password. */
kNWErrorPKCS12Password = -313,
/** PKCS12 data password required. */
kNWErrorPKCS12PasswordRequired = -314,
/** PKCS12 data contains no identities. */
kNWErrorPKCS12NoItems = -307,
/** PKCS12 data contains multiple identities. */
@@ -144,22 +194,43 @@ typedef NS_ENUM(NSInteger, NWError) {
kNWErrorKeychainCreateIdentity = -303,
};
typedef NS_ENUM(NSInteger, NWEnvironment) {
NWEnvironmentNone = 0,
NWEnvironmentSandbox = 1,
NWEnvironmentProduction = 2,
NWEnvironmentAuto = 3,
};
typedef NS_ENUM(NSInteger, NWEnvironmentOptions) {
NWEnvironmentOptionNone = 0,
NWEnvironmentOptionSandbox = 1 << NWEnvironmentSandbox,
NWEnvironmentOptionProduction = 1 << NWEnvironmentProduction,
NWEnvironmentOptionAny = NWEnvironmentOptionSandbox | NWEnvironmentOptionProduction
};
/** NSError dictionary key for integer code that indicates underlying reason. */
extern NSString * const NWErrorReasonCodeKey;
/** A collection of helper methods to support Cocoa-style error handling (`NSError`).
Most methods in this framework return `NO` or `nil` to indicate an error occurred. In that case an error object will be assigned. This class provides a mapping from codes to description string and some methods to instantiate the `NSError` object.
*/
/** Returns string for given environment, for logging purposes */
NSString * descriptionForEnvironentOptions(NWEnvironmentOptions environmentOptions);
NSString * descriptionForEnvironent(NWEnvironment environment);
NSString * descriptionForCertType(NWCertType type);
@interface NWErrorUtil : NSObject
/** @name Helpers */
/** Assigns the error with provided code and associated description, for returning `NO`. */
+ (BOOL)noWithErrorCode:(NWError)code error:(NSError **)error;
+ (BOOL)noWithErrorCode:(NWError)code reason:(NSInteger)reason error:(NSError **)error;
/** Assigns the error with provided code and associated description, for returning `nil`. */
+ (id)nilWithErrorCode:(NWError)code error:(NSError **)error;
// deprecated
+ (NSString *)stringWithError:(NWError)error __deprecated;
+ (id)nilWithErrorCode:(NWError)code reason:(NSInteger)reason error:(NSError **)error;
@end
+72 -11
View File
@@ -7,6 +7,48 @@
#import "NWType.h"
NSString * const NWErrorReasonCodeKey = @"NWErrorReasonCodeKey";
NSString * descriptionForEnvironentOptions(NWEnvironmentOptions environmentOptions)
{
switch (environmentOptions) {
case NWEnvironmentOptionNone: return @"No environment";
case NWEnvironmentOptionSandbox: return @"Sandbox";
case NWEnvironmentOptionProduction: return @"Production";
case NWEnvironmentOptionAny: return @"Sandbox|Production";
}
return nil;
}
NSString * descriptionForEnvironent(NWEnvironment environment)
{
switch (environment) {
case NWEnvironmentNone: return @"none";
case NWEnvironmentProduction: return @"production";
case NWEnvironmentSandbox: return @"sandbox";
case NWEnvironmentAuto: return @"auto";
}
return nil;
}
NSString * descriptionForCertType(NWCertType type)
{
switch (type) {
case kNWCertTypeNone: return @"none";
case kNWCertTypeIOSDevelopment:
case kNWCertTypeIOSProduction: return @"iOS";
case kNWCertTypeMacDevelopment:
case kNWCertTypeMacProduction: return @"macOS";
case kNWCertTypeSimplified: return @"All";
case kNWCertTypeWebProduction: return @"Website";
case kNWCertTypeVoIPServices: return @"VoIP";
case kNWCertTypeWatchKitServices: return @"WatchKit";
case kNWCertTypePasses: return @"Pass";
case kNWCertTypeUnknown: return @"unknown";
}
return nil;
}
@implementation NWErrorUtil
+ (NSString *)stringWithCode:(NWError)code
@@ -47,6 +89,18 @@
case kNWErrorSSLDroppedByServer : return @"SSL handshake dropped by server";
case kNWErrorSSLAuthFailed : return @"SSL handshake authentication failed";
case kNWErrorSSLHandshakeFail : return @"SSL handshake failed";
case kNWErrorSSLHandshakeUnknownRootCert : return @"SSL handshake root not a known anchor";
case kNWErrorSSLHandshakeNoRootCert : return @"SSL handshake chain not verifiable to root";
case kNWErrorSSLHandshakeCertExpired : return @"SSL handshake expired certificates";
case kNWErrorSSLHandshakeXCertChainInvalid : return @"SSL handshake invalid certificate chain";
case kNWErrorSSLHandshakeClientCertRequested : return @"SSL handshake expecting client cert";
case kNWErrorSSLHandshakeServerAuthCompleted : return @"SSL handshake auth interrupted";
case kNWErrorSSLHandshakePeerCertExpired : return @"SSL handshake certificate expired";
case kNWErrorSSLHandshakePeerCertRevoked : return @"SSL handshake certificate revoked";
case kNWErrorSSLHandshakePeerCertUnknown : return @"SSL handshake certificate unknown";
case kNWErrorSSLHandshakeInternalError : return @"SSL handshake internal error";
case kNWErrorSSLInDarkWake : return @"SSL handshake in dark wake";
case kNWErrorSSLHandshakeClosedAbort : return @"SSL handshake connection closed via error";
case kNWErrorSSLHandshakeTimeout : return @"SSL handshake timeout";
case kNWErrorReadDroppedByServer : return @"Read connection dropped by server";
@@ -67,6 +121,7 @@
case kNWErrorPKCS12Decode : return @"PKCS12 data cannot be read or is malformed";
case kNWErrorPKCS12AuthFailed : return @"PKCS12 data password incorrect";
case kNWErrorPKCS12Password : return @"PKCS12 data wrong password";
case kNWErrorPKCS12PasswordRequired : return @"PKCS12 data password required";
case kNWErrorPKCS12NoItems : return @"PKCS12 data contains no identities";
case kNWErrorPKCS12MultipleItems : return @"PKCS12 data contains multiple identities";
@@ -79,31 +134,37 @@
#pragma mark - Helpers
+ (NSError *)errorWithErrorCode:(NWError)code
+ (NSError *)errorWithErrorCode:(NWError)code reason:(NSInteger)reason
{
NSDictionary *info = @{ NSLocalizedDescriptionKey: [self stringWithCode:code] };
NSString *description = [self stringWithCode:code];
if (reason) description = [NSString stringWithFormat:@"%@ (%i)", description, (int)reason];
NSMutableDictionary *info = @{ NSLocalizedDescriptionKey:description }.mutableCopy;
if (reason) [info setValue:@(reason) forKey:NWErrorReasonCodeKey];
return [NSError errorWithDomain:@"NWPusherErrorDomain" code:code userInfo:info];
}
+ (BOOL)noWithErrorCode:(NWError)code error:(NSError *__autoreleasing *)error
{
return [self noWithErrorCode:code reason:0 error:error];
}
+ (BOOL)noWithErrorCode:(NWError)code reason:(NSInteger)reason error:(NSError *__autoreleasing *)error
{
NSAssert(code != kNWErrorNone, @"code != kNWErrorNone");
if (error) *error = [self errorWithErrorCode:code];
if (error) *error = [self errorWithErrorCode:code reason:reason];
return NO;
}
+ (id)nilWithErrorCode:(NWError)code error:(NSError *__autoreleasing *)error
{
return [self nilWithErrorCode:code reason:0 error:error];
}
+ (id)nilWithErrorCode:(NWError)code reason:(NSInteger)reason error:(NSError *__autoreleasing *)error
{
NSAssert(code != kNWErrorNone, @"code != kNWErrorNone");
if (error) *error = [self errorWithErrorCode:code];
if (error) *error = [self errorWithErrorCode:code reason:reason];
return nil;
}
#pragma mark - Deprecated
+ (NSString *)stringWithError:(NWError)error
{
return [self stringWithCode:error];
}
@end
Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 KiB

After

Width:  |  Height:  |  Size: 367 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 363 KiB

After

Width:  |  Height:  |  Size: 181 KiB

+57 -55
View File
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5053" systemVersion="13C64" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment defaultVersion="1070" identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5053"/>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner">
@@ -21,7 +22,7 @@
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application">
<customObject id="-3" userLabel="Application" customClass="NSObject">
<connections>
<outlet property="delegate" destination="kaW-YJ-UA5" id="0Xg-Lu-QoV"/>
</connections>
@@ -63,7 +64,7 @@
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit NewApplication" keyEquivalent="q" id="4sb-4s-VLi">
<menuItem title="Pusher" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
@@ -158,7 +159,7 @@
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="600" height="300"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1177"/>
<value key="minSize" type="size" width="500" height="200"/>
<view key="contentView" id="se5-gp-TjO">
<rect key="frame" x="0.0" y="0.0" width="600" height="300"/>
@@ -166,7 +167,6 @@
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="2E1-cP-egh">
<rect key="frame" x="480" y="252" width="106" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<constraints>
<constraint firstAttribute="width" constant="94" id="Rut-jE-8JY"/>
</constraints>
@@ -180,7 +180,6 @@
</button>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="aJR-Gv-8Xr">
<rect key="frame" x="18" y="256" width="463" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Select certificate" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="RvW-sH-WOM" id="XcZ-r4-iAc">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
@@ -194,22 +193,8 @@
<action selector="certificateSelected:" target="kaW-YJ-UA5" id="Asf-IM-UFv"/>
</connections>
</popUpButton>
<comboBox verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="xpc-0j-elb">
<rect key="frame" x="20" y="230" width="563" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<comboBoxCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" enabled="NO" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Device push token (only first 64 hex chars used, other text is ignored)" drawsBackground="YES" completes="NO" numberOfVisibleItems="5" id="Dzy-yi-6QY">
<font key="font" size="10" name="Monaco"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</comboBoxCell>
<connections>
<action selector="tokenSelected:" target="kaW-YJ-UA5" id="p9a-qh-3Nh"/>
<outlet property="delegate" destination="kaW-YJ-UA5" id="ZZ9-SB-ZBN"/>
</connections>
</comboBox>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="imk-VN-mp1">
<rect key="frame" x="18" y="202" width="155" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<rect key="frame" x="18" y="180" width="155" height="26"/>
<constraints>
<constraint firstAttribute="width" constant="150" id="rN0-Vp-M6c"/>
</constraints>
@@ -231,17 +216,16 @@
</popUpButtonCell>
</popUpButton>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="c5v-al-Hn5">
<rect key="frame" x="176" y="202" width="155" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<rect key="frame" x="176" y="180" width="160" height="26"/>
<constraints>
<constraint firstAttribute="width" constant="150" id="DV9-wc-su5"/>
<constraint firstAttribute="width" constant="155" id="DV9-wc-su5"/>
</constraints>
<popUpButtonCell key="cell" type="push" title="Priority: None" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="5dF-Og-jd1" id="ijp-4f-mXC">
<popUpButtonCell key="cell" type="push" title="Priority: None" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="5dF-Og-jd1" id="ijp-4f-mXC">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" title="OtherViews" id="XbO-4x-lw5">
<items>
<menuItem title="Priority: None" id="5dF-Og-jd1"/>
<menuItem title="Priority: None" state="on" id="5dF-Og-jd1"/>
<menuItem title="Conserve power (5)" id="7DJ-kb-Wf3"/>
<menuItem title="Immediately (10)" id="eBG-1S-cUL"/>
</items>
@@ -249,9 +233,8 @@
</popUpButtonCell>
</popUpButton>
<segmentedControl verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="EnU-aP-5PD">
<rect key="frame" x="464" y="199" width="118" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<segmentedCell key="cell" alignment="left" style="rounded" trackingMode="selectOne" id="Olm-G5-Man">
<rect key="frame" x="456" y="177" width="126" height="24"/>
<segmentedCell key="cell" borderStyle="border" alignment="left" style="rounded" trackingMode="selectOne" id="Olm-G5-Man">
<font key="font" metaFont="system"/>
<segments>
<segment label="Payload" selected="YES"/>
@@ -264,7 +247,6 @@
</segmentedControl>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="pAB-wf-piT">
<rect key="frame" x="504" y="13" width="82" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<constraints>
<constraint firstAttribute="width" constant="70" id="huG-oV-gOx"/>
</constraints>
@@ -278,7 +260,6 @@
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="M70-t1-JuG">
<rect key="frame" x="18" y="23" width="486" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" id="d6h-q1-H0e">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@@ -286,29 +267,29 @@
</textFieldCell>
</textField>
<scrollView horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Q6j-iu-9I9">
<rect key="frame" x="20" y="45" width="560" height="152"/>
<autoresizingMask key="autoresizingMask"/>
<rect key="frame" x="20" y="45" width="560" height="130"/>
<clipView key="contentView" id="e4e-ov-ymY">
<rect key="frame" x="1" y="1" width="558" height="150"/>
<rect key="frame" x="1" y="1" width="558" height="128"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView importsGraphics="NO" findStyle="panel" continuousSpellChecking="YES" allowsUndo="YES" usesRuler="YES" usesFontPanel="YES" verticallyResizable="YES" allowsNonContiguousLayout="YES" quoteSubstitution="YES" dashSubstitution="YES" spellingCorrection="YES" smartInsertDelete="YES" id="ad5-lb-L5u">
<rect key="frame" x="0.0" y="0.0" width="558" height="150"/>
<textView importsGraphics="NO" richText="NO" verticallyResizable="YES" findStyle="panel" allowsCharacterPickerTouchBarItem="NO" allowsUndo="YES" allowsNonContiguousLayout="YES" textCompletion="NO" id="ad5-lb-L5u">
<rect key="frame" x="0.0" y="0.0" width="558" height="128"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<size key="minSize" width="558" height="150"/>
<size key="minSize" width="558" height="128"/>
<size key="maxSize" width="573" height="10000000"/>
<attributedString key="textStorage">
<fragment content="..">
<attributes>
<font key="NSFont" metaFont="toolTip"/>
<font key="NSFont" metaFont="smallSystem"/>
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
</attributes>
</fragment>
</attributedString>
<color key="insertionPointColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<size key="minSize" width="558" height="150"/>
<size key="maxSize" width="573" height="10000000"/>
<allowedInputSourceLocales>
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
</allowedInputSourceLocales>
<connections>
<outlet property="delegate" destination="kaW-YJ-UA5" id="bUh-Oq-w5B"/>
</connections>
@@ -321,13 +302,12 @@
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="sbz-Qw-fOe">
<rect key="frame" x="543" y="1" width="16" height="150"/>
<rect key="frame" x="543" y="1" width="16" height="128"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gQs-Aa-IJi">
<rect key="frame" x="470" y="49" width="104" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<constraints>
<constraint firstAttribute="width" constant="100" id="Vlu-lQ-8rQ"/>
</constraints>
@@ -338,21 +318,18 @@
</textFieldCell>
</textField>
<scrollView hidden="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="z4n-XE-cfI">
<rect key="frame" x="20" y="45" width="560" height="152"/>
<autoresizingMask key="autoresizingMask"/>
<rect key="frame" x="20" y="45" width="560" height="130"/>
<clipView key="contentView" id="uaF-sl-etn">
<rect key="frame" x="1" y="1" width="558" height="150"/>
<rect key="frame" x="1" y="1" width="558" height="128"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView importsGraphics="NO" findStyle="panel" continuousSpellChecking="YES" allowsUndo="YES" usesRuler="YES" usesFontPanel="YES" verticallyResizable="YES" allowsNonContiguousLayout="YES" quoteSubstitution="YES" dashSubstitution="YES" spellingCorrection="YES" smartInsertDelete="YES" id="pi6-RR-ayT">
<rect key="frame" x="0.0" y="0.0" width="558" height="150"/>
<textView importsGraphics="NO" richText="NO" verticallyResizable="YES" usesFontPanel="YES" findStyle="panel" continuousSpellChecking="YES" allowsUndo="YES" usesRuler="YES" allowsNonContiguousLayout="YES" quoteSubstitution="YES" dashSubstitution="YES" spellingCorrection="YES" smartInsertDelete="YES" id="pi6-RR-ayT">
<rect key="frame" x="0.0" y="0.0" width="558" height="128"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" name="windowBackgroundColor" catalog="System" colorSpace="catalog"/>
<size key="minSize" width="558" height="150"/>
<size key="minSize" width="558" height="128"/>
<size key="maxSize" width="573" height="10000000"/>
<color key="insertionPointColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<size key="minSize" width="558" height="150"/>
<size key="maxSize" width="573" height="10000000"/>
</textView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@@ -362,10 +339,32 @@
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="pny-Of-exT">
<rect key="frame" x="543" y="1" width="16" height="150"/>
<rect key="frame" x="543" y="1" width="16" height="128"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<button translatesAutoresizingMaskIntoConstraints="NO" id="hU6-Ym-KR3">
<rect key="frame" x="18" y="235" width="223" height="18"/>
<buttonCell key="cell" type="check" title="Should use sandbox environment" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="ros-Zj-bni">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="sanboxCheckBoxDidPressed:" target="kaW-YJ-UA5" id="kzM-IO-iQv"/>
</connections>
</button>
<comboBox verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="xpc-0j-elb">
<rect key="frame" x="20" y="208" width="563" height="23"/>
<comboBoxCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" enabled="NO" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Device push token (only first 64 hex chars used, other text is ignored)" drawsBackground="YES" completes="NO" numberOfVisibleItems="5" id="Dzy-yi-6QY">
<font key="font" size="10" name="Monaco"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</comboBoxCell>
<connections>
<action selector="tokenSelected:" target="kaW-YJ-UA5" id="p9a-qh-3Nh"/>
<outlet property="delegate" destination="kaW-YJ-UA5" id="ZZ9-SB-ZBN"/>
</connections>
</comboBox>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="pAB-wf-piT" secondAttribute="trailing" constant="20" id="1DK-KM-tMh"/>
@@ -387,9 +386,11 @@
<constraint firstItem="c5v-al-Hn5" firstAttribute="leading" secondItem="imk-VN-mp1" secondAttribute="trailing" constant="8" id="Syg-OZ-s0W"/>
<constraint firstItem="2E1-cP-egh" firstAttribute="top" secondItem="se5-gp-TjO" secondAttribute="top" constant="20" id="VPW-kd-JRb"/>
<constraint firstItem="pAB-wf-piT" firstAttribute="top" secondItem="z4n-XE-cfI" secondAttribute="bottom" constant="4" id="VSi-vV-wpY"/>
<constraint firstItem="xpc-0j-elb" firstAttribute="top" secondItem="aJR-Gv-8Xr" secondAttribute="bottom" constant="8" id="ejA-7v-S2S"/>
<constraint firstItem="hU6-Ym-KR3" firstAttribute="top" secondItem="aJR-Gv-8Xr" secondAttribute="bottom" constant="8" symbolic="YES" id="ZTZ-NV-b30"/>
<constraint firstItem="EnU-aP-5PD" firstAttribute="top" secondItem="c5v-al-Hn5" secondAttribute="top" constant="4" id="emm-N1-qPy"/>
<constraint firstAttribute="trailing" secondItem="z4n-XE-cfI" secondAttribute="trailing" constant="20" id="gM0-t7-RqF"/>
<constraint firstItem="hU6-Ym-KR3" firstAttribute="leading" secondItem="aJR-Gv-8Xr" secondAttribute="leading" id="h8B-8W-BTt"/>
<constraint firstItem="xpc-0j-elb" firstAttribute="top" secondItem="hU6-Ym-KR3" secondAttribute="bottom" constant="8" symbolic="YES" id="hqj-w5-p6V"/>
<constraint firstItem="M70-t1-JuG" firstAttribute="leading" secondItem="se5-gp-TjO" secondAttribute="leading" constant="20" id="ief-Fk-3Mg"/>
<constraint firstAttribute="trailing" secondItem="gQs-Aa-IJi" secondAttribute="trailing" constant="28" id="oT0-VS-Mam"/>
<constraint firstAttribute="bottom" secondItem="M70-t1-JuG" secondAttribute="bottom" constant="23" id="pWW-7F-Cxq"/>
@@ -414,6 +415,7 @@
<outlet property="_priorityPopup" destination="c5v-al-Hn5" id="6zL-7L-7t3"/>
<outlet property="_pushButton" destination="pAB-wf-piT" id="ndY-Uh-dgS"/>
<outlet property="_reconnectButton" destination="2E1-cP-egh" id="4CL-8O-MKG"/>
<outlet property="_sanboxCheckBox" destination="hU6-Ym-KR3" id="9Zb-UH-d23"/>
<outlet property="_tokenCombo" destination="xpc-0j-elb" id="f1o-6I-zGl"/>
<outlet property="window" destination="F0z-JX-Cv5" id="a4g-51-daC"/>
</connections>
+88 -48
View File
@@ -6,12 +6,7 @@
//
#import "NWAppDelegate.h"
#import "NWHub.h"
#import "NWNotification.h"
#import "NWSecTools.h"
#import "NWLCore.h"
#import "NWPushFeedback.h"
#import <PusherKit/PusherKit.h>
@interface NWAppDelegate () <NWHubDelegate> @end
@@ -27,6 +22,7 @@
IBOutlet NSPopUpButton *_expiryPopup;
IBOutlet NSPopUpButton *_priorityPopup;
IBOutlet NSScrollView *_logScroll;
IBOutlet NSButton *_sanboxCheckBox;
NWHub *_hub;
NSDictionary *_config;
@@ -109,6 +105,14 @@
[self reconnect];
}
- (IBAction)sanboxCheckBoxDidPressed:(NSButton *)sender
{
if (_selectedCertificate)
{
[self reconnect];
}
}
- (void)notification:(NWNotification *)notification didFailWithError:(NSError *)error
{
dispatch_async(dispatch_get_main_queue(), ^{
@@ -138,10 +142,10 @@
NWLogWarn(@"No push certificates in keychain.");
}
certs = [certs sortedArrayUsingComparator:^NSComparisonResult(NWCertificateRef a, NWCertificateRef b) {
BOOL adev = [NWSecTools isSandboxCertificate:a];
BOOL bdev = [NWSecTools isSandboxCertificate:b];
if (adev != bdev) {
return adev ? NSOrderedAscending : NSOrderedDescending;
NWEnvironmentOptions envOptionsA = [NWSecTools environmentOptionsForCertificate:a];
NWEnvironmentOptions envOptionsB = [NWSecTools environmentOptionsForCertificate:b];
if (envOptionsA != envOptionsB) {
return envOptionsA < envOptionsB;
}
NSString *aname = [NWSecTools summaryWithCertificate:a];
NSString *bname = [NWSecTools summaryWithCertificate:b];
@@ -159,13 +163,20 @@
NSMutableString *suffix = @" ".mutableCopy;
[_certificatePopup removeAllItems];
[_certificatePopup addItemWithTitle:@"Select Push Certificate"];
NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
for (NSArray *pair in _certificateIdentityPairs) {
NWCertificateRef certificate = pair[0];
BOOL hasIdentity = (pair[1] != NSNull.null);
BOOL sandbox = [NWSecTools isSandboxCertificate:certificate];
NSString *summary = [NWSecTools summaryWithCertificate:certificate];
NWEnvironmentOptions environmentOptions = [NWSecTools environmentOptionsForCertificate:certificate];
NSString *summary = nil;
NWCertType certType = [NWSecTools typeWithCertificate:certificate summary:&summary];
NSString *type = descriptionForCertType(certType);
NSDate *date = [NWSecTools expirationWithCertificate:certificate];
NSString *expire = [NSString stringWithFormat:@" [%@]", date ? [formatter stringFromDate:date] : @"expired"];
// summary = @"com.example.app";
[_certificatePopup addItemWithTitle:[NSString stringWithFormat:@"%@%@%@%@", hasIdentity ? @"imported: " : @"", summary, sandbox ? @" (sandbox)" : @"", suffix]];
[_certificatePopup addItemWithTitle:[NSString stringWithFormat:@"%@%@ (%@ %@)%@%@", hasIdentity ? @"imported: " : @"", summary, type, descriptionForEnvironentOptions(environmentOptions), expire, suffix]];
[suffix appendString:@" "];
}
[_certificatePopup addItemWithTitle:@"Import PKCS #12 file (.p12)..."];
@@ -197,6 +208,9 @@
NSData *data = [NSData dataWithContentsOfURL:url];
NSError *error = nil;
NSArray *ids = [NWSecTools identitiesWithPKCS12Data:data password:password error:&error];
if (!ids && password.length == 0 && error.code == kNWErrorPKCS12Password) {
ids = [NWSecTools identitiesWithPKCS12Data:data password:nil error:&error];
}
if (!ids) {
NWLogWarn(@"Unable to read p12 file: %@", error.localizedDescription);
return;
@@ -272,6 +286,18 @@
}
}
- (NWEnvironment)selectedEnvironmentForCertificate:(NWCertificateRef)certificate
{
return (_sanboxCheckBox.state & NSOnState) ? NWEnvironmentSandbox : NWEnvironmentProduction;
}
- (NWEnvironment)preferredEnvironmentForCertificate:(NWCertificateRef)certificate
{
NWEnvironmentOptions environmentOptions = [NWSecTools environmentOptionsForCertificate:certificate];
return (environmentOptions & NWEnvironmentOptionSandbox) ? NWEnvironmentSandbox : NWEnvironmentProduction;
}
#pragma mark - Connection
- (void)connectWithCertificateAtIndex:(NSUInteger)index
@@ -279,14 +305,16 @@
if (index == 0) {
[_certificatePopup selectItemAtIndex:0];
_lastSelectedIndex = 0;
[self selectCertificate:nil identity:nil];
[self selectCertificate:nil identity:nil environment:NWEnvironmentSandbox];
_tokenCombo.enabled = NO;
[self loadSelectedToken];
} else if (index <= _certificateIdentityPairs.count) {
[_certificatePopup selectItemAtIndex:index];
_lastSelectedIndex = index;
NSArray *pair = [_certificateIdentityPairs objectAtIndex:index - 1];
[self selectCertificate:pair[0] identity:pair[1] == NSNull.null ? nil : pair[1]];
NWCertificateRef certificate = pair[0];
NWIdentityRef identity = pair[1];
[self selectCertificate:certificate identity:identity == NSNull.null ? nil : identity environment:[self preferredEnvironmentForCertificate:certificate]];
_tokenCombo.enabled = YES;
[self loadSelectedToken];
} else {
@@ -295,12 +323,32 @@
}
}
- (void)selectCertificate:(NWCertificateRef)certificate identity:(NWIdentityRef)identity
- (void)disableButtons
{
_pushButton.enabled = NO;
_reconnectButton.enabled = NO;
_sanboxCheckBox.enabled = NO;
}
- (void)enableButtonsForCertificate:(NWCertificateRef)certificate environment:(NWEnvironment)environment
{
NWEnvironmentOptions environmentOptions = [NWSecTools environmentOptionsForCertificate:certificate];
BOOL shouldEnableEnvButton = (environmentOptions == NWEnvironmentOptionAny);
BOOL shouldSelectSandboxEnv = (environment == NWEnvironmentSandbox);
_pushButton.enabled = YES;
_reconnectButton.enabled = YES;
_sanboxCheckBox.enabled = shouldEnableEnvButton;
_sanboxCheckBox.state = shouldSelectSandboxEnv ? NSOnState : NSOffState;
}
- (void)selectCertificate:(NWCertificateRef)certificate identity:(NWIdentityRef)identity environment:(NWEnvironment)environment
{
if (_hub) {
[_hub disconnect]; _hub = nil;
_pushButton.enabled = NO;
_reconnectButton.enabled = NO;
[self disableButtons];
NWLogInfo(@"Disconnected from APN");
}
@@ -308,20 +356,20 @@
[self updateTokenCombo];
if (certificate) {
BOOL sandbox = [NWSecTools isSandboxCertificate:certificate];
NSString *summary = [NWSecTools summaryWithCertificate:certificate];
NWLogInfo(@"Connecting to APN.. (%@%@)", summary, sandbox ? @" sandbox" : @"");
NWLogInfo(@"Connecting to APN... (%@ %@)", summary, descriptionForEnvironent(environment));
dispatch_async(_serial, ^{
NSError *error = nil;
NWIdentityRef ident = identity ?: [NWSecTools keychainIdentityWithCertificate:certificate error:&error];
NWHub *hub = [NWHub connectWithDelegate:self identity:ident error:&error];
NWHub *hub = [NWHub connectWithDelegate:self identity:ident environment:environment error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
if (hub) {
NWLogInfo(@"Connected (%@%@)", summary, sandbox ? @" sandbox" : @"");
NWLogInfo(@"Connected (%@ %@)", summary, descriptionForEnvironent(environment));
_hub = hub;
_pushButton.enabled = YES;
_reconnectButton.enabled = YES;
[self enableButtonsForCertificate:certificate environment:environment];
} else {
NWLogWarn(@"Unable to connect: %@", error.localizedDescription);
[hub disconnect];
@@ -334,22 +382,12 @@
- (void)reconnect
{
NWLogInfo(@"Reconnecting..");
_pushButton.enabled = NO;
_reconnectButton.enabled = NO;
dispatch_async(_serial, ^{
NSError *error = nil;
BOOL connected = [_hub reconnectWithError:&error];
dispatch_async(dispatch_get_main_queue(), ^{
if (connected) {
NWLogInfo(@"Reconnected");
_pushButton.enabled = YES;
} else {
NWLogWarn(@"Unable to reconnect: %@", error.localizedDescription);
}
_reconnectButton.enabled = YES;
});
});
NSString *summary = [NWSecTools summaryWithCertificate:_selectedCertificate];
NWEnvironment environment = [self selectedEnvironmentForCertificate:_selectedCertificate];
NWLogInfo(@"Reconnecting to APN...(%@ %@)", summary, descriptionForEnvironent(environment));
[self selectCertificate:_selectedCertificate identity:nil environment:environment];
}
- (void)push
@@ -372,7 +410,7 @@
if (read) {
if (!failed) NWLogInfo(@"Payload has been pushed");
} else {
NWLogWarn(@"Unable to read failed: %@", error.localizedDescription);
NWLogWarn(@"Unable to read: %@", error.localizedDescription);
}
[_hub trimIdentifiers];
});
@@ -390,17 +428,17 @@
NWLogWarn(@"Unable to connect to feedback service: no certificate selected");
return;
}
BOOL sandbox = [NWSecTools isSandboxCertificate:certificate];
NWEnvironment environment = [self selectedEnvironmentForCertificate:certificate];
NSString *summary = [NWSecTools summaryWithCertificate:certificate];
NWLogInfo(@"Connecting to feedback service.. (%@%@)", summary, sandbox ? @" sandbox" : @"");
NWLogInfo(@"Connecting to feedback service.. (%@ %@)", summary, descriptionForEnvironent(environment));
NSError *error = nil;
NWIdentityRef identity = [NWSecTools keychainIdentityWithCertificate:_selectedCertificate error:&error];
NWPushFeedback *feedback = [NWPushFeedback connectWithIdentity:identity error:&error];
NWPushFeedback *feedback = [NWPushFeedback connectWithIdentity:identity environment:[self selectedEnvironmentForCertificate:certificate] error:&error];
if (!feedback) {
NWLogWarn(@"Unable to connect to feedback service: %@", error.localizedDescription);
return;
}
NWLogInfo(@"Reading feedback service.. (%@%@)", summary, sandbox ? @" sandbox" : @"");
NWLogInfo(@"Reading feedback service.. (%@ %@)", summary, descriptionForEnvironent(environment));
NSArray *pairs = [feedback readTokenDatePairsWithMax:1000 error:&error];
if (!pairs) {
NWLogWarn(@"Unable to read feedback: %@", error.localizedDescription);
@@ -421,14 +459,16 @@
- (NSString *)identifierWithCertificate:(NWCertificateRef)certificate
{
BOOL sandbox = [NWSecTools isSandboxCertificate:certificate];
NWEnvironmentOptions environmentOptions = [NWSecTools environmentOptionsForCertificate:certificate];
NSString *summary = [NWSecTools summaryWithCertificate:certificate];
return summary ? [NSString stringWithFormat:@"%@%@", summary, sandbox ? @"-sandbox" : @""] : nil;
return summary ? [NSString stringWithFormat:@"%@-%@", summary, descriptionForEnvironentOptions(environmentOptions)] : nil;
}
- (NSMutableArray *)tokensWithCertificate:(NWCertificateRef)certificate create:(BOOL)create
{
NSString *identifier = [self identifierWithCertificate:certificate];
NWEnvironment environment = [self selectedEnvironmentForCertificate:_selectedCertificate];
NSString *summary = [NWSecTools summaryWithCertificate:certificate];
NSString *identifier = summary ? [NSString stringWithFormat:@"%@%@", summary, environment == NWEnvironmentSandbox ? @"-sandbox" : @""] : nil;
if (!identifier) return nil;
NSArray *result = _config[@"identifiers"][identifier];
if (create && !result) result = (_config[@"identifiers"][identifier] = @[].mutableCopy);
+3 -3
View File
@@ -9,7 +9,7 @@
<key>CFBundleIconFile</key>
<string>icon</string>
<key>CFBundleIdentifier</key>
<string>com.noodlewerk.${PRODUCT_NAME:rfc1034identifier}</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@@ -17,11 +17,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.5.4</string>
<string>0.7.5</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>10</string>
<string>19</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key>
+2 -2
View File
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = 'NWPusher'
s.version = '0.5.4'
s.summary = 'OS X and iOS application and framework to play with the Apple Push Notification Service (APNS).'
s.version = '0.7.5'
s.summary = 'OS X and iOS application and framework to play with the Apple Push Notification service (APNs).'
s.homepage = 'https://github.com/noodlewerk/NWPusher'
s.license = { :type => 'BSD', :file => 'LICENSE.txt' }
s.author = { 'Leonard van Driel' => 'leonardvandriel@gmail.com' }
+504 -35
View File
@@ -7,9 +7,45 @@
objects = {
/* Begin PBXBuildFile section */
5C7803881D3C4668002107FB /* PusherKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C7803861D3C4668002107FB /* PusherKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C78038B1D3C4668002107FB /* PusherKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C7803841D3C4668002107FB /* PusherKit.framework */; };
5C78038C1D3C4668002107FB /* PusherKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5C7803841D3C4668002107FB /* PusherKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5C7803911D3C4683002107FB /* NWHub.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A1189682D30043DA98 /* NWHub.m */; };
5C7803921D3C4683002107FB /* NWNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A3189682D30043DA98 /* NWNotification.m */; };
5C7803931D3C4683002107FB /* NWPusher.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A5189682D30043DA98 /* NWPusher.m */; };
5C7803941D3C4683002107FB /* NWPushFeedback.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A7189682D30043DA98 /* NWPushFeedback.m */; };
5C7803951D3C4683002107FB /* NWSecTools.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A9189682D30043DA98 /* NWSecTools.m */; };
5C7803961D3C4683002107FB /* NWSSLConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232AB189682D30043DA98 /* NWSSLConnection.m */; };
5C7803971D3C4683002107FB /* NWType.m in Sources */ = {isa = PBXBuildFile; fileRef = B34BF1B318DDF401004BA9F7 /* NWType.m */; };
5C7803981D3C4698002107FB /* NWLCore.c in Sources */ = {isa = PBXBuildFile; fileRef = B3376A61172BB71200242EBB /* NWLCore.c */; };
5C7803991D3C4749002107FB /* NWHub.h in Headers */ = {isa = PBXBuildFile; fileRef = B3F232A0189682D30043DA98 /* NWHub.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C78039A1D3C4749002107FB /* NWNotification.h in Headers */ = {isa = PBXBuildFile; fileRef = B3F232A2189682D30043DA98 /* NWNotification.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C78039B1D3C4749002107FB /* NWPusher.h in Headers */ = {isa = PBXBuildFile; fileRef = B3F232A4189682D30043DA98 /* NWPusher.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C78039C1D3C4749002107FB /* NWPushFeedback.h in Headers */ = {isa = PBXBuildFile; fileRef = B3F232A6189682D30043DA98 /* NWPushFeedback.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C78039D1D3C4749002107FB /* NWSecTools.h in Headers */ = {isa = PBXBuildFile; fileRef = B3F232A8189682D30043DA98 /* NWSecTools.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C78039E1D3C4749002107FB /* NWSSLConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = B3F232AA189682D30043DA98 /* NWSSLConnection.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C78039F1D3C4749002107FB /* NWType.h in Headers */ = {isa = PBXBuildFile; fileRef = B34BF1B218DDF401004BA9F7 /* NWType.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C7803A01D3C4749002107FB /* NWLCore.h in Headers */ = {isa = PBXBuildFile; fileRef = B3376A62172BB71200242EBB /* NWLCore.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C7803AA1D3C4826002107FB /* PusherKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C7803A81D3C4826002107FB /* PusherKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C7803AD1D3C4826002107FB /* PusherKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C7803A61D3C4826002107FB /* PusherKit.framework */; };
5C7803AF1D3C4826002107FB /* PusherKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5C7803A61D3C4826002107FB /* PusherKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5C7803B31D3C486F002107FB /* NWLCore.c in Sources */ = {isa = PBXBuildFile; fileRef = B3376A61172BB71200242EBB /* NWLCore.c */; };
5C7803B41D3C487B002107FB /* NWHub.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A1189682D30043DA98 /* NWHub.m */; };
5C7803B51D3C487B002107FB /* NWNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A3189682D30043DA98 /* NWNotification.m */; };
5C7803B61D3C487B002107FB /* NWPusher.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A5189682D30043DA98 /* NWPusher.m */; };
5C7803B71D3C487B002107FB /* NWPushFeedback.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A7189682D30043DA98 /* NWPushFeedback.m */; };
5C7803B81D3C487B002107FB /* NWSecTools.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A9189682D30043DA98 /* NWSecTools.m */; };
5C7803B91D3C487B002107FB /* NWSSLConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232AB189682D30043DA98 /* NWSSLConnection.m */; };
5C7803BA1D3C487B002107FB /* NWType.m in Sources */ = {isa = PBXBuildFile; fileRef = B34BF1B318DDF401004BA9F7 /* NWType.m */; };
5C7803BB1D3C488C002107FB /* NWHub.h in Headers */ = {isa = PBXBuildFile; fileRef = B3F232A0189682D30043DA98 /* NWHub.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C7803BC1D3C488C002107FB /* NWNotification.h in Headers */ = {isa = PBXBuildFile; fileRef = B3F232A2189682D30043DA98 /* NWNotification.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C7803BD1D3C488C002107FB /* NWPusher.h in Headers */ = {isa = PBXBuildFile; fileRef = B3F232A4189682D30043DA98 /* NWPusher.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C7803BE1D3C488C002107FB /* NWPushFeedback.h in Headers */ = {isa = PBXBuildFile; fileRef = B3F232A6189682D30043DA98 /* NWPushFeedback.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C7803BF1D3C488C002107FB /* NWSecTools.h in Headers */ = {isa = PBXBuildFile; fileRef = B3F232A8189682D30043DA98 /* NWSecTools.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C7803C01D3C488C002107FB /* NWSSLConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = B3F232AA189682D30043DA98 /* NWSSLConnection.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C7803C11D3C488C002107FB /* NWType.h in Headers */ = {isa = PBXBuildFile; fileRef = B34BF1B218DDF401004BA9F7 /* NWType.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C7803C21D3C488C002107FB /* NWLCore.h in Headers */ = {isa = PBXBuildFile; fileRef = B3376A62172BB71200242EBB /* NWLCore.h */; settings = {ATTRIBUTES = (Public, ); }; };
B3005FC318F43659009BB7C3 /* Application.xib in Resources */ = {isa = PBXBuildFile; fileRef = B3005FC218F43659009BB7C3 /* Application.xib */; };
B3376A63172BB71200242EBB /* NWLCore.c in Sources */ = {isa = PBXBuildFile; fileRef = B3376A61172BB71200242EBB /* NWLCore.c */; };
B3376A64172BB71200242EBB /* NWLCore.c in Sources */ = {isa = PBXBuildFile; fileRef = B3376A61172BB71200242EBB /* NWLCore.c */; };
B33FB1C8172B185C006529CE /* icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = B33FB1BB172B185C006529CE /* icon.icns */; };
B33FB1C9172B185C006529CE /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B33FB1BC172B185C006529CE /* main.m */; };
B33FB1CB172B185C006529CE /* NWAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B33FB1BF172B185C006529CE /* NWAppDelegate.m */; };
@@ -26,8 +62,6 @@
B33FB215172B303D006529CE /* Icon-72@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B33FB211172B303D006529CE /* Icon-72@2x.png */; };
B33FB216172B303D006529CE /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = B33FB212172B303D006529CE /* icon.png */; };
B33FB217172B303D006529CE /* Icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B33FB213172B303D006529CE /* Icon@2x.png */; };
B34BF1B418DDF401004BA9F7 /* NWType.m in Sources */ = {isa = PBXBuildFile; fileRef = B34BF1B318DDF401004BA9F7 /* NWType.m */; };
B34BF1B518DDF401004BA9F7 /* NWType.m in Sources */ = {isa = PBXBuildFile; fileRef = B34BF1B318DDF401004BA9F7 /* NWType.m */; };
B395BA12172BC17A00631932 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = B3C6BE0015FD30E900F1F3F1 /* README.md */; };
B3AFABEF172C81910027346A /* config.plist in Resources */ = {isa = PBXBuildFile; fileRef = B3AFABEE172C81910027346A /* config.plist */; };
B3B4DCD318A7998300F9F258 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = B3B4DCD218A7998300F9F258 /* LICENSE.txt */; };
@@ -36,21 +70,57 @@
B3C6BDD315FD27E900F1F3F1 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B3C6BDD215FD27E900F1F3F1 /* Security.framework */; };
B3C6BE0115FD30E900F1F3F1 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = B3C6BE0015FD30E900F1F3F1 /* README.md */; };
B3F23256189657DA0043DA98 /* pusher.p12 in Resources */ = {isa = PBXBuildFile; fileRef = B3F23255189657DA0043DA98 /* pusher.p12 */; };
B3F232AE189682D30043DA98 /* NWHub.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A1189682D30043DA98 /* NWHub.m */; };
B3F232AF189682D30043DA98 /* NWHub.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A1189682D30043DA98 /* NWHub.m */; };
B3F232B0189682D30043DA98 /* NWNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A3189682D30043DA98 /* NWNotification.m */; };
B3F232B1189682D30043DA98 /* NWNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A3189682D30043DA98 /* NWNotification.m */; };
B3F232B2189682D30043DA98 /* NWPusher.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A5189682D30043DA98 /* NWPusher.m */; };
B3F232B3189682D30043DA98 /* NWPusher.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A5189682D30043DA98 /* NWPusher.m */; };
B3F232B4189682D30043DA98 /* NWPushFeedback.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A7189682D30043DA98 /* NWPushFeedback.m */; };
B3F232B5189682D30043DA98 /* NWPushFeedback.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A7189682D30043DA98 /* NWPushFeedback.m */; };
B3F232B6189682D30043DA98 /* NWSecTools.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A9189682D30043DA98 /* NWSecTools.m */; };
B3F232B7189682D30043DA98 /* NWSecTools.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232A9189682D30043DA98 /* NWSecTools.m */; };
B3F232B8189682D30043DA98 /* NWSSLConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232AB189682D30043DA98 /* NWSSLConnection.m */; };
B3F232B9189682D30043DA98 /* NWSSLConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = B3F232AB189682D30043DA98 /* NWSSLConnection.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
5C7803891D3C4668002107FB /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = B3C6BD7215FD24D200F1F3F1 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 5C7803831D3C4668002107FB;
remoteInfo = "PusherKit-iOS";
};
5C7803AB1D3C4826002107FB /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = B3C6BD7215FD24D200F1F3F1 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 5C7803A51D3C4826002107FB;
remoteInfo = "PusherKit-OSX";
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
5C7803901D3C4668002107FB /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
5C78038C1D3C4668002107FB /* PusherKit.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
5C7803AE1D3C4826002107FB /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
5C7803AF1D3C4826002107FB /* PusherKit.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
5C7803841D3C4668002107FB /* PusherKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PusherKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5C7803861D3C4668002107FB /* PusherKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PusherKit.h; sourceTree = "<group>"; };
5C7803871D3C4668002107FB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5C7803A61D3C4826002107FB /* PusherKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PusherKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5C7803A81D3C4826002107FB /* PusherKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PusherKit.h; sourceTree = "<group>"; };
5C7803A91D3C4826002107FB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
B3005FC218F43659009BB7C3 /* Application.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = Application.xib; sourceTree = "<group>"; };
B3376A61172BB71200242EBB /* NWLCore.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = NWLCore.c; path = Mac/NWLCore.c; sourceTree = SOURCE_ROOT; };
B3376A62172BB71200242EBB /* NWLCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NWLCore.h; path = Mac/NWLCore.h; sourceTree = SOURCE_ROOT; };
@@ -106,11 +176,26 @@
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
5C7803801D3C4668002107FB /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
5C7803A21D3C4826002107FB /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
B33FB1CE172B1A66006529CE /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
B33FB20F172B1EC2006529CE /* Security.framework in Frameworks */,
5C78038B1D3C4668002107FB /* PusherKit.framework in Frameworks */,
B33FB204172B1BAD006529CE /* CoreGraphics.framework in Frameworks */,
B33FB202172B1BA5006529CE /* Foundation.framework in Frameworks */,
B33FB200172B1B9F006529CE /* UIKit.framework in Frameworks */,
@@ -123,12 +208,31 @@
files = (
B3C6BDD315FD27E900F1F3F1 /* Security.framework in Frameworks */,
B3C6BD8015FD24D200F1F3F1 /* Cocoa.framework in Frameworks */,
5C7803AD1D3C4826002107FB /* PusherKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
5C7803851D3C4668002107FB /* PusherKit-iOS */ = {
isa = PBXGroup;
children = (
5C7803861D3C4668002107FB /* PusherKit.h */,
5C7803871D3C4668002107FB /* Info.plist */,
);
path = "PusherKit-iOS";
sourceTree = "<group>";
};
5C7803A71D3C4826002107FB /* PusherKit-OSX */ = {
isa = PBXGroup;
children = (
5C7803A81D3C4826002107FB /* PusherKit.h */,
5C7803A91D3C4826002107FB /* Info.plist */,
);
path = "PusherKit-OSX";
sourceTree = "<group>";
};
B3376A5F172B9EFD00242EBB /* Supporting Files */ = {
isa = PBXGroup;
children = (
@@ -193,6 +297,8 @@
B3F2329D189682D30043DA98 /* Classes */,
B33FB1BA172B185C006529CE /* Mac */,
B33FB1ED172B1A7A006529CE /* Touch */,
5C7803851D3C4668002107FB /* PusherKit-iOS */,
5C7803A71D3C4826002107FB /* PusherKit-OSX */,
B3C6BD7E15FD24D200F1F3F1 /* Frameworks */,
B3C6BD7C15FD24D200F1F3F1 /* Products */,
);
@@ -203,6 +309,8 @@
children = (
B3C6BD7B15FD24D200F1F3F1 /* Pusher.app */,
B33FB1D1172B1A66006529CE /* PusherTouch.app */,
5C7803841D3C4668002107FB /* PusherKit.framework */,
5C7803A61D3C4826002107FB /* PusherKit.framework */,
);
name = Products;
sourceTree = "<group>";
@@ -245,7 +353,78 @@
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
5C7803811D3C4668002107FB /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
5C7803881D3C4668002107FB /* PusherKit.h in Headers */,
5C7803991D3C4749002107FB /* NWHub.h in Headers */,
5C78039A1D3C4749002107FB /* NWNotification.h in Headers */,
5C78039B1D3C4749002107FB /* NWPusher.h in Headers */,
5C78039C1D3C4749002107FB /* NWPushFeedback.h in Headers */,
5C78039D1D3C4749002107FB /* NWSecTools.h in Headers */,
5C78039E1D3C4749002107FB /* NWSSLConnection.h in Headers */,
5C78039F1D3C4749002107FB /* NWType.h in Headers */,
5C7803A01D3C4749002107FB /* NWLCore.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
5C7803A31D3C4826002107FB /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
5C7803AA1D3C4826002107FB /* PusherKit.h in Headers */,
5C7803BB1D3C488C002107FB /* NWHub.h in Headers */,
5C7803BC1D3C488C002107FB /* NWNotification.h in Headers */,
5C7803BD1D3C488C002107FB /* NWPusher.h in Headers */,
5C7803BE1D3C488C002107FB /* NWPushFeedback.h in Headers */,
5C7803BF1D3C488C002107FB /* NWSecTools.h in Headers */,
5C7803C01D3C488C002107FB /* NWSSLConnection.h in Headers */,
5C7803C11D3C488C002107FB /* NWType.h in Headers */,
5C7803C21D3C488C002107FB /* NWLCore.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
5C7803831D3C4668002107FB /* PusherKit-iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5C78038F1D3C4668002107FB /* Build configuration list for PBXNativeTarget "PusherKit-iOS" */;
buildPhases = (
5C78037F1D3C4668002107FB /* Sources */,
5C7803801D3C4668002107FB /* Frameworks */,
5C7803811D3C4668002107FB /* Headers */,
5C7803821D3C4668002107FB /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "PusherKit-iOS";
productName = "PusherKit-iOS";
productReference = 5C7803841D3C4668002107FB /* PusherKit.framework */;
productType = "com.apple.product-type.framework";
};
5C7803A51D3C4826002107FB /* PusherKit-OSX */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5C7803B01D3C4826002107FB /* Build configuration list for PBXNativeTarget "PusherKit-OSX" */;
buildPhases = (
5C7803A11D3C4826002107FB /* Sources */,
5C7803A21D3C4826002107FB /* Frameworks */,
5C7803A31D3C4826002107FB /* Headers */,
5C7803A41D3C4826002107FB /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "PusherKit-OSX";
productName = "PusherKit-OSX";
productReference = 5C7803A61D3C4826002107FB /* PusherKit.framework */;
productType = "com.apple.product-type.framework";
};
B33FB1D0172B1A66006529CE /* PusherTouch */ = {
isa = PBXNativeTarget;
buildConfigurationList = B33FB1EA172B1A66006529CE /* Build configuration list for PBXNativeTarget "PusherTouch" */;
@@ -253,10 +432,12 @@
B33FB1CD172B1A66006529CE /* Sources */,
B33FB1CE172B1A66006529CE /* Frameworks */,
B33FB1CF172B1A66006529CE /* Resources */,
5C7803901D3C4668002107FB /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
5C78038A1D3C4668002107FB /* PBXTargetDependency */,
);
name = PusherTouch;
productName = PusherTouch;
@@ -270,10 +451,12 @@
B3C6BD7715FD24D200F1F3F1 /* Sources */,
B3C6BD7815FD24D200F1F3F1 /* Frameworks */,
B3C6BD7915FD24D200F1F3F1 /* Resources */,
5C7803AE1D3C4826002107FB /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
5C7803AC1D3C4826002107FB /* PBXTargetDependency */,
);
name = PusherMac;
productName = Pusher;
@@ -287,8 +470,18 @@
isa = PBXProject;
attributes = {
CLASSPREFIX = NW;
LastUpgradeCheck = 0500;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = noodlewerk;
TargetAttributes = {
5C7803831D3C4668002107FB = {
CreatedOnToolsVersion = 8.0;
ProvisioningStyle = Automatic;
};
5C7803A51D3C4826002107FB = {
CreatedOnToolsVersion = 8.0;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = B3C6BD7515FD24D200F1F3F1 /* Build configuration list for PBXProject "NWPusher" */;
compatibilityVersion = "Xcode 3.2";
@@ -304,11 +497,27 @@
targets = (
B3C6BD7A15FD24D200F1F3F1 /* PusherMac */,
B33FB1D0172B1A66006529CE /* PusherTouch */,
5C7803831D3C4668002107FB /* PusherKit-iOS */,
5C7803A51D3C4826002107FB /* PusherKit-OSX */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
5C7803821D3C4668002107FB /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
5C7803A41D3C4826002107FB /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
B33FB1CF172B1A66006529CE /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -341,20 +550,42 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
5C78037F1D3C4668002107FB /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5C7803951D3C4683002107FB /* NWSecTools.m in Sources */,
5C7803961D3C4683002107FB /* NWSSLConnection.m in Sources */,
5C7803911D3C4683002107FB /* NWHub.m in Sources */,
5C7803941D3C4683002107FB /* NWPushFeedback.m in Sources */,
5C7803981D3C4698002107FB /* NWLCore.c in Sources */,
5C7803921D3C4683002107FB /* NWNotification.m in Sources */,
5C7803971D3C4683002107FB /* NWType.m in Sources */,
5C7803931D3C4683002107FB /* NWPusher.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
5C7803A11D3C4826002107FB /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5C7803B81D3C487B002107FB /* NWSecTools.m in Sources */,
5C7803B41D3C487B002107FB /* NWHub.m in Sources */,
5C7803BA1D3C487B002107FB /* NWType.m in Sources */,
5C7803B71D3C487B002107FB /* NWPushFeedback.m in Sources */,
5C7803B61D3C487B002107FB /* NWPusher.m in Sources */,
5C7803B51D3C487B002107FB /* NWNotification.m in Sources */,
5C7803B31D3C486F002107FB /* NWLCore.c in Sources */,
5C7803B91D3C487B002107FB /* NWSSLConnection.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
B33FB1CD172B1A66006529CE /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B33FB1FC172B1A7A006529CE /* main.m in Sources */,
B3F232B5189682D30043DA98 /* NWPushFeedback.m in Sources */,
B33FB1FD172B1A7A006529CE /* NWAppDelegate.m in Sources */,
B34BF1B518DDF401004BA9F7 /* NWType.m in Sources */,
B3F232AF189682D30043DA98 /* NWHub.m in Sources */,
B3F232B7189682D30043DA98 /* NWSecTools.m in Sources */,
B3F232B3189682D30043DA98 /* NWPusher.m in Sources */,
B3F232B9189682D30043DA98 /* NWSSLConnection.m in Sources */,
B3F232B1189682D30043DA98 /* NWNotification.m in Sources */,
B3376A64172BB71200242EBB /* NWLCore.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -362,22 +593,207 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B3F232B4189682D30043DA98 /* NWPushFeedback.m in Sources */,
B3F232AE189682D30043DA98 /* NWHub.m in Sources */,
B3F232B6189682D30043DA98 /* NWSecTools.m in Sources */,
B34BF1B418DDF401004BA9F7 /* NWType.m in Sources */,
B3F232B2189682D30043DA98 /* NWPusher.m in Sources */,
B3F232B8189682D30043DA98 /* NWSSLConnection.m in Sources */,
B3F232B0189682D30043DA98 /* NWNotification.m in Sources */,
B33FB1C9172B185C006529CE /* main.m in Sources */,
B33FB1CB172B185C006529CE /* NWAppDelegate.m in Sources */,
B3376A63172BB71200242EBB /* NWLCore.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
5C78038A1D3C4668002107FB /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5C7803831D3C4668002107FB /* PusherKit-iOS */;
targetProxy = 5C7803891D3C4668002107FB /* PBXContainerItemProxy */;
};
5C7803AC1D3C4826002107FB /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5C7803A51D3C4826002107FB /* PusherKit-OSX */;
targetProxy = 5C7803AB1D3C4826002107FB /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
5C78038D1D3C4668002107FB /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
INFOPLIST_FILE = "PusherKit-iOS/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.zats.PusherKit-iOS";
PRODUCT_NAME = PusherKit;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
5C78038E1D3C4668002107FB /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
INFOPLIST_FILE = "PusherKit-iOS/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.zats.PusherKit-iOS";
PRODUCT_NAME = PusherKit;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
5C7803B11D3C4826002107FB /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CODE_SIGN_IDENTITY = "";
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_VERSION = A;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
INFOPLIST_FILE = "PusherKit-OSX/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.zats.PusherKit-OSX";
PRODUCT_NAME = PusherKit;
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
5C7803B21D3C4826002107FB /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CODE_SIGN_IDENTITY = "";
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_VERSION = A;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
INFOPLIST_FILE = "PusherKit-OSX/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.zats.PusherKit-OSX";
PRODUCT_NAME = PusherKit;
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
B33FB1EB172B1A66006529CE /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -398,7 +814,9 @@
"$(inherited)",
);
INFOPLIST_FILE = "Touch/PusherTouch-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 6.1;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.noodlewerk.pusher;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -423,8 +841,10 @@
GCC_PREFIX_HEADER = "Touch/PusherTouch-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = "NWL_LIB=Pusher";
INFOPLIST_FILE = "Touch/PusherTouch-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 6.1;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
PRODUCT_BUNDLE_IDENTIFIER = com.noodlewerk.pusher;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -439,11 +859,22 @@
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
@@ -452,7 +883,9 @@
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
ONLY_ACTIVE_ARCH = YES;
@@ -466,14 +899,26 @@
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
SDKROOT = macosx;
@@ -483,6 +928,7 @@
B3C6BD9A15FD24D200F1F3F1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Mac/PusherMac-Prefix.pch";
@@ -491,7 +937,9 @@
"$(inherited)",
);
INFOPLIST_FILE = "Mac/PusherMac-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.7;
PRODUCT_BUNDLE_IDENTIFIER = "com.noodlewerk.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = Pusher;
WRAPPER_EXTENSION = app;
};
@@ -500,6 +948,7 @@
B3C6BD9B15FD24D200F1F3F1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Mac/PusherMac-Prefix.pch";
@@ -508,7 +957,9 @@
"$(inherited)",
);
INFOPLIST_FILE = "Mac/PusherMac-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.7;
PRODUCT_BUNDLE_IDENTIFIER = "com.noodlewerk.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = Pusher;
WRAPPER_EXTENSION = app;
};
@@ -517,6 +968,24 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
5C78038F1D3C4668002107FB /* Build configuration list for PBXNativeTarget "PusherKit-iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5C78038D1D3C4668002107FB /* Debug */,
5C78038E1D3C4668002107FB /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
5C7803B01D3C4826002107FB /* Build configuration list for PBXNativeTarget "PusherKit-OSX" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5C7803B11D3C4826002107FB /* Debug */,
5C7803B21D3C4826002107FB /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
B33FB1EA172B1A66006529CE /* Build configuration list for PBXNativeTarget "PusherTouch" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5C7803A51D3C4826002107FB"
BuildableName = "PusherKit.framework"
BlueprintName = "PusherKit-OSX"
ReferencedContainer = "container:NWPusher.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5C7803A51D3C4826002107FB"
BuildableName = "PusherKit.framework"
BlueprintName = "PusherKit-OSX"
ReferencedContainer = "container:NWPusher.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5C7803A51D3C4826002107FB"
BuildableName = "PusherKit.framework"
BlueprintName = "PusherKit-OSX"
ReferencedContainer = "container:NWPusher.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5C7803831D3C4668002107FB"
BuildableName = "PusherKit.framework"
BlueprintName = "PusherKit-iOS"
ReferencedContainer = "container:NWPusher.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5C7803831D3C4668002107FB"
BuildableName = "PusherKit.framework"
BlueprintName = "PusherKit-iOS"
ReferencedContainer = "container:NWPusher.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5C7803831D3C4668002107FB"
BuildableName = "PusherKit.framework"
BlueprintName = "PusherKit-iOS"
ReferencedContainer = "container:NWPusher.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
+26
View File
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 noodlewerk. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
+24
View File
@@ -0,0 +1,24 @@
//
// PusherKit-OSX.h
// PusherKit-OSX
//
// Created by Sash Zats on 7/17/16.
// Copyright © 2016 noodlewerk. All rights reserved.
//
#import <Cocoa/Cocoa.h>
//! Project version number for PusherKit-OSX.
FOUNDATION_EXPORT double PusherKit_OSXVersionNumber;
//! Project version string for PusherKit-OSX.
FOUNDATION_EXPORT const unsigned char PusherKit_OSXVersionString[];
#import <PusherKit/NWHub.h>
#import <PusherKit/NWLCore.h>
#import <PusherKit/NWNotification.h>
#import <PusherKit/NWPushFeedback.h>
#import <PusherKit/NWPusher.h>
#import <PusherKit/NWSSLConnection.h>
#import <PusherKit/NWSecTools.h>
+24
View File
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
+23
View File
@@ -0,0 +1,23 @@
//
// PusherKit-iOS.h
// PusherKit-iOS
//
// Created by Sash Zats on 7/17/16.
// Copyright © 2016 noodlewerk. All rights reserved.
//
#import <UIKit/UIKit.h>
//! Project version number for PusherKit-iOS.
FOUNDATION_EXPORT double PusherKit_iOSVersionNumber;
//! Project version string for PusherKit-iOS.
FOUNDATION_EXPORT const unsigned char PusherKit_iOSVersionString[];
#import <PusherKit/NWHub.h>
#import <PusherKit/NWLCore.h>
#import <PusherKit/NWNotification.h>
#import <PusherKit/NWPusher.h>
#import <PusherKit/NWSSLConnection.h>
#import <PusherKit/NWSecTools.h>
#import <PusherKit/NWPushFeedback.h>
+65 -17
View File
@@ -1,17 +1,17 @@
<img src="Touch/Icon@2x.png" alt="Pusher Icon" width="72"/>
<img src="icon.png" alt="Pusher Icon" width="72"/>
Pusher
======
*OS X and iOS application and framework to play with the Apple Push Notification Service (APNS)*
*OS X and iOS application and framework to play with the Apple Push Notification service (APNs)*
<img src="Docs/osx1.png" alt="Pusher OS X" width="612"/>
Installation
------------
Install the Mac app using [Homebrew cask](https://github.com/phinze/homebrew-cask):
Install the Mac app using [Homebrew cask](https://github.com/caskroom/homebrew-cask):
```shell
brew cask install pusher
@@ -21,10 +21,16 @@ Or download the latest `Pusher.app` binary:
- [Download latest binary](https://github.com/noodlewerk/NWPusher/releases/latest)
Alternatively, you can include NWPusher as a framework, using [CocoaPods](http://cocoapods.org/):
Alternatively, you can include NWPusher as a framework, using [CocoaPods](https://cocoapods.org/):
```ruby
pod 'NWPusher', '~> 0.5.4'
pod 'NWPusher', '~> 0.7.0'
```
or [Carthage](https://github.com/Carthage/Carthage) (iOS 8+ is required to use Cocoa Touch Frameworks)
```
github "noodlewerk/NWPusher"
```
Or simply include the source files you need. NWPusher has a modular architecture and does not have any external dependencies, so use what you like.
@@ -48,7 +54,7 @@ Mac OS X application for sending push notifications through the APN service:
- *Stores device tokens* so you don't have to copy-paste them every time
- Handles *PKCS #12* files (.p12)
- Automatic configuration for *sandbox*
- Reports *detailed error messages* returned by APNS
- Reports *detailed error messages* returned by APNs
- Reads from *feedback service*
OS X and iOS framework for sending pushes from your own application:
@@ -75,16 +81,16 @@ Let's start with the SSL certificate. The goal is to get both the certificate *a
Keep in mind that you will eventually be downloading a certificate, which you will need to install in your keychain together with the private key. This should look something like this:
<img src="Docs/keychain1.png" alt="Keychain export" width="681"/>
<img src="Docs/keychain1.png" alt="Keychain export" width="690"/>
NB: There is `Development` and `Production` certificates, which should (generally) correspond to respectively `DEBUG` and `RELEASE` versions of your app. Make sure you get the right one, check *Development (sandbox) or Production*, *iOS or Mac*, and the *bundle identifier*.
The push certificate should be exported to a PKCS12 file, which allows you to share these with fellow developers:
<img src="Docs/keychain2.png" alt="PKCS12 file" width="679"/>
<img src="Docs/keychain2.png" alt="PKCS12 file" width="690"/>
### Device token
Now you need to obtain a device token, which is a 64 character hex string (256 bits indeed). This should be done from within the iOS app you're going to push to. Add the following lines to the application delegate (Xcode 6 required):
Now you need to obtain a device token, which is a 64 character hex string (256 bits). This should be done from within the iOS app you're going to push to. Add the following lines to the application delegate (Xcode 6 required):
```objective-c
- (BOOL)application:(UIApplication *)application
@@ -172,17 +178,17 @@ If everything is set up correctly, you only need to *Connect* and *Push*. Then y
Again, if things are not working as expected, take a look at the *Troubleshooting* section below or post an issue on GitHub.
Consult Apple's documentation for more info on the APNS architecture: [Apple Push Notification Service](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html)
Consult Apple's documentation for more info on the APNs architecture: [Apple Push Notification Service](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html)
Pushing from code
-----------------
Pusher can also be used as a framework to send notifications programmatically. The included Xcode project provides examples for both OS X and iOS. The easiest way to include NWPusher is through CocoaPods:
```ruby
pod 'NWPusher', '~> 0.5.4'
pod 'NWPusher', '~> 0.7.0'
```
Alternatively you can include just the files you need from the `Classes` folder. Make sure you link with `Foundation.framework` and `Security.framework`.
CocoaPods also compiles documentation, which can be accessed through [CocoaDocs](http://cocoadocs.org/docsets/NWPusher). Alternatively you can include just the files you need from the `Classes` folder. Make sure you link with `Foundation.framework` and `Security.framework`.
Before any notification can be sent, you first need to create a connection. When this connection is established, any number of payloads can be sent.
@@ -196,7 +202,7 @@ To create a connection directly from a PKCS12 (.p12) file:
NSError *error = nil;
NWPusher *pusher = [NWPusher connectWithPKCS12Data:pkcs12 password:@"pa$$word" error:&error];
if (pusher) {
NSLog(@"Connected to APNS");
NSLog(@"Connected to APNs");
} else {
NSLog(@"Unable to connect: %@", error);
}
@@ -210,7 +216,7 @@ When pusher is successfully connected, send a payload to your device:
NSError *error = nil;
BOOL pushed = [pusher pushPayload:payload token:token identifier:rand() error:&error];
if (pushed) {
NSLog(@"Pushed to APNS");
NSLog(@"Pushed to APNs");
} else {
NSLog(@"Unable to push: %@", error);
}
@@ -228,7 +234,7 @@ After a second or so, we can take a look to see if the notification was accepted
} else if (read) {
NSLog(@"Read and none failed");
} else {
NSLog(@"Unable to read failed: %@", error);
NSLog(@"Unable to read: %@", error);
}
```
@@ -262,7 +268,7 @@ Consult Apple's documentation for more info on the client-server communication:
Feedback Service
----------------
The feedback service is part of the Apple Push Notification Service. The feedback service is basically a list containing device tokens that became invalid. Apple recommends that you read from the feedback service once every 24 hours, and no longer send notifications to listed devices. Note that this can be used to find out who removed your app from their device.
The feedback service is part of the Apple Push Notification service. The feedback service is basically a list containing device tokens that became invalid. Apple recommends that you read from the feedback service once every 24 hours, and no longer send notifications to listed devices. Note that this can be used to find out who removed your app from their device.
Communication with the feedback service can be done with the `NWPushFeedback` class. First connect using one of the `connect` methods:
@@ -292,6 +298,46 @@ When connected read the device token and date of invalidation:
Apple closes the connection after the last device token is read.
Pushing to macOS
---------------
On macOS, you obtain a device token for your app by calling the `registerForRemoteNotificationTypes:` method of the `NSApplication` object. It is recommended that you call this method at launch time as part of your normal startup sequence. The first time your app calls this method, the app object requests the token from APNs. After the initial call, the app object contacts APNs only when the device token changes; otherwise, it returns the existing token quickly.
The app object notifies its delegate asynchronously upon the successful or unsuccessful retrieval of the device token. You use these delegate callbacks to process the device token or to handle any errors that arose. You must implement the following delegate methods to track whether registration was successful:
- Use the `application:didRegisterForRemoteNotificationsWithDeviceToken:` to receive the device token and forward it to your server.
- Use the `application:didFailToRegisterForRemoteNotificationsWithError:` to respond to errors.
Note: If the device token changes while your app is running, the app object calls the appropriate delegate method again to notify you of the change.
The app delegate calls the `registerForRemoteNotificationTypes:` method as part of its regular launch-time setup, passing along the types of interactions that you intend to use. Upon receiving the device token, the `application:didRegisterForRemoteNotificationsWithDeviceToken:` method forwards it to the apps associated server using a custom method. If an error occurs during registration, the app temporarily disables any features related to remote notifications. Those features are re-enabled when a valid device token is received.
```objective-c
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
// Configure the user interactions first.
[self configureUserInteractions];
[NSApp registerForRemoteNotificationTypes:(NSRemoteNotificationTypeAlert | NSRemoteNotificationTypeSound)];
}
```
```objective-c
- (void)application:(NSApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// Forward the token to your server.
[self forwardTokenToServer:deviceToken];
}
```
```objective-c
- (void)application:(NSApplication *)application
didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"Remote notification support is unavailable due to error: %@", error);
[self disableRemoteNotificationFeatures];
}
```
Certificate and key files
-------------------------
Pusher reads certificate and key data from PKCS12 files. This is a binary format that bundles both X.509 certificates and a private key in one file. Conversion from other file formats to and from PKCS12 is provided by the OpenSSL CLI.
@@ -360,11 +406,13 @@ If it fails to connect then check:
- Can you connect with the push servers? Try `[NWPusher connectWithIdentity:identity error:&error]` or `[NWPusher connectWithPKCS12Data:pkcs12 password:password error:&error]`.
- Pusher connects on port `2195` with hosts `gateway.push.apple.com` and `gateway.sandbox.push.apple.com`, and on port `2196` with hosts `feedback.push.apple.com` and `feedback.sandbox.push.apple.com`. Make sure your firewall is configured to allow these connections.
If nothing is delivered to the device then check:
- Is the device online? Is it able to receive push notifications from other services? Try to get pushes from other apps, for example a messenger. Many wireless connections work visibly fine, but do not deliver push notifications. Try to switch to another wifi or cellular network.
- Are you pushing to the right device token? This token should be returned by the OS of the receiving device, in the callback `-application: didRegisterForRemoteNotificationsWithDeviceToken:`. The push certificate should match the provisioning profile of the app, check *Development or Production*, *iOS or Mac*, and the *bundle identifier*.
- Are you pushing to the right device token? This token should be returned by the OS of the receiving device, in the callback `-application: didRegisterForRemoteNotificationsWithDeviceToken:`. The push certificate should match the provisioning profile of the app, check *Development or Production*, *iOS or Mac*, and the *bundle identifier*. Make sure the receiving app is closed, so it cannot interfere with the delivery.
- Does the push call succeed? Isn't there any negative response from the push server or feedback server? Both `[pusher pushPayload:payload token:token identifier:rand() error:&error]` and `[pusher readFailedIdentifier:&identifier apnError:&apnError error:&error]` should return `YES`, but wait a second between pushing and reading. Also try to connect to the feedback service to read feedback.
+132 -40
View File
@@ -6,12 +6,7 @@
//
#import "NWAppDelegate.h"
#import "NWHub.h"
#import "NWPusher.h"
#import "NWNotification.h"
#import "NWLCore.h"
#import "NWSSLConnection.h"
#import "NWSecTools.h"
#import <PusherKit/PusherKit.h>
// TODO: Export your push certificate and key in PKCS12 format to pusher.p12 in the root of the project directory.
static NSString * const pkcs12FileName = @"pusher.p12";
@@ -32,9 +27,13 @@ static NWPusherViewController *controller = nil;
UITextField *_textField;
UIButton *_pushButton;
UILabel *_infoLabel;
UISwitch *_sanboxSwitch;
NWHub *_hub;
NSUInteger _index;
dispatch_queue_t _serial;
NWIdentityRef _identity;
NWCertificateRef _certificate;
}
- (void)viewDidLoad
@@ -47,11 +46,22 @@ static NWPusherViewController *controller = nil;
_serial = dispatch_queue_create("NWAppDelegate", DISPATCH_QUEUE_SERIAL);
_connectButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
_connectButton.frame = CGRectMake(20, 20, self.view.bounds.size.width - 40, 40);
_connectButton.frame = CGRectMake(20, 20, (self.view.bounds.size.width - 40)/2, 40);
[_connectButton setTitle:@"Connect" forState:UIControlStateNormal];
[_connectButton addTarget:self action:@selector(connect) forControlEvents:UIControlEventTouchUpInside];
[_connectButton addTarget:self action:@selector(connectButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_connectButton];
_sanboxSwitch = [[UISwitch alloc] init];
_sanboxSwitch.frame = CGRectMake((self.view.bounds.size.width + 40)/2, 20, 40, 40);
[_sanboxSwitch addTarget:self action:@selector(sanboxCheckBoxDidPressed:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:_sanboxSwitch];
UILabel *sandboxLabel = [[UILabel alloc] init];
sandboxLabel.frame = CGRectMake(CGRectGetMaxX(_sanboxSwitch.frame) + 10, 20, 80, 40);
sandboxLabel.font = [UIFont systemFontOfSize:12];
sandboxLabel.text = @"Use sandbox";
[self.view addSubview:sandboxLabel];
_textField = [[UITextField alloc] init];
_textField.frame = CGRectMake(20, 70, self.view.bounds.size.width - 40, 26);
_textField.text = @"Testing..";
@@ -66,46 +76,107 @@ static NWPusherViewController *controller = nil;
[self.view addSubview:_pushButton];
_infoLabel = [[UILabel alloc] init];
_infoLabel.frame = CGRectMake(20, 156, self.view.bounds.size.width - 40, 26);
_infoLabel.frame = CGRectMake(20, 156, self.view.bounds.size.width - 40, 60);
_infoLabel.font = [UIFont systemFontOfSize:12];
_infoLabel.numberOfLines = 0;
[self.view addSubview:_infoLabel];
NWLogInfo(@"Connect with Apple's Push Notification service");
[self loadCertificate];
}
- (void)connect
- (void)loadCertificate
{
if (!_hub) {
NWLogInfo(@"Connecting..");
_connectButton.enabled = NO;
dispatch_async(_serial, ^{
NSURL *url = [NSBundle.mainBundle URLForResource:pkcs12FileName withExtension:nil];
NSData *pkcs12 = [NSData dataWithContentsOfURL:url];
NSError *error = nil;
NWHub *hub = [NWHub connectWithDelegate:self PKCS12Data:pkcs12 password:pkcs12Password error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
if (hub) {
NSError *error = nil;
NWCertificateRef certificate = [NWSecTools certificateWithIdentity:hub.pusher.connection.identity error:&error];
NWError(error);
BOOL sandbox = [NWSecTools isSandboxCertificate:certificate];
NSString *summary = [NWSecTools summaryWithCertificate:certificate];
NWLogInfo(@"Connected to APN: %@%@", summary, sandbox ? @" (sandbox)" : @"");
_hub = hub;
_pushButton.enabled = YES;
[_connectButton setTitle:@"Disconnect" forState:UIControlStateNormal];
} else {
NWLogWarn(@"Unable to connect: %@", error.localizedDescription);
}
_connectButton.enabled = YES;
});
});
} else {
_pushButton.enabled = NO;
[_hub disconnect]; _hub = nil;
NWLogInfo(@"Disconnected");
[_connectButton setTitle:@"Connect" forState:UIControlStateNormal];
NSURL *url = [NSBundle.mainBundle URLForResource:pkcs12FileName withExtension:nil];
NSData *pkcs12 = [NSData dataWithContentsOfURL:url];
NSError *error = nil;
NSArray *ids = [NWSecTools identitiesWithPKCS12Data:pkcs12 password:pkcs12Password error:&error];
if (!ids) {
NWLogWarn(@"Unable to read p12 file: %@", error.localizedDescription);
return;
}
for (NWIdentityRef identity in ids) {
NSError *error = nil;
NWCertificateRef certificate = [NWSecTools certificateWithIdentity:identity error:&error];
if (!certificate) {
NWLogWarn(@"Unable to import p12 file: %@", error.localizedDescription);
return;
}
_identity = identity;
_certificate = certificate;
}
}
- (IBAction)sanboxCheckBoxDidPressed:(UISwitch *)sender
{
if (_certificate)
{
[self disconnect];
[self connectToEnvironment:[self selectedEnvironmentForCertificate:_certificate]];
}
}
- (NWEnvironment)selectedEnvironmentForCertificate:(NWCertificateRef)certificate
{
return _sanboxSwitch.isOn ? NWEnvironmentSandbox : NWEnvironmentProduction;
}
- (NWEnvironment)preferredEnvironmentForCertificate:(NWCertificateRef)certificate
{
NWEnvironmentOptions environmentOptions = [NWSecTools environmentOptionsForCertificate:certificate];
return (environmentOptions & NWEnvironmentOptionSandbox) ? NWEnvironmentSandbox : NWEnvironmentProduction;
}
- (void)connectButtonPressed
{
if (_hub)
{
[self disconnect];
_connectButton.enabled = YES;
[_connectButton setTitle:@"Connect" forState:UIControlStateNormal];
return;
}
NWEnvironment preferredEnvironment = [self preferredEnvironmentForCertificate:_certificate];
[self connectToEnvironment:preferredEnvironment];
}
- (void)disconnect
{
[self disableButtons];
[_hub disconnect]; _hub = nil;
NWLogInfo(@"Disconnected");
}
- (void)connectToEnvironment:(NWEnvironment)environment
{
[self disableButtons];
NWLogInfo(@"Connecting..");
dispatch_async(_serial, ^{
NSError *error = nil;
NWHub *hub = [NWHub connectWithDelegate:self identity:_identity environment:environment error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
if (hub) {
NSString *summary = [NWSecTools summaryWithCertificate:_certificate];
NWLogInfo(@"Connected to APN: %@ (%@)", summary, descriptionForEnvironent(environment));
_hub = hub;
[_connectButton setTitle:@"Disconnect" forState:UIControlStateNormal];
} else {
NWLogWarn(@"Unable to connect: %@", error.localizedDescription);
}
[self enableButtonsForCertificate:_certificate environment:environment];
});
});
}
- (void)push
@@ -131,6 +202,27 @@ static NWPusherViewController *controller = nil;
});
}
#pragma mark - BUtton states
- (void)disableButtons
{
_pushButton.enabled = NO;
_connectButton.enabled = NO;
_sanboxSwitch.enabled = NO;
}
- (void)enableButtonsForCertificate:(NWCertificateRef)certificate environment:(NWEnvironment)environment
{
NWEnvironmentOptions environmentOptions = [NWSecTools environmentOptionsForCertificate:certificate];
BOOL shouldEnableEnvButton = (environmentOptions == NWEnvironmentOptionAny);
BOOL shouldSelectSandboxEnv = (environment == NWEnvironmentSandbox);
_pushButton.enabled = YES;
_connectButton.enabled = YES;
_sanboxSwitch.enabled = shouldEnableEnvButton;
_sanboxSwitch.on = shouldSelectSandboxEnv;
}
#pragma mark - NWLogging
+3 -3
View File
@@ -24,7 +24,7 @@
</dict>
</dict>
<key>CFBundleIdentifier</key>
<string>com.noodlewerk.pusher</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@@ -32,11 +32,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.5.4</string>
<string>0.7.5</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>10</string>
<string>19</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIPrerenderedIcon</key>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB