@@ -36,19 +36,21 @@ class Message(object):
3636 android: An instance of ``messaging.AndroidConfig`` (optional).
3737 webpush: An instance of ``messaging.WebpushConfig`` (optional).
3838 apns: An instance of ``messaging.ApnsConfig`` (optional).
39+ fcm_options: An instance of ``messaging.FcmOptions`` (optional).
3940 token: The registration token of the device to which the message should be sent (optional).
4041 topic: Name of the FCM topic to which the message should be sent (optional). Topic name
4142 may contain the ``/topics/`` prefix.
4243 condition: The FCM condition to which the message should be sent (optional).
4344 """
4445
4546 def __init__ (self , data = None , notification = None , android = None , webpush = None , apns = None ,
46- token = None , topic = None , condition = None ):
47+ fcm_options = None , token = None , topic = None , condition = None ):
4748 self .data = data
4849 self .notification = notification
4950 self .android = android
5051 self .webpush = webpush
5152 self .apns = apns
53+ self .fcm_options = fcm_options
5254 self .token = token
5355 self .topic = topic
5456 self .condition = condition
@@ -65,8 +67,10 @@ class MulticastMessage(object):
6567 android: An instance of ``messaging.AndroidConfig`` (optional).
6668 webpush: An instance of ``messaging.WebpushConfig`` (optional).
6769 apns: An instance of ``messaging.ApnsConfig`` (optional).
70+ fcm_options: An instance of ``messaging.FcmOptions`` (optional).
6871 """
69- def __init__ (self , tokens , data = None , notification = None , android = None , webpush = None , apns = None ):
72+ def __init__ (self , tokens , data = None , notification = None , android = None , webpush = None , apns = None ,
73+ fcm_options = None ):
7074 _Validators .check_string_list ('MulticastMessage.tokens' , tokens )
7175 if len (tokens ) > 100 :
7276 raise ValueError ('MulticastMessage.tokens must not contain more than 100 tokens.' )
@@ -76,6 +80,7 @@ def __init__(self, tokens, data=None, notification=None, android=None, webpush=N
7680 self .android = android
7781 self .webpush = webpush
7882 self .apns = apns
83+ self .fcm_options = fcm_options
7984
8085
8186class Notification (object ):
@@ -107,16 +112,18 @@ class AndroidConfig(object):
107112 data: A dictionary of data fields (optional). All keys and values in the dictionary must be
108113 strings. When specified, overrides any data fields set via ``Message.data``.
109114 notification: A ``messaging.AndroidNotification`` to be included in the message (optional).
115+ fcm_options: A ``messaging.AndroidFcmOptions`` to be included in the message (optional).
110116 """
111117
112118 def __init__ (self , collapse_key = None , priority = None , ttl = None , restricted_package_name = None ,
113- data = None , notification = None ):
119+ data = None , notification = None , fcm_options = None ):
114120 self .collapse_key = collapse_key
115121 self .priority = priority
116122 self .ttl = ttl
117123 self .restricted_package_name = restricted_package_name
118124 self .data = data
119125 self .notification = notification
126+ self .fcm_options = fcm_options
120127
121128
122129class AndroidNotification (object ):
@@ -165,6 +172,18 @@ def __init__(self, title=None, body=None, icon=None, color=None, sound=None, tag
165172 self .channel_id = channel_id
166173
167174
175+ class AndroidFcmOptions (object ):
176+ """Options for features provided by the FCM SDK for Android.
177+
178+ Args:
179+ analytics_label: contains additional options for features provided by the FCM Android SDK
180+ (optional).
181+ """
182+
183+ def __init__ (self , analytics_label = None ):
184+ self .analytics_label = analytics_label
185+
186+
168187class WebpushConfig (object ):
169188 """Webpush-specific options that can be included in a message.
170189
@@ -279,14 +298,17 @@ class APNSConfig(object):
279298 Args:
280299 headers: A dictionary of headers (optional).
281300 payload: A ``messaging.APNSPayload`` to be included in the message (optional).
301+ fcm_options: A ``messaging.APNSFcmOptions`` instance to be included in the message
302+ (optional).
282303
283304 .. _APNS Documentation: https://developer.apple.com/library/content/documentation\
284305 /NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html
285306 """
286307
287- def __init__ (self , headers = None , payload = None ):
308+ def __init__ (self , headers = None , payload = None , fcm_options = None ):
288309 self .headers = headers
289310 self .payload = payload
311+ self .fcm_options = fcm_options
290312
291313
292314class APNSPayload (object ):
@@ -387,6 +409,29 @@ def __init__(self, title=None, subtitle=None, body=None, loc_key=None, loc_args=
387409 self .launch_image = launch_image
388410
389411
412+ class APNSFcmOptions (object ):
413+ """Options for features provided by the FCM SDK for iOS.
414+
415+ Args:
416+ analytics_label: contains additional options for features provided by the FCM iOS SDK
417+ (optional).
418+ """
419+
420+ def __init__ (self , analytics_label = None ):
421+ self .analytics_label = analytics_label
422+
423+
424+ class FcmOptions (object ):
425+ """Options for features provided by SDK.
426+
427+ Args:
428+ analytics_label: contains additional options to use across all platforms (optional).
429+ """
430+
431+ def __init__ (self , analytics_label = None ):
432+ self .analytics_label = analytics_label
433+
434+
390435class _Validators (object ):
391436 """A collection of data validation utilities.
392437
@@ -442,6 +487,14 @@ def check_string_list(cls, label, value):
442487 raise ValueError ('{0} must not contain non-string values.' .format (label ))
443488 return value
444489
490+ @classmethod
491+ def check_analytics_label (cls , label , value ):
492+ """Checks if the given value is a valid analytics label."""
493+ value = _Validators .check_string (label , value )
494+ if value is not None and not re .match (r'^[a-zA-Z0-9-_.~%]{1,50}$' , value ):
495+ raise ValueError ('Malformed {}.' .format (label ))
496+ return value
497+
445498
446499class MessageEncoder (json .JSONEncoder ):
447500 """A custom JSONEncoder implementation for serializing Message instances into JSON."""
@@ -468,13 +521,29 @@ def encode_android(cls, android):
468521 'restricted_package_name' : _Validators .check_string (
469522 'AndroidConfig.restricted_package_name' , android .restricted_package_name ),
470523 'ttl' : cls .encode_ttl (android .ttl ),
524+ 'fcm_options' : cls .encode_android_fcm_options (android .fcm_options ),
471525 }
472526 result = cls .remove_null_values (result )
473527 priority = result .get ('priority' )
474528 if priority and priority not in ('high' , 'normal' ):
475529 raise ValueError ('AndroidConfig.priority must be "high" or "normal".' )
476530 return result
477531
532+ @classmethod
533+ def encode_android_fcm_options (cls , fcm_options ):
534+ """Encodes a AndroidFcmOptions instance into a json."""
535+ if fcm_options is None :
536+ return None
537+ if not isinstance (fcm_options , AndroidFcmOptions ):
538+ raise ValueError ('AndroidConfig.fcm_options must be an instance of '
539+ 'AndroidFcmOptions class.' )
540+ result = {
541+ 'analytics_label' : _Validators .check_analytics_label (
542+ 'AndroidFcmOptions.analytics_label' , fcm_options .analytics_label ),
543+ }
544+ result = cls .remove_null_values (result )
545+ return result
546+
478547 @classmethod
479548 def encode_ttl (cls , ttl ):
480549 """Encodes a AndroidConfig TTL duration into a string."""
@@ -553,7 +622,7 @@ def encode_webpush(cls, webpush):
553622 'headers' : _Validators .check_string_dict (
554623 'WebpushConfig.headers' , webpush .headers ),
555624 'notification' : cls .encode_webpush_notification (webpush .notification ),
556- 'fcmOptions ' : cls .encode_webpush_fcm_options (webpush .fcm_options ),
625+ 'fcm_options ' : cls .encode_webpush_fcm_options (webpush .fcm_options ),
557626 }
558627 return cls .remove_null_values (result )
559628
@@ -653,6 +722,7 @@ def encode_apns(cls, apns):
653722 'headers' : _Validators .check_string_dict (
654723 'APNSConfig.headers' , apns .headers ),
655724 'payload' : cls .encode_apns_payload (apns .payload ),
725+ 'fcm_options' : cls .encode_apns_fcm_options (apns .fcm_options ),
656726 }
657727 return cls .remove_null_values (result )
658728
@@ -670,6 +740,20 @@ def encode_apns_payload(cls, payload):
670740 result [key ] = value
671741 return cls .remove_null_values (result )
672742
743+ @classmethod
744+ def encode_apns_fcm_options (cls , fcm_options ):
745+ """Encodes an APNSFcmOptions instance into JSON."""
746+ if fcm_options is None :
747+ return None
748+ if not isinstance (fcm_options , APNSFcmOptions ):
749+ raise ValueError ('APNSConfig.fcm_options must be an instance of APNSFcmOptions class.' )
750+ result = {
751+ 'analytics_label' : _Validators .check_analytics_label (
752+ 'APNSFcmOptions.analytics_label' , fcm_options .analytics_label ),
753+ }
754+ result = cls .remove_null_values (result )
755+ return result
756+
673757 @classmethod
674758 def encode_aps (cls , aps ):
675759 """Encodes an Aps instance into JSON."""
@@ -790,10 +874,25 @@ def default(self, obj): # pylint: disable=method-hidden
790874 'token' : _Validators .check_string ('Message.token' , obj .token , non_empty = True ),
791875 'topic' : _Validators .check_string ('Message.topic' , obj .topic , non_empty = True ),
792876 'webpush' : MessageEncoder .encode_webpush (obj .webpush ),
877+ 'fcm_options' : MessageEncoder .encode_fcm_options (obj .fcm_options ),
793878 }
794879 result ['topic' ] = MessageEncoder .sanitize_topic_name (result .get ('topic' ))
795880 result = MessageEncoder .remove_null_values (result )
796881 target_count = sum ([t in result for t in ['token' , 'topic' , 'condition' ]])
797882 if target_count != 1 :
798883 raise ValueError ('Exactly one of token, topic or condition must be specified.' )
799884 return result
885+
886+ @classmethod
887+ def encode_fcm_options (cls , fcm_options ):
888+ """Encodes an FcmOptions instance into JSON."""
889+ if fcm_options is None :
890+ return None
891+ if not isinstance (fcm_options , FcmOptions ):
892+ raise ValueError ('Message.fcm_options must be an instance of FcmOptions class.' )
893+ result = {
894+ 'analytics_label' : _Validators .check_analytics_label (
895+ 'FcmOptions.analytics_label' , fcm_options .analytics_label ),
896+ }
897+ result = cls .remove_null_values (result )
898+ return result
0 commit comments