I have done the following in Swift:
let currentUser = Auth.auth().currentUser
currentUser?.getTokenForcingRefresh(true) {idToken, error in
if let error = error {
// Handle error
print("error (below)")
print(error)
return;
}
print("idToken = " + idToken!) // token looks like this: kpJhbGRiOiJSUzI1NiIsIntpZCI9Ijg0MjIuYzc3NTWkOWZmTjI3OBQxZTkyNTpkNWZjZjUwNzg2YTFmNGIifQ.eyJpc3MiOiJodHRwczovL3NlY3Vy... (it's really long)
//..do stuff with token
}
I am now trying to do the equivalent for Android. The firebase documentation touches on the topic but does not explain getting the token extensively. I have tried the following:
Log.d(TAG, user.getIdToken(true));
However, this gives me the following error when I attempt to authenticate this alone on my backend server:
Error: Decoding Firebase ID token failed. Make sure you passed the
entire string JWT which represents an ID token. See
https://firebase.google.com/docs/auth/admin/verify-id-tokens for
details on how to retrieve an ID token.
at FirebaseAuthError.Error (native)
at FirebaseAuthError.FirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:25:28)
at new FirebaseAuthError (/user_code/node_modules/firebase-admin/lib/utils/error.js:90:23)
at FirebaseTokenGenerator.verifyIdToken (/user_code/node_modules/firebase-admin/lib/auth/token-generator.js:155:35)
at Auth.verifyIdToken (/user_code/node_modules/firebase-admin/lib/auth/auth.js:104:37)
at admin.database.ref.child.child.child.child.child.child.orderByChild.once.then.snapshot
(/user_code/index.js:1430:22)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
I believe this is because there needs to be an onSuccessListener but am not sure, nor have had success implementing it as follows:
user.getIdToken(true).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Log.d(TAG, "onSuccess: taskSnapshot = " + taskSnapshot);
}
});
Your second approach is close, you just need to use <GetTokenResult> instead of <UploadTask.TaskSnapshot> as that is for uploading images using Firebase Storage.
Try this:
user.getIdToken(true).addOnSuccessListener(new OnSuccessListener<GetTokenResult>() {
#Override
public void onSuccess(GetTokenResult result) {
String idToken = result.getToken();
//Do whatever
Log.d(TAG, "GetTokenResult result = " + idToken);
}
});
You can get the user token like below code
FirebaseAuth mAuth = FirebaseAuth.getInstance();
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
information
FirebaseUser user = Objects.requireNonNull(task.getResult()).getUser();
assert user != null;
user.getIdToken(true).addOnSuccessListener(result -> {
String idToken = result.getToken();
//Do whatever
Log.d(TAG, "GetTokenResult result = " + idToken);
});
} else {
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
Toast.makeText(getApplicationContext(), "Your code is not correct!", Toast.LENGTH_SHORT).show();
code.");
}
}
}
});
}
Related
I have an android app that I created using the Login Activity Template (New Project -> Login Activity -> Java, API 26), which created a scaffold with the data and ui.login packages. I'm trying to implement Firebase auth with email & password.
Following the docs and also understanding the function of each class, I started touching the class LoginDataSource (from data package) and adding the following code:
public class LoginDataSource {
private static final String TAG = "EmailPassword";
private FirebaseAuth mAuth;
public Result<LoggedInUser> login(String username, String password) {
// Initialize Firebase Auth
mAuth = FirebaseAuth.getInstance();
try {
mAuth.signInWithEmailAndPassword(username, password)
.addOnCompleteListener(LoginActivity.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
Log.d(TAG, "signInWithEmail:success");
//FirebaseUser user = mAuth.getCurrentUser();
//updateUI(user);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithEmail:failure", task.getException());
//Toast.makeText(LoginActivity.this, "Authentication failed.", Toast.LENGTH_SHORT).show();
//updateUI(null);
}
}
});
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
Log.d(TAG,"user display name: " + user.getDisplayName());
LoggedInUser appUser = new LoggedInUser( user.getUid(), user.getDisplayName());
return new Result.Success<>(appUser);
} catch (Exception e) {
return new Result.Error(new IOException("Error logging in", e));
}
As I understand, the addOnCompleteListener expects my activity, which lives in the ui.login package, so when I try to use it, I get the error:
'com.example.appname.ui.login.LoginActivity' is not an enclosing class
When I use the this keyword, I get the error:
Cannot resolve method 'addOnCompleteListener(com.samuelkb.aipuzzles.data.LoginDataSource, anonymous com.google.android.gms.tasks.OnCompleteListener<com.google.firebase.auth.AuthResult>)'
It makes sense to keep the logic in my data package and not in my UI package.
I'm unsure how I should implement Firebase in my app, so any guidance is welcome.
I'm new to NoSQL databases, but I'm attempting to use Firestore with an Android mobile application I'm developing.
I can write to the DB without any issues, but I can't read data. See code below:
DocumentReference docRef = db.collection("users").document("abc#gmail.com");
docRef.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
User userFromDB = documentSnapshot.toObject(User.class);
}
});
When I was debugging, program execution didn't enter the 'onSuccess' function.
The code I'm using is based off the documentation (Get Data with Cloud Firestore - Custom Objects). I made sure that the 'User' fields in my code match the ones in the DB, and they all have 'get' methods.
Also, these are my rules:
match /{document=**} {
allow read, write: if true
}
I've been stuck on this for a while, any help would be highly appreciated.
The onSuccessListener is for write actions to the database. For getting data you need to use the onCompletedListener as shown in the official documentation:
DocumentReference docRef = db.collection("users").document("abc#gmail.com");
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
Log.d(TAG, "DocumentSnapshot data: " + document.getData());
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
}
});
I am trying to make a function that checks if a username is taken or if it is available, how I have it in firestore is that the UniqueID is the username and not a field. This is the function:
private boolean checkUsernameValidity(String enteredUsername) {
/**
* Create code for querying through firestore DB for enteredUsername
*/
final boolean[] usernameAvailable = {true};
String USERTAG = "User documents";
Log.d("Entered Username: ", enteredUsername);
DocumentReference userDocRef = users.document(enteredUsername);
userDocRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
Log.d(USERTAG, "DocumentSnapshot data: " + document.getData());
Log.d("Warning", "Uh oh username is taken");
usernameAvailable[0] = false;
Toast.makeText(CreateAccount.this,
"This username is taken! Please enter a different username",
Toast.LENGTH_SHORT)
.show();
} else {
Log.d(USERTAG, "No such document, This Username is available");
}
} else {
Log.d(USERTAG, "get failed with ", task.getException());
}
}
});
/**
* If there was a user with entered username found already;
*/
if(!usernameAvailable[0]) {
return false;
}
if (enteredUsername.length() < 5) {
Toast.makeText(CreateAccount.this, "This username is too short",
Toast.LENGTH_SHORT)
.show();
return false;
}
Log.d("Status", "All Good!");
return true;
}
The function returns true according to the debugger before the usernameAvailable[0] is changed. Picture here:
In the picture, the Log of a successful status is printed before the log that says that the username was taken. I'm guessing that the function needs to be an asynchronous or something along those lines but I'm not 100% on creating asynchronous methods. How do I make it so that my function retrieves the document if it exists and sets my usernameAvailable[0] to false inside the get document function before going through the rest of the checkUsernameValidity method.
P.S.
usernameAvailable is a final array of booleans instead of just a boolean because it is accessed inside inner class
What you said is on the right track. The get() call you're making on the DocumentReference internally starts an asynchronous task which defers the network request to a background thread. If this wasn't the case then you would have a non-responsive app for the time it takes to receive the result. So instead of receiving the result synchoronously, in your code you attach an OnCompleteListener<*> which Firebase uses to call your onChanged method once the request is complete so that you can handle the result.
For a simple solution you can implement some sort of callback into checkUsernameValidity to process the result from wherever you are calling from. An implementation would look something like this:
interface Callback {
void onResult(boolean valid);
}
void checkUsernameValidity(Callback callback) {
userDocRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
callback.onResult(true);
}
});
}
I would recommend doing some research on asynchronicity and the basic concept of callbacks.
I'm new to Android development ... ;-)
I need to know how to read a specific document I saved to Firestore, without having to copy the "documentPath" manually from the Cloud Firestore Console!
How do you do this automatically?
Next, I put some of the code where the documentPath is that I need to configure:
DocumentReference user = mFirestore.collection("Users").document(idUsers).collection("Companies").document(**"documentPath"**)
link to the image:
Company that I registered now and that I wish to need to show the user automatically
link to the document:
Document fields
I'm testing the following class:
private void ReadSingleEmpresa() {
FirebaseAuth autenticacao = ConfiguracaoFirebase.getFirebaseAutenticacao();
String idUsuario = Base64Custom.codificarBase64(autenticacao.getCurrentUser().getEmail());
DocumentReference user = mFirestore.collection("Users").document(idUsuario).collection("Companies").document("gaSpr59pbeMmO9UpFxQQ");//document path
user.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
Log.d("ler doc", "DocumentSnapshot data: " + document.getData());
StringBuilder fields = new StringBuilder("");
//Some document fields
fields.append("Company name: ").append(document.get("nomeEmpresa"));
fields.append("\nEmail: ").append(document.get("emailRepresentante"));
fields.append("\nTelephone number: ").append(document.get("telefoneRepresentante"));
txtEmpresa.setText(fields.toString());
} else {
Log.d("ler doc", "No such document");
}
} else {
Log.d("ler doc", "get failed with ", task.getException());
}
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
}
This is the result:
Result of reading some document fields
It works but I do not know how to get the document I just registered among several. I only get it when I manually copy the document ID ...
I can't read data from the firestore database. I can write to it although sometimes the data appears on firestore console (very) late.
And i can Delete a record although it is only delete (from firestore console) when i do a write.
It is some stupid simple error that i make, but i can't find it. Buffers? Setting? i don't know :-(
It looks like firestore is delayed responding, it never reach the line with:
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful())
....
Below the logcat lines...
I am using java/android app
Thanks in advance for any help
,, E/PlayMissionActivity: sleep 2 <==
,, E/PlayMissionActivity: sleep 2 <==
,, W/Firestore: (0.6.6-dev) [OnlineStateTracker]: Could not reach Firestore backend.
,, E/PlayMissionActivity: sleep 2 <==
My Code (just a copy of the samples)
public class MyPlay extends AppCompatActivity {
FirebaseFirestore dbRef = null;
protected void onCreate(Bundle savedInstanceState) {
{
initDB();
getDocument();
int q=0;
while (q<10) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
q += 1;
Log.e(LOG_TAG, "sleep 2 " + "<==");
}
}
public void initDB() {
dbRef = FirebaseFirestore.getInstance();
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder()
.setTimestampsInSnapshotsEnabled(true)
.build();
dbRef.setFirestoreSettings(settings);
}
public void getDocument() {
DocumentReference docRef = dbRef.collection("users").document("123");
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
Log.d(TAG, "----------------------------> DocumentSnapshot data: " + document.getData());
} else {
Log.d(TAG, "----------------------------> No such document");
}
} else {
Log.d(TAG, "----------------------------> get failed with ", task.getException());
}
}
});
}
}
app/build.gradle:
compile 'com.google.firebase:firebase-core:16.0.1'
compile 'com.google.firebase:firebase-firestore:17.0.2'
compile 'com.google.code.gson:gson:2.8.4'
Firestore rules:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
Firestore data:
users/123/born=1815
users/123/first="Ada"
users/123/last="Lovelace"
Solved it, it was indeed fundamental.
Basically i didn't understand the concept of threads, events etc.
When a thread (event) is running, the thread that is reading firestore db is waiting for finishing the main thread. (Pseudo code, when the onCreate is finished)
Probably someone can explain it better i am just an old amature
So what isn't working (pseudo code android activity):
onCreat{
object = readFirestore
print object.id <== this line will give you an error
}
readFirestore() {
read id
onSucces
object = document.toObject()
}
So what's working fine:
onCreat{
object = readFirestore
}
readFirestore() {
read id
onSucces
object = document.toObject()
print object.id <== this line will print your result
}