How to send..........hreadStar - xamarin.forms

I have a tapPage with Viem model and i am making a toast from VM but i am getting an exception
TabMenuMyArticlesava.Lang.RuntimeException: Can't toast on a thread that has not called Looper.prepare()
I don't want to DisplayAlert, how else can i display an alert to user from MVVM? I found this
But i am not really sure how if that is not connected only to Xamarin.Android
new System.Threading.Thread(new ThreadStart(() =>
{
RunOnUiThread(() => { Toast.MakeText(ApplicationContext, "xxxxxx", ToastLength.Short).Show(); });
})).Start();

use MainThread
MainThread.BeginInvokeOnMainThread(() =>
{
Toast.MakeText(ApplicationContext, "xxxxxx", ToastLength.Short).Show();
});

Related

FirebaseMessaging.onMessageOpenedApp and FirebaseMessaging.instance.getInitialMessagenot working in firebase messaging flutter

I am using firebase messaging with local notifications but FirebaseMessaging.onMessageOpenedApp and FirebaseMessaging.instance .getInitialMessage is not working as I want to open the app on notification click.
Here is my code:
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
log("onMessageOpenedApp is fired");
await flutterLocalNotificationsPlugin.cancelAll();
LoginStorage storage = LoginStorage();
log("storage.getIsLogin() = ${storage.getIsLogin()}");
if (storage.getIsLogin() == "true") {
Get.off(() => ChatPage(
roomId: message.data["room_id"],
roomName: message.data["roomname"],
totalMsgs: "0",
roomType: message.data["room_type"],
));
} else {
Get.off(() => LoginPage());
}
log('A new onMessageOpenedApp event was published!');
});
Try this code
FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message){
if(message!=null){
log("onMessageOpenedApp is fired");
await flutterLocalNotificationsPlugin.cancelAll();
LoginStorage storage = LoginStorage();
log("storage.getIsLogin() = ${storage.getIsLogin()}");
if (storage.getIsLogin() == "true") {
Get.off(() => ChatPage(
roomId: message.data["room_id"],
roomName: message.data["roomname"],
totalMsgs: "0",
roomType: message.data["room_type"],
));
} else {
Get.off(() => LoginPage());
}
log('A new onMessageOpenedApp event was published!');
}
});
You wrote the perfect code, but this issue is not about the code. This happened because your app is in foreground when you fire the notification,
the app needs to be terminated or in the background at this time.
Also add following code it help when your app have a fresh start
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage message) {
//Navigate Here
});
Hope this helps you...

Firebase V9 does not give error in catch when offline

I want to set state in catch even if user offline but firebase V9 setDoc does not give anything in catch when user offline
For Example: in Authentication, if the user offline firebase gives (network error) in catch but in firestore "add document" no message from catch...
This is by design thanks to Firestore's Offline Behaviour (queued up to the right spot, but I do recommend watching in full).
The promise will resolve once the server has acknowledged the request. If the server is currently unavailable, that request is cached within the SDK and attempted as soon as a connection is restored. During this window, the Promise will be kept in its pending state because that's the state its actually in - pending. While the promise may not resolve, all your local realtime listeners and such will still fire off and your app will function as normal - just offline.
Dealing with this behaviour is an exercise for the developer. One way to approach this would be to use Promise.race() to implement your own offline-handling logic.
As a quick & dirty example, here's a setDocWithTimeout implementation:
const setDocWithTimeout = (ref, data, options) => {
const timeoutMS = options && options.timeout || 10000;
const setDocPromise = setDoc(ref, data);
return Promise.race([
setDocPromise.then(() => ({ timeout: false })),
new Promise((resolve, reject) => setTimeout(resolve, timeoutMS, { timeout: true, promise: setDocPromise }));
]);
}
which you can apply using:
try {
const result = await setDocWithTimeout(doc(db, "cities", "new-city-2"), data);
if (result.timeout) {
// offline? (could be poor connection too)
console.log("Document added to Firestore queue");
// dismiss any blocking UIs/loading bubbles
// tell user will be written to server later
await result.promise; // wait for write to complete as before
}
// online! (or back online)
console.log("Document written successfully!");
} catch (err) {
console.error(`error found! ${err}`);
}
Alternatively where an error is thrown:
const setDocWithTimeoutError = (ref, data, options) => {
const timeoutMS = options && options.timeout || 10000;
const setDocPromise = setDoc(ref, data);
return Promise.race([
setDocPromise,
new Promise((_, reject) => setTimeout(reject, timeoutMS, new Error("timeout"));
]);
}
which you can apply using:
try {
await setDocWithTimeoutError(doc(db, "cities", "new-city-2"), data);
console.log("Document written successfully!");
} catch (err) {
console.error(`error found! ${err}`);
}
works on web v9, see
docs from v8.
import { onLog } from 'firebase/app';
onLog((e) => {
const { level, message } = e;
if (level === 'warn') {
console.log('connection interruption after intial load was success:', message);
}
if (level === 'error') {
console.log('no connection on inital load:', message);
}
});

RNFirebase v6 Push Notifications are not coming both iOS&Android

I am trying to send notifications from firebase console to my react-native app
I followed the poor documentation here as much as I understand: https://invertase.io/oss/react-native-firebase/v6/messaging/quick-start
I installed #react-native-firebase/app and /messaging and here is my code in component:
componentDidMount() {
this.reqNotifications()
this.checkNotificationPermission()
}
reqNotifications() {
requestNotifications(['alert', 'badge', 'sound']).then(({status, settings}) => {
console.log('NOTIFICATION STATUS' + status)
});
}
async checkNotificationPermission() {
const enabled = await messaging().hasPermission();
if (enabled) {
console.log('APPROVED');
await messaging().registerForRemoteNotifications()
messaging().getToken().then(token => console.log('token: >> ' + token))
} else {
console.log('NOT APPROVED');
}
}
I am requesting permission via react-native-permissions and permission request is
working.
My Apple APNs are OK on Apple and Firebase console
And I am getting my token by getToken() method on the code
succesfully.
But I cant send anything to device from firebase; nothing happening on neither foreground nor background . I tried with-token test and also tried normal but no, nothing happens.
I added this code to componentDidMount:
messaging().onMessage(async remoteMessage => {
console.log('FCM Message Data:', remoteMessage.data);
});
As I understand this subscribes for cloud messages and when I send some cloud message notification from firebase-console, I should get console output; but nothing happens.
I dont know what am I missing but I think there is a big update on this package and most of docs are for previous version and I really stuck here thanks for assist
for rnfirebase.io V6
componentDidMount = async () => {
this.checkNotificationPermission();
await messaging().requestPermission({provisional: true});
await messaging().registerDeviceForRemoteMessages();
await this.getFCMToken();
if (Platform.OS === 'android') {
this.createAndroidNotificationChannel();
}
this.backgroundState();
this.foregroundState();
};
checkNotificationPermission = () => {
firebase
.messaging()
.hasPermission()
.then(enabled => {
if (!enabled) {
this.promptForNotificationPermission();
}
});
};
promptForNotificationPermission = () => {
firebase
.messaging()
.requestPermission({provisional: true})
.then(() => {
console.log('Permission granted.');
})
.catch(() => {
console.log('Permission rejected.');
});
};
createAndroidNotificationChannel() {
const channel = new firebase.notifications.Android.Channel(
'channelId',
'Push Notification',
firebase.notifications.Android.Importance.Max,
).setDescription('Turn on to receive push notification');
firebase.notifications().android.createChannel(channel);
}
foregroundState = () => {
const unsubscribe = messaging().onMessage(async notification => {
console.log('Message handled in the foregroundState!', notification);
});
return unsubscribe;
};
// Register background handler
backgroundState = () => {
messaging().setBackgroundMessageHandler(async notification => {
console.log('Message handled in the background!', notification);
});
};

Login page lets user get inside the app even if the authentication failed

I've made a simple app with phone authentication (sms).
My problem splits to two, the first part is that the verification code (sms) is always wrong somehow (I do get it, however it doesn't pass the confirmation), and the second part (as stated in the title) is that the user can still access the main activities even if authentication failed.
the function is invoked via a button.
the function is :
signIn(){
const appVerifier = this.recaptchaVerifier;
const phoneNumberString = "+972" + this.phoneNumber.substring(1,10);
firebase.auth().signInWithPhoneNumber(phoneNumberString, appVerifier)
.then( confirmationResult => {
// SMS sent. Prompt user to type the code from the message, then sign the
// user in with confirmationResult.confirm(code).
let prompt = this.alertCtrl.create({
title: 'Enter the Confirmation code',
inputs: [{ name: 'confirmationCode', placeholder: 'Confirmation Code' }],
buttons: [
{ text: 'Cancel',
handler: data => { console.log('Cancel clicked'); }
},
{ text: 'Send',
handler: data => {
confirmationResult.confirm(data.confirmationCode)
.then(function (result) {
// User signed in successfully.
this.uid = result.user.uid
this.addUser(this.fullName, this.uid);
console.log(result.user);
// ...
}).catch(function (error) {
console.log("Invalid code") // always getting here
});
}
}
]
});
prompt.present();
}).catch(function (error) {
console.log("SMS not sent")
});
}
UPDATE (app.component)
the decision is made in the constructor of app.component.ts
constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) {
var that = this
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
statusBar.styleDefault();
splashScreen.hide();
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
that.rootPage = TabsPage; // even though auth failed, he comes here
} else {
that.rootPage = LoginPage;
}
});
});
}
I dont see it in your code but anywhere you call a method to push the main App-Page. You only should show the main App-Page after User successfully logged in. If this dont work maybe the user comes inside of your app, because the Firebase function is asynchron.

Ionic2/Angular2 wait for SQLite database to open before querying

I'm using Ionic 2 (Angular 2) for a Hybrid app. I inject a shared provider into the page that will display data from my SQLite3 database and then proceed to load the data. However, on creation of my database provider opening the database takes some time (very little). My code (as of this moment) however does not wait for the database to be opened before querying, which obviously results in an error.
How can I structure my code that it will wait for the database to be opened in order to evade a crash?
The constructor of my database provider:
constructor(private platform: Platform) {
this.platform.ready().then(() => {
if(this.isOpen !== true) {
this.storage = new SQLite();
this.storage.openDatabase({name: "data.db", location: "default"}).then(() => {
this.isOpen = true;
this.storage.executeSql("CREATE TABLE IF NOT EXISTS people (id INTEGER PRIMARY KEY AUTOINCREMENT, firstname TEXT, lastname TEXT)", []);
});
}
});
console.log('Hello Database Provider');
This provider gets injected into the constructor of my page.
When the page (home page) is loaded it triggers an event that calls a load() function.
ionViewDidLoad() {
this.load();
console.log('Hello Home Page');
The load function:
public load() {
this.database.getPeople().then((result) => {
this.itemList = <Array<Object>> result;
}, (error) => {
console.log("LOAD ERROR: ", error);
});
I'm very much hoping someone can point me in the right direction :)
I've finally found a solution to my problem.
For starters I've added a function to my provider that checks if the database is loaded, if it isn't it proceeds to load it:
public openSQLiteDatabase() {
return new Promise((resolve, reject) => {
if(this.isOpen) {
console.log("DB IS OPEN");
resolve(this.isOpen);
}
else {
console.log("DB IS NOT OPEN");
this.platform.ready().then(() => {
this.storage.openDatabase({name: "data.db", location: "default"}).then(() => {
this.appsettings.openSQLiteDatabase().then(() => {
this.appsettings.getSettings().then((result) => {
let settings: Settings = <Settings> result;
this.selectedDataset = settings.selectedDataset;
this.isOpen = true;
resolve(this.isOpen);
});
});
}, (error) => {
reject(error);
});
});
}
});}
As this function returns a promise (JS Promises) it allows me to wait for the database to be opened before doing anything else (such as querying).
My function in the page-specific TypeScript file:
ionViewDidLoad() {
this.database.openSQLiteDatabase().then(() => {
this.loadDictionary();
});}
With code like this I never have problems with queries being performed before my database has been opened!

Resources