Skip to content

Commit

Permalink
Support fcm tokens for iOS phones as well (#768)
Browse files Browse the repository at this point in the history
* Support fcm tokens for iOS phones as well

By default, the FCM plugin generates FCM tokens for both android and iOS.
I don't like this on principle because it makes it harder to migrate to a
different push service later.

So we typically configure the app to generate APNS tokens and map on the server
side. But that now requires editing GoogleServices.plist (FCM is the default)
and it is easy to forget to do that.

However, others may also not have this concern, and it does simplify the server
side logic significantly to not have to do the mapping.

So I now support FCM on both platforms, and add a config option to specify
whether we are using APNS or FCM for iOS.

If we are using FCM, we can skip the entire mapping logic

* Fix the default push configuration

Otherwise the tests fail

* Fix the sample push configuration in the tests as well

I don't know why the test generates this file when we also copy it
from `bin/deploy/push_conf.py` But not going to get into that complexity now.

* Add a new test

- Pass in the `apns` token type in one more location
- Add a new test for the FCM token type to ensure that the mapping shortcut works properly
  • Loading branch information
shankari authored Sep 5, 2020
1 parent a1c109e commit 02d23b2
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 3 deletions.
1 change: 1 addition & 0 deletions bin/deploy/push_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
data['provider'] = 'firebase'
data['server_auth_token'] = 'firebase_api_key'
data['app_package_name'] = 'edu.berkeley.eecs.embase'
data['ios_token_format'] = 'apns'
f = open(real_path, "w")
f.write(json.dumps(data))
f.close()
3 changes: 2 additions & 1 deletion conf/net/ext_service/push.json.sample
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"provider": "firebase",
"server_auth_token": "Get from firebase console",
"app_package_name": "full package name from config.xml. e.g. edu.berkeley.eecs.emission or edu.berkeley.eecs.embase. Defaults to edu.berkeley.eecs.embase"
"app_package_name": "full package name from config.xml. e.g. edu.berkeley.eecs.emission or edu.berkeley.eecs.embase. Defaults to edu.berkeley.eecs.embase",
"ios_token_format": "apns"
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def __init__(self, push_config):
else:
logging.warning("No package name specified, defaulting to embase")
self.app_package_name = "edu.berkeley.eecs.embase"
self.is_fcm_format = push_config["ios_token_format"] == "fcm"

def get_and_invalidate_entries(self):
# Need to figure out how to do this on firebase
Expand All @@ -39,6 +40,10 @@ def print_dev_flag_warning():
logging.warning("https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages")

def map_existing_fcm_tokens(self, token_map):
if self.is_fcm_format:
logging.info("iOS tokens are already in the FCM format, no mapping required")
return ({"ios": token_map["ios"],
"android": token_map["android"]}, [])
# android tokens never need to be mapped, so let's just not even check them
mapped_token_map = {"ios": [],
"android": token_map["android"]}
Expand Down
29 changes: 27 additions & 2 deletions emission/tests/netTests/TestPush.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ def setUp(self):
with open(self.push_conf_path, "w") as fd:
fd.write(json.dumps({
"provider": "firebase",
"server_auth_token": "firebase_api_key"
"server_auth_token": "firebase_api_key",
"ios_token_format": "apns"
}))
logging.debug("Finished setting up %s" % self.push_conf_path)
with open(self.push_conf_path) as fd:
Expand All @@ -74,6 +75,7 @@ def testGetDefaultInterface(self):
def testMappingQueries(self):
import emission.net.ext_service.push.notify_queries as pnq
import emission.core.wrapper.user as ecwu
import emission.core.get_database as edb

self.test_email_1 = "test_push_1"
self.test_email_2 = "test_push_2"
Expand Down Expand Up @@ -108,7 +110,7 @@ def testFcmMapping(self):
logging.debug("test token map = %s" % self.test_token_map)

try:
fcm_instance = pnif.get_interface({"server_auth_token": "firebase_api_key"})
fcm_instance = pnif.get_interface({"server_auth_token": "firebase_api_key", "ios_token_format": "apns"})
(mapped_token_map, unmapped_token_list) = fcm_instance.map_existing_fcm_tokens(self.test_token_map)
# At this point, there is nothing in the database, so no iOS tokens will be mapped
self.assertEqual(len(mapped_token_map["ios"]), 0)
Expand Down Expand Up @@ -152,6 +154,29 @@ def testFcmMapping(self):
finally:
# Delete everything from the database
edb.get_push_token_mapping_db().delete_many({})

def testFcmNoMapping(self):
import emission.net.ext_service.push.notify_interface_impl.firebase as pnif
import emission.core.get_database as edb

self.test_token_list_ios = ["device_token_ios_%s" % i for i in range(10)]
self.test_token_list_android = ["device_token_android_%s" % i for i in range(10)]
self.test_token_map = {"ios": self.test_token_list_ios,
"android": self.test_token_list_android}
logging.debug("test token map = %s" % self.test_token_map)

fcm_instance = pnif.get_interface({"server_auth_token": "firebase_api_key", "ios_token_format": "fcm"})
(mapped_token_map, unmapped_token_list) = fcm_instance.map_existing_fcm_tokens(self.test_token_map)
# These are assumed to be FCM tokens directly, so no mapping required
self.assertEqual(len(mapped_token_map["ios"]), 10)
# android tokens should not be mapped, so they will be returned as-is
self.assertEqual(len(mapped_token_map["android"]), 10)

# no tokens will be returned as needing a mapping
self.assertEqual(len(unmapped_token_list), 0)

# and there will be no entries in the token mapping database
self.assertEqual(edb.get_push_token_mapping_db().count_documents({}), 0)

if __name__ == '__main__':
import emission.tests.common as etc
Expand Down

0 comments on commit 02d23b2

Please sign in to comment.