How to not use Firebase Topics Messaging and Device Group Messaging? - firebase

Wanted to ask in my special case about sending FCM. I read about the Firebase Topic messaging and Device group messaging but dont think it will work in my scenario.
I have a Firebase connected app that need help!
I want to create a place where the app user can send a chat message and there is nobody listening, or there could be a million+ people listening.
There are millions or even billions of chat rooms and there is no way to tell how many are listening on any chat, there could be miljons billions listening, there could be this many notifications to inform users that a new message is posted
When a user sends the chat a message, the notification must be sent to everyone who is listening.
how could I do this?

You can simply use Firebase database to create a chat app as you seek. There are tons of tutorials for that specific application actually.
Typically, the structure would look something like this:
{
"chats": {
"one": {
"title": "Historical Tech Pioneers",
"lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
"timestamp": 1459361875666
},
"two": { ... },
"three": { ... }
},
"members": {
"one": {
"ghopper": true,
"alovelace": true,
"eclarke": true
},
"two": { ... },
"three": { ... }
},
"messages": {
"one": {
"m1": {
"name": "eclarke",
"message": "The relay seems to be malfunctioning.",
"timestamp": 1459361875337
},
"m2": { ... },
"m3": { ... }
},
"two": { ... },
"three": { ... }
}
}
(source)
So whenever a user sends a message through your app, you'd just create a new node under messages and update the appropriate entry under chats. I'd post more about the client-side process, but I'm not sure which platform you're using
EDIT
To clarify a bit further, you should listen to the chats node on your platform for any changes, once the timestamp of the last message changes from what you have stored on device, you check messages. That, or you can simply listen for childAdded in messages.
Regarding your comment, you don't really need FCM in this case unless you want to push notifications, in which case you'll need your own server for that to listen for the changes as well and dispatch the notifications appropriately.

Related

AWS Amplify Show AppSync/GraphQL Subscription Connection Status

After creating an AWS AppSync/GraphQL subscription -- how do I get the subscriptions connection status and any future connection status changes?
The AWS Amplify documentation is clear on how to create a subscription:
const subscription = API.graphql(
graphqlOperation(subscriptions.onCreateTodo)
).subscribe({
next: ({ provider, value }) => console.log({ provider, value }),
error: (error) => console.warn(error)
});
The documentation is also clear on how to get subscription connection statuses using hub:
Hub.listen('api', (data: any) => {
const { payload } = data;
if (payload.event === CONNECTION_STATE_CHANGE) {
const connectionState = payload.data.connectionState as ConnectionState;
console.log(connectionState);
}
});
But this hub example listens to all GraphQL subscriptions. How can I listen to a specific subscription? Or when listening to all subscriptions -- is there a way to associate a hub connection with a specific GraphQL subscription?
A simplified example: In an app, I have a chat page and a GraphQL subscription that listens for new chats. I also have a page that shows the results of a long running backend process and a GraphQL subscription that listens for process complete. Hub listens to all GraphQL subscriptions and one of the subscriptions has been disconnected. Which GraphQL subscription has been disconnected so the app can display a message to the user?
The object returned by hub looks like this. I'm guessing the _linked properties link back to the specific GraphQL subscription. But I'm not seeing any human readable properties to determine which GraphQL subscription it's linked to.
{
"channel": "api",
"payload": {
"event": "ConnectionStateChange",
"data": {
"provider": {
"socketStatus": 0,
"keepAliveTimeout": 300000,
"subscriptionObserverMap": {},
"promiseArray": [],
"connectionStateMonitor": {
"_linkedConnectionState": {
"networkState": "connected",
"connectionState": "disconnected",
"intendedConnectionState": "disconnected",
"keepAliveState": "healthy"
},
"_linkedConnectionStateObservable": {},
"_linkedConnectionStateObserver": {
"_subscription": {
"_observer": {},
"_state": "ready"
}
}
},
"keepAliveTimeoutId": 108,
"keepAliveAlertTimeoutId": 109
},
"connectionState": "Connecting"
},
"message": "Connection state is Connecting"
},
"source": "PubSub",
"patternInfo": []
}
The GraphQL subscription returns a provider object that looks like this. It also has a connectionStateMonitor property. But when trying to display this property it errors with: Property 'connectionStateMonitor' is private and only accessible within class 'AWSAppSyncRealTimeProvider'
{
"provider": {
"socketStatus": 0,
"keepAliveTimeout": 300000,
"subscriptionObserverMap": {},
"promiseArray": [],
"connectionStateMonitor": {
"_linkedConnectionState": {
"networkState": "connected",
"connectionState": "disconnected",
"intendedConnectionState": "disconnected",
"keepAliveState": "healthy"
},
"_linkedConnectionStateObservable": {},
"_linkedConnectionStateObserver": {
"_subscription": {
"_observer": {},
"_state": "ready"
}
}
},
"keepAliveTimeoutId": 1056,
"keepAliveAlertTimeoutId": 1057
},
"value": {
"data": {
"BSubscribeToTest": {
"matchIt": 10,
"item": {
"rateRequestId": "123"
}
}
}
}
}
You need a combination of:
Hub.listen('some-channel', callback); and
Hub.dispatch('some-channel', {event, data, message});
That channel name (first parameter) can be added dynamically so that you are monitoring multiple channels in an application. Each channel can then be listened to and subscribed to separately and you can check the status, data, etc for each one.
Because you are listening on the example "api' channel above you would need to add that channel to this line:
graphqlOperation(subscriptions.onCreateTodo, 'api') Take note of the 'api' at the end.

How to achieve time-sensitive flag in APNS JSON output via FCM?

iOS distinguishes between messages by UNNotificationInterruptionLevel. I would like to achieve that messages sent via FCM have the time-sensitive interruption-level.
Is this equivalent to just sending messages in FCM with high priority? Unfortunately it's not super clear to me from looking at the docs.
The interruption level is automatically handled by system, not by FCM. That's different than the high priority.
You should be able to use it as it is by following Apple's documentation. FCM supports passing down the interruption-level in the payload.
I achieved this by having this payload in my firebase console file:
var message = {
notification: {
title: "Notification Title",
body: `${initiatedUsername} sent you message`,
},
"data": {
"target_exec":"messaging"
},
"apns": {
"payload": {
"aps": {
"alert": {
"title": "Notification Title",
"body": `${initiatedUsername} sent you a message`
},
"badge": 1,
"sound": "default",
"interruption-level": "time-sensitive"
}
}
},
token: fcmToken,
};
You can change the token attribute to topic aswell, if you'd rather like to send a message to a topic.
Hope this might help somebody out here!

Storing data on Firebase to be queried later

We have an application that will store data on Firebase (database) that will then be queried later.
What is the correct format to store the data in.
The example data will be completedGames. They will have data such as:
UserId
TimeToComplete
GameData
Etc...
The query later will then look for all completed games by UserId. We want to ensure the data is collected in the best way possible to query later, rather than refactoring later.
In your case, first off - be sure you have a good reason to use Firebase over Firestore. Once you're confident you should stick with Firebase Realtime Database, look at the below excerpt of documentation. So, you might actually have 2 separate parent nodes, 1 for userId and another for games. Each game node's child is a particular game, which has a child tree of game users (by userId).
Flatten data
structures
If the data is instead split into separate paths, also called
denormalization, it can be efficiently downloaded in separate calls,
as it is needed. Consider this flattened structure:
{
// Chats contains only meta info about each conversation
// stored under the chats's unique ID
"chats": {
"one": {
"title": "Historical Tech Pioneers",
"lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
"timestamp": 1459361875666
},
"two": { ... },
"three": { ... }
},
// Conversation members are easily accessible
// and stored by chat conversation ID
"members": {
// we'll talk about indices like this below
"one": {
"ghopper": true,
"alovelace": true,
"eclarke": true
},
"two": { ... },
"three": { ... }
},
// Messages are separate from data we may want to iterate quickly
// but still easily paginated and queried, and organized by chat
// conversation ID
"messages": {
"one": {
"m1": {
"name": "eclarke",
"message": "The relay seems to be malfunctioning.",
"timestamp": 1459361875337
},
"m2": { ... },
"m3": { ... }
},
"two": { ... },
"three": { ... }
}
}

Firebase database data aggregation

Let's take a look at "Instagram-like" app, as an example.
In the feed we got posts, with user avatar and name at the top, photo or video below, and last comments, likes count and post time at the bottom.
Basically, at the client I'm waiting to get from backend something like
{
username: "John",
avatar:"some_link",
photo:"photo_url",
likes:"9",
time:"182937428",
comments:[comments there]
}
but using Firebase, I need to store data in more flat way. so there will be "users", "posts" and "comments" in data JSON.
How am I suppose to aggregate data from those nodes in some kind of single object, which is easy to use at client?
Or should I ask Firebase for posts, than for all users in it, and for all their comments, and do aggregation after all three 'requests' are done?
You should implement "shallow" tree structure, and use references where needed.
That means that for most cases in your app you should use the object as at is, Making sure that it contain the "essential data" (in the example below "the chat title"), and keys for "further" information (in the example, keys to the "members").
from firebase docs (https://firebase.google.com/docs/database/web/structure-data):
bad
{
// This is a poorly nested data architecture, because iterating the children
// of the "chats" node to get a list of conversation titles requires
// potentially downloading hundreds of megabytes of messages
"chats": {
"one": {
"title": "Historical Tech Pioneers",
"messages": {
"m1": { "sender": "ghopper", "message": "Relay malfunction found. Cause: moth." },
"m2": { ... },
// a very long list of messages
}
},
"two": { ... }
}
}
good
{
// Chats contains only meta info about each conversation
// stored under the chats's unique ID
"chats": {
"one": {
"title": "Historical Tech Pioneers",
"lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
"timestamp": 1459361875666
},
"two": { ... },
"three": { ... }
},
// Conversation members are easily accessible
// and stored by chat conversation ID
"members": {
// we'll talk about indices like this below
"one": {
"ghopper": true,
"alovelace": true,
"eclarke": true
},
"two": { ... },
"three": { ... }
},
// Messages are separate from data we may want to iterate quickly
// but still easily paginated and queried, and organized by chat
// conversation ID
"messages": {
"one": {
"m1": {
"name": "eclarke",
"message": "The relay seems to be malfunctioning.",
"timestamp": 1459361875337
},
"m2": { ... },
"m3": { ... }
},
"two": { ... },
"three": { ... }
}
}

Bulk Send Message not working in MobileFirst Platform

I am trying to use the Bulk Send Message API in IBM MobileFirst Platform Foundation 7.0. Unfortunately, the example JSON from the docs does not work and gets an error about the object structure being sent.
This is the JSON Object I'm sending:
{
"//ArrayOfMessageBody": [
{
"messages": {
"alert": "Test message"
},
"settings": {
"apns": {
"actionKey": "Ok"
}
},
"target": {
"consumerIds": [
"MyConsumerId1"
],
"deviceIds": [
"MyDeviceId1"
],
"platforms": [
"A"
]
}
}
]
}
And Here is the server's response error:
com.ibm.json.java.JSONObject cannot be cast to com.ibm.json.java.JSONArray
I am having success sending to devices via the single Send Message API, so I know messaging works. However, Bulk Send Message is failing.
It turns out that the documentation was what hung me up. If you send an array of messages to the bulk send message endpoint it will work.
[{message1}, {message2}, ...]
I'm still not sure what the whole //ArrayOfMessageBody thing is.

Resources