Unable to get the Onesignal userid when the user install the app first time in Flutter - flutter

I want to store the onesignal User Id in the database when the user install my app first time. I wrote the following code which is not allowing me to do so.
However when the user Logged out from the app and re-login then I am able to retrieve the onesignal user ID and able to save in the Database.
Future<void> initPlatformState(username) async {
if (!mounted) return;
OneSignal.shared.setLogLevel(OSLogLevel.verbose, OSLogLevel.none);
OneSignal.shared.setRequiresUserPrivacyConsent(_requireConsent);
var settings = {
OSiOSSettings.autoPrompt: false,
OSiOSSettings.promptBeforeOpeningPushUrl: true
};
OneSignal.shared
.setSubscriptionObserver((OSSubscriptionStateChanges changes) {
print("SUBSCRIPTION STATE CHANGED: ${changes.jsonRepresentation()}");
});
OneSignal.shared.setPermissionObserver((OSPermissionStateChanges changes) {
print("PERMISSION STATE CHANGED: ${changes.jsonRepresentation()}");
});
OneSignal.shared.setEmailSubscriptionObserver(
(OSEmailSubscriptionStateChanges changes) {
print("EMAIL SUBSCRIPTION STATE CHANGED ${changes.jsonRepresentation()}");
});
await OneSignal.shared
.init("MY Onesignal APP ID", iOSSettings: settings);
OneSignal.shared
.setInFocusDisplayType(OSNotificationDisplayType.notification);
var status = await OneSignal.shared.getPermissionSubscriptionState();
onesignalUserId = status.subscriptionStatus.userId;
print("player ID: "+ onesignalUserId.toString()); // printing only in re-login
_saveOneSignalId(onesignalUserId,username); // my save funtion into the DB
}

You can call the below function inside your main.dart file when initialising the One Signal to get playerId/userId. The below function is called when user opend the app for first time or when the userId (playerId) changes.
OneSignal.shared.setSubscriptionObserver((OSSubscriptionStateChanges changes) async {
String onesignalUserId = changes.to.userId;
print('Player ID: ' + onesignalUserId);
}
The playerId/userId can be used to send test notification or notifications to particular user.

Please try this.
OneSignal.shared.setSubscriptionObserver((OSSubscriptionStateChanges changes)
async{
var status = await OneSignal.shared.getPermissionSubscriptionState();
if (status.subscriptionStatus.subscribed){
String onesignalUserId = status.subscriptionStatus.userId;
print('Player ID: ' + onesignalUserId);
}

Related

How to send expo push notification to multiple devices?

I'm trying to send Expo push notifications to multiple devices. I'm retrieving the Expo tokens from Firestore. When I enter the tokens manually, it works! It sends the notification to both devices I'm using, but when I retrieve the data from Firestore, it only sends the notification to one device.
async function sendPushNotification(readx) {
const message = {
to: readx,
sound: "default",
title: "Original Title",
body: "And here is the body!",
data: { someData: "goes here" },
};
const retrieveNetwork = async () => {
try {
//const querySnapshot = await getDocs(collection(db, "cities"));
const q = query(collection(db, "users"));
const querySnapshot = await getDocs(q);
setRead(querySnapshot.docs.map((doc) => doc.data().expoUser));
setReadx(JSON.stringify(read));
} catch (e) {
alert(e);
}
};
The retrieving of data from the firestore seems to be an issue , as your code is using the Snapshot for querying the data ,it should get the token id for both the devices in the loop and then return to the await sync to call the notification function.As per the Firebase documentation on reading multiple documents, you'll see that it uses the data() function on each DocumentSnapshot to get at the fields of that document.
So try to modify accordingly,like use doc.role and doc.token instead of doc.data().role and doc.data().token.
Check this example code below:
let tokenList = []; const userNotificationTokenDocs = await db.collection("userToken").doc(userId).get() .then(querySnapshot => { querySnapshot.forEach((doc) => { console.log(doc.data().Tokens); tokenList.push(doc.data().Tokens); }); return null; });
Also you may try adding the below to your code:
userToken.forEach((token) => { console.log(token); tokens.push(token); });
Checkout these following with similar implementation:
Push notification firestore
Triggering expo sdk to push notification to users
Notification to a collection of token
Array token sending notification
Just solved. Need to change
<Button
title="Press to Send Notification"
onPress={async () => {
await sendPushNotification(expoPushToken);
}}
/>
to
<Button
title="Press to Send Notification"
onPress={async () => {
await sendPushNotification(readx);
}}
/>

How to create push notification one device to another device like chat app?

I am working on a chat application, I want to push notification for specific user when his message send me so i should deliver message with notification bar.
/// Get the token, save it to the database for current user
_saveDeviceToken() async {
// Get the current user
String uid = 'jeffd23';
// FirebaseUser user = await _auth.currentUser();
// Get the token for this device
String fcmToken = await _fcm.getToken();
// Save it to Firestore
if (fcmToken != null) {
var tokens = _db
.collection('users')
.document(uid)
.collection('tokens')
.document(fcmToken);
await tokens.setData({
'token': fcmToken,
'createdAt': FieldValue.serverTimestamp(), // optional
'platform': Platform.operatingSystem // optional
});
}
}

Flutter uni_links duplicate the app every time a link is clicked

I am implementing a password recovery function based on the url sent to the email. Opening the app based on that url was successful. But instead of directly opening the required page in the app that is in the background, it duplicates the app. Although it still leads me to the password recovery page, now there will be 2 same apps running side by side
Procedure
Enter your email to send the password reset link
Click submit
Open the email containing the recovery link
Duplicate the app and open a recovery password page
Things what happen
Splash screen, first page open in the app, I am trying to do as instructed from uni_links package but still no success. Currently the function getInitialLink has the effect of opening the app based on the recovery link
class SplashController extends GetxController {
final SharedPreferencesHelper _helper = Get.find<SharedPreferencesHelper>();
late StreamSubscription sub;
#override
void onReady() async {
super.onReady();
await checkToken();
}
Future<void> checkToken() async {
await Future.delayed(Duration(seconds: 3));
var token = _helper.getToken();
if (token == null) {
Get.offNamed(Routes.LOGIN);
} else {
Get.offNamed(Routes.MAIN);
}
}
#override
void onInit() {
super.onInit();
initUniLinks();
}
Future<Null> initUniLinks() async {
// Platform messages may fail, so we use a try/catch PlatformException.
try {
String? initialLink = await getInitialLink();
if (initialLink != null) {
print("okay man");
Get.toNamed(Routes.RECOVERY);
}
sub = getLinksStream().listen((link) {
}, onError: (err) {
});
} on PlatformException {
// Handle exception by warning the user their action did not succeed
// return?
}
}
}
I found the solution, actually this answer is already on Stackoverflow, and it's really simple.
In the AndroidManifest.xml file of the app. Find "android:launchMode" and change its old value to singleTask. And here is the result
android:launchMode="singleTask"

Google Auth Page always shown, how to Auth only first time

I am making a calendar app with flutter using googleApi library.
but, When you turn off the app, need to auth again in web site.
i want auth only first time.
is it possible?
// mycode
get _SCOPES => [CalendarApi.CalendarScope];
await clientViaUserConsent(_clientID, _SCOPES, prompt)
.then((AuthClient client) async {
CalendarClient.calendar = CalendarApi(client);
calendarId = await CalendarClient.calendar.calendarList
.list()
.then((value) => value.items[0].id);
});
void saveData(AccessCredentials credentials) {
GetStorage().write(credetialKey, {
"accessTokenData": credentials.accessToken.data,
"accessTokenExpiry": credentials.accessToken.expiry.toString(),
"refreshToken": credentials.refreshToken,
"scopes": credentials.scopes,
"idToken": credentials.idToken
});
}
AccessCredentials getCredetial() {
try {
var map = GetStorage().read(credetialKey);
return AccessCredentials(
AccessToken("Bearer", map["accessTokenData"] as String,
DateTime.parse(map["accessTokenExpiry"])),
map["refreshToken"],
map["scopes"].cast<String>(),
idToken: map["idToken"] as String);
} catch (e) {
return null;
}
}
Client cli = Client();
var c = await refreshCredentials(_clientID, getCredetial(), cli)
.catchError((e) {
print(e);
});
authenticatedClient(cli, c);
error :
DetailedApiRequestError(status: 401, message: Request is missing required authentication credential. Expected OAuth 2 access tok
You can save user session using for example sharedPreferences. Each time the user launch the app your must first check if the session is saved so you can skip the auth process, otherwise you initiate the authentication
i solved it.
save AccessCredentials,
and use autoRefreshingClient;
Client cli = Client();
var c = await refreshCredentials(_clientID, getCredetial(), cli)
.catchError((e) {
print(e);
});
cli = autoRefreshingClient(_clientID, c, cli);

Flutter: Firebase user's name doesn't get updated when user logs in for the first time

I am trying to fetch a user's ID when a person is logged in with their firebase account. When I try to login a new user for the first time, I can fetch their id however the user's details only reflect after the person navigates from one page to another using the navigation bar. Is there a way I can get rid of that? I want the user's display name to reflect as soon as they create a new account.
This is my current code that I call in my initState()
getCurrentUser() async {
try {
final user = await _auth.currentUser();
if (user != null) {
setState(() {
loggedInUser = user;
id = user.uid;
username = user.displayName;
});
}
} catch (e) {
print(e);
}
}