I'm setting up the package react-native-moengage in my react-native app. Followed the guidelines here for react-native all the way to tracking events. Yet calling trackEvent on my code does not publish anything and does not throw an error at JS level.
Running on react-native:0.59and react-native-moengage:^3.0.0
Have not done anything weird beyond what is in the documentation, set up a service to call ReactMoE.trackEvent from sagas. I set up logs and indeed trackEvent is getting called
Pretty much this is it
import ReactMoE from 'react-native-moengage'
class MoengageService {
...
constructor() {
ReactMoE.isExistingUser(true);
}
setUser(userId: string, email: string, name: string) {
ReactMoE.setUserUniqueID(userId);
ReactMoE.setUserEmailID(email);
ReactMoE.setUserAttribute('inAppName', name)
}
unsetUser() {
ReactMoE.logout()
}
logEvent = (event: string, data = {}) => {
const timestamp = moment().valueOf()
const dataToLog = {
...data,
timestamp,
}
ReactMoE.trackEvent(event, dataToLog)
}
...
}
export const instance = new MoengageService()
I also succesfully set up moengage natively thanks to a previous SO question, or so I believe.
I would expect something to appear in the dashboard, it's blank with the big text up top saying I have not received anything in the last hour
How do I get it to push to dashboard?
EDIT
Just for clarification, I am not interested (yet) in push notifications or any of the like, which is why I skipped setting up firebase and everything
After Checking the logs and thinking out loud, I noticed the issue was that the dashboard was being misused, we were checking for debug logs on live instead of test.
If you followed the docs and see nothing, try to check which environment are you reading. Test for debug apps, Live for signed apps.
A helpful thing to check logs, adb logcat MoEngage_v${Your moengage native version here}
Related
I have the current workflow for my authentication
User signs in via google OAuth2
User is then given a server_auth_code which they send to my backend authentication
The auth code is validated on the back end and users is sent a JWT
I had this all working in raw Java with the Android SDK, but Flutter seemed a lot nicer. But now when using the google_sign_in plugin on android, I am unable to retrieve the serverAuthCore anymore, this plugin just wants to return null the entire time.
I Am using the client ID that's specified for Android, however, I tested the WebApplication that's auto-generated by google too but that's the same issue (Null serverAutHCode)
This is the code that I am currently using:
/// Provides the `GoogleSignIn` class
import 'package:google_sign_in/google_sign_in.dart';
class GoogleLoginPage extends StatefulWidget {
final String name = "Logging in with google.";
late GoogleSignIn _googleSignIn;
GoogleLoginPage() : super() {
_googleSignIn = GoogleSignIn(
scopes: ['https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile'],
serverClientId: "XX-XXX.apps.googleusercontent.com"
);
}
Future<void> fetchAuthToken() async {
try {
var response = await _googleSignIn.signIn();
log(response?.serverAuthCode ?? "No server auth code");
_googleSignIn.signOut();
} catch (error) {
print("ERR");
print(error);
}
}
#override
State<GoogleLoginPage> createState() => GoogleLoginState();
}
The output of this code is: [log] No server auth code
The question:
Am I doing something wrong? As mentioned this works 100% on my java project using the google play services SDK so I know it's nothing to do with my google console configurations.
Okay so I figured out the issues:
It appears that by default the google login plugin for flutter comes on an older version (If I remember correctly it was 20.0.5)
I Simply changed the version to the latest version:
'com.google.android.gms:play-services-auth:20.2.0'
You can do this by editing the project's build.gradle (In IntelliJ you open build.gradle and click "Open for editing in the android studio" in the top right, from there you need to find the gradle file for google_sign_in, and change the import there, remember to click sync in the top right of android studio before you close out of it)
And I began to receive my serverAuthCode as normal, cheers!
I have been trying to integrate AppCheck with my Android app, but I can't seem to make a valid request.
As for test purposes, I have been using the following code:
Android Code
class Application : MultiDexApplication() {
override fun onCreate() {
FirebaseApp.initializeApp(this)
val appCheck = FirebaseAppCheck.getInstance()
if (BuildConfig.DEBUG) appCheck.installAppCheckProviderFactory(DebugAppCheckProviderFactory.getInstance(), true)
else appCheck.installAppCheckProviderFactory(SafetyNetAppCheckProviderFactory.getInstance(), true)
super.onCreate()
}
}
class TestActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
val data = "This is a test!"
Firebase.functions.getHttpsCallable("test").call(data).addOnCompleteListener {
if (it.isSuccessful) {
val result = it.result.data
print(result)
}
else {
val exception = it.exception
print(exception)
}
}
}
}
Function Code
const functions = require("firebase-functions")
exports.test = functions.https.onCall((data, context) => {
if (context.app == undefined) {
functions.logger.error("Test - Failed validating device integrity!")
throw new functions.https.HttpsError("failed-precondition", "The function must be called from an App Check verified app")
}
return data
})
I have added the DebugAppCheckProviderFactory token to the Firebase console, but no matter what I do, if it is an emulator or physical device, when I call the function, the failed-precondition exception is always thrown.
Checking the function logs, I can see that the app is missing:
I have already read the documentation multiple times and I can't seem to be missing any step. Am I missing something or is there anything I can do to find the root cause for this?
Thank you for your time!
EDIT:
As for Martin suggestion, I created a new OnRequest function and added the X-Firebase-AppCheck header. I received the token correctly and was able to validate it successfully with:
firebaseAdmin.appCheck().verifyToken(appCheckToken)
So, my guess is that Android is not adding the X-Firebase-AppCheck automatically to the OnCall function like it should.
I ran the code and made some breakpoints through the code and noticed the following. The call method from Firebase is adding the Firebase-Instance-ID-Token but I can't seem to find the X-Firebase-AppCheck header anywhere. Maybe I am not supposed to see this value, or maybe I just can't find where it is being added. Or maybe it is not added at all, thus I can't validate my context.app at all.
It may be required to obtain an AppCheckToken:
FirebaseAppCheck
.getInstance()
.getAppCheckToken(false)
.addOnSuccessListener(new OnSuccessListener<AppCheckToken>() {
#Override
public void onSuccess(#NonNull AppCheckToken tokenResponse) {
String appCheckToken = tokenResponse.getToken();
...
}
});
Which has to be passed along, with the HTTP request (the example shows Retrofit, which could also be used instead of HttpsCallable:
#GET("yourExampleEndpoint")
Call<List<String>> exampleData(
#Header("X-Firebase-AppCheck") String appCheckToken,
...
);
Where FirebaseFunctions.getInstance().getHttpsCallable().call() doesn't tell how or if one has to explicitly set that X-Firebase-AppCheck header. Cloud Functions should usually receive an X-Firebase-AppCheck header - with the previously retrieved AppCheck token:
const appCheckToken = req.header('X-Firebase-AppCheck');
if (!appCheckToken) {
res.status(401);
return next('Unauthorized');
}
try {
const appCheckClaims = await firebaseAdmin.appCheck().verifyToken(appCheckToken);
// If verifyToken() succeeds, continue with the next middleware function in the stack.
return next();
} catch (err) {
res.status(401);
return next('Unauthorized');
}
One can also issue own tokens ...and checking for context-app is also valid.
Update: The Protocol specification for https.onCall reads:
Optional: X-Firebase-AppCheck: <token>
The Firebase App Check token provided by the client app making the request. The backend automatically verifies this token and decodes it, injecting the appId in the handler's context. If the token cannot be verified, the request is rejected.Available for SDK >=3.14.0
To install the minimum required NodeJS dependencies:
npm install firebase-functions#">=3.14.0"
npm install firebase-admin#">=9.8.0"
And last, but not least ...there's even a debug helper for that:
dependencies {
debugImplementation "com.google.firebase:firebase-appcheck-debug:16.0.0-beta02"
}
After testing everything with no success, in a desperate move, I tried to look to unrelated files and found the solution.
In my build.gradle I was importing all the Firebase dependencies with the bom:
implementation platform("com.google.firebase:firebase-bom:27.0.0")
implementation "com.google.firebase:firebase-crashlytics-ktx"
implementation "com.google.firebase:firebase-analytics-ktx"
implementation "com.google.firebase:firebase-firestore-ktx"
implementation "com.google.firebase:firebase-functions-ktx"
implementation "com.google.firebase:firebase-auth-ktx"
So I thought: "Can the firebase-bom be importing an outdated functions-ktx dependency?"
And guess what? As soon as I imported the dependencies without the bom, I started to see the X-Firebase-AppCheck being added and the context.app being valid.
I ended up with the following build.gralde:
implementation "com.google.firebase:firebase-crashlytics-ktx:18.2.1"
implementation "com.google.firebase:firebase-analytics-ktx:19.0.0"
implementation "com.google.firebase:firebase-firestore-ktx:23.0.3"
implementation "com.google.firebase:firebase-functions-ktx:20.0.0"
implementation "com.google.firebase:firebase-auth-ktx:21.0.1"
After a little more investigation, I found out that I was using an outdated firebase-bom version. Android Studio used to let me know if there was a new version for the dependencies, but it did not notice me for the firebase-bom. Turns out, that I just need to update my firebase-bom dependency.
TL;DR
Check your Android Firebase libraries version!
According to GitHub sample project and Tealium's documentation for Kotlin I created such TealiumHelper:
object TealiumHelper {
fun init(application: Application) {
val tealiumConfig = TealiumConfig(
application,
accountName = BuildConfig.TEALIUM_ACCOUNT_NAME,
profileName = BuildConfig.TEALIUM_PROFILE_NAME,
environment = BuildConfig.TEALIUM_ENVIRONMENT
)
// Display logs only for DEV
Logger.Companion.logLevel = BuildConfig.TEALIUM_LOGLEVEL
// Make it start working
Tealium.create(BuildConfig.TEALIUM_INSTANCE, tealiumConfig)
}
fun trackEvent(name: String, data: Map<String, Any>? = null) {
val eventDispatch = TealiumEvent(name, data)
Tealium[BuildConfig.TEALIUM_INSTANCE]?.track(eventDispatch)
}
fun trackView(name: String, data: Map<String, Any>? = null) {
val viewDispatch = TealiumView(name, data)
Tealium[BuildConfig.TEALIUM_INSTANCE]?.track(viewDispatch)
}
}
I get logs by Tealium so it should be working fine.
2021-05-17 14:28:56.694 22812-22894/xxx.xxx.xxx D/Tealium-1.2.2: Dispatch(fc5c0) - Ready - {tealium_event_type=view, tealium_event=XXX ...}
But after I call trackView or trackEvent, my events don't go to server.
There is also additional log infor which I don't know what does it mean. Documentation doesn't say much about it:
2021-05-17 14:28:59.352 22812-22894/xxx.xxx.xxx I/Tealium-1.2.2: Asset not found (tealium-settings.json)
How could I fix it? What does Asset not found mean?
#deadfish I manage the mobile team here at Tealium, so I can point you in the right direction. You can safely ignore the Asset Not Found log - this just indicates that no local settings file was found, so by default, the remote settings will be used. We'll look at addressing this to make the log message a little more helpful. There are a couple of things that might cause data not to be sent. Firstly, I can't see any Dispatchers specified in your TealiumConfig object. As specified in the docs, you need to add either the TagManagement or Collect dispatcher, which are the modules that send the data from the device. The Collect module sends data to the server-side platform (I think this is what you need), while the TagManagement module processes the data client-side using JavaScript. Please feel free to get in touch with our support team or contact us by raising an issue on our GitHub repo if you need further personalized support.
To begin with, I'm working on a Unity Game where I'm authenticating user when the game starts. My build environment is android. I'm using Firebase authentication for Google Play Games Services to authenticate user.
When the game starts in my android device or emulator, it is able to authenticate Play Games Services as well as able to connect with Firebase (I'm getting analytics data). However, when I pass the PlayGames AuthCode into Firebase.Auth Credentials, it stops executing the code (I've debug log for it). It does not throw any error in LogCat except
Firebase | server_auth_code
I tried searching web for different issues, but nothing. I checked my keys in player setting, firebase settings, OAuth 2.0 credentials on my Google API console and even check keys from my Google Play Console (which I'm not using at this stage). I have even checked my test users email addresses in Game Services and tried multiple google play games account. But issue still persist.
I'm using similar script in my other unity project where authentication works like a charm. I tried to use same script here and ended up with this issue: here. However, I solved it by removing all the packages and re-importing them into unity and changed my call functions in the script. Now, I'm stuck at this issue.
Here is cs file:
using GooglePlayGames;
using GooglePlayGames.BasicApi;
using UnityEngine.SocialPlatforms;
using System.Threading.Tasks;
public class SetFirebase : MonoBehaviour
{
string authCode;
void Start()
{
PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder().
RequestServerAuthCode(false /* Don't force refresh */).Build();
PlayGamesPlatform.InitializeInstance(config);
PlayGamesPlatform.Activate();
Social.localUser.Authenticate((bool success) =>
{
if (success)
{
authCode = PlayGamesPlatform.Instance.GetServerAuthCode();
Debug.Log("PlayGames successfully authenticated!");
Debug.Log("AuthCode: " + authCode);
}
else
{
Debug.Log("PlayGames SignIn Failed");
}
});
Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task =>
{
var dependencyStatus = task.Result;
if (dependencyStatus == Firebase.DependencyStatus.Available)
{
Debug.Log("Firebase Ready!!!");
RunFirebase();
}
else
{
Debug.LogError(System.String.Format("Could not resolve all Firebase dependencies: {0}", dependencyStatus));
}
});
}
private void RunFirebase(){
Firebase.Auth.FirebaseAuth auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
Debug.Log("init firebase auth ");
Firebase.Auth.Credential credential = Firebase.Auth.PlayGamesAuthProvider.GetCredential(authCode);
Debug.Log(" passed auth code ");
auth.SignInWithCredentialAsync(credential).ContinueWith(task =>
{
if (task.IsCanceled)
{
Debug.LogError("SignInOnClick was canceled.");
return;
}
if (task.IsFaulted)
{
Debug.LogError("SignInOnClick encountered an error: " + task.Exception);
return;
}
Firebase.Auth.FirebaseUser newUser = task.Result;
Debug.LogFormat("SignInOnClick: User signed in successfully: {0} ({1})", newUser.DisplayName, newUser.UserId);
});
}
}
My LogCat executes everything till "init firebase auth" but does not execute "passed auth code" so I know there is some issue in passing the credentials. It also does not run anything inside auth.SignInWithCredentialAsync(credential).
Any help or suggestion would be highly appreciated. Thank you.
There are two things I may suggest:
1) Replace ContinueWith with ContinueWithOnMainThread. This is a Firebase Extension that will guarantee that your logic runs on the main Unity thread (which tends to resolve many Unity specific issues). I go into more detail about that here.
2) Your logic may have a race condition between the Authenticate callback and the CheckAndFixDependenciesAsync continuation. These will not necessarily run in the order that you see them in your logic.
If I were building this system, I might prefer using Coroutines and a custom yield instruction:
class Authenticate : CustomYieldInstruction
{
private bool _keepWaiting = true;
public override bool keepWaiting => _keepWaiting;
public Authenticate(Social.ILocalUser user) {
user.Authenticate((bool success)=>{
/* old authentication code here */
_keepWaiting = false;
});
}
}
Then in a coroutine have something like:
private IEnumerator InitializeCoroutine() {
/* old authentication code */
// I'm ignoring error checking for now, but it shouldn't be hard to figure in.
// I'm mostly going from memory now anyway
// start both authentication processes in parallel
var authenticate = new Authenticate(Social.localUser);
var firebaseDependenciesTask = FirebaseApp.CheckAndFixDependenciesAsync();
// wait on social
yield return authenticate;
// wait on Firebase. If it finished in the meantime this should just fall through
yield return new WaitUntil(()=>firebaseDependenciesTask.IsComplete);
RunFirebase();
}
This way my logic looks roughly synchronous whilst still maintaining the asynchronosity (spell check claims that I made up that word) of the systems you're depending on and you avoid threading related issues that arise when using ContinueWith.
Let me know if that helps!
--Patrick
I have an issue with react-native-firebase (or firebase) in which my app does not receive a trigger after the auth token refreshes. It's pretty much the same issue as [1], but they never posted a solution.
So, what happens is that both on an Android phone and on the Android emulator (no idea about iOS), signing up, logging in and logging out works perfectly, meaning the listeners correctly see when I do a logout() etc. But the listeners never fire when the token refreshes.
My first question is: Am I correct to assume that the onIdTokenChanged-listener should automatically fire after 60 minutes without having to do anything else, e.g. call any firebase function, such that the app just sits there doing nothing for 60 minutes and then receiving the event and replacing the token?
My main component which contains the listeners looks like this:
class ReduxAppWrapper extends Component {
componentDidMount() {
firebase.auth().onAuthStateChanged((user) => {
console.log('COMP DID MOUNT: AUTH STATE CHANGED! ' + JSON.stringify(user));
});
firebase.auth().onIdTokenChanged((user) => {
console.log('COMP DID MOUNT: TOKEN CHANGED! ' + JSON.stringify(user));
});
firebase.auth().onUserChanged((user) => {
console.log('COMP DID MOUNT: USER CHANGED! ' + JSON.stringify(user));
});
};
render() {
return (
<ReduxProvider store={store}>
<MenuProvider>
<PaperProvider>
<AppContainer />
</PaperProvider>
</MenuProvider>
</ReduxProvider>);
}
}
Normally inside the listener I have a function that dispatches a redux-action such that the authentication information is broadcast across my components. Inside those components I use the jwt token for http-requests to my backend.
Now the backend of course uses firebase to validate that token (and this is where the problem occurs after the 60 minutes since it retrieves an outdated jwt), but I think I am right to assume that the problem lies within the app since the refresh does not happen.
I'd be really glad if someone could point me to where to look, I also tried to find out in the firebase console whether a token refresh event was sent, but I could not find anything about that.
So basically:
1) Am I right to assume that the firebase.auth().onIdTokenChanged() function should be called without me doing anything else? Or is it not enough to define the listener once in the main component (also regarding the fact that other screens will be rendered on top of that due to the stack-nvigation).
2) If the code is fine, do you have any hints for where to look?
Thanks so much!
[1] https://github.com/invertase/react-native-firebase/issues/531
For anyone with the same issue, I ended up asking firebase asking for the token everytime I needed it. I still think this should not be necessary but I did not want to spend any more time analyzing why the refresh did not work automatically. So what I am doing in the app is
firebase.auth().currentUser.getIdToken().then((token) => {
fetch(url, {
method: 'GET',
headers: { Authorization: token }
})
}
¯\_(ツ)_/¯
Apparently, with getIdToken, Firebase only makes a call to its server to get a new token if the current token has expired; it does not create unnecessary requests if it does not have to.
Quite a crucial detail which can be confusing if you are not aware of it and makes you (rightfully) assume that onIdTokenChanged is a listener which you would need to use to automatically update the token ...
https://firebase.google.com/docs/reference/js/firebase.User.html#getidtoken
Returns the current token if it has not expired. Otherwise, this will refresh the token and return a new one.