hey I try to check if the phone number that the user is insert is exist in my firebase auth
(LoginActivity)
I try this way
String phoneNumber = "+1234567890";
mAuth.fetchSignInMethodsForEmail(phoneNumber)
.addOnCompleteListener(new OnCompleteListener<SignInMethodQueryResult>() {
#Override
public void onComplete(#NonNull Task<SignInMethodQueryResult> task) {
if (task.isSuccessful()) {
SignInMethodQueryResult result = task.getResult();
List<String> signInMethods = result.getSignInMethods();
if (signInMethods.contains("phone")) {
// Phone number is already in use in Firebase Auth
} else {
// Phone number is not in use in Firebase Auth
}
} else {
// An error occurred
}
}
});
and when it comes to this function the debugger jump for it and don't doing anything
.addOnCompleteListener(new OnCompleteListener() {
I try with firebase SDK admin and it also doesn't work
can anyone know how to solve this?
There are three ways in which you can solve this problem. Two options are on the client, using Java code, and another one using Admin SDK.
Solution 1
When a user signs in for the first time into your app, then save user data in Firestore using a schema that looks like this:
db
|
--- users (collection)
|
--- $uid (document)
|
--- phoneNumber: "+1234567890"
To check if a user with the +1234567890 already exists, then you have to perform a query that looks like this in Java:
FirebaseFirestore db = FirebaseFirestore.getInstance();
Query queryPhoneNumber = db.collection("users").whereEqualTo("phoneNumber", "+1234567890");
queryPhoneNumber.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
if (document.exists()) {
Log.d(TAG, "User already exists.");
} else {
Log.d(TAG, "User doesn't exist.");
}
}
} else {
Log.d(TAG, task.getException().getMessage()); //Never ignore potential errors!
}
}
});
Solution 2
Another more elegant and easy solution would be to use Query#count() method:
queryPhoneNumber.count();
If the result is > 0 then it means that the user already exists, otherwise it doesn't exist.
Solution 3
The last solution would be to use a Callable Cloud Function that can be called from your app. Because we use the Admin SDK in Cloud Functions you can call the getUserByPhoneNumber() method. In code it will look like this:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.checkPhoneNumberExists = functions.https.onCall((data, context) => {
return admin.auth()
.getUserByPhoneNumber(data.phoneNumber)
.then((userRecord) => {
return { phoneNumber: true }
})
.catch((error) => {
throw new functions.https.HttpsError('invalid-argument', "phoneNumber doesn't exist");
});
});
Using this approach, there is no need to save user data in Firestore. The Admin SDK will directly query the FirebaseAuth service.
Related
I am working on an application where anyone can list their products. I am storing data in Firebase Firestore in nested collection Now I want to retrieve that data and show that on my home screen. Now the data is showing but the problem is that it is showing only when I am login in with that same number through that I list that data into Firebase but when I try to log in with another number the data doesn't show. I want that to show to everyone who logged in to the app. Basically My app is just like OLX where anyone can list anything which shows to everyone.
MY CODE TO RETRIEVE THE DATA
//CODE TO GET CURRENT ID OR USER
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
//CODE TO GET THE DATA FROM FIREBASE
DocumentReference uidRef = firebaseFirestore.collection("listing_details").document(uid);
CollectionReference roomDetailsRef = uidRef.collection("room_details");
String doc_id = roomDetailsRef.document().getId();
roomDetailsRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
if (document != null) {
RoomsDetails obj = document.toObject(RoomsDetails.class);
roomsDetails.add(obj);
}
}
roomsAdapter.notifyDataSetChanged();
} else {
Log.d(TAG, task.getException().getMessage()); //Never ignore potential errors!
}
}
});
You have .document(uid) in your path where UID is User ID of user currently logged in. When you use another phone number, that's a different user.
If you want to fetch room_details documents from all listing_details documents then you can use Collection Group queries like this:
db.collectionGroup("room_details").get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
// ... iterate over all docs and render
}
});
This question already has an answer here:
How to check a certain data already exists in firestore or not
(1 answer)
Closed 2 years ago.
I need to return the value that is retrieved from the document snapshot. I can see the correct value in the LOG but since it is out of scope, and only in onComplete, I cannot access it.
Can you please help?
public String getCoEmail() {
coUserReference = db.collection("users").document(email);
coUserReference.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
String coEmail = document.getString("coEmail");
Log.d(TAG, "DocumentSnapshot data: " + document.getString("coEmail"));
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
}
});
return coEmail;
}
Return it after Log.d:
Log.d(TAG, "DocumentSnapshot data: " + document.getString("coEmail"));
return document.getString("coEmail");
Data is loaded from Firestore (and most cloud APIs) asynchronously, and your main code continues while this is going on. This means that your return coEmail now runs before the coEmail = document.getString("coEmail"), even if you were to fix the scoping problem.
The solution is to make sure all code that needs the data is inside the onComplete method, or called from there. See for a longer example of this: How to check a certain data already exists in firestore or not, or Firestore OncompleteListener
I've looked for multiple solutions here but couldn't find anything specific to my situation and therefore am posting a question here while I still continue looking for a solution. I'm fairly new to Firestore still and their guide/docs are still unclear.
My phone application has a system to get a user to enter in a name. This name is to be used to traverse the Firestore database and if the name exists as a field for one of the users, then the method must return a boolean of true.
This query is to be triggered by a "continue button" which is in my main activity as shown below:
//Authenticate user and proceed to next activity
continueBtn = (Button) findViewById(R.id.continue_btn);
continueBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//On click create a db reference and perform a query on it to find current user
//and authenticate it.
CollectionReference myRef = database.collection("users");
Query findNameQ = myRef.whereEqualTo("name", mUserName);
authenticateUser(findNameQ, mUserName);//I need to pass to this method a variable 'findNameQ' which can be used to validate the existence of a user.
//mUserName is the name it's looking for.
}
});
Once the query is run then it runs the authenticateUser method which basically validates the existence of the user and creates a new one if the user doesn't exist. Here's the method:
private void authenticateUser(Query findNameQ, String mUserName)
{
//Read from database and check if user exists
//if current users name matches to one in database then set userExists to true.
if (findNameQ != null)
{
userExists = true;
Toast.makeText(this, "User exists!", Toast.LENGTH_SHORT).show();
}
Toast.makeText(this, "User doesn't exist!", Toast.LENGTH_SHORT).show();
}
I'd like to use if (findNameQ != false) instead of null, how do I make it so my findNameQ variable is a boolean and not a query object?
In order to know if a user name exists in Firestore database, you need to use a get() call. Just creating a Query object will not provide you much. Beside that, if you are checking findNameQ != null it will always evaluate to true because findNameQ object is created and will never be null. So to solve this, please use the following lines of code:
productsRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
if (document.exists()) {
authenticateUser(findNameQ, mUserName);
}
}
}
}
});
Please also note, that using a addSnapshotListener will not help you because it will attach a listener to get data in real time but this is not what you need. You need to get the data only once.
You can use a boolean variable as
boolean nameFound = false;
Now, attach a snapshot listener to your query to check whether the name exists or not:
findNameQ.addSnapshotListener(new EventListener<QuerySnapshot>(){
#Override
public void onEvent(QuerySnapshot queryDocumentSnapshots, FirebaseFirestoreException e) {
for (DocumentSnapshot ds: queryDocumentSnapshots){
if (ds!=null && ds.exists()){
Toast.makeText(RegisterActivity.this, "Username Exists!", Toast.LENGTH_SHORT).show();
nameFound = true;
}
}
}
});
else the default value of nameFound that is false will be used. Now, use can use if else to call your authentication method based on the value of nameFound.
I'm trying to create an app that only uses phone authorization from firebase. Since the login/signup is done through same process, which is verifying the sent code. How can i check if a user already exists in firebase? I need this to show them appropriate User Interface.
Right now, the only way to do that is via the Firebase Admin SDK. There is an API to lookup a user by phone number.
admin.auth().getUserByPhoneNumber(phoneNumber)
.then(function(userRecord) {
// User found.
})
.catch(function(error) {
console.log("Error fetching user data:", error);
});
You can check whether user already exist in Firebase by compare it metadata. see code example:
PhoneAuthCredential phoneAuthCredential = PhoneAuthProvider.getCredential(verificationId, smsCode);
FirebaseAuth.getInstance().signInWithCredential(phoneAuthCredential).addOnCompleteListener(PhoneLoginEnterCodeActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task){
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
FirebaseUser user = task.getResult().getUser();
long creationTimestamp = user.getMetadata().getCreationTimestamp();
long lastSignInTimestamp = user.getMetadata().getLastSignInTimestamp();
if (creationTimestamp == lastSignInTimestamp) {
//do create new user
} else {
//user is exists, just do login
}
} else {
// Sign in failed, display a message and update the UI
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
// The verification code entered was invalid
}
}
}
});
There is an additionalUserInfo property that you can query like so (Kotlin):
firebaseAuth.signInWithCredential(credential)
.addOnCompleteListener {
it.result.additionalUserInfo?.isNewUser // new user check
}
If I borrow #Eltanan Derek code:
PhoneAuthCredential phoneAuthCredential = PhoneAuthProvider.getCredential(verificationId, smsCode);
FirebaseAuth.getInstance().signInWithCredential(phoneAuthCredential).addOnCompleteListener(PhoneLoginEnterCodeActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task){
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
FirebaseUser user = task.getResult().getUser().getAdditionalUserInfo();
if (user.isNewUser()) {
//do create new user
} else {
//user is exists, just do login
}
} else {
// Sign in failed, display a message and update the UI
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
// The verification code entered was invalid
}
}
}
});
Is this script wrong, because the data I receive is null while I've added data on the Cloud Firestore. I do not use RecyclerView because I only need one data only.
This is the script:
private void getCustomer(){
firestoreDB.collection("customer")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
customers = new ArrayList<>();
for (DocumentSnapshot doc : task.getResult()) {
Customer customer = doc.toObject(Customer.class);
customer.setId_customer(doc.getId());
customers.add(customer);
}
} else {
// Log.d(TAG, "Error getting documents: ", task.getException());
}
}
});
firestoreListener = firestoreDB.collection("customer")
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
if (e != null) {
// Log.e(TAG, "Listen failed!", e);
return;
}
customers = new ArrayList<>();
for (DocumentSnapshot doc : documentSnapshots) {
Customer customer = doc.toObject(Customer.class);
customer.setId_customer(doc.getId());
customers.add(customer);
}
}
});
id_customer = customers.get(0).getId_customer();
}
and this is my firestore:
You cannot use something now that hasn't been loaded yet. With other words, you cannot simply use the following line of code:
id_customer = customers.get(0).getId_customer();
Outside the onSuccess() method because it will always be null due the asynchronous behaviour of this method. This means that by the time you are trying to use the id_customer variable outside that method, the data hasn't finished loading yet from the database and that's why is not accessible.
A quick solve for this problem would be to use that result only inside the onSuccess() method, or if you want to use it outside, I recommend you see the last part of my anwser from this post in which I have exaplined how it can be done using a custom callback. You can also take a look at this video for a better understanding.