@@ -36,19 +36,21 @@ class Message(object):
36
36
android: An instance of ``messaging.AndroidConfig`` (optional).
37
37
webpush: An instance of ``messaging.WebpushConfig`` (optional).
38
38
apns: An instance of ``messaging.ApnsConfig`` (optional).
39
+ fcm_options: An instance of ``messaging.FcmOptions`` (optional).
39
40
token: The registration token of the device to which the message should be sent (optional).
40
41
topic: Name of the FCM topic to which the message should be sent (optional). Topic name
41
42
may contain the ``/topics/`` prefix.
42
43
condition: The FCM condition to which the message should be sent (optional).
43
44
"""
44
45
45
46
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 ):
47
48
self .data = data
48
49
self .notification = notification
49
50
self .android = android
50
51
self .webpush = webpush
51
52
self .apns = apns
53
+ self .fcm_options = fcm_options
52
54
self .token = token
53
55
self .topic = topic
54
56
self .condition = condition
@@ -65,8 +67,10 @@ class MulticastMessage(object):
65
67
android: An instance of ``messaging.AndroidConfig`` (optional).
66
68
webpush: An instance of ``messaging.WebpushConfig`` (optional).
67
69
apns: An instance of ``messaging.ApnsConfig`` (optional).
70
+ fcm_options: An instance of ``messaging.FcmOptions`` (optional).
68
71
"""
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 ):
70
74
_Validators .check_string_list ('MulticastMessage.tokens' , tokens )
71
75
if len (tokens ) > 100 :
72
76
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
76
80
self .android = android
77
81
self .webpush = webpush
78
82
self .apns = apns
83
+ self .fcm_options = fcm_options
79
84
80
85
81
86
class Notification (object ):
@@ -107,16 +112,18 @@ class AndroidConfig(object):
107
112
data: A dictionary of data fields (optional). All keys and values in the dictionary must be
108
113
strings. When specified, overrides any data fields set via ``Message.data``.
109
114
notification: A ``messaging.AndroidNotification`` to be included in the message (optional).
115
+ fcm_options: A ``messaging.AndroidFcmOptions`` to be included in the message (optional).
110
116
"""
111
117
112
118
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 ):
114
120
self .collapse_key = collapse_key
115
121
self .priority = priority
116
122
self .ttl = ttl
117
123
self .restricted_package_name = restricted_package_name
118
124
self .data = data
119
125
self .notification = notification
126
+ self .fcm_options = fcm_options
120
127
121
128
122
129
class AndroidNotification (object ):
@@ -165,6 +172,18 @@ def __init__(self, title=None, body=None, icon=None, color=None, sound=None, tag
165
172
self .channel_id = channel_id
166
173
167
174
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
+
168
187
class WebpushConfig (object ):
169
188
"""Webpush-specific options that can be included in a message.
170
189
@@ -279,14 +298,17 @@ class APNSConfig(object):
279
298
Args:
280
299
headers: A dictionary of headers (optional).
281
300
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).
282
303
283
304
.. _APNS Documentation: https://developer.apple.com/library/content/documentation\
284
305
/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html
285
306
"""
286
307
287
- def __init__ (self , headers = None , payload = None ):
308
+ def __init__ (self , headers = None , payload = None , fcm_options = None ):
288
309
self .headers = headers
289
310
self .payload = payload
311
+ self .fcm_options = fcm_options
290
312
291
313
292
314
class APNSPayload (object ):
@@ -387,6 +409,29 @@ def __init__(self, title=None, subtitle=None, body=None, loc_key=None, loc_args=
387
409
self .launch_image = launch_image
388
410
389
411
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
+
390
435
class _Validators (object ):
391
436
"""A collection of data validation utilities.
392
437
@@ -442,6 +487,14 @@ def check_string_list(cls, label, value):
442
487
raise ValueError ('{0} must not contain non-string values.' .format (label ))
443
488
return value
444
489
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
+
445
498
446
499
class MessageEncoder (json .JSONEncoder ):
447
500
"""A custom JSONEncoder implementation for serializing Message instances into JSON."""
@@ -468,13 +521,29 @@ def encode_android(cls, android):
468
521
'restricted_package_name' : _Validators .check_string (
469
522
'AndroidConfig.restricted_package_name' , android .restricted_package_name ),
470
523
'ttl' : cls .encode_ttl (android .ttl ),
524
+ 'fcm_options' : cls .encode_android_fcm_options (android .fcm_options ),
471
525
}
472
526
result = cls .remove_null_values (result )
473
527
priority = result .get ('priority' )
474
528
if priority and priority not in ('high' , 'normal' ):
475
529
raise ValueError ('AndroidConfig.priority must be "high" or "normal".' )
476
530
return result
477
531
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
+
478
547
@classmethod
479
548
def encode_ttl (cls , ttl ):
480
549
"""Encodes a AndroidConfig TTL duration into a string."""
@@ -553,7 +622,7 @@ def encode_webpush(cls, webpush):
553
622
'headers' : _Validators .check_string_dict (
554
623
'WebpushConfig.headers' , webpush .headers ),
555
624
'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 ),
557
626
}
558
627
return cls .remove_null_values (result )
559
628
@@ -653,6 +722,7 @@ def encode_apns(cls, apns):
653
722
'headers' : _Validators .check_string_dict (
654
723
'APNSConfig.headers' , apns .headers ),
655
724
'payload' : cls .encode_apns_payload (apns .payload ),
725
+ 'fcm_options' : cls .encode_apns_fcm_options (apns .fcm_options ),
656
726
}
657
727
return cls .remove_null_values (result )
658
728
@@ -670,6 +740,20 @@ def encode_apns_payload(cls, payload):
670
740
result [key ] = value
671
741
return cls .remove_null_values (result )
672
742
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
+
673
757
@classmethod
674
758
def encode_aps (cls , aps ):
675
759
"""Encodes an Aps instance into JSON."""
@@ -790,10 +874,25 @@ def default(self, obj): # pylint: disable=method-hidden
790
874
'token' : _Validators .check_string ('Message.token' , obj .token , non_empty = True ),
791
875
'topic' : _Validators .check_string ('Message.topic' , obj .topic , non_empty = True ),
792
876
'webpush' : MessageEncoder .encode_webpush (obj .webpush ),
877
+ 'fcm_options' : MessageEncoder .encode_fcm_options (obj .fcm_options ),
793
878
}
794
879
result ['topic' ] = MessageEncoder .sanitize_topic_name (result .get ('topic' ))
795
880
result = MessageEncoder .remove_null_values (result )
796
881
target_count = sum ([t in result for t in ['token' , 'topic' , 'condition' ]])
797
882
if target_count != 1 :
798
883
raise ValueError ('Exactly one of token, topic or condition must be specified.' )
799
884
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