Guys am trying to make a voip with the help of firebase messaging as a trigger for voip when app is terminated however, over 100% of what I searched on net relies on the old firebase_messaging.configure to trigger the app to open on receiving notification function which is no longer available in the latest unless I downgrade my flutter version to ancient times which is not an option for me at this point. And the call never go through due to this changes. Can anyone please help me out.
Future initNotifications () async {
firebaseMessaging.getInitialMessage().then((RemoteMessage? message) async {
if (message?.notification != null) {
navigatorKey.currentState?.pushNamed("/on_call");
}
if (kDebugMode) {
print("app is terminated");
}
if (message != null) {
getNumber();
navigatorKey.currentState?.pushNamed("/voice_call_page");
if (kDebugMode) {
print("New notifications");
}
}
});
FirebaseMessaging.onMessage.listen(handleMessage);}
void handleMessage(RemoteMessage message) async {
navigatorKey.currentState?.pushNamed("/on_call");
if (message.notification != null) {
setState(() {
avatarLink = message.notification!.title;
callerName = message.notification!.body;
});
}
}
This only works when it is opened in app but not when the app is terminated, please help.
Related
Buying a product works fine but when I try to get the bought products on startup of the app the listening is not working.
The logger.i("purchaseInit") message is not displayed.
purchaseInit() {
StreamSubscription<List<PurchaseDetails>> _subscription;
final Stream purchaseUpdated = InAppPurchase.instance.purchaseStream;
_subscription = purchaseUpdated.listen((purchaseDetailsList) {
logger.i("purchaseInit"); // not showing up
_listenToPurchaseUpdated(purchaseDetailsList);
}, onDone: () {
_subscription.cancel();
}, onError: (error) {
// handle error
});}
void _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) {
purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async {
if (purchaseDetails.status == PurchaseStatus.pending) {
logger.i("_showPendingUI()");
} else {
if (purchaseDetails.status == PurchaseStatus.error) {
logger.i(purchaseDetails.error);
} else if (purchaseDetails.status == PurchaseStatus.purchased ||
purchaseDetails.status == PurchaseStatus.restored) {
logger.i(purchaseDetails);
}
if (purchaseDetails.pendingCompletePurchase) {
await InAppPurchase.instance.completePurchase(purchaseDetails);
}
}
});
}
It seems, you are just listening to purchases by subscribing to the stream. But previous purchases are not emitted by the stream upon startup of the app or upon subscribing to it.
In order to get a list of previous purchases, you must trigger a restore.
await InAppPurchase.instance.restorePurchases();
This will re-emit the previous purchases of non-consumable products and your listener will be able to handle them.
However, I suggest that you try to keep track of what the user purchased yourself and only call restorePurchases() if necessary.
https://pub.dev/packages/in_app_purchase#restoring-previous-purchases
I'm having an issue dealing with Firebase push notifications when the App is KILLED.
What's happening:
First of all, push notifications should work like this. When you tap, you are redirected to a Move-Type Job or an Event-Type Job.
When app is in BACKGROUND MODE, push notification shows as it should,
and it redirects to the page that it should.
When App is KILLED, push notifications still shows, but when you tap on them you are not redirected, you are just opening the App.
Future initialize() async {
await getConnectivity();
if (hasInternet) {
try {
await configurePushNotificationHandlers();
} catch (e) {
hasApiConnection = false;
}
}
}
Future configurePushNotificationHandlers() async {
await navigationService.navigateReplacementWithParams(ErrorPage());
await _firebaseMessaging.requestPermission(
alert: true,
badge: true,
provisional: false,
sound: true,
);
String fbToken = await _firebaseMessaging.getToken();
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
if (message.data != null && message.data.containsKey('showInPageNotification')) {
numberOfNotifications++;
}
notifyListeners();
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
print('A new onMessageOpenedApp event was published!');
if (message.data != null && message.data.containsKey('job_id')) {
String jobId = message.data['job_id'];
String jobType = message.data['job_type'];
jobType = jobType.toLowerCase();
if (jobType == 'move') {
await goToJobDetail(jobId);
} else {
await goToEventDetail(jobId);
}
}
});
Anyone has a clue of why does this happens? Push notifications are working fine, it's the redirection the current ISSUE. Thanks!
Use FirebaseMessaging.instance.getInitialMessage() method to get messages
If App is Closed/Killed
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage message) {
print("FirebaseMessaging.getInitialMessage $message");
});
Try this and let me know.
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"
I want to connect my Flutter app to bluetooth device with flutter_blue library, and return a result (anything) when the connection is ON. But I don't understand how to do.
Here my code :
Future connect(BluetoothDevice device) async {
_btDevice = device;
StreamSubscription<BluetoothDeviceState> subscription;
subscription = device.state.listen((event) async {
if (event != BluetoothDeviceState.connected) {
await device.connect();
} else {
await device.discoverServices().then((value) => _initFeatures(value));
}
})
..onDone(() {
// Cascade
print("onDone");
});
subscription.asFuture();
//subscription.cancel();
}
And when I call this function with
await newDevice.connect(bluetoothDevice).then((value) => print('OK'));
OK is written before the real connection. _initFeatures if well call when the device is connected.
I try to use asFuture from StreamSubscription with onDone, but that change nothing.
Could you help me please ?
UPDATE 12/10
I've worked on another project for few monthes, and when I come back, I can't solve the problem, so I add the full code.
The concept is a class widget calls the connect future in other class and need to receipt the end of work.
Widget
Future<void> _connectDevice() async {
try {
widget.device.connect(widget.btDevice!).then((value) => _initValue());
} catch (e) {
print(e);
}
}
_initValue() is a method to create the rest of the screen
and the Future connect()
Future connect(BluetoothDevice device) async {
_btDevice = device;
StreamSubscription<BluetoothDeviceState> subscription;
subscription = device.state.listen((event) async {
if (event != BluetoothDeviceState.connected) {
await device.connect();
} else {
await device
.discoverServices()
.then((value) => _initFeatures(value))
.then((value) => print("OK"));
}
});
await subscription.asFuture();
await subscription.cancel();
}
What I'd like is the Future finishes when print("OK") is called, in order .then((value) => _initValue()); is called.
The problem is only this end. Maybe it's not the good way to implement this kind of solution.
Now I am develop in app purchase using this lib in flutter. After verify the receipt on the server side, I want to finish the purchase workflow. This is my code in flutter client side:
void _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList, Context<PayState> ctx) {
purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async {
if (purchaseDetails.status == PurchaseStatus.pending) {
RestLog.logger("PurchaseStatus pending..." + ctx.state.payModel.isAvailable.toString());
_showPendingUI(ctx);
} else {
if (purchaseDetails.status == PurchaseStatus.error) {
RestLog.logger("PurchaseStatus error");
_handleError(purchaseDetails.error!, ctx);
} else if (purchaseDetails.status == PurchaseStatus.restored) {
RestLog.logger("purchase successful trigger verify");
PayVerifyModel payVerifyModel = PayVerifyModel(orderId: purchaseDetails.purchaseID, receipt: purchaseDetails.verificationData.serverVerificationData);
int result = await Pay.verifyUserPay(payVerifyModel);
if(result == 0){
RestLog.logger("verify success:" + result.toString());
await InAppPurchase.instance.completePurchase(purchaseDetails);
}else{
RestLog.logger("verify failed:" + result.toString());
}
}else if(purchaseDetails.status == PurchaseStatus.purchased ){
RestLog.logger("purchaseDetails purchased:" + purchaseDetails.productID);
}
if (purchaseDetails.pendingCompletePurchase) {
await InAppPurchase.instance.completePurchase(purchaseDetails);
}
}
});
}
after verify success, I am using this code to finish the purchase:
await InAppPurchase.instance.completePurchase(purchaseDetails);
but it seems did not work. It still runs in verify workflow the next time enter the purchase page, am I missing something? what should I do to make it work? This function InAppPurchase.instance.completePurchase did not return any status so I could not if it execute success.
I have tried to wrap a try catch in the outer level if the InAppPurchase.instance.completePurchase(purchaseDetails) code run into issue.But there is no error output.
I just do not known the transaction of purchase finished success. what should I do to get the result of complete transaction?