Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 9 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,45 +26,36 @@ A version of supported Ruby, currently:
To use this gem, you need to instantiate a client with your firebase credentials:

```ruby
fcm = FCM.new(
GOOGLE_APPLICATION_CREDENTIALS_PATH,
FIREBASE_PROJECT_ID
)
fcm = FCM.new(GOOGLE_APPLICATION_CREDENTIALS_PATH)
```

**Note:** The Firebase project ID is automatically extracted from your Firebase service credentials file.

## About the `GOOGLE_APPLICATION_CREDENTIALS_PATH`
The `GOOGLE_APPLICATION_CREDENTIALS_PATH` is meant to contain your firebase credentials.

The easiest way to provide them is to pass here an absolute path to a file with your credentials:

```ruby
fcm = FCM.new(
'/path/to/credentials.json',
FIREBASE_PROJECT_ID
)
fcm = FCM.new('/path/to/credentials.json')
```

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:

```ruby
fcm = FCM.new(
StringIO.new(ENV.fetch('FIREBASE_CREDENTIALS')),
FIREBASE_PROJECT_ID
)

fcm = FCM.new(StringIO.new(ENV.fetch('FIREBASE_CREDENTIALS')))
```

The gem will automatically extract the `project_id` from your Firebase service credentials file.

## Usage

## HTTP v1 API

To migrate to HTTP v1 see: https://firebase.google.com/docs/cloud-messaging/migrate-v1

```ruby
fcm = FCM.new(
GOOGLE_APPLICATION_CREDENTIALS_PATH,
FIREBASE_PROJECT_ID
)
fcm = FCM.new(GOOGLE_APPLICATION_CREDENTIALS_PATH)
message = {
'token': "000iddqd", # send to a specific device
# 'topic': "yourTopic",
Expand Down Expand Up @@ -108,8 +99,7 @@ https://firebase.google.com/docs/cloud-messaging/android/device-group#managing_d

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:

`project_id` is the SENDER_ID in your cloud settings.
https://firebase.google.com/docs/cloud-messaging/concept-options#senderid
**Note:** The `project_id` parameter used in device group management is your Firebase project's sender ID, which can be found in your Firebase project settings under Cloud Messaging.

```ruby
params = { key_name: "appUser-Chris",
Expand Down
34 changes: 26 additions & 8 deletions lib/fcm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@ class FCM
INSTANCE_ID_API = "https://iid.googleapis.com"
TOPIC_REGEX = /[a-zA-Z0-9\-_.~%]+/

def initialize(json_key_path = "", project_name = "", http_options = {})
def initialize(json_key_path = '', http_options = {})
@json_key_path = json_key_path
@project_name = project_name
@http_options = http_options
end

# See https://firebase.google.com/docs/cloud-messaging/send-message
# See https://firebase.google.com/docs/cloud-messaging/send/v1-api
# {
# "token": "4sdsx",
# "notification": {
Expand All @@ -42,17 +41,17 @@ def initialize(json_key_path = "", project_name = "", http_options = {})
# }
# }
# }
# fcm = FCM.new(json_key_path, project_name)
# fcm = FCM.new(json_key_path)
# fcm.send_v1(
# { "token": "4sdsx",, "to" : "notification": {}.. }
# )
def send_notification_v1(message)
return if @project_name.empty?
return if firebase_project_id.empty?

post_body = { 'message': message }
for_uri(BASE_URI_V1) do |connection|
response = connection.post(
"#{@project_name}/messages:send", post_body.to_json
"#{firebase_project_id}/messages:send", post_body.to_json
)
build_response(response)
end
Expand Down Expand Up @@ -168,7 +167,7 @@ def send_to_topic(topic, options = {})

for_uri(BASE_URI_V1) do |connection|
response = connection.post(
"#{@project_name}/messages:send", body.to_json
"#{firebase_project_id}/messages:send", body.to_json
)
build_response(response)
end
Expand All @@ -181,7 +180,7 @@ def send_to_topic_condition(condition, options = {})

for_uri(BASE_URI_V1) do |connection|
response = connection.post(
"#{@project_name}/messages:send", body.to_json
"#{firebase_project_id}/messages:send", body.to_json
)
build_response(response)
end
Expand Down Expand Up @@ -298,4 +297,23 @@ def json_key
File.open(@json_key_path)
end
end

def firebase_project_id
@firebase_project_id ||= extract_project_id
end

def extract_project_id
return '' if @json_key_path.nil? || @json_key_path == ''

json_content = if @json_key_path.respond_to?(:read)
@json_key_path.read.tap { @json_key_path.rewind }
else
File.read(@json_key_path)
end

credentials = JSON.parse(json_content)
credentials['project_id'] || ''
rescue JSON::ParserError, Errno::ENOENT
''
end
end
20 changes: 11 additions & 9 deletions spec/fcm_spec.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "spec_helper"

describe FCM do
let(:project_name) { 'test-project' }
let(:firebase_project_id) { 'test-project' }
let(:json_key_path) { 'path/to/json/key.json' }
let(:client) { FCM.new(json_key_path) }

Expand All @@ -15,6 +15,8 @@

before do
allow(client).to receive(:json_key)
allow(client).to receive(:extract_project_id)
.and_return(firebase_project_id)

# Mock the Google::Auth::ServiceAccountCredentials
allow(Google::Auth::ServiceAccountCredentials).to receive(:make_creds).
Expand All @@ -38,9 +40,9 @@
end

describe "#send_v1 or #send_notification_v1" do
let(:client) { FCM.new(json_key_path, project_name) }
let(:client) { FCM.new(json_key_path) }

let(:uri) { "#{FCM::BASE_URI_V1}#{project_name}/messages:send" }
let(:uri) { "#{FCM::BASE_URI_V1}#{firebase_project_id}/messages:send" }
let(:status_code) { 200 }

let(:stub_fcm_send_v1_request) do
Expand Down Expand Up @@ -177,8 +179,8 @@
include_examples 'succesfuly send notification'
end

context 'when project_name is empty' do
let(:project_name) { '' }
context 'when firebase_project_id is empty' do
let(:firebase_project_id) { '' }
let(:send_v1_params) do
{
'token' => '4sdsx',
Expand Down Expand Up @@ -249,9 +251,9 @@
end

describe '#send_to_topic' do
let(:client) { FCM.new(json_key_path, project_name) }
let(:client) { FCM.new(json_key_path) }

let(:uri) { "#{FCM::BASE_URI_V1}#{project_name}/messages:send" }
let(:uri) { "#{FCM::BASE_URI_V1}#{firebase_project_id}/messages:send" }

let(:topic) { 'news' }
let(:params) do
Expand Down Expand Up @@ -300,9 +302,9 @@
end

describe "#send_to_topic_condition" do
let(:client) { FCM.new(json_key_path, project_name) }
let(:client) { FCM.new(json_key_path) }

let(:uri) { "#{FCM::BASE_URI_V1}#{project_name}/messages:send" }
let(:uri) { "#{FCM::BASE_URI_V1}#{firebase_project_id}/messages:send" }

let(:topic_condition) { "'foo' in topics" }
let(:params) do
Expand Down