android firebase Remote config: device does not receive test variant - android

I cannot get my Android device to receive a test variant during the AB experiment.
What i did
In Firebase admin panel, I created a variable with this value:
And created an AB test with three variants:
Then I got an instance token as per docs:
FirebaseInstallations.getInstance().getToken(/* forceRefresh */true)
.addOnCompleteListener(new OnCompleteListener<InstallationTokenResult>() {
#Override
public void onComplete(#NonNull Task<InstallationTokenResult> task) {
if (task.isSuccessful() && task.getResult() != null) {
Log.d("Installations", "Installation auth token: " + task.getResult().getToken());
promise.resolve(task.getResult().getToken());
} else {
Log.e("Installations", "Unable to get Installation auth token");
}
}
});
and added it to my test devices list:
What happened
However, after rebooting the app (I also cleaned the cache and force-stopped it just in case it cached something) it still receives the original default value:
...
Map<String, Object> responseMap = new HashMap<>(2);
responseMap.put("result", result);
responseMap.put("constants", module.getConstantsForApp(FirebaseApp.DEFAULT_APP_NAME));
Log.d("REMOTECONFIG", responseMap.toString());
...
in the logs:
10-04 10:25:12.886 16964 16964 D REMOTECONFIG: {result=true, constants={minimumFetchInterval=43200, fetchTimeout=60, values={testValue=Bundle[{source=remote, value=somedefault}]}, lastFetchTime=1601796312020, lastFetchStatus=success}}
Why is that? what am I missing? I doublechecked my token, verified it with jwt.io, it is valid and not expired.

Related

Unknown field "a" appears in firestore when saving fcm token to database

I am grabbing the android device token and saving it to firestore. This works in most of the cases totally fine. Now I encountered a device where it does not work. Oddly enough I end up with attributes in firestore that my model does not reflect and I do not understand where those attributes and their values come from.
This is my method to retrieve the token:
public static void updateToken(String userId, FcmToken.Action action) {
if (StringUtils.checkNull(userId)) return;
//FCM
FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> {
if (!task.isSuccessful()) {
Log.w(TAG, "Could not get firebase token. ", task.getException());
return;
}
String token = task.getResult();
Log.i(TAG, "[FCM TOKEN]: " + token);
//Do not ask firebase to write an existing token again,
//this only creates traffic and costs but does not change the database
String storedToken = FcmProvider.loadToken(false);
if (StringUtils.checkNull(storedToken) || !token.equals(storedToken) || action == FcmToken.Action.DELETE) {
FcmToken fcmToken = new FcmToken(token, userId, action);
FcmRepo.getInstance().setToken(fcmToken, documentId -> {
Log.d(TAG, "Token " + action + " successfully");
FcmProvider.saveToken(token);
}, e -> {
Log.d(TAG, "Failed to " + action + " token. " + e);
});
} else {
Log.d(TAG, "Stored token is identical. No update needed");
}
});
}
This is the FcmToken class (And I assume the way I use the field values here are the issue, yet I do not understand the outcome)
#Getter
#Setter
#IgnoreExtraProperties
public class FcmToken {
private String userId;
private FieldValue fcmToken;
#ServerTimestamp
private Date ut;
public enum Action {SET, DELETE}
public FcmToken(String fcmToken, String userId, Action action) {
this.userId = userId;
if (action == Action.SET) this.fcmToken = FieldValue.arrayUnion(fcmToken);
else if (action == Action.DELETE) this.fcmToken = FieldValue.arrayRemove(fcmToken);
}
}
For completness this is the method I use to set the token:
public void setToken(#NonNull FcmToken fcmToken, #Nullable OnSetSuccessListener callbackSuccess, #Nullable OnFailureListener callbackFailure) {
getFcmRef().document(fcmToken.getUserId()).set(fcmToken, SetOptions.merge()).addOnCompleteListener(task ->...);
}
Now this is what ends up in my firestore for that user only:
This HAS to to come from the app itself. There is no other way this document could have been created:
If I use another device or the emulator the result looks like expected. Where does the "a" field come from? Why is it assigned to userId and why is there no fcmToken field?
The problem is, that I do not have physical access to the phone that produces this behaviour (Samsung S21 Ultra, Android 12). I need to debug this without having access to the log outputs.
But I know that the task comes back successfully (I used another version to save the error in the token field and there was none).
Any ideas?
This typically means that you didn't configure ProGuard correctly, and it's minifying the classes that you're writing to the database.
You'll need to prevent ProGuard from modifying the classes that you use to interact with the database. See the Firebase documentation on configuring ProGuard (the link is for the Realtime Database, but the same applies to Firestore), or one of these previous questions about configuring ProGuard for Firebase.

FirebaseRemoteConfig.fetchAndActivate() fails with 'TOO_MANY_REGISTRATIONS' for some users

My code uses Remote Config to check for app updates as follows:
ForceUpdateChecker.with(this).onUpdateNeeded(this).check();
final FirebaseRemoteConfig firebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
// set in-app defaults
Map<String, Object> remoteConfigDefaults = new HashMap();
remoteConfigDefaults.put(ForceUpdateChecker.KEY_UPDATE_REQUIRED, false);
remoteConfigDefaults.put(ForceUpdateChecker.KEY_CURRENT_VERSION, "2.00.229");
remoteConfigDefaults.put(ForceUpdateChecker.KEY_UPDATE_URL,
"https://play.google.com/store/apps/details?id=com.chiaramail.pento");
firebaseRemoteConfig.setDefaultsAsync(remoteConfigDefaults);
firebaseRemoteConfig.fetchAndActivate() // fetch config from server and activate
.addOnCompleteListener(new OnCompleteListener<Boolean>() {
#Override
public void onComplete(#NonNull Task<Boolean> task) {
if (task.isSuccessful()) {
Log.d(TAG, "FirebaseRemoteConfig fetched");
} else {
Log.d(TAG, "FirebaseRemoteConfig error:" + task.getResult());
}
}
});
Since I've updated the release containing this code, several users have crashed with the result 'TOO_MANY_REGISTRATIONS'. I believe I've looked at all the SO posts that relate to this problem, but none of them are using fetchAndActivate(). Also, I only have about 1200 users at this point, so hopefully the number of fetches isn't the problem; besides, as I understand it, Remote Config was built to push changes out to one's entire user base, so 1200 users (perhaps up to 6000 devices, max) should not be a problem.

Unity - SignInWithCredentialAsync causes internal error when using Firebase with Facebook Login

I am a Unity programmer and I am using Firebase to manage user accounts. I tried to set up Facebook Login. No problems with the Facebook sdk and I can log in successfully. However, when the credential returned by Facebook sdk is used as a parameter of FirebaseAuth.DefaultInstance.SignInWithCredentialAsync, it returns internal error.
And here is my code:
void authCallBack(IResult result) {
if (result.Error != null) {
Debug.Log(result.Error);
}
else {
if (FB.IsLoggedIn) {
Debug.Log("Log in successfully.");
AccessToken token = AccessToken.CurrentAccessToken;
Credential credential = FacebookAuthProvider.GetCredential(token.TokenString);
accessToken(credential);
}
else
Debug.Log("not logged in");
}
}
public void accessToken(Credential firebaseResult) {
FirebaseAuth auth = FirebaseAuth.DefaultInstance;
Debug.Log("Auth CurrentUser: " + FirebaseAuth.DefaultInstance.CurrentUser);
if (!FB.IsLoggedIn){
return;
}
if (auth.CurrentUser != null && !string.IsNullOrEmpty(auth.CurrentUser.UserId)){
Debug.Log("CurrentUser ID: " + auth.CurrentUser.UserId);
auth.CurrentUser.LinkAndRetrieveDataWithCredentialAsync(firebaseResult).ContinueWith(task =>
{
if (task.IsCanceled || task.IsFaulted)
{
Debug.LogError("LinkWithCredentialAsync encountered an error: " + task.Exception);
// TODO: Show error message to player
return;
}
FirebaseUser newUser = task.Result.User;
Debug.LogFormat("Credentials successfully linked to Firebase user: {0} ({1})",
newUser.DisplayName, newUser.UserId);
});
} else {
auth.SignInWithCredentialAsync(firebaseResult).ContinueWith(task =>
{
if (task.IsCanceled || task.IsFaulted) {
Debug.LogError("SignInWithCredentialAsync encountered an error: " + task.Exception.InnerExceptions[0].Message);
// TODO: Show error message to player
return;
}
FirebaseUser newUser = task.Result;
Debug.LogFormat("Credentials successfully created Firebase user: {0} ({1})",
newUser.DisplayName, newUser.UserId);
});
}
}
More details in VS Debugging:
When I test it on my Android device, it comes out an error message g_methods_cached only.
Can anyone help?
P.S. Here is another question asked yesterday and I don't know if it is relevant.
FirebaseAuthWebException not found. Please verify the AAR
Oh, I have made a silly mistake!
In the Facebook Developer page, there is the App Secret in Setting > Basic. And it has to be added into Firebase Console with the App ID. No problem right now. And then......
I just copied the App Secret without showing and pasted into Firebase Console.
Which means I have set 8 black dots (●●●●●●●●) as my App Secret in my Firebase Console. I know it is too silly. But just in case there is someone careless like me.

The Facebook login doesn't work anymore since I upgraded the Firebase app to the new Console (only)

I had a working app with Facebook & Email Login feature, since I upgrade the Firebase console (only, the sdk has not been update).
The app release before the Firebase 3.0 was working before, but it is not anymore able to sign/log with Facebook after the console has been upgraded.
What I have done:
1 - Upgraded the Firebase console
Because of Firebase & Facebook console update, I also had to put the Oauth Callback to the Facebook App
2 - Pasted the Firebase Facebook OAuth Callback to the Facebook console (before it was void) `https://xxx.firebaseapp.com/__/auth/handler``
The Exception:
The firebase Auth listener trigger a Firebase Error :
Invalid authentication credentials provided. and Facebook :
{"providerErrorInfo":{"code":400,"message":"Unsuccessful debug_token
response from Facebook: {\"error\":{\"message\":\"(#100) You must
provide an app access token or a user access token that is an owner or
developer of the
app\",\"type\":\"OAuthException\",\"code\":100,\"fbtrace_id\":\"DG4lLRJHFBS\"}}"}}
The FirebaseError Code:
In the decompiled code of the FirebaseAndroidSdk, the error object is:
0 = {java.util.LinkedHashMap$LinkedEntry#22680} "code" ->
"INVALID_CREDENTIALS"
1 = {java.util.LinkedHashMap$LinkedEntry#22681}
"message" -> "Invalid authentication credentials provided."
2 = {java.util.LinkedHashMap$LinkedEntry#22682} "details" ->
"{"providerErrorInfo":{"code":400,"message":"Unsuccessful debug_token
response from Facebook: {\"error\":{\"message\":\"(#100) You must
provide an app access token or a user access token that is an owner or
developer of the app\",\"type\":\"OAuthException\",\"code\":100,\"fbtrace_id\":\"BtB3JF2qmku\"}}"}}"
with the decompiled code:
private void makeAuthenticationRequest(String urlPath, Map<String, String> params, AuthResultHandler handler) {
final AuthenticationManager.AuthAttempt attempt = this.newAuthAttempt(handler);
this.makeRequest(urlPath, HttpRequestType.GET, params, Collections.emptyMap(), new RequestHandler() {
public void onResult(Map<String, Object> result) {
Object errorResponse = result.get("error");
String token = (String)Utilities.getOrNull(result, "token", String.class);
if(errorResponse == null && token != null) {
if(!AuthenticationManager.this.attemptHasBeenPreempted(attempt)) {
AuthenticationManager.this.authWithCredential(token, result, attempt);
}
} else {
FirebaseError error = AuthenticationManager.this.decodeErrorResponse(errorResponse);
AuthenticationManager.this.fireAuthErrorIfNotPreempted(error, attempt);
}
}
public void onError(IOException e) {
FirebaseError error = new FirebaseError(-24, "There was an exception while connecting to the authentication server: " + e.getLocalizedMessage());
AuthenticationManager.this.fireAuthErrorIfNotPreempted(error, attempt);
}
});
}
At AuthListener level, the firebaseError code : -20
https://www.firebase.com/docs/java-api/javadoc/com/firebase/client/FirebaseError.html
The specified authentication credentials are invalid.
The Facebook Error Code:
code 400
Nothing relevant found here : https://developers.facebook.com/docs/graph-api/using-graph-api/#errors
The code for Authing:
public void authWithFirebase(final String provider, Map<String, String> options) {
if (options.containsKey(AUTH_OPTIONS_ERROR)) {
EventBus.getDefault().post(new MessageToDisplayEvent(options.get(AUTH_OPTIONS_ERROR), true));
} else {
if (provider.equalsIgnoreCase(AUTH_PROVIDER_TWITTER)) {
// if the provider is twitter, we must pass in additional options, so use the options endpoint
ref.authWithOAuthToken(provider, options, new AuthResultHandler(provider));
} else {
// if the provider is not twitter, we just need to pass in the oauth_token
ref.authWithOAuthToken(provider, options.get(AUTH_OPTIONS_TOKEN), new AuthResultHandler(provider));
}
}
}
TOKEN Validity:
From the code above, the Token is confirmed valid since :
https://graph.facebook.com/app?access_token=%7Byour_access_token%7D return a valid JSON
And the Facebook Tool AccessToken https://developers.facebook.com/tools/debug/accesstoken return a still valid TOKEN
What changed from user point of view:
Now, When I click on the FacebookLoginButton, I have a new dialog that ask "connection as %FacebookUserName", with 2 buttons ("Unconnect" & "Cancel")
I posted a bug report at Firebase, but I even do not know if this is Facebook or Firebase, any help, advise for exploring new issue surface or solution is welcome.
In Facebook Developper Console, switch-off the option about the "app key that is integrated in the client".
For me this changed the behavior. I will give more information as far I get from Firebase/Facebook
Here is a French Screenshot to help you setting up Facebook:

Firebase : Permission denied - while setValue()

I am trying to build a chat application using firebase.
The structure for message table :
message -
$message_id
- $message_push_id
- message {
sender : 3,
receiver : 58,
token : token_of_sender,
message : hi
....}
message_id here is generated using the sender and receiver ids "3_58"
I am using push to save messages into firebase.
{
"rules": {
".read": true,
"message":
{
"$messageid": {
"$messagepushid":
{
".read": true,
".write": "auth != null && !data.exists()",
".indexOn": ["token", "userid", "receiverid", "sent_time"],
".validate": "auth.token == newData.child('token').val() && newData.hasChildren(['token', 'userid', 'receiverid', 'text'])"
}
}
}
}
}
I have already generated token using custom token generator :
Firebase firebase = getFirebase();
Map<String, Object> authPayload = new HashMap<String, Object>();
authPayload.put("uid", user.getUserid());
authPayload.put("token", user.getToken());
TokenGenerator tokenGenerator = new TokenGenerator(Constants.FIREBASE_KEY);
TokenOptions tokenOptions = new TokenOptions();
tokenOptions.setAdmin(false);
final String firebaseToken = tokenGenerator.createToken(authPayload, tokenOptions);
firebase.authWithCustomToken(firebaseToken, new Firebase.AuthResultHandler() {
#Override
public void onAuthenticated(AuthData authData) {
Log.d("Auth", "Success : " + authData.toString());
Log.d("Auth", "Token : " + firebaseToken);
SharedPrefs.setFirebaseUserToken(getActivity(), firebaseToken);
}
#Override
public void onAuthenticationError(FirebaseError
firebaseError) {
firebaseError.toException().printStackTrace();
}
});
I am trying to push a new message but I am getting error :
RepoOperation﹕ setValue at /message/3_58/-Jy2We4cqLjuQNF6Oyhs failed: FirebaseError: Permission denied
I am unable to figure out where I am going wrong.
This is the code to send chat :
mConversationReferenceFireBase = mFireBase.child("message").child(mConversationId);
Chat conversation = new Chat( mToken, mUserId, mReceiverId, message );
mConversationReferenceFireBase.push().setValue(conversation, new Firebase.CompletionListener() {
#Override
public void onComplete(FirebaseError firebaseError, Firebase firebase) {
if (firebaseError != null) {
Log.e("Conversation", firebaseError.toString());
}
}
});
mConversationId = 3_58
The token here is generated for a user. We have a separate server to maintain the user accounts. The token is being used to upload/ download any files, the firebase is used as Chat Server.
With the rules set to .read = true and .write = true; everything works, however when I am attempting to have an authentication performed, it results in the error mentioned above. I've tried using the token from token generator, to check if I may possibly be using the wrong token.
I am following this example to generate token for firebase auth :
https://www.firebase.com/docs/web/guide/login/custom.html
Since storing a firebase secret key is bad in terms of security, what other alternative can be followed to generate a token for authentication?
I was too stuck on this point and here's what helped me.
First things first, there are two types of users who can access database from firebase
Authorized
Non-authorized
By default it is set to non-authorized but then they do not have any permissions neither read nor write, so initially if you try to perform any operation you get the permission denied error.
So basically one has to change the required permissions on the firebase console in-order to access the database.
Complete answer here
Check the rule defined in your firebase account and also the simulator options. Description is given below in a image.

Categories

Resources