Firebase & Flutter (on Android) - MessagingToken is null - firebase

I'm running into trouble with some of my app's subscribers. We recently introduced the ability to send out notifications to our users using FirebaseMessaging. I should also mention that the app is on Android only.
Here is a brief section of code that we are running
updateUser(Userx user) async {
var messagingToken = await FirebaseMessaging.instance.getToken();
var packageInfo = await PackageInfo.fromPlatform();
user.messagingToken = messagingToken!;
user.appVersion = packageInfo.version;
await Users.updateUser(user);
}
It turns out that the FirebaseMessaging.instance.getToken() sometimes returns null and I can't figure out why that would be the case. The documentation also doesn't say much.
Could this be device specific? Maybe a user-setting to not allow any in-app messages?
A potential workaround is of course to null-check the token and simply accept it being null but I would like to understand the reasons behind that.
I found one more method that could be helpful, but I'm unsure about it.
Call FirebaseMessaging.instance.isSupported() first and act based on the result.

Related

How to get discord bot to handle separate processes/ link to another bot

I am trying to create something of an application bot. I need the bot to be triggered in a generic channel and then continue the application process in a private DM channel with the applicant.
My issue is this : The bot can have only one on_message function defined. I find it extremely complicated (and inefficient) to check everytime if the on_message was triggered by a message from a DM channel vs the generic channel. Also, makes it difficult to keep track of an applicants answers. I want to check if the following is possible : Have the bot respond to messages from the generic channel as usual. If it receives an application prompt, start a new subprocess (or bot?) that handles the DMs with the applicant separately.
Is the above possible? if not, is there an alternative to handling this in a better way ?
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.channel.type==discord.ChannelType.private:
await dm_channel.send("Whats your age?") ## Question 2
elif message.channel.type == discord.ChannelType.text:
if message.content.startswith('$h'):
member = message.author
if "apply" in message.content:
await startApply(member)
else:
await message.channel.send('Hello!')
# await message.reply('Hello!', mention_author=True)
async def startApply(member):
dm_channel = await member.create_dm()
await dm_channel.send("Whats your name?") ## Question 1
I have the above code as of now. I want the startApply function to trigger a new bot/subprocess to handle the DMs with an applicant.
Option 1
Comparatively speaking, a single if check like that is not too much overhead, but there are a few different solutions. First, you could try your hand at slash commands. This is library built as an extension for the discord.py library for slash commands. You could make one that only works in DM's, and then have it run from there with continuous slash commands.
Option 2
Use a webhook to start up a new bot. This is most likely more complicated, as youll have to get a domain or find some sort of free service to catch webhooks. You could use a webhook like this though to 'wake up' a bot and have it chat with the user in dm's.
Option 3 (Recommended)
Create functions that handle the text depending on the channel, and keep that if - elif in there. As i said, one if isn't that bad. If you had functions that are called in your code that handled everything, it actually should be fairly easy to deal with:
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.channel.type==discord.ChannelType.private:
respondToPrivate(message)
elif message.channel.type == discord.ChannelType.text:
repondToText(message)
In terms of keeping track of the data, if this is a smaller personal project, MySQL is great and easy to learn. You can have each function store whatever data needed to the database so that you can have it stored to be looked at / safe in case of bot crash & then it will also be out of memory.

Flutter dynamic links test

Edited Question :
I have an issue with Firebase Dynamic Links Packag , My goal is getting know if new user installed and opend my app for first time to give him a rewards like 10 point . I tried to search everywhere but no answer,in firebase website there is option to know if user install for first time.
My Goal is : Getting value for first time install & how to debug this code ?
initDynamicLinks when app Lanched :
void initDynamicLinks() async {
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
}
},
onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
}
);
final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deepLink = data?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
}
}
.
You're mixing two things here.
The First-opens tab gives you the number of unique users who clicked on your Firebase Dynamic Link for the first time.
If you want to know how many unique users used your app, by clicking the Firebase Dynamic Link or not to get to your app, you have to implement the Firebase Analytics plugin to your app.
This way you'll get access to Dashboards showing you how many Unique users you have.
EDIT
Reading your comment, looks like your question is not related to your problem.
What you want here is to attribute rewards for users who invited their friends thanks to a referral link.
Since I never implemented this witout a dedicated backend, the only thing I can share is a use-case I used some time ago explaining the logic to follow to implement it.
https://firebase.google.com/docs/dynamic-links/use-cases/rewarded-referral
EDIT 2
The logic explained in the documentation is the following :
1- Generate a Dynamic Link for UserA.
2- UserA sends the Dynamic Link to someone (called UserB).
3- When UserB starts the app from a Dynamic Link, retrieve the referral informations in the app (to retrieve UserA's informations)
4- Call a route on your backend to attribute the reward to UserA (and check if UserB is really a new user in your database).
The point is, you shouldn't manage a referral/referrer relationship on the client's side (it would be way too easily abused/hacked).
It's the job of a backend (or cloud function) to manage this.
Once you have received the link clickthrough in your app use the google_analytics package to log an event.
Related thread here:
Flutter log event with google analytics
To be honest i have never used Firebase Dynamic Links , But if your Goal is to Achieve a first open or login token , you can always use the Sharedpreferences package , in my case iam using it to navigate to different pages passed on the first login value .
i think that Sharedpreferences is more reliable and easier than what you are trying to achieve with firebase
UPDATE:
what you actually want to do is make a firebase collection with IMEI numbers , when there is a new IMEI that means a new user , when that IMEI is in your collection that means that the app is not installed for the first time ,
you can use this package imei_plugin to get IMEI number and store it on firebase

Flutter Dynamic Links get added parameters

So, I am currently using Flutter to develop an IOS-App and added Firebase.
I am trying to use PayPal-Connect with the url_launcher package. As the PayPal-Connect link looks like this:
https://www.sandbox.paypal.com/connect?flowEntry=static&client_id=[<my_client_Id>]&scope=&redirect_uri=[<my_url>]
I am trying to use Firebase Dynamic Links for the redirect_uri to go back to the app and fetch the data I got from Pay-Pal as url parameters. The problem is that whenever I run this code:
Future<void> retrieveDynamicLink() async {
final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deepLink = data?.link;
if (deepLink != null) {
print(deepLink);
print(deepLink.queryParameters['code']);
}
}
The logs say:
flutter: https://domain.page.link/ppc
flutter: null
But I know from the Paypal-Connect Docs that they add a code=[<some_code>] parameter.
But is the thing I plan to do even possible with Dynamic Links? Or Am I doing something completely wrong?
Checking the implementation, it looks like you're trying to implement something similar to a reward referral use case. The reason why deepLink.queryParameters['code'] returns null is because there's no code parameter configured on the deep link of the Firebase Dynamic Link that has been handled.
To configure a query parameter for code, the deep link of your Dynamic Link should look something similar to https://example.com/?code={CODE}

Firebase + Flutter : get platform user used to sign in

I have an app with 3 sign in methods: Google, Facebook & mail.
I want to show the users that are signed in with mail a different screen.
Is it possible to get the sign in method form the package firebase authentication?
I know I can fix this by using firestore & checking if a statement is true or false. But that will cost me a read every time a user opens the app...
This seems to be what you want: https://firebase.google.com/docs/reference/android/com/google/firebase/auth/FirebaseUser.html#getProviderData()
In my app where I use Google logins only, I have firebaseUser.providerData[1].providerId == 'google.com'.
Btw, firebaseUser.providerData[0].providerId == 'firebase'.
I guess you could check them all and look for what providers you get for different kinds of users.
Edit: here's what I get when logging in with e-mail: https://postimg.cc/BXWGGN6h
Firebase has a special property providerId. But, as mentioned #GazihanAlankus it always returns firebase.
And, the property firebaseUser.providerData[1].providerId sometimes not exists (for example when user used anonymous login).
So, we should use appropriate approaches, for example:
FirebaseUser user = await _firebaseAuth.currentUser();
if (user.providerData.length < 2) {
// do something
}
else {
print(res.providerId);
}
The list of values, that are returned by property providerId:
EmailAuthProviderID: password
PhoneAuthProviderID: phone
GoogleAuthProviderID: google.com
FacebookAuthProviderID: facebook.com
TwitterAuthProviderID: twitter.com
GitHubAuthProviderID: github.com
AppleAuthProviderID: apple.com
YahooAuthProviderID: yahoo.com
MicrosoftAuthProviderID: hotmail.com
I got this list from the cool research here What is the full list of provider id's for firebase.UserInfo.providerId?
In my app I used
FirebaseAuth.instance.currentUser.providerData[0].providerId == 'google.com'.,
cause providerData[1] doesn't contain any value
For anyone reading this in 2022, Firebase now has nice new docs for Flutter and in it they have this, which I personally found super useful:
if (user != null) {
for (final providerProfile in user.providerData) {
// ID of the provider (google.com, apple.cpm, etc.)
final provider = providerProfile.providerId;
// UID specific to the provider
final uid = providerProfile.uid;
// Name, email address, and profile photo URL
final name = providerProfile.displayName;
final emailAddress = providerProfile.email;
final profilePhoto = providerProfile.photoURL;
}
}
Source: Firebase documentation
But that will cost me a read every time a user opens the app. THIS IS TRUTH!
Alternatively, you can create your own app DB using SQFLite, and create only one table (user) in that, having a field of signUpMethod having possible values are google, facebook and mail. Whenever you opens the app, first check that in your db, if this is mail, redirect to another screen which you want, else call firebase service
Cheers!

When I connect to firebase, I only see the structures and no devices (Nest API)

I am trying to read basic information about thermostats using the methods in the thermostat control example (https://developer.nest.com/documentation/control), but when I connect to firebase I only see the structure object (which only contains name, away, smoke_co_alarms, structure_id and thermostats) in the snapshot– There is no devices object. I am connecting to firebase using
var nestToken = $.cookie('nest_token');
var dataRef = new Firebase('wss://developer-api.nest.com/');
dataRef.auth(nestToken);
I tried to connect directly to devices using wss://developer-api.nest.com/devices, but that only returns an undefined data-structure.
I've also tried connecting to firebase using https://developer-api.nest.com/ and https://developer-api.nest.com/, but they raised an authorization error and caused my javascript to go into an infinite loop sending requests.
I'm reading data using:
dataRef.on('value', function (snapshot) {
var data = snapshot.val();
structure = firstChild(data.structures);
console.log(data);
console.log(data.structures);
console.log(data.devices);
console.log(data.devices.thermostats);
console.log(structure.thermostats);
};
Lastly, I tried it on an account with real devices and one with virtual devices, so I know that couldn't be causing it (even though I didn't expect it to).
Any ideas what I am doing wrong? The issue couldn't be in my App.js file, could it? Is there some configuration I need to do on the user's end in addition to the authentication? I get the feeling it's probably something really simple that's staring me in the face.
So I figured it out: It's a permissions issue. When my client-profile was setup, it only requested permission to read the away/home status. So when I query Firebase it only returns the a snapshot with structure because that is where the away/home status can be read. So, in summary, if you're not seeing the devices structure, even though devices are associated with the user, check your client permissions.
Using (some of) your code, I have no trouble seeing the devices object:
var dataRef = new Firebase('wss://developer-api.nest.com');
dataRef.auth(nestTokenLive);
dataRef.on('value', function (snapshot) {
var data = snapshot.val();
console.log(data);
console.log(data.devices);
});
Results in:
> Object {devices: Object, structures: Object}
> Object {thermostats: Object}

Resources