fcm 1.0.8 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16615f79f5432e2a352dc3c26e42d48efed7727a86f04f2b9d2bf93cca47aae6
4
- data.tar.gz: d2fe30204d7ef51288014fbcc2df5f211ea8d8b4dbbc28cb9af0d9fadc54d6c7
3
+ metadata.gz: 72a9acc9e72359d421c740b5ac8ce3c9547a587a1e08672931a51355523b27a0
4
+ data.tar.gz: 250eb8a97008cc4affc39a512695c5cf9339baa35de77854169746ed80fcf7c3
5
5
  SHA512:
6
- metadata.gz: 06c32340bae1ab25e1d66c06d63fa5d7276214604902218a1a9f5cf06774a60a08ab4bc700616f63ed5563a8b106227ef073168fcbfa29798348fadec2480767
7
- data.tar.gz: ffa28e382feba7728e496318ea546237c9c5070ccc175d71a2dc83e9adf0a58efa932336a729549599978b6a2406ec01e80bd060997f779631d3a53122660b59
6
+ metadata.gz: 0beb8691a1a5dc0090ce92cb584c1f44aa97545de9f45d649a65b2ac4cd2196db8178ace4675a7f39deca00bcb8650fb4a9e71569b609f24aa6942fa88e08c2c
7
+ data.tar.gz: e079ef26d913c7e418e89943cedc980034f03d49cc749c681ee8e4e237fe6a2a059342f012c235a84d2ba227fa8941671e9834350beea5ce93e6ee7341f2aa49
@@ -13,7 +13,7 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  strategy:
15
15
  matrix:
16
- ruby: ['2.7', '3.0', '3.1']
16
+ ruby: ['2.7', '3.0', '3.1', '3.3']
17
17
 
18
18
  steps:
19
19
  - uses: actions/checkout@master
data/.gitignore CHANGED
@@ -49,3 +49,4 @@ Gemfile.lock
49
49
  .rvmrc
50
50
  spec/reports
51
51
  *.gem
52
+ .env
data/README.md CHANGED
@@ -22,6 +22,38 @@ For Android you will need a device running 2.3 (or newer) that also have the Goo
22
22
  A version of supported Ruby, currently:
23
23
  `ruby >= 2.4`
24
24
 
25
+ ## Getting Started
26
+ To use this gem, you need to instantiate a client with your firebase credentials:
27
+
28
+ ```ruby
29
+ fcm = FCM.new(
30
+ GOOGLE_APPLICATION_CREDENTIALS_PATH,
31
+ FIREBASE_PROJECT_ID
32
+ )
33
+ ```
34
+
35
+ ## About the `GOOGLE_APPLICATION_CREDENTIALS_PATH`
36
+ The `GOOGLE_APPLICATION_CREDENTIALS_PATH` is meant to contain your firebase credentials.
37
+
38
+ The easiest way to provide them is to pass here an absolute path to a file with your credentials:
39
+
40
+ ```ruby
41
+ fcm = FCM.new(
42
+ '/path/to/credentials.json',
43
+ FIREBASE_PROJECT_ID
44
+ )
45
+ ```
46
+
47
+ As per their secret nature, you might not want to have them in your repository. In that case, another supported solution is to pass a `StringIO` that contains your credentials:
48
+
49
+ ```ruby
50
+ fcm = FCM.new(
51
+ StringIO.new(ENV.fetch('FIREBASE_CREDENTIALS')),
52
+ FIREBASE_PROJECT_ID
53
+ )
54
+
55
+ ```
56
+
25
57
  ## Usage
26
58
 
27
59
  ## HTTP v1 API
@@ -30,13 +62,13 @@ To migrate to HTTP v1 see: https://firebase.google.com/docs/cloud-messaging/migr
30
62
 
31
63
  ```ruby
32
64
  fcm = FCM.new(
33
- API_TOKEN,
34
65
  GOOGLE_APPLICATION_CREDENTIALS_PATH,
35
66
  FIREBASE_PROJECT_ID
36
67
  )
37
68
  message = {
38
- 'topic': "89023", # OR token if you want to send to a specific device
39
- # 'token': "000iddqd",
69
+ 'token': "000iddqd", # send to a specific device
70
+ # 'topic': "yourTopic",
71
+ # 'condition': "'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)",
40
72
  'data': {
41
73
  payload: {
42
74
  data: {
@@ -62,58 +94,42 @@ message = {
62
94
  }
63
95
  }
64
96
 
65
- fcm.send_v1(message)
66
- ```
67
-
68
- ## HTTP Legacy Version
69
-
70
- To migrate to HTTP v1 see: https://firebase.google.com/docs/cloud-messaging/migrate-v1
71
-
72
- For your server to send a message to one or more devices, you must first initialise a new `FCM` class with your Firebase Cloud Messaging server key, and then call the `send` method on this and give it 1 or more (up to 1000) registration tokens as an array of strings. You can also optionally send further [HTTP message parameters](https://firebase.google.com/docs/cloud-messaging/http-server-ref) like `data` or `time_to_live` etc. as a hash via the second optional argument to `send`.
73
-
74
- Example sending notifications:
75
-
76
- ```ruby
77
- require 'fcm'
78
-
79
- fcm = FCM.new("my_server_key")
80
-
81
- registration_ids= ["12", "13"] # an array of one or more client registration tokens
82
-
83
- # See https://firebase.google.com/docs/cloud-messaging/http-server-ref for all available options.
84
- options = { "notification": {
85
- "title": "Portugal vs. Denmark",
86
- "body": "5 to 1"
87
- }
88
- }
89
- response = fcm.send(registration_ids, options)
97
+ fcm.send_v1(message) # or fcm.send_notification_v1(message)
90
98
  ```
91
99
 
92
- Currently `response` is just a hash containing the response `body`, `headers` and `status_code`. Check [here](https://firebase.google.com/docs/cloud-messaging/server#response) to see how to interpret the responses.
93
-
94
100
  ## Device Group Messaging
95
101
 
96
102
  With [device group messaging](https://firebase.google.com/docs/cloud-messaging/notifications), you can send a single message to multiple instance of an app running on devices belonging to a group. Typically, "group" refers a set of different devices that belong to a single user. However, a group could also represent a set of devices where the app instance functions in a highly correlated manner. To use this feature, you will first need an initialised `FCM` class.
97
103
 
104
+ The maximum number of members allowed for a notification key is 20.
105
+ https://firebase.google.com/docs/cloud-messaging/android/device-group#managing_device_groups
106
+
98
107
  ### Generate a Notification Key for device group
99
108
 
100
109
  Then you will need a notification key which you can create for a particular `key_name` which needs to be uniquely named per app in case you have multiple apps for the same `project_id`. This ensures that notifications only go to the intended target app. The `create` method will do this and return the token `notification_key`, that represents the device group, in the response:
101
110
 
111
+ `project_id` is the SENDER_ID in your cloud settings.
112
+ https://firebase.google.com/docs/cloud-messaging/concept-options#senderid
113
+
102
114
  ```ruby
103
- params = {key_name: "appUser-Chris",
115
+ params = { key_name: "appUser-Chris",
104
116
  project_id: "my_project_id",
105
- registration_ids: ["4", "8", "15", "16", "23", "42"]}
117
+ registration_ids: ["4", "8", "15", "16", "23", "42"] }
106
118
  response = fcm.create(*params.values)
107
119
  ```
108
120
 
109
- ### Send to Notification Key
121
+ ### Send to Notification device group
110
122
 
111
- Now you can send a message to a particular `notification_key` via the `send_with_notification_key` method. This allows the server to send a single [data](https://firebase.google.com/docs/cloud-messaging/concept-options#data_messages) payload or/and [notification](https://firebase.google.com/docs/cloud-messaging/concept-options#notifications) payload to multiple app instances (typically on multiple devices) owned by a single user (instead of sending to some registration tokens). Note: the maximum number of members allowed for a `notification_key` is 20.
123
+ To send messages to device groups, use the HTTP v1 API,
124
+ Sending messages to a device group is very similar to sending messages to an individual device, using the same method to authorize send requests. Set the token field to the group notification key
112
125
 
113
126
  ```ruby
114
- response = fcm.send_with_notification_key("notification_key",
115
- data: {score: "3x1"},
116
- collapse_key: "updated_score")
127
+ message = {
128
+ 'token': "NOTIFICATION_KEY", # send to a device group
129
+ # ...data
130
+ }
131
+
132
+ fcm.send_v1(message)
117
133
  ```
118
134
 
119
135
  ### Add/Remove Registration Tokens
@@ -136,23 +152,51 @@ response = fcm.remove(*params.values)
136
152
 
137
153
  ## Send Messages to Topics
138
154
 
139
- FCM [topic messaging](https://firebase.google.com/docs/cloud-messaging/topic-messaging) allows your app server to send a message to multiple devices that have opted in to a particular topic. Based on the publish/subscribe model, topic messaging supports unlimited subscriptions per app. Sending to a topic is very similar to sending to an individual device or to a user group, in the sense that you can use the `fcm.send_with_notification_key()` method where the `notification_key` matches the regular expression `"/topics/[a-zA-Z0-9-_.~%]+"`:
155
+ FCM [topic messaging](https://firebase.google.com/docs/cloud-messaging/topic-messaging) allows your app server to send a message to multiple devices that have opted in to a particular topic. Based on the publish/subscribe model, one app instance can be subscribed to no more than 2000 topics. Sending to a topic is very similar to sending to an individual device or to a user group, in the sense that you can use the `fcm.send_v1` method where the `topic` matches the regular expression `"/topics/[a-zA-Z0-9-_.~%]+"`:
140
156
 
141
157
  ```ruby
142
- response = fcm.send_with_notification_key("/topics/yourTopic",
143
- notification: {body: "This is a FCM Topic Message!"})
158
+ message = {
159
+ 'topic': "yourTopic", # send to a device group
160
+ # ...data
161
+ }
162
+
163
+ fcm.send_v1(message)
144
164
  ```
145
165
 
146
- Or you can use the helper:
166
+ Or you can use the `fcm.send_to_topic` helper:
147
167
 
148
168
  ```ruby
149
169
  response = fcm.send_to_topic("yourTopic",
150
- notification: {body: "This is a FCM Topic Message!"})
170
+ notification: { body: "This is a FCM Topic Message!"} )
171
+ ```
172
+
173
+ ## Send Messages to Topics with Conditions
174
+
175
+ FCM [topic condition messaging](https://firebase.google.com/docs/cloud-messaging/android/topic-messaging#build_send_requests) to send a message to a combination of topics, specify a condition, which is a boolean expression that specifies the target topics.
176
+
177
+ ```ruby
178
+ message = {
179
+ 'condition': "'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)", # send to topic condition
180
+ # ...data
181
+ }
182
+
183
+ fcm.send_v1(message)
184
+ ```
185
+
186
+ Or you can use the `fcm.send_to_topic_condition` helper:
187
+
188
+ ```ruby
189
+ response = fcm.send_to_topic_condition(
190
+ "'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)",
191
+ notification: {
192
+ body: "This is an FCM Topic Message sent to a condition!"
193
+ }
194
+ )
151
195
  ```
152
196
 
153
197
  ### Sending to Multiple Topics
154
198
 
155
- To send to combinations of multiple topics, the FCM [docs](https://firebase.google.com/docs/cloud-messaging/send-message#send_messages_to_topics_2) require that you set a **condition** key (instead of the `to:` key) to a boolean condition that specifies the target topics. For example, to send messages to devices that subscribed to _TopicA_ and either _TopicB_ or _TopicC_:
199
+ To send to combinations of multiple topics, require that you set a **condition** key to a boolean condition that specifies the target topics. For example, to send messages to devices that subscribed to _TopicA_ and either _TopicB_ or _TopicC_:
156
200
 
157
201
  ```
158
202
  'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)
@@ -188,18 +232,38 @@ Given a registration token and a topic name, you can add the token to the topic
188
232
 
189
233
  ```ruby
190
234
  topic = "YourTopic"
191
- registration_id= "12" # a client registration tokens
192
- response = fcm.topic_subscription(topic, registration_id)
235
+ registration_token= "12" # a client registration token
236
+ response = fcm.topic_subscription(topic, registration_token)
237
+ # or unsubscription
238
+ response = fcm.topic_unsubscription(topic, registration_token)
193
239
  ```
194
240
 
195
241
  Or you can manage relationship maps for multiple app instances [Google Instance ID server API. Manage relationship](https://developers.google.com/instance-id/reference/server#manage_relationship_maps_for_multiple_app_instances)
196
242
 
197
243
  ```ruby
198
244
  topic = "YourTopic"
199
- registration_ids= ["4", "8", "15", "16", "23", "42"] # an array of one or more client registration tokens
200
- response = fcm.batch_topic_subscription(topic, registration_ids)
245
+ registration_tokens= ["4", "8", "15", "16", "23", "42"] # an array of one or more client registration tokens
246
+ response = fcm.batch_topic_subscription(topic, registration_tokens)
201
247
  # or unsubscription
202
- response = fcm.batch_topic_unsubscription(topic, registration_ids)
248
+ response = fcm.batch_topic_unsubscription(topic, registration_tokens)
249
+ ```
250
+
251
+ ## Get Information about the Instance ID
252
+
253
+ Given a registration token, you can retrieve information about the token using the [Google Instance ID server API](https://developers.google.com/instance-id/reference/server).
254
+
255
+ ```ruby
256
+ registration_token= "12" # a client registration token
257
+ response = fcm.get_instance_id_info(registration_token)
258
+ ```
259
+
260
+ To get detailed information about the instance ID, you can pass an optional
261
+ `options` hash to the `get_instance_id_info` method:
262
+
263
+ ```ruby
264
+ registration_token= "12" # a client registration token
265
+ options = { "details" => true }
266
+ response = fcm.get_instance_id_info(registration_token, options)
203
267
  ```
204
268
 
205
269
  ## Mobile Clients
@@ -210,6 +274,20 @@ The guide to set up an iOS app to get notifications is here: [Setting up a FCM C
210
274
 
211
275
  ## ChangeLog
212
276
 
277
+ ### 2.0.0
278
+ #### Breaking Changes
279
+ - Remove deprecated `API_KEY`
280
+ - Remove deprecated `send` method
281
+ - Remove deprecated `send_with_notification_key` method
282
+ - Remove `subscribe_instance_id_to_topic` method
283
+ - Remove `unsubscribe_instance_id_from_topic` method
284
+ - Remove `batch_subscribe_instance_ids_to_topic` method
285
+ - Remove `batch_unsubscribe_instance_ids_from_topic` method
286
+
287
+ #### Supported Features
288
+ - Add HTTP v1 API support for `send_to_topic_condition` method
289
+ - Add HTTP v1 API support for `send_to_topic` method
290
+
213
291
  ### 1.0.8
214
292
  - caches calls to `Google::Auth::ServiceAccountCredentials` #103
215
293
  - Allow `faraday` versions from 1 up to 2 #101
data/fcm.gemspec CHANGED
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "fcm"
6
- s.version = "1.0.8"
6
+ s.version = "2.0.0"
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ["Kashif Rasul", "Shoaib Burq"]
9
9
  s.email = ["kashif@decision-labs.com", "shoaib@decision-labs.com"]
data/lib/fcm.rb CHANGED
@@ -7,20 +7,14 @@ class FCM
7
7
  BASE_URI = "https://fcm.googleapis.com"
8
8
  BASE_URI_V1 = "https://fcm.googleapis.com/v1/projects/"
9
9
  DEFAULT_TIMEOUT = 30
10
- FORMAT = :json
11
10
 
12
- # constants
13
11
  GROUP_NOTIFICATION_BASE_URI = "https://android.googleapis.com"
14
12
  INSTANCE_ID_API = "https://iid.googleapis.com"
15
13
  TOPIC_REGEX = /[a-zA-Z0-9\-_.~%]+/
16
14
 
17
- attr_accessor :timeout, :api_key, :json_key_path, :project_base_uri
18
-
19
- def initialize(api_key, json_key_path = "", project_name = "", client_options = {})
20
- @api_key = api_key
21
- @client_options = client_options
15
+ def initialize(json_key_path = "", project_name = "")
22
16
  @json_key_path = json_key_path
23
- @project_base_uri = BASE_URI_V1 + project_name.to_s
17
+ @project_name = project_name
24
18
  end
25
19
 
26
20
  # See https://firebase.google.com/docs/cloud-messaging/send-message
@@ -47,48 +41,24 @@ class FCM
47
41
  # }
48
42
  # }
49
43
  # }
50
- # fcm = FCM.new(api_key, json_key_path, project_name)
51
- # fcm.send(
44
+ # fcm = FCM.new(json_key_path, project_name)
45
+ # fcm.send_v1(
52
46
  # { "token": "4sdsx",, "to" : "notification": {}.. }
53
47
  # )
54
48
  def send_notification_v1(message)
55
- return if @project_base_uri.empty?
49
+ return if @project_name.empty?
56
50
 
57
51
  post_body = { 'message': message }
58
-
59
- response = Faraday.post("#{@project_base_uri}/messages:send") do |req|
60
- req.headers["Content-Type"] = "application/json"
61
- req.headers["Authorization"] = "Bearer #{jwt_token}"
62
- req.body = post_body.to_json
52
+ for_uri(BASE_URI_V1) do |connection|
53
+ response = connection.post(
54
+ "#{@project_name}/messages:send", post_body.to_json
55
+ )
56
+ build_response(response)
63
57
  end
64
- build_response(response)
65
58
  end
66
59
 
67
60
  alias send_v1 send_notification_v1
68
61
 
69
- # See https://developers.google.com/cloud-messaging/http for more details.
70
- # { "notification": {
71
- # "title": "Portugal vs. Denmark",
72
- # "text": "5 to 1"
73
- # },
74
- # "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
75
- # }
76
- # fcm = FCM.new("API_KEY")
77
- # fcm.send(
78
- # ["4sdsx", "8sdsd"], # registration_ids
79
- # { "notification": { "title": "Portugal vs. Denmark", "text": "5 to 1" }, "to" : "bk3RNwTe3HdFQ3P1..." }
80
- # )
81
- def send_notification(registration_ids, options = {})
82
- post_body = build_post_body(registration_ids, options)
83
-
84
- for_uri(BASE_URI) do |connection|
85
- response = connection.post("/fcm/send", post_body.to_json)
86
- build_response(response, registration_ids)
87
- end
88
- end
89
-
90
- alias send send_notification
91
-
92
62
  def create_notification_key(key_name, project_id, registration_ids = [])
93
63
  post_body = build_post_body(registration_ids, operation: "create",
94
64
  notification_key_name: key_name)
@@ -152,28 +122,29 @@ class FCM
152
122
  end
153
123
  end
154
124
 
155
- def send_with_notification_key(notification_key, options = {})
156
- body = { to: notification_key }.merge(options)
157
- execute_notification(body)
158
- end
159
-
160
- def topic_subscription(topic, registration_id)
125
+ def topic_subscription(topic, registration_token)
161
126
  for_uri(INSTANCE_ID_API) do |connection|
162
- response = connection.post("/iid/v1/#{registration_id}/rel/topics/#{topic}")
127
+ response = connection.post(
128
+ "/iid/v1/#{registration_token}/rel/topics/#{topic}"
129
+ )
163
130
  build_response(response)
164
131
  end
165
132
  end
166
133
 
167
- def batch_topic_subscription(topic, registration_ids)
168
- manage_topics_relationship(topic, registration_ids, "Add")
134
+ def topic_unsubscription(topic, registration_token)
135
+ batch_topic_unsubscription(topic, [registration_token])
136
+ end
137
+
138
+ def batch_topic_subscription(topic, registration_tokens)
139
+ manage_topics_relationship(topic, registration_tokens, 'Add')
169
140
  end
170
141
 
171
- def batch_topic_unsubscription(topic, registration_ids)
172
- manage_topics_relationship(topic, registration_ids, "Remove")
142
+ def batch_topic_unsubscription(topic, registration_tokens)
143
+ manage_topics_relationship(topic, registration_tokens, 'Remove')
173
144
  end
174
145
 
175
- def manage_topics_relationship(topic, registration_ids, action)
176
- body = { to: "/topics/#{topic}", registration_tokens: registration_ids }
146
+ def manage_topics_relationship(topic, registration_tokens, action)
147
+ body = { to: "/topics/#{topic}", registration_tokens: registration_tokens }
177
148
 
178
149
  for_uri(INSTANCE_ID_API) do |connection|
179
150
  response = connection.post("/iid/v1:batch#{action}", body.to_json)
@@ -181,41 +152,38 @@ class FCM
181
152
  end
182
153
  end
183
154
 
184
- def send_to_topic(topic, options = {})
185
- if topic.gsub(TOPIC_REGEX, "").length == 0
186
- send_with_notification_key("/topics/" + topic, options)
187
- end
188
- end
189
-
190
155
  def get_instance_id_info(iid_token, options = {})
191
156
  params = options
192
157
 
193
158
  for_uri(INSTANCE_ID_API) do |connection|
194
- response = connection.get("/iid/info/" + iid_token, params)
159
+ response = connection.get("/iid/info/#{iid_token}", params)
195
160
  build_response(response)
196
161
  end
197
162
  end
198
163
 
199
- def subscribe_instance_id_to_topic(iid_token, topic_name)
200
- batch_subscribe_instance_ids_to_topic([iid_token], topic_name)
201
- end
202
-
203
- def unsubscribe_instance_id_from_topic(iid_token, topic_name)
204
- batch_unsubscribe_instance_ids_from_topic([iid_token], topic_name)
205
- end
206
-
207
- def batch_subscribe_instance_ids_to_topic(instance_ids, topic_name)
208
- manage_topics_relationship(topic_name, instance_ids, "Add")
209
- end
210
-
211
- def batch_unsubscribe_instance_ids_from_topic(instance_ids, topic_name)
212
- manage_topics_relationship(topic_name, instance_ids, "Remove")
164
+ def send_to_topic(topic, options = {})
165
+ if topic.gsub(TOPIC_REGEX, '').length.zero?
166
+ body = { 'message': { 'topic': topic }.merge(options) }
167
+
168
+ for_uri(BASE_URI_V1) do |connection|
169
+ response = connection.post(
170
+ "#{@project_name}/messages:send", body.to_json
171
+ )
172
+ build_response(response)
173
+ end
174
+ end
213
175
  end
214
176
 
215
177
  def send_to_topic_condition(condition, options = {})
216
178
  if validate_condition?(condition)
217
- body = { condition: condition }.merge(options)
218
- execute_notification(body)
179
+ body = { 'message': { 'condition': condition }.merge(options) }
180
+
181
+ for_uri(BASE_URI_V1) do |connection|
182
+ response = connection.post(
183
+ "#{@project_name}/messages:send", body.to_json
184
+ )
185
+ build_response(response)
186
+ end
219
187
  end
220
188
  end
221
189
 
@@ -228,7 +196,8 @@ class FCM
228
196
  ) do |faraday|
229
197
  faraday.adapter Faraday.default_adapter
230
198
  faraday.headers["Content-Type"] = "application/json"
231
- faraday.headers["Authorization"] = "key=#{api_key}"
199
+ faraday.headers["Authorization"] = "Bearer #{jwt_token}"
200
+ faraday.headers["access_token_auth"]= "true"
232
201
  extra_headers.each do |key, value|
233
202
  faraday.headers[key] = value
234
203
  end
@@ -286,13 +255,6 @@ class FCM
286
255
  not_registered_ids
287
256
  end
288
257
 
289
- def execute_notification(body)
290
- for_uri(BASE_URI) do |connection|
291
- response = connection.post("/fcm/send", body.to_json)
292
- build_response(response)
293
- end
294
- end
295
-
296
258
  def has_canonical_id?(result)
297
259
  !result["registration_id"].nil?
298
260
  end