Error: "data must only contain string values" firebase cloud messaging - android

I'm trying to send some data from my node.js server to an android client via FCM(Firebase Cloud Messaging). I get the following error: "data must only contain string values" when sending it. My data contains 2 JSONObjects. Do I have to convert them to strings or what is the way to go here? Thanks.
var message = {
notification:{
"title": "Alert!",
"body": position[0] + " has left Area: " + activeGeofences[i][1].name
},
data:{
Geofence: activeGeofences[i][1],
Position: position[1]
},
token: activeGeofences[i][0]
};

To convert any JSON objects to a string, you can use JSON.stringify(). On the receiving side you can then use JSON.parse() (or your platform's equivalent) to parse the string back into a tree structure.

You can also do this, since it seemed more accurate to me
data: {
key1: "value1",
key2: "value2",
}
you just have to make sure that value1 or value2 or any n key's value pair is string if its a int or anything else it would throw the error. This could save you from parsing thing.

Inside data object data type should be always strings.
If you will pass type a number data type an error will occur.
let message = {
notification: {
title: payload.title,
body: payload.message,
},
data: {
name: 'sds',
type: '2',
_id: 'sdsd',
},
token: deviceToken,
};

Related

Consuming polymorphic json "data: { put_anything_here }" with Gson & Retrofit

I'm not sure if polymorphic is the right term to use so my apologies.
I'm working with the following API:
Request body:
{
"user_id": "user_id",
"command": "submit_document",
}
Response:
{
"result": "success",
"code": 200,
"status": "ok",
"screen": "documents_rejected", // This is unique for different `data`
"next_screen": "",
"message": "Successful",
"data": {
// `data` is always a json object with known fields and parameters
}
}
I have data classes ready for different types of data responses like:
data class PhoneData(
#SerializedName("phone_number")
val phoneNumber: String? = null,
#SerializedName("phone_status")
val phoneStatus: String? = null
)
for "screen": "phone" and the following for another screen:
data class Data(
val deepLink: String? = null
)
The problem is, at the start, I have to make the following request to retrieve the current screen:
{
"user_id": "user_id",
"command": "get_current_screen",
}
which returns a similar response as above:
{
"result": "success",
"code": 200,
"status": "ok",
"screen": "main_screen", // Different types of screen types are known.
"next_screen": "",
"message": "Successful",
"data": {
// `data` is always a json object but the object could contain anything depending on the `screen` type.
}
}
but the data field could contain anything depending on the screen
data class SplashScreenData(
// How do I make this data class combine all other data classes? One ugly approach is to add all the fields from different `data` classes here and use this one only.
)
I found about the RuntimeTypeAdapterFactory for polymorphic cases but am not sure how to make it work when there's no "type" like field within the data object (screen is unique but it's outside the data object).
It would be very helpful if someone has a solution or could point me in a direction.
val frameTextReceived: String = frame.readText()
val jsonObject = JsonParser.parseString(frameTextReceived).asJsonObject
val type = when (jsonObject.get("type").asString) {
TYPE_JOIN_ROOM -> JoinRoom::class.java
TYPE_GAME_MOVE -> GameMove::class.java
TYPE_DISCONNECT_REQUEST -> DisconnectRequest::class.java
else -> BaseModel::class.java
}
val payload = gson.fromJson(frameTextReceived, type)
This is my solution, here I have type parameter by which I can know in which class I have to deserialize the object but in your case you have screen parameter, you can use this.

How to send simple "push notification" from one device to other device?

I have an application that I made with Flutter. I am trying to write a method for users to add each other as friends in my application, but before I do this, I want to send push notifications from one device to the other. Actually, I think if I start, I can solve the rest with my own algorithm.
Ways I've tried:
installed node.js
from project terminal: firebase login
firebase init
functions file created and exists in my project
i have index.ts file
I get unique token for each device when app opened.
I want to put a simple notification sending code in the index.ts file, but I couldn't. And this notification should work from one device to another.
Here is simple solution to send device to device notification.
First create json formatted parameters like below
var params = {
"to": "device token",
"notification": {
"title": "Notification Title",
"body": "Notification Message",
"sound": "default",
},
"data": {
"customId": "01",
"badge": 0,
"alert": "Alert"
}
};
Then var url = 'https://fcm.googleapis.com/fcm/send'; call as api.
Get response like below code
var response = await http.post(url,
headers: {
"Authorization": "key= Web server Key over here",
"Content-Type": "application/json"
},body: json.encode(params)
);
if (response.statusCode == 200) {
Map<String, dynamic> map = json.decode(response.body);
print("fcm.google: "+map.toString());
}
else {
Map<String, dynamic> error = jsonDecode(response.body);
print("fcm.google: "+error.toString());
}

Firebase RemoteMessage has filled Bundle but getData() is empty

My firbase RemoteMessage has a mBundle with 12 key value pairs, according to debugger, those field were filled .
But when I say: remoteMessage.getData(); the resulting ArrayMap Map<String, String> has size 0 and thus no elements.
How can I access the Map of remoteMessage?
I know this might be late but You can get the data from Notification Object in RemoteMessage
String title = remoteMessage.getNotification().getTitle();
String body = remoteMessage.getNotification().getBody();
hope this helps
I also encountered same problem.
And finally fixed this problem.
In my case, server side's sending FCM payload problem.
like this.
options = {
priority: 'high',
notification: {
title: "title",
body: "message",
url: "some_url",
image_url: "some_image_url"
}
And I updated like following,
options = {
priority: 'high',
notification: {
title: "title",
body: "message",
},
data: {
url: "some_url",
image_url: "some_image_url"
}
After that, I could get payload values by remoteMessage.getData().
The debugger initially showed the data field as empty, but calling getData() returned the result, and the debugger then showed the correct map.

Firebase realtime database structure in chat app

sorry for my bad English level, I'm from Argentina.
I have the following messages data structure in Firebase:
"messages"
"-KezmqXSdKCNFFA432Uc___-KfCEwklG_y3naRDIUiY"
"messageDate": "20170620"
"messageTime": "18:44"
"message": "Hi"
"-KezFDSAADFASFFS3221___-KASDF32324SDFASD1FS"
"messageDate": "20170620"
"messageTime": "22:23"
"message": "How are you?"
Where -KezmqXSdKCNFFA432Uc, -KfCEwklG_y3naRDIUiY, -KezFDSAADFASFFS3221 and -KASDF32324SDFASD1FS are users.
My problem is that I created a childEventListener in "messages" node to receive new users messages but I am receiving all the new messages of all the users (I'm logged in one user per app) because my childListener is in "messages" node.
Is it correct that if I have 1000 users when adding a message, a new message reaches the 1000 users? (Assuming that within the app, you can check to which user that message belongs).
Thanks!
If you do a structure like similar to this:
-chats
- chatUID
- members
- userUID
- lastMessageSent:messageUID
- ... more properties
-chatMessages
- chatUID
- messageUID
- sentBy: userUID
- messageDate:""
- messageTime:""
- message:""
-userChats
- userUID
- chatUID
you can attach a listener to /userChats/userUID, which will display active chats, and a listener to /chatMessages/chatUID, which will get all chat messages for a specific chat conversation.
This way is a lot easier to setup firebase security rules, and users will only receive chat messages which they are apart of.
Thanks to #Linxy for a brilliant answer
I have created a firebase database regarding #Linxy answer
Here is the complete JSON export
{
"Chats" : {
"-Lsfsd234xda" : {
"lastMessageSent" : "-LrDEBo1-Message",
"members" : [ "-LrDEBoLokW-5mhaT3ys", "-LrDEBoLokW-5mhaT3yz" ],
"more_properties" : "goes here"
}
},
"Users" : {
"-LrDEBoLokW-5mhaT3ys" : {
"id" : "-LrDEBoLokW-5mhaT3ys",
"userDisplayName" : "Qadir Hussain",
"userEmail" : "XXXXX.XXXX#gmail.com",
"userPhotoUrl" : "https://lh3.googleusercontent.com/a-/AAuE7XXXXXXXXX"
},
"-LrDEBoLokW-5mhaT3yz" : {
"id" : "-LrDEBoLokW-5mhaT3yz",
"userDisplayName" : "Ishaq Bhojani",
"userEmail" : "XXXXXXX.XXXXXX#gmail.com",
"userPhotoUrl" : "https://lh3.googleusercontent.com/a-/AAuE7mB3KTbXXXXXXXX"
}
},
"chatMessages" : {
"-Lsfsd234xda" : {
"-LrDEBo-MessageUID" : {
"message" : "Hi there!",
"messageDate" : "10/10/2019",
"messageTime" : "10:16pm",
"sentBy" : "-LrDEBoLokW-5mhaT3ys"
},
"-LrDEBo1-MessageUID" : {
"message" : "Hello",
"messageDate" : "10/10/2019",
"messageTime" : "10:17pm",
"sentBy" : "-LrDEBoLokW-5mhaT3yz"
}
}
},
"userChats" : {
"-LrDEBoLokW-5mhaT3ys" : {
"0" : "-Lsfsd234xda",
"1" : "-Lsfsd234xda1",
"chatUID" : "-Lsfsd234xda"
}
}
}
I know it's late to answer but for future readers although Linxy's answer is neater, I would like to point out a more efficient one having been tried both structures:
ChatMessages
smallerUID_biggerUID
messageUID
sentBy : userUID
messageDate : ""
message : ""
.
.
.
.
UserChats
userUID
pairUID
lastMessage : ""
.
.
.
.
In this way, instead of first finding out the chatId then finding out which user is associated with that chatId, we can directly search which users should appear in our active chat tab and get thouse users' information (username, profilePicture). The reason for that is we can always calculate the chatId if we know the user's id we would like to message with. So for the message tab, we calculate the chatId (smallerUID_biggerUID) in client side and search for the messages in referencing it.
In order to structure your database, please read this post: Structuring your Firebase Data correctly for a Complex App. You'll find here for sure the answer to your question.
As a conclusion, try to flatten(denormalize) your database as much as possible.
Hope it helps.
this structure doesn't support what you want to do, it better to change it by using something like channels, where a channel contains the messages between two persons, so when any one of them send a message the other one will be notified.
{
"users": {
"userId": {
"conversations": {
"conversationId": {
"unseenCount": 0
},
"conversationId2": {
"unseenCount": 3
}
}
},
"conversations": {
"conversationId": {
"displayedMessage": "Message",
"members": {
"userId1": true,
"userId2": true
},
"messages": {
"messageId": {
"type": "text",
"text": "Hello",
"createdAt": "",
"senderId": "userId",
"status": "sent",
"payload": ""
}
},
"lastMessage": "my last message"
}
}
}
I think this will be the best structure for it:
{
messages: {
A8Fcn28ak9ask46: {
chat_id: "combination of sender and receivers number",
sender_id: "person sending the message",
receiver_id: "person send it to",
text: "message that the user types",
timestamp: "123981849404"
},
...
}
}
then when u get the results, you can filter through the chat_id's in forward and in reverse, which will get the conversation between two people.
Hope it helps.

Structure for Android app with complex database

Be kind this is my first question on StackOverflow :p. I am hoping its specific enough.
Here is how the project is structured
REST API built using NodeJS and MongoDB (mongoose has been used for modelling the database schemas) with a Express server.
Android app.
Web app using AngularJS
My question is regarding how I should structure synchronisation of data between the Android app and the REST API. The following points bring clarity to the entire scenario -
The database model (on the server) is pretty complex with each database model having multiple subdocuments.
There are about 6 - 7 models which reference each other.
I am currently using Volley to get the data from the remote server.
I am also considering adding a SyncAdapter for syncing the data regularly and am not sure as to how to incorporate this with a local database. Should I have a different ContentProvider for every table / model in the database? and how should I handle nested schemas (that are in the remote server) locally?
To summarise my question what I exactly want to know is considering that there will be about 15-20 requests per user per day for about 100,000 users daily, would the best approach be to -
Use volley to do all my database work.
Use a local database (SQLite) along with a SyncAdapter to keep the data in sync automatically? If this is the case could you recommend some resources to better understand how to integrate a complex database with SyncAdapter.
Anything else you suggest for structuring this app.
To demonstrate the complexity of the app please have a look at the models below
This is the user model
var AddressSchema = new Schema({
name: String,
address: String,
mobile: String,
pincode: String,
city: String,
state: String
});
var CartSchema = new Schema({
book: { type: Schema.Types.ObjectId, ref: 'Book' },
quantity: {
type: Number,
default: 1
},
dateAdded: Date
});
var WishlistSchema = new Schema({
book: { type: Schema.Types.ObjectId, ref: 'Book' },
dateAdded: Date
});
var OrderSchema = new Schema({
orderNumber: String,
cart: [CartSchema],
totalAmount: Number,
deliveryCharge: Number,
discountAmount: Number,
address: [AddressSchema],
date: Date,
deliveryDate: Date,
deliveryStatus: String
});
var SellOrderSchema = new Schema({
orderNumber: String,
bookDetails: [{
isbn: String,
title: String,
quantity: {
type: Number,
default: 1
}
}],
address: [AddressSchema],
date: {
type: Date,
default: Date.now()
}
});
var ReceivedOrdersSchema = new Schema({
orderNumber: String,
bookDetails: [{
book: { type: Schema.Types.ObjectId, ref: 'Book' },
quantity: Number,
price: Number
}],
dueDate: Date,
status: {
type: String,
default: 'Pending'
}
});
var CouponSchema = new Schema({
coupon: [{ type: Schema.Types.ObjectId, ref: 'Coupon' }],
used: Number,
totalDiscount: Number
});
var UserSchema = new Schema({
name: String,
email: { type: String, lowercase: true },
role: {
type: String,
default: 'user'
},
hashedPassword: String,
provider: String,
salt: String,
facebook: {},
twitter: {},
google: {},
github: {},
usedCoupons: [CouponSchema],
cart: [CartSchema],
wishlist: [WishlistSchema],
orders: [OrderSchema],
sellOrders: [SellOrderSchema],
addresses: [AddressSchema],
booksToSell: [{ type: Schema.Types.ObjectId, ref: 'Book' }],
receivedOrders: [ReceivedOrdersSchema]
});
This is the books model
var BookSchema = new Schema({
_creator : {type: Schema.Types.ObjectId, ref: 'User'},
title: String,
subtitle: String,
author: String,
language: String,
pages: Number,
publisher: String,
publishedDate: String,
isbn10: String,
isbn13: String,
description: String,
dimensions: {
height: String,
width: String,
thickness: String
},
category: String,
rating: String,
bookType: String,
imageLinks: {
extraLarge: String,
large: String,
medium: String,
small: String,
smallThumbnail: String,
thumbnail: String,
uploaded: String
},
uploadedImageLink: String,
supplierData: {
mrp: Number,
supplierPrice: Number,
quantity: Number
},
pricing: {
salesPrice: Number,
deliveryCharge: Number
},
dateAdded: Date,
isFeatured: Boolean,
isBestseller: Boolean
});
There are 5-6 other such models that are dependent on each other
Static Data
Data like your UserTable is mostly static so you can store it in SQLite (or even Shared Preferences) for fast local data access. Also the stored data about books(title, author etc) is pretty much static (I don't think the author changes that often) so caching it in a SQLite is easy and straight-forward.
Dynamic Data
Caching dynamic data? Hard, useless but if you have to use Volley, it helps you a lot. Volley caches your responses using HTTP tags like Expire and Last-Modified. Your app will send a HTTP Request with an If-Modified-Since tag that contains a timestamp. If the data from your server has changed since that timestamp you will receive a normal response. Otherwise, you will receive a HTTP 304 Not Modified and you can use your old cached data. In both cases you app will save the current timestamp and use that next time. All of this is handled by Volley and hidden from you, but is useful to know. You will have to figure out how to handle this on the server side. If you don't want your server to handle to many connections, you could show your user cached data first and implement a Pull to Request gesture that would send a request.
Offline Access
Volley gives you an abstraction layer for times when you app isn't able to access the internet, but you should add a clear visual indicator for the user so they know that whatever you have showed them could have changed in the meantime.
All in all, you should divide your data based on how often it changes and according to that employ different strategies. Specify an expiration period or date to volley when you know it.

Categories

Resources