I am trying to run the below cod which initialises the Firebase Admin SDK, and send a notification message.
const admin = require('firebase-admin/app');
const errorCodes = require('source/error-codes');
const PropertiesReader = require('properties-reader');
const prop = PropertiesReader('properties.properties');
exports.sendSingleNotification = async (event, context) => {
const params = event.queryStringParameters;
var serviceAccount = require("xxx-xxx-firebase-adminsdk-xxx-xxx.json");
try {
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
console.log("INITIALIZED");
// This registration token comes from the client FCM SDKs.
const registrationToken = params.fcmtoken;
console.log()
const message = {
notification: {
title: 'FooCorp up 1.43% on the day',
body: 'FooCorp gained 11.80 points to close at 835.67, up 1.43% on the day.'
},
token: registrationToken
};
// Send a message to the device corresponding to the provided
// registration token.
admin.getMessaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
return {"response":response}
})
.catch((error) => {
console.log('Error sending message:', error);
return {"error 1":error}
});
} catch (error) {
console.log(error);
return {"error 2":error}
}
};
Here the serviceAccount means the path of the Firebase private key file which is in the root of this project.
However when I run this code I always end up with the following error.
START RequestId: e66ffdd9-ab9c-4a68-ade2-7cfa97f42c31 Version: $LATEST
at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)] (/var/task/source/fcm/send-single-notification.js:14:42)rt' of undefined
END RequestId: e66ffdd9-ab9c-4a68-ade2-7cfa97f42c31
Something is undefined and I can't figure out what it is or what the error is.
How can I fix this?
Related
I'm trying to send notifications based on business logic that runs (on nodejs) on my server via a cron.
Issue
Notifications aren't appearing on the device.
Description
I'm using the firebase admin node package.
My code looks something like this
import admin from "firebase-admin";
import serviceAccount from "../../firebase-admin.json" assert { type: 'json' };
import { getMessaging } from 'firebase-admin/messaging';
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
...
console.log(message);
await getMessaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
My log output is something like this
{
notification: {
title: 'This is a string',
body: 'This is another string'
},
token: 'aLphaNumeric:reallyLongAlphaNumericWithDashesAndUnderscores'
}
Successfully sent message: projects/<project-name>/messages/<id>
Everything I'm seeing suggests this should be sent!
sendMulticast and the Admin FCM APIs allow you to multicast a message to a list of device registration tokens. You can specify up to 500 device registration tokens per invocation.
sendMulticast take 2 arguments as input, 1st one is notification which contains the title and body of the message.
The other argument is fcmTokens with type array, so you must pass that argument as array even though there is only one fcmToken
//Import the file where you have imported the service file.
const adminApp = require("../firebase/firebaseConfig");
const notificationToAll = (title, body, tokens) => {
var notibody = {
notification: {
title: title,
body: body,
},
tokens: tokens,
};
return new Promise((resolve, reject) => {
adminApp
.messaging()
.sendMulticast(notibody)
.then((response) => {
console.log(response.responses);
if (response.responses[0].error != undefined) {
console.log(JSON.stringify(response.responses[0].error));
}
resolve(response);
})
.catch((error) => {
console.log(JSON.stringify(error));
reject(error);
});
});
};
module.exports = notificationToAll;
app.js
const notificationToAll = require("./helper/notification");
notificationToAll(
"This is a string",
`This is another string`,
["aLphaNumeric:reallyLongAlphaNumericWithDashesAndUnderscores"]
)
This is tested code and working in a live environment.
i am building chat app with flutter and I try to send notification to specific device using the cloud function so when a user send message to his friend then his friend get notification with the message but I get that error
note : I don not have any knowledge with javascript or node js
Unhandled error Error: Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string.
at Object.validateResourcePath (/workspace/node_modules/#google-cloud/firestore/build/src/path.js:446:15)
at CollectionReference.doc (/workspace/node_modules/#google-cloud/firestore/build/src/reference.js:2061:20)
at /workspace/index.js:14:12
at fixedLen (/workspace/node_modules/firebase-functions/lib/providers/https.js:72:41)
at /workspace/node_modules/firebase-functions/lib/common/providers/https.js:407:32
at processTicksAndRejections (node:internal/process/task_queues:96:5)
first I try to get the device token and save it to firebase
void getToken() async {
await fcm.getToken().then((value) {
tokens = value;
print('my token22 is $tokens');
saveToken(tokens: tokens);
});
}
void saveToken({String? tokens}) async {
FirebaseFirestore.instance.collection('userToken').doc(userphone).set({
'token': tokens,
});
}
then I try to call this token at index.js file at function function
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.addMessage = functions.https.onCall(
(data, context) => {
const friendPhone = data.text;
const userDoc = admin
.firestore()
.collection("userToken")
.doc(friendPhone)
.get();
const deviceTokens = userDoc.data();
console.log(deviceTokens);
const title = data.title;
const body = data.body;
try {
if (deviceTokens) {
exports.myFunction = functions.firestore
.document("chats/{chatId}/messegeId/{messageId}")
.onWrite((snap, context) => {
console.log(snap.data());
admin.messaging().sendToDevice(deviceTokens,
{
notification: {title: title,
body: body,
clickAction: "FLUTTER_NOTIFICATION_CLICK",
},
});
});
}
} catch (error) {
console.log(error);
throw new functions.https.
HttpsError("invalid-argument", "some message");
}
}
);
after that I call the function at sendMessege button so that when the user send messgege it work
Future<void> writeMessage({
String? message,
String? title,
String? friendPhone,
}) async {
HttpsCallable callable =
FirebaseFunctions.instance.httpsCallable("addMessage");
final resp = await callable.call(<String, dynamic>{
"text": friendPhone,
"title": title,
"body": message,
});
print("result: ${resp.data}");
}
oare you sure that the path for the friendPhone is a valid path in firebase?
Is there maybe a spelling mistake in messageId?
document("chats/{chatId}/messegeId/{messageId}")
You wrote messegeId instead of messageId
Hope that helps.
I’m trying to create a push notification and after a comment is made in my realtime database.
I use this code which I learned from here
import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin';
export const sendenPushNeu = functions.database
.ref ('/placeID/{placeID}')
.onCreate((snapshot, context) => {
var app = admin.initializeApp({
credential: admin.credential.cert('/Users/...Desktop/firebasedesktop/key.json')
});
var registrationToken = 'dplk1...bS7eu';
var message = {
data: {
score: '850',
time: '2:45'
},
token: registrationToken
};
// Send a message to the device corresponding to the provided
// registration token.
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
})
But I don't get a notification.
I am new to javascript and cannot see what is wrong here.
I do want to create an access token in the backend and need to pass to the front end to connect to the video chat room.
This is my back-end code
const twilioAccountSid = process.env.twilioAccountSid;
const twilioApiKey = process.env.twilioApiKey;
const twilioApiSecret = process.env.twilioApiSecret;
const room = "cool room";
app.post("/access-token", (req, res) => {
try {
console.log(
"sid",
twilioAccountSid,
"key",
twilioApiKey,
"secret",
twilioApiSecret
);
const identity = "user";
// Create Video Grant
const videoGrant = new VideoGrant({
room,
});
// Create an access token which we will sign and return to the client,
// containing the grant we just created
const token = new AccessToken(
twilioAccountSid,
twilioApiKey,
twilioApiSecret,
{ identity: identity }
);
token.addGrant(videoGrant);
// Serialize the token to a JWT string
console.log(token.toJwt());
res.status(200).json(token.toJwt());
} catch (error) {
console.warn(error);
res.sendStatus(500);
}
});
For the Twilio account SID I used my dashboard's SID which is starting from AC
For the API key I added the friendly name I gave to the API key when I created it.
API secret is that API key's secret id.
A token is crearted succefully and passed to the front-end.
This is my front-end code
const connectRoom = async () => {
try {
const token = await axios.post("http://localhost:5000/access-token");
connect(token.data, { name: roomName, video: { width: 640 } }).then(
(room) => {
console.log(`Successfully joined a Room: ${room}`);
room.on("participantConnected", (participant) => {
console.log(`A remote Participant connected: ${participant}`);
participant.tracks.forEach((publication) => {
console.log("for each");
if (publication.isSubscribed) {
const track = publication.track;
document
.getElementById("remote-media-div")
.appendChild(track.attach());
}
});
participant.on("trackSubscribed", (track) => {
document
.getElementById("remote-media-div")
.appendChild(track.attach());
});
});
},
(error) => {
console.error(`Unable to connect to Room: ${error.message}`);
}
);
} catch (error) {
console.log(error);
}
Then I get this error
Unable to connect to Room: Invalid Access Token issuer/subject
How do I solve this problem?
Any help!
Thanks in advance
You can create an API Key here (or via the Console). Note, the API Key starts with SK....
REST API: API Keys
My code :
exports.fcmSend = functions.firestore.document('messages/{userId}').onCreate(event => {
console.log("fcm send method");
const message = event.data.data();
const userId = event.params.userId;
const token_id = 'asdfsadfdsafds';
let token = "";
const payload = {
notification: {
title: "Test",
body: "Test",
icon: "https://placeimg.com/250/250/people"
}
};
db.collection('fcmTokens').doc('token_id').get().then((doc) => {
console.log(doc.id, '=>', doc.data());
const data = doc.data();
token = data.token;
console.log("token", token);
})
.then(() => {
return event.data.ref.set({"title": "hello"}).sendToDevice(token, payload);
})
.catch((err) => {
console.log('Error getting documents', err);
return err;
});
});
Error :
Error getting documents TypeError:
event.data.ref.set(...).sendToDevice is not a function
at db.collection.doc.get.then.then (/user_code/index.js:117:50)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
There are two separate Firebase products involved here:
Cloud Firestore, where you stroke the FCM tokens for a user.
the Cloud Messaging Admin SDK, which you use to send notifications to a user.
The sendToDevice method exists on the Admin SDK for Cloud Messaging, not on a Firestore database reference where you're trying to invoke it.
To fix the problem you'll first need to import the Admin SDK into your index.js:
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
Then you modify your functions for step 1 and 2. It should look something like this:
// Load the tokens from Firestore
db.collection('fcmTokens').doc('token_id').get().then((doc) => {
console.log(doc.id, '=>', doc.data());
const data = doc.data();
token = data.token;
console.log("token", token);
const payload = {
notification: {
title: 'hello',
}
};
return admin.messaging().sendToDevice(token, payload)
})
.catch((err) => {
console.log('Error getting documents', err);
return err;
});