-
Notifications
You must be signed in to change notification settings - Fork 364
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FCM support - v1.1 #660
FCM support - v1.1 #660
Changes from all commits
74b4258
509dae4
d8559d6
8f3cacf
0279be2
9e083a9
b3cb24b
20a3fe4
2f467bd
8f662c2
3043dd7
0b18e5b
fb5d567
39040cb
6a9e199
576b336
99b33af
6498354
a5eccd6
4429f85
fd260e5
3fdf3ca
06aa50e
ccecae3
4ab0185
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
class Rpush710Updates < ActiveRecord::Migration["#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"] | ||
def self.up | ||
add_column :rpush_apps, :firebase_project_id, :string | ||
add_column :rpush_apps, :json_key, :text | ||
end | ||
|
||
def self.down | ||
remove_column :rpush_apps, :firebase_project_id | ||
remove_column :rpush_apps, :json_key | ||
end | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
require 'active_support/all' | ||
require 'net-http2' | ||
require 'jwt' | ||
require 'googleauth' | ||
|
||
require 'rails' | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
module Rpush | ||
module Client | ||
module ActiveModel | ||
module Fcm | ||
module App | ||
def self.included(base) | ||
base.instance_eval do | ||
# TODO: Add whatever validation is needed here | ||
# validates :auth_key, presence: true | ||
end | ||
end | ||
|
||
def service_name | ||
'fcm' | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module Rpush | ||
module Client | ||
module ActiveModel | ||
module Fcm | ||
class ExpiryCollapseKeyMutualInclusionValidator < ::ActiveModel::Validator | ||
def validate(record) | ||
return unless record.collapse_key && !record.expiry | ||
record.errors.add :expiry, 'must be set when using a collapse_key' | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
module Rpush | ||
module Client | ||
module ActiveModel | ||
module Fcm | ||
module Notification | ||
FCM_PRIORITY_HIGH = Rpush::Client::ActiveModel::Apns::Notification::APNS_PRIORITY_IMMEDIATE | ||
FCM_PRIORITY_NORMAL = Rpush::Client::ActiveModel::Apns::Notification::APNS_PRIORITY_CONSERVE_POWER | ||
FCM_PRIORITIES = [FCM_PRIORITY_HIGH, FCM_PRIORITY_NORMAL] | ||
|
||
ROOT_NOTIFICATION_KEYS = %w[title body image].freeze | ||
ANDROID_NOTIFICATION_KEYS = %w[icon tag color click_action body_loc_key body_loc_args title_loc_key | ||
title_loc_args channel_id ticker sticky event_time local_only | ||
default_vibrate_timings default_light_settings vibrate_timings | ||
visibility notification_count light_settings].freeze | ||
|
||
def self.included(base) | ||
base.instance_eval do | ||
validates :device_token, presence: true | ||
validates :priority, inclusion: { in: FCM_PRIORITIES }, allow_nil: true | ||
|
||
validates_with Rpush::Client::ActiveModel::PayloadDataSizeValidator, limit: 4096 | ||
validates_with Rpush::Client::ActiveModel::RegistrationIdsCountValidator, limit: 1000 | ||
|
||
validates_with Rpush::Client::ActiveModel::Fcm::ExpiryCollapseKeyMutualInclusionValidator | ||
validates_with Rpush::Client::ActiveModel::Fcm::NotificationKeysInAllowedListValidator | ||
end | ||
end | ||
|
||
def payload_data_size | ||
multi_json_dump(as_json['message']['data']).bytesize | ||
end | ||
|
||
# This is a hack. The schema defines `priority` to be an integer, but FCM expects a string. | ||
# But for users of rpush to have an API they might expect (setting priority to `high`, not 10) | ||
# we do a little conversion here. | ||
def priority=(priority) | ||
case priority | ||
when 'high', FCM_PRIORITY_HIGH | ||
super(FCM_PRIORITY_HIGH) | ||
when 'normal', FCM_PRIORITY_NORMAL | ||
super(FCM_PRIORITY_NORMAL) | ||
else | ||
errors.add(:priority, 'must be one of either "normal" or "high"') | ||
end | ||
end | ||
|
||
def dry_run=(value) | ||
fail ArgumentError, 'FCM does not support dry run' if value | ||
end | ||
|
||
def mutable_content=(value) | ||
fail ArgumentError, 'RPush does not currently support mutable_content for FCM' if value | ||
end | ||
|
||
def as_json(options = nil) # rubocop:disable Metrics/PerceivedComplexity | ||
json = { | ||
'data' => data, | ||
'android' => android_config, | ||
'token' => device_token | ||
} | ||
# Android does not appear to handle content_available anymore. Instead "priority" should be used | ||
# with "low" being a background only message. APN however should support this field. | ||
# json['content_available'] = content_available if content_available | ||
json['notification'] = root_notification if notification | ||
{ 'message' => json } | ||
end | ||
|
||
def android_config | ||
json = { | ||
'notification' => android_notification, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't think we need to set explicitly notification here since original library don't have it and we can set it dynamically when someone creating the object, for some use case devs used to configure all stuff under There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's make it more dynamic and remove setting custom sound, default sound under notification key There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Setting the notification here can cause issues as data messages would not get handled when the application is running in the background. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @muzzamilpulsate @KrakenWagen This was done to try and make migration as easy as possible. My understanding of the api changes google provided (documentation) was that previously Google's backend manipulated things to make them Android or Apple friendly, while the new api does not. That said, if this will cause issues with data messages that obviously would need to be fixed. What exactly is the issue with data messages? Is it that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem here could be that 'notification' is a reserved keyword, so even if this is not setting the root 'notification' key, setting 'android'->'notification' is enough to cause data messages to not be handled in the background. https://firebase.google.com/docs/cloud-messaging/concept-options#data_messages
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Setting The link you shared is for the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We had to comment out this line in order to make it work for our project. We are using |
||
} | ||
json['collapse_key'] = collapse_key if collapse_key | ||
json['priority'] = priority_str if priority | ||
json['ttl'] = "#{expiry}s" if expiry | ||
json | ||
end | ||
|
||
def notification=(value) | ||
super(value.with_indifferent_access) | ||
end | ||
|
||
def root_notification | ||
return {} unless notification | ||
|
||
notification.slice(*ROOT_NOTIFICATION_KEYS) | ||
end | ||
|
||
def android_notification | ||
json = notification&.slice(*ANDROID_NOTIFICATION_KEYS) || {} | ||
json['notification_priority'] = priority_for_notification if priority | ||
json['sound'] = sound if sound | ||
json['default_sound'] = !sound || sound == 'default' ? true : false | ||
json | ||
end | ||
|
||
def priority_str | ||
case | ||
when priority <= 5 then 'normal' | ||
else | ||
'high' | ||
end | ||
end | ||
|
||
def priority_for_notification | ||
case priority | ||
when 0 then 'PRIORITY_UNSPECIFIED' | ||
when 1 then 'PRIORITY_MIN' | ||
when 2 then 'PRIORITY_LOW' | ||
when 5 then 'PRIORITY_DEFAULT' | ||
when 6 then 'PRIORITY_HIGH' | ||
when 10 then 'PRIORITY_MAX' | ||
else | ||
'PRIORITY_DEFAULT' | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
module Rpush | ||
module Client | ||
module ActiveModel | ||
module Fcm | ||
class NotificationKeysInAllowedListValidator < ::ActiveModel::Validator | ||
def validate(record) | ||
return unless record.notification | ||
|
||
allowed_keys = Notification::ROOT_NOTIFICATION_KEYS + Notification::ANDROID_NOTIFICATION_KEYS | ||
invalid_keys = record.notification.keys - allowed_keys | ||
|
||
return if invalid_keys.empty? | ||
|
||
record.errors.add(:notification, "contains invalid keys: #{invalid_keys.join(', ')}") | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
module Rpush | ||
module Client | ||
module ActiveRecord | ||
module Fcm | ||
class App < Rpush::Client::ActiveRecord::App | ||
include Rpush::Client::ActiveModel::Fcm::App | ||
end | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the new
fcm_canonical_id
reflection is missing from the updated template?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/lufia/til/blob/master/fcm.rst#canonical-registration-id
I understand that Canonical ID is no longer used
(Someone please point out if I am wrong).