apnotic 1.6.1 → 1.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +19 -0
- data/.tool-versions +1 -1
- data/LICENSE.md +1 -1
- data/README.md +60 -48
- data/apnotic.gemspec +1 -1
- data/lib/apnotic/abstract_notification.rb +2 -1
- data/lib/apnotic/connection.rb +4 -0
- data/lib/apnotic/instance_cache.rb +6 -2
- data/lib/apnotic/notification.rb +10 -0
- data/lib/apnotic/provider_token.rb +1 -1
- data/lib/apnotic/request.rb +1 -1
- data/lib/apnotic/version.rb +1 -1
- metadata +9 -9
- data/.travis.yml +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7afbcc0c9a9fa876ff60430ae040d24b91d8d5e55808dd274f81bab1e2d1e918
|
4
|
+
data.tar.gz: 85e7c9d84e759f6c020306103036e3afa8fe94d0acf4e1321c132bef00066ae9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 569b7b8d3dba2e149ad4f6dd6056123d288a5cdd93acb0739ba39b18345f6b0d1e68335c33f6f8e43a772a67dccefaf084bf2e854b23ebf20582950301294733
|
7
|
+
data.tar.gz: be11e416771518cd8d56ff25ec3bb3679a27f1f1fbdbec7105d3d9e90ca600bbe50118b6d097d5b5145dcbbae95c3bbe74c5d39d276af5952e7c59cb4f8dcfc6
|
@@ -0,0 +1,19 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
strategy:
|
9
|
+
matrix:
|
10
|
+
ruby-version: ['2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2']
|
11
|
+
steps:
|
12
|
+
- uses: actions/checkout@v2
|
13
|
+
- name: Set up Ruby
|
14
|
+
uses: ruby/setup-ruby@v1
|
15
|
+
with:
|
16
|
+
ruby-version: ${{ matrix.ruby-version }}
|
17
|
+
bundler-cache: true
|
18
|
+
- name: Run tests
|
19
|
+
run: bundle exec rake
|
data/.tool-versions
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby 2.
|
1
|
+
ruby 3.2.1
|
data/LICENSE.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2016 Roberto Ostinelli.
|
3
|
+
Copyright (c) 2016-2023 Roberto Ostinelli.
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[![Build Status](https://
|
1
|
+
[![Build Status](https://github.com/ostinelli/apnotic/actions/workflows/ci.yml/badge.svg)](https://github.com/ostinelli/apnotic/actions/workflows/ci.yml)
|
2
2
|
[![Code Climate](https://codeclimate.com/github/ostinelli/apnotic/badges/gpa.svg)](https://codeclimate.com/github/ostinelli/apnotic)
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/apnotic.svg)](https://badge.fury.io/rb/apnotic)
|
4
4
|
|
@@ -201,16 +201,19 @@ To create a new persistent connection:
|
|
201
201
|
Apnotic::Connection.new(options)
|
202
202
|
```
|
203
203
|
|
204
|
-
| Option
|
205
|
-
|
206
|
-
| :cert_path
|
207
|
-
| :cert_pass
|
208
|
-
| :
|
209
|
-
| :
|
210
|
-
| :
|
211
|
-
| :
|
212
|
-
| :
|
213
|
-
| :
|
204
|
+
| Option | Description
|
205
|
+
|------------------|------------
|
206
|
+
| :cert_path | `Required` The path to a valid APNS push certificate or any object that responds to `:read`. Supported formats: `.pem`, `.p12` (`:cert` auth), or `.p8` (`:token` auth).
|
207
|
+
| :cert_pass | `Optional` The certificate's password.
|
208
|
+
| :auth_method | `Optional` The options are `:cert` or `:token`. Defaults to `:cert`.
|
209
|
+
| :team_id | `Required for :token auth` Team ID from [Membership Details](https://developer.apple.com/account/#!/membership/).
|
210
|
+
| :key_id | `Required for :token auth` ID from [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources/authkeys).
|
211
|
+
| :url | `Optional` Defaults to https://api.push.apple.com:443.
|
212
|
+
| :connect_timeout | `Optional` Expressed in seconds, defaults to 30.
|
213
|
+
| :proxy_addr | `Optional` Proxy server. e.g. http://proxy.example.com
|
214
|
+
| :proxy_port | `Optional` Proxy port. e.g. 8080
|
215
|
+
| :proxy_user | `Optional` User name for proxy authentication. e.g. user_name
|
216
|
+
| :proxy_pass | `Optional` Password for proxy authentication. e.g. pass_word
|
214
217
|
|
215
218
|
Note that since `:cert_path` can be any object that responds to `:read`, it is possible to pass in a certificate string directly by wrapping it up in a `StringIO` object:
|
216
219
|
|
@@ -224,47 +227,47 @@ It is also possible to create a connection that points to the Apple Development
|
|
224
227
|
Apnotic::Connection.development(options)
|
225
228
|
```
|
226
229
|
|
227
|
-
> The concepts of PRODUCTION and DEVELOPMENT are different from what they used to be in previous specifications. Anything built directly from
|
230
|
+
> The concepts of PRODUCTION and DEVELOPMENT are different from what they used to be in previous specifications. Anything built directly from Xcode and loaded on your phone will have the app generate DEVELOPMENT tokens, while everything else (TestFlight, Apple Store, HockeyApp, ...) will be considered as PRODUCTION environment.
|
228
231
|
|
229
232
|
#### Methods
|
230
233
|
|
231
|
-
|
234
|
+
- **cert_path** → **`string`**
|
232
235
|
|
233
|
-
|
236
|
+
Returns the path to the certificate.
|
234
237
|
|
235
|
-
|
238
|
+
- **on(event, &block)**
|
236
239
|
|
237
|
-
Allows to set a callback for the connection. The only available event is `:error`, which allows to set a callback when an error is raised at socket level, hence in the underlying socket thread.
|
240
|
+
Allows to set a callback for the connection. The only available event is `:error`, which allows to set a callback when an error is raised at socket level, hence in the underlying socket thread.
|
238
241
|
|
239
|
-
```ruby
|
240
|
-
connection.on(:error) { |exception| puts "Exception has been raised: #{exception}" }
|
241
|
-
```
|
242
|
+
```ruby
|
243
|
+
connection.on(:error) { |exception| puts "Exception has been raised: #{exception}" }
|
244
|
+
```
|
242
245
|
|
243
|
-
> If the `:error` callback is not set, the underlying socket thread may raise an error in the main thread at unexpected execution times.
|
246
|
+
> If the `:error` callback is not set, the underlying socket thread may raise an error in the main thread at unexpected execution times.
|
244
247
|
|
245
|
-
|
248
|
+
- **url** → **`URL`**
|
246
249
|
|
247
|
-
|
250
|
+
Returns the URL of the APNS endpoint.
|
248
251
|
|
249
252
|
##### Blocking calls
|
250
253
|
|
251
|
-
|
254
|
+
- **push(notification, timeout: 30)** → **`Apnotic::Response` or `nil`**
|
252
255
|
|
253
|
-
|
256
|
+
Sends a notification. Returns `nil` in case a timeout occurs.
|
254
257
|
|
255
258
|
##### Non-blocking calls
|
256
259
|
|
257
|
-
|
260
|
+
- **prepare_push(notification)** → **`Apnotic::Push`**
|
258
261
|
|
259
|
-
|
262
|
+
Prepares an async push.
|
260
263
|
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
+
```ruby
|
265
|
+
push = client.prepare_push(notification)
|
266
|
+
```
|
264
267
|
|
265
|
-
|
268
|
+
- **push_async(push)**
|
266
269
|
|
267
|
-
|
270
|
+
Sends the push asynchronously.
|
268
271
|
|
269
272
|
|
270
273
|
### `Apnotic::ConnectionPool`
|
@@ -315,10 +318,19 @@ These are all Accessor attributes.
|
|
315
318
|
| `category` | "
|
316
319
|
| `custom_payload` | "
|
317
320
|
| `thread_id` | "
|
321
|
+
| `target_content_id` | "
|
322
|
+
| `interruption_level` | Refer to [Payload Key Reference](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification#2943363) for details. iOS 15+
|
323
|
+
| `relevance_score` | Refer to [Payload Key Reference](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification#2943363) for details. iOS 15+
|
324
|
+
| `stale_date` | Refer to [Payload Key Reference](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification#2943363) for details. iOS 16+
|
325
|
+
| `content_state` | Refer to [Payload Key Reference](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification#2943363) for details. iOS 16+
|
326
|
+
| `timestamp` | Refer to [Payload Key Reference](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification#2943363) for details. iOS 16+
|
327
|
+
| `event` | Refer to [Payload Key Reference](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification#2943363) for details. iOS 16+
|
328
|
+
| `dismissal_date` | Refer to [Payload Key Reference](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification#2943363) for details. iOS 16+
|
318
329
|
| `apns_id` | Refer to [Communicating with APNs](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html) for details.
|
319
330
|
| `expiration` | "
|
320
331
|
| `priority` | "
|
321
332
|
| `topic` | "
|
333
|
+
| `push_type` | Refer to [Sending Notification Requests to APNs](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns) for details, defaults to alert or background (when content-availabe key is set to 1)
|
322
334
|
| `url_args` | Values for [Safari push notifications](https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NotificationProgrammingGuideForWebsites/PushNotifications/PushNotifications.html#//apple_ref/doc/uid/TP40013225-CH3-SW12).
|
323
335
|
| `mutable_content` | Key for [UNNotificationServiceExtension](https://developer.apple.com/reference/usernotifications/unnotificationserviceextension).
|
324
336
|
| `apns_collapse_id` | Key for setting the identification of a notification and allowing for the updating of the content of that notification in a subsequent push. More information avaible in [WWDC 2016 - Session 707 Introduction to Notifications](https://developer.apple.com/videos/play/wwdc2016/707/?time=1134). iOS 10+
|
@@ -352,21 +364,21 @@ The response to a call to `connection.push`.
|
|
352
364
|
|
353
365
|
#### Methods
|
354
366
|
|
355
|
-
|
367
|
+
- **body** → **`hash` or `string`**
|
356
368
|
|
357
|
-
|
369
|
+
Returns the body of the response in Hash format if a valid JSON was returned, otherwise just the RAW body.
|
358
370
|
|
359
|
-
|
371
|
+
- **headers** → **`hash`**
|
360
372
|
|
361
|
-
|
373
|
+
Returns a Hash containing the Headers of the response.
|
362
374
|
|
363
|
-
|
375
|
+
- **ok?** → **`boolean`**
|
364
376
|
|
365
|
-
|
377
|
+
Returns if the push was successful.
|
366
378
|
|
367
|
-
|
379
|
+
- **status** → **`string`**
|
368
380
|
|
369
|
-
Returns the status code.
|
381
|
+
Returns the status code.
|
370
382
|
|
371
383
|
|
372
384
|
### `Apnotic::Push`
|
@@ -374,21 +386,21 @@ The push object to be sent in an async call.
|
|
374
386
|
|
375
387
|
#### Methods
|
376
388
|
|
377
|
-
|
389
|
+
- **http2_request** → **`NetHttp2::Request`**
|
378
390
|
|
379
|
-
|
391
|
+
Returns the HTTP/2 request of the push.
|
380
392
|
|
381
|
-
|
393
|
+
- **on(event, &block)**
|
382
394
|
|
383
|
-
|
395
|
+
Allows to set a callback for the request. Available events are:
|
384
396
|
|
385
|
-
|
397
|
+
`:response`: triggered when a response is fully received (called once).
|
386
398
|
|
387
|
-
|
399
|
+
Even if Apnotic is thread-safe, the async callbacks will be executed in a different thread, so ensure that your code in the callbacks is thread-safe.
|
388
400
|
|
389
|
-
|
390
|
-
|
391
|
-
|
401
|
+
```ruby
|
402
|
+
push.on(:response) { |response| p response.headers }
|
403
|
+
```
|
392
404
|
|
393
405
|
## Getting Your APNs Certificate
|
394
406
|
|
data/apnotic.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.email = ["roberto@ostinelli.net"]
|
12
12
|
spec.summary = %q{Apnotic is an Apple Push Notification gem able to provide instant feedback.}
|
13
13
|
spec.homepage = "http://github.com/ostinelli/apnotic"
|
14
|
-
spec.required_ruby_version = '>=2.
|
14
|
+
spec.required_ruby_version = '>=2.4.0'
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
17
|
spec.bindir = "exe"
|
data/lib/apnotic/connection.rb
CHANGED
@@ -114,6 +114,7 @@ module Apnotic
|
|
114
114
|
def build_ssl_context
|
115
115
|
@build_ssl_context ||= begin
|
116
116
|
ctx = OpenSSL::SSL::SSLContext.new
|
117
|
+
ctx.security_level = 1 if development? && ctx.respond_to?(:security_level)
|
117
118
|
begin
|
118
119
|
p12 = OpenSSL::PKCS12.new(certificate, @cert_pass)
|
119
120
|
ctx.key = p12.key
|
@@ -146,5 +147,8 @@ module Apnotic
|
|
146
147
|
@provider_token_cache.call
|
147
148
|
end
|
148
149
|
|
150
|
+
def development?
|
151
|
+
url == APPLE_DEVELOPMENT_SERVER_URL
|
152
|
+
end
|
149
153
|
end
|
150
154
|
end
|
@@ -17,12 +17,16 @@ module Apnotic
|
|
17
17
|
private
|
18
18
|
|
19
19
|
def expired?
|
20
|
-
|
20
|
+
now - @cached_at >= @ttl
|
21
21
|
end
|
22
22
|
|
23
23
|
def new_value
|
24
|
-
@cached_at =
|
24
|
+
@cached_at = now
|
25
25
|
@cached_value = @instance.send(@method)
|
26
26
|
end
|
27
|
+
|
28
|
+
def now
|
29
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
30
|
+
end
|
27
31
|
end
|
28
32
|
end
|
data/lib/apnotic/notification.rb
CHANGED
@@ -4,6 +4,8 @@ module Apnotic
|
|
4
4
|
|
5
5
|
class Notification < AbstractNotification
|
6
6
|
attr_accessor :alert, :badge, :sound, :content_available, :category, :custom_payload, :url_args, :mutable_content, :thread_id
|
7
|
+
attr_accessor :target_content_id, :interruption_level, :relevance_score
|
8
|
+
attr_accessor :stale_date, :content_state, :timestamp, :event, :dismissal_date
|
7
9
|
|
8
10
|
def background_notification?
|
9
11
|
aps.count == 1 && aps.key?('content-available') && aps['content-available'] == 1
|
@@ -21,6 +23,14 @@ module Apnotic
|
|
21
23
|
result.merge!('url-args' => url_args) if url_args
|
22
24
|
result.merge!('mutable-content' => mutable_content) if mutable_content
|
23
25
|
result.merge!('thread-id' => thread_id) if thread_id
|
26
|
+
result.merge!('target-content-id' => target_content_id) if target_content_id
|
27
|
+
result.merge!('interruption-level' => interruption_level) if interruption_level
|
28
|
+
result.merge!('relevance-score' => relevance_score) if relevance_score
|
29
|
+
result.merge!('stale-date' => stale_date) if stale_date
|
30
|
+
result.merge!('content-state' => content_state) if content_state
|
31
|
+
result.merge!('timestamp' => timestamp) if timestamp
|
32
|
+
result.merge!('event' => event) if event
|
33
|
+
result.merge!('dismissal-date' => dismissal_date) if dismissal_date
|
24
34
|
end
|
25
35
|
end
|
26
36
|
|
data/lib/apnotic/request.rb
CHANGED
@@ -16,7 +16,7 @@ module Apnotic
|
|
16
16
|
h.merge!('apns-id' => notification.apns_id) if notification.apns_id
|
17
17
|
h.merge!('apns-expiration' => notification.expiration) if notification.expiration
|
18
18
|
h.merge!('apns-priority' => notification.priority) if notification.priority
|
19
|
-
h.merge!('apns-push-type' => notification.background_notification? ? 'background' : 'alert'
|
19
|
+
h.merge!('apns-push-type' => notification.push_type || (notification.background_notification? ? 'background' : 'alert'))
|
20
20
|
h.merge!('apns-topic' => notification.topic) if notification.topic
|
21
21
|
h.merge!('apns-collapse-id' => notification.apns_collapse_id) if notification.apns_collapse_id
|
22
22
|
h.merge!('authorization' => notification.authorization_header) if notification.authorization_header
|
data/lib/apnotic/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apnotic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roberto Ostinelli
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: net-http2
|
@@ -86,17 +86,17 @@ dependencies:
|
|
86
86
|
- - "~>"
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: '3.0'
|
89
|
-
description:
|
89
|
+
description:
|
90
90
|
email:
|
91
91
|
- roberto@ostinelli.net
|
92
92
|
executables: []
|
93
93
|
extensions: []
|
94
94
|
extra_rdoc_files: []
|
95
95
|
files:
|
96
|
+
- ".github/workflows/ci.yml"
|
96
97
|
- ".gitignore"
|
97
98
|
- ".rspec"
|
98
99
|
- ".tool-versions"
|
99
|
-
- ".travis.yml"
|
100
100
|
- Gemfile
|
101
101
|
- LICENSE.md
|
102
102
|
- README.md
|
@@ -120,7 +120,7 @@ homepage: http://github.com/ostinelli/apnotic
|
|
120
120
|
licenses:
|
121
121
|
- MIT
|
122
122
|
metadata: {}
|
123
|
-
post_install_message:
|
123
|
+
post_install_message:
|
124
124
|
rdoc_options: []
|
125
125
|
require_paths:
|
126
126
|
- lib
|
@@ -128,15 +128,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
128
128
|
requirements:
|
129
129
|
- - ">="
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 2.
|
131
|
+
version: 2.4.0
|
132
132
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
133
|
requirements:
|
134
134
|
- - ">="
|
135
135
|
- !ruby/object:Gem::Version
|
136
136
|
version: '0'
|
137
137
|
requirements: []
|
138
|
-
rubygems_version: 3.1
|
139
|
-
signing_key:
|
138
|
+
rubygems_version: 3.0.3.1
|
139
|
+
signing_key:
|
140
140
|
specification_version: 4
|
141
141
|
summary: Apnotic is an Apple Push Notification gem able to provide instant feedback.
|
142
142
|
test_files: []
|