Giter VIP home page Giter VIP logo

firebase_cloud_messenger's Introduction

firebase_cloud_messenger

Check out PLM's blog post about our development and use of firebase_cloud_messenger for more information about setting up and getting started.

firebase_cloud_messenger wraps Google's API to make sending push notifications to iOS, android, and web push notifications from your server easy.

NB: Google released the FCM HTTP v1 API in November 2017, giving legacy status to the older but still supported HTTP and XMPP apis. This gem only targets the [FCM HTTP v1 API], which Google recommends using for new projects, because it is the most up-to-date and secure.

Installation

Add this line to your application's Gemfile:

gem 'firebase_cloud_messenger'

And then execute:

$ bundle

Or install it yourself as:

$ gem install firebase_cloud_messenger

Setup

In order for google to authenticate requests to Firebase Cloud Messenger, you must either have your service account credentials file in a place that's accessible, or provide credentials as env vars.

Setup Method 1: Service Account JSON Path Supplied As Env Var

$ export GOOGLE_APPLICATION_CREDENTIALS = "path/to/credentials/file.json"`

Setup Method 2: Service Account JSON Path Supplied To FirebaseCloudMessenger

FirebaseCloudMessenger.credentials_path = "path/to/credentials/file.json"

Setup Method 3: Service Account Credentials Set as Env Vars

$ export GOOGLE_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----..."
$ export GOOGLE_CLIENT_EMAIL = "[email protected]"

Also set the project_id, which is otherwise read from the json service account file:

FirebaseCloudMessenger.project_id = "1234567"

Usage

Sending a Message

You can see how your message should be structured here firebase_cloud_messenger provides built-in data classes for each json object type in the FCM API specification, but you can also build up a hash message on your own, or use some combination of the two.

Send messages with built-in data objects, which can be built through a hash argument to the initializer or via writer methods:

android_notification = FirebaseCloudMessenger::Android::Notification.new(title: "title")
android_config = FirebaseCloudMessenger::Android::Config.new(notification: android_notification)
message = FirebaseCloudMessenger::Message.new(android: android_config, token: "a_device_token")

FirebaseCloudMessenger.send(message: message) # => { "name" => "name_from_fcm" }

# OR

android_notification = FirebaseCloudMessenger::Android::Notification.new
android_notification.title = "title"

android_config = FirebaseCloudMessenger::Android::Config.new
android_config.notification = android_notification

message = FirebaseCloudMessenger::Message.new
message.android = android_config
message.token = "a_device_token"

FirebaseCloudMessenger.send(message: message) # => { "name" => "name_from_fcm" }

or with just a hash:

message = {
  android: {
    notification: {
      title: "title"
    }
  },
  token: "a_device_token"
}

FirebaseCloudMessenger.send(message: message) # => { "name" => "name_from_fcm" }

or some combination of the two:

message = FirebaseCloudMessenger::Message.new(android: { notification: { title: "title" } }, token: "a_device_token" )
FirebaseCloudMessenger.send(message: message) # => { "name" => "name_from_fcm" }

Error Handling

If something goes wrong, ::send will raise an instance of a subclass of FirebaseCloudMessenger::Error with helpful info on what went wrong:

message = FirebaseCloudMessenger::Message.new(android: { bad: "data" }, token: "a_device_token"})
begin
  FirebaseCloudMessenger.send(message: message)
rescue FirebaseCloudMessenger::Error => e
  e.class # => FirebaseCloudMessenger::BadRequest
  e.short_message # => A message from fcm about what's wrong with the request
  e.response_status # => 400
  e.details # => An array of error details from fcm
end

Message Validation

Many errors can be caught before sending by validating a message before sending it.

Validate your message either by via the Firebase Cloud Messenger API:

message = FirebaseCloudMessenger::Message.new(android: { bad: "data" })
message.valid?(against_api: true) # => false
message.errors # => [<error_msg>]

or client-side, via json-schema:

message = FirebaseCloudMessenger::Message.new(android: { bad: "data" }, token: "a_device_token")
message.valid? # => false
message.errors # => ["The property '#/android' contains additional properties [\"bad\"] outside of the schema when none are allowed in schema..."]

Validate your hash message (returns only true or false):

message = {
  android: { bad: "data" },
  token: "a_device_token"
}

#api-side
FirebaseCloudMessenger.validate_message(message, against_api: true) # => false

#OR

#client-side
FirebaseCloudMessenger.validate_message(message) # => false

Development

After checking out the repo, run bundle to install dependencies. Then, run bundle exec rake test to run the tests.

firebase_cloud_messenger's People

Contributors

adia-stansbury avatar bill-kolokithas avatar edudepetris avatar ezilocchi avatar kaito0228 avatar machty avatar sidonath avatar swiknaba avatar tomek1024 avatar vincedevendra avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

firebase_cloud_messenger's Issues

Lack of APNS documentation and probable apns alert issue

Lack of apns documentation. Had to read the codebase. Anyway get an error trying to send an alert via APNS.

message = {
  apns: { payload: { alert: { title: "title" }, badge: 2 } },
  token: "my_fcm_reg_id"
}

FirebaseCloudMessenger.send(message: message)

=> FirebaseCloudMessenger::BadRequest:       Status: 400

      Request contains an invalid argument.

as well as

notification = FirebaseCloudMessenger::Notification.new(title: "title")
apns_alert = FirebaseCloudMessenger::Apns::Alert.new(title: "title")
apns_payload = FirebaseCloudMessenger::Apns::Payload.new(alert: apns_alert, badge: 2)
apns_config = FirebaseCloudMessenger::Apns::Config.new(payload: apns_payload)

msg = FirebaseCloudMessenger::Message.new(name: "name",
                                          notification: notification,
                                          apns: apns_config,
                                          token: "my_fcm_reg_id")

       => 
FirebaseCloudMessenger::BadRequest:       Status: 400

      Request contains an invalid argument.

Correct me if I'm trying to send it the wrong way.

Nested objects inside of the data attribute on payload

Hi.

Is it possible to send custom payloads inside of the data attribute? For example, nested objects? I am trying to send some nested objects inside of the data attribute and I am getting the following errors:

Message: Invalid JSON payload received. Unknown name "metadata" at 'message.android.data[3].value': Cannot find field.

Thank you.

Duplicate Messages

i keep getting 2 messages instead of one when I try to send a message using the gem however when i use the console i normally get only 1 message

iOS (APNS) Examples?

This is working excellent for pushing to Android following your example. But I cannot get the APNS or iOS combination of values and configuration to work. Do you have any APNS examples that you could provide?

'image' intentionally ignored?

So, I'm trying to send an image URL with my notifications.
This is supported by FCM for both iOS and Android in either of the following ways:

{
     notification: { :title, :body, :image }, 
     android: { notification: { ...., :image, .... } }, 
     apns: { :headers, :payload, fcm_options: { :image } } 
}
 

But it seems :image is consistently ignored. The accessible attributes in the gem's code
are frozen to include everything other than :image

Can this be changed? Or, has this been done intentionally for some reason?

Thanks for your help
Abhinav.

Too many retries don't cause client to raise

In our case the client keeps receiving responses with code 401. The FCM authentication works fine, but the configured APNS key doesn't seem to be working temporarily, so the FCM servers aren't able to properly authenticate with Apple and just bubble the 401 back to the client. The response includes that information, but since it also happens to be a 401 it just keeps trying to refresh its access token until it times out.

if response_successful?(response) || retry_count > max_retry_count
return message_from_response(response)
elsif response.code == "401"
refresh_access_token_info
else
raise Error.from_response(response)
end

{"error"=>
  {"code"=>401,
   "message"=>"Auth error from APNS or Web Push Service",
   "status"=>"UNAUTHENTICATED",
   "details"=>
    [{"@type"=>"type.googleapis.com/google.firebase.fcm.v1.FcmError",
      "errorCode"=>"THIRD_PARTY_AUTH_ERROR"}]}}

I'd expect the client to raise if the final retry wasn't successful, but as it stands it just returns the above error. Is there a specific reason why that's not the case or would a PR that changes this behavior be welcome?

Make service account credentials values settable indvidually

Right now, we rely on the googleauth library to fetch the appropriate oauth access token. That library relies on access to a json credentials file that contains service account information from FCM.

In order to make setting up an environment easier and more reproducible, it would be nice to be able to set the values in the json service account file individually, via env vars or some other mechanism.

It may be possible to do this with googleauth, but I think it may also be easier to use Google's authentication HTTP api directly, rather than their gem.

I imagine the api for this gem would like something like this:

service_account = FirebaseCloudMessenger::ServiceAccount.new
service_account.project_id = ENV['FCM_PROJECT_ID']
service_account.private_key = ENV['FCM_PRIVATE_KEY']
...
FirebaseCloudMessenger.service_account = service_account
FirebaseCloudMessenger.send(message: <message>)

This would involve a rewrite of AuthClient. I'd like also to do this in a way that is backward-compatible--If a credentials_path is supplied instead of service_account, the service account could be built by Client instead.

This would also allow us to drop our dependency on googleauth, which might make our maintenance a bit more difficult, but dropping a dependency is always nice.

cc. @bryanalves

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.