In my app I am tracking app install referrals using Branch and I also have a custom event called SIGN_UP which gets sent after the sign up request completes.|
So after using a branch link (fb one in particular) to install and sign up in my app, even though I get normal campaign data in the INSTALL event, I do not seem to get any relevant data in my custom one:
Screenshot of dashboard webhook events when filtered by AAID (see how columns Campaign, Ad Partner 3P, Ad Partner, Channel, Feature are empty in the first row.)
Any reason why this happens?
Code used:
In my Application class:
#Override
public void onCreate() {
super.onCreate();
// ...
Branch.getAutoInstance(this);
// ...
}
In my launcher Activity:
private val callback = Branch.BranchReferralInitListener { referringParams, error ->
if (error == null) {
Timber.i("BRANCH SDK success: %s", referringParams.toString())
} else {
Timber.e("BRANCH SDK error: %s", error.message)
}
}
override fun onStart() {
super.onStart()
Branch.sessionBuilder(this).withCallback(callback).withData(this.intent?.data).init()
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
Branch.sessionBuilder(this).withCallback(callback).reInit()
}
When sending a SIGN_UP event:
Branch.getInstance().setIdentity(memberId)
BranchEvent("SIGN_UP")
.addCustomDataProperty("UDID", udid)
.logEvent(activity)
Branch version: 5.0.1
For Facebook as Ad Network, Branch has the following data limitations
We cannot send device-level Facebook attribution data to third parties.
We cannot send events attributed to Facebook via Data Integrations. Please instead consider analyzing this data in-house (using Webhooks, the Daily Export API, or CSV Exports), or using the Branch Dashboard for all of your analytics and attribution needs.
This data is also not returned in the deeplink session initialization callback within the app. Also, you must have signed Facebook's "Advanced Mobile Measurement" agreement ("Data Use Terms for Advanced Mobile App Measurement") to view this data.
Related
I am currently using Firebase-UI for Android to implement authentication flow in my app. I currently have Google, Facebook, and Email auth providers enabled. My Android app is built using Jetpack Compose and I'm using rememberLauncherForActivityResult to launch the login intent. Everything is working as expected with the normal flow.
However, when I try to use my Facebook login with the same email that I have previously authenticated using Gmail, I am getting the below error.
A sign-in error occurred.
com.google.firebase.auth.FirebaseAuthUserCollisionException: This credential is already associated with a different user account.**
at com.google.android.gms.internal.firebase-auth-api.zzxc.zzb(com.google.firebase:firebase-auth##21.1.0:4)
at com.google.android.gms.internal.firebase-auth-api.zzya.zza(com.google.firebase:firebase-auth##21.1.0:7)
at com.google.android.gms.internal.firebase-auth-api.zzyb.zzl(com.google.firebase:firebase-auth##21.1.0:1)
at com.google.android.gms.internal.firebase-auth-api.zzxy.zzq(com.google.firebase:firebase-auth##21.1.0:3)
at com.google.android.gms.internal.firebase-auth-api.zzxy.zze(com.google.firebase:firebase-auth##21.1.0:1)
at com.google.android.gms.internal.firebase-auth-api.zzxa.zze(com.google.firebase:firebase-auth##21.1.0:1)
at com.google.android.gms.internal.firebase-auth-api.zzvf.zzd(com.google.firebase:firebase-auth##21.1.0:8)
at com.google.android.gms.internal.firebase-auth-api.zzuf.zzb(com.google.firebase:firebase-auth##21.1.0:2)
at com.google.android.gms.internal.firebase-auth-api.zzyj.zzb(com.google.firebase:firebase-auth##21.1.0:12)
at com.google.android.gms.internal.firebase-auth-api.zzyj.zza(com.google.firebase:firebase-auth##21.1.0:14)
at com.google.android.gms.internal.firebase-auth-api.zzxp.zzq(com.google.firebase:firebase-auth##21.1.0:4)
at com.google.android.gms.internal.firebase-auth-api.zzug.zzb(com.google.firebase:firebase-auth##21.1.0:4)
at com.google.android.gms.internal.firebase-auth-api.zzvf.zzM(com.google.firebase:firebase-auth##21.1.0:5)
at com.google.android.gms.internal.firebase-auth-api.zzvf.zzs(com.google.firebase:firebase-auth##21.1.0:4)
at com.google.android.gms.internal.firebase-auth-api.zzxb.zzm(com.google.firebase:firebase-auth##21.1.0:6)
at com.google.android.gms.internal.firebase-auth-api.zzvr.zzc(com.google.firebase:firebase-auth##21.1.0:1)
at com.google.android.gms.internal.firebase-auth-api.zzyc.run(com.google.firebase:firebase-auth##21.1.0:1)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
at java.lang.Thread.run(Thread.java:1012)
I would like someway to handle this exception but I am not able to find a way. Am I missing something obvious?
Here is my implementation
ProfileViewModel.kt
override fun buildLoginIntent(): Intent {
val authUILayout = AuthMethodPickerLayout.Builder(R.layout.auth_ui)
.setGoogleButtonId(R.id.btn_gmail)
.setEmailButtonId(R.id.btn_email)
.setFacebookButtonId(R.id.btn_facebook)
.build()
val googleScopes = arrayListOf(
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"
)
val intent = AuthUI.getInstance().createSignInIntentBuilder()
.setAvailableProviders(
listOf(
AuthUI.IdpConfig.EmailBuilder().build(),
AuthUI.IdpConfig.GoogleBuilder().setScopes(googleScopes).build(),
AuthUI.IdpConfig.FacebookBuilder().build()
)
)
.enableAnonymousUsersAutoUpgrade()
.setLogo(R.mipmap.ic_launcher)
.setAuthMethodPickerLayout(authUILayout)
.build()
return intent
}
#SuppressLint("RestrictedApi")
override fun onLoginResult(result: FirebaseAuthUIAuthenticationResult) {
// Handle result
}
ProfileUI.kt
Composable UI where I launch the intent
val loginLauncher = rememberLauncherForActivityResult(
profileViewModel.buildLoginActivityResult()
) { result ->
if (result != null) {
profileViewModel.onLoginResult(result = result)
}
}
if (isAnonymousUser) {
SignInUI() {
loginLauncher.launch(profileViewModel.buildLoginIntent())
}
}
However, when I try to use my Facebook login with the same email that I have previously authenticated using Gmail, I am getting the below error.
This credential is already associated with a different user account.
That's the expected behavior since your user was first time authenticated with Google. When you authenticate a user in Firebase with Google, there is a user created that contains the data that corresponds to that particular provider. If you try to use that data to authenticate to Facebook, the authentication will fail, because the user was already created with another provider, hence the error.
A solution for this kind of situation would be to check if the user already exists, before authenticating it. If the user already exists, then you have to read the provider and display a message to the user, so it can choose the right authentication provider.
Another option might be to allow the creation of different accounts for different providers. You can find this option which is called "Create multiple accounts for each identity provider" right inside the Firebase Console, in the Settings tab inside the Authentication.
I'm trying to implement referral in my app with Firebase Dynamic link.
The happy path would be:
Link is shared with a JWT token as parameter
Another user clicks on the link, doesn't have the app so it goes to the Playstore
After app was installed, at app startup, the JWT token is retrieved trough parameters and stored locally
New signup is complete, the token is sent to the backend to activate referrer's reward
Problem is that in this scenario, step 3 doesn't find any data at first app startup, whereas it is found when I click on the link anew after the app has been installed.
This is the way the link is generated for the referrer:
val parameters = new DynamicLink.SocialMetaTagParameters.Builder()
.setImageUrl(...)
.setTitle(...)
.build();
val link = Uri.parse("https://my.domain.com/path/?token=${jwtToken}");
val dynamicLink = FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLink(link)
.setSocialMetaTagParameters(parameters)
.setDomainUriPrefix("https://my.domain.com")
.setAndroidParameters(DynamicLink.AndroidParameters.Builder().build()))
.setIosParameters(...)
.setNavigationInfoParameters(
DynamicLink.NavigationInfoParameters.Builder()
.setForcedRedirectEnabled(true)
.build
).buildDynamicLink()
The link is shorten by:
FirebaseDynamicLinks.getInstance().createDynamicLink()
.setDomainUriPrefix("https://my.domain.com/")
.setLongLink(dynamicLink.getUri())
.buildShortDynamicLink()
.addOnCompleteListener(activity, task -> {
if (task.isSuccessful() && task.getResult() != null) {
linkCallback.success(task.getResult().getShortLink().toString());
} else {
linkCallback.failure(task.getException());
}
})
At app's opening, link is read in the onResume() method of the starting activity :
override fun onResume() {
super.onResume()
FirebaseDynamicLinks.getInstance()
.getDynamicLink(getIntent()) // getIntent() refers to the Activity's method
.addOnSuccessListener(activity) { data -> // Get deep link from result (may be null if no link is found)
val isReferralLink = data?.link?.toString()?.startsWith("https://my.domain.com/path") == true
val jwt = data?.link?.getQueryParameter("token")
// Here, data is null. <-------
// Other attempt :
data?.let { aiData ->
FirebaseAppInvite.getInvitation(aiData)?.let { result ->
// Here result is still null
}
}
}
}
I've seen on a stack overflow thread that it doesn't survive to beta track install, so I tried to leave the beta and use remote config to hide it in production track, but I have not been able see any difference.
And the version I'm using is :
implementation 'com.google.firebase:firebase-dynamic-links:21.0.0'
implementation 'com.google.firebase:firebase-analytics:20.0.0'
implementation 'com.google.firebase:firebase-invites:17.0.0'
Question:
Is there something I'm missing here ?
Thank you in advance for your help !
EDIT:
In this scenario the link and token are correctly found.
Link is shared with a JWT token as parameter
Another user clicks on the link, doesn't have the app so it goes to the Playstore
After app was installed, the second user clicks again on the link and opens the app for the first time
Ok so after a few days of testing and researches, I found out why it was not working.
FirebaseDynamicLinks.getInstance()
.getDynamicLink(getIntent())
.addOnSuccessListener(activity) { data ->
// Some data reading
}
In this case I was using the addOnSuccessListener() with an activity as parameter, which makes it lifecycle aware. In my app, a new user (fresh install) will be redirected to an onboarding activity, so the listener's activity is paused, and the callback is never fired.
=> TLDR: Removing this activity parameter solved my problem.
i have integrated Azure AD B2C on my mobile App using MSAL library. I have created the user flows for SignIn and SignUp. I'am getting the access token once the authentication is success. so i have my logout button designed on my Mobile App on one of my Activity Page, so once i click on my logout button designed on App, i need to get the user signedOut from the App. so how can we do the SignOut in AZURE AD B2C MSAL on Android?
is it ok even if i clear the access token saved on my preference? or is there any other way to signout from Azure side provideb by MSAL library?
The MSAL library provides a logout method that clears the cache in browser storage and sends a sign-out request to Azure Active Directory (Azure AD). Request will be done against the end_session_endpoint URL obtained from the B2C policy metadata. Keep in mind single sign out is supported only by custom policies and that it's scoped to the same browser, not device.
For a Native Android mobile app please use the signout function in Ms Document
To remove this user from the cache, you must call removeAccount() for each policy.
PublicClientApplication publicClient = MyApplication.getInstance().getPublicClient();
User currentUser = Helpers.getUserByPolicy(publicClient.getUsers(), Constant.SIGN_UP_POLICY);
publicClient.remove(currentUser);
//Load account using publicClientApplication
private fun loadAccounts(mMultipleAccountApp: IMultipleAccountPublicClientApplication) {
mMultipleAccountApp.getAccounts(object: IPublicClientApplication.LoadAccountsCallback {
override fun onTaskCompleted(result: List<IAccount>) {
val accountList: List<IAccount> = result
removeAccounts(mMultipleAccountApp, accountList)
}
override fun onError(exception: MsalException) {
Log.d("Error",exception.message)
}
})
}
//call remove account
private fun removeAccounts(
mMultipleAccountApp: IMultipleAccountPublicClientApplication,
accountList: List<IAccount>
) {
val removeCallback =
object : IMultipleAccountPublicClientApplication.RemoveAccountCallback {
override fun onRemoved() {
// Redirect to login
}
override fun onError(exception: MsalException) {
Log.d("Error",exception.message)
}
}
B2CUser.signOutAsync(
accountList,
mMultipleAccountApp, removeCallback
)
}
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
We have recently switched from Google Analytics SDK to Firebase SDK in our Android app.
Before that, we used INSTALL_REFERRER to get the user's source and medium.
Now we have started an App Campaign on Google Ads and INSTALL_REFERRER no longer works, though conversions keep coming.
How do we use Firebase SDK to know that user came from Google Ads campaign?
I think you'll want to use the Play Install Referrer API.
The link above cautions that the install referrer information will be available for 90 days and to only invoke the API during the first run of the app to avoid unnecessary API calls.
Here's an example (taking from the link above), assuming you have added the library to your build.gradle file:
Initialization:
private lateinit var referrerClient: InstallReferrerClient
...
referrerClient = InstallReferrerClient.newBuilder(this).build()
referrerClient.startConnection(object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(responseCode: Int) {
when (responseCode) {
InstallReferrerResponse.OK -> {
// Connection established
}
InstallReferrerResponse.FEATURE_NOT_SUPPORTED -> {
// API not available on the current Play Store app
}
InstallReferrerResponse.SERVICE_UNAVAILABLE -> {
// Connection could not be established
}
}
}
override fun onInstallReferrerServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
})
Getting the referrer:
val response: ReferrerDetails = referrerClient.installReferrer
val referrer = response.installReferrer
val clickTimestamp = response.referrerClickTimestampSeconds
val installTimestamp = response.installBeginTimestampSeconds
Wrapping Up:
referrerClient.endConnection()
Checking for gclid (Google Ads)
if ("gclid" in referrer) {
//report to Firebase Analytics
} else {
//do something else
}
In this way, we will determine gclid only if the user has clicked on the advertisement in the browser, but if he clicked on the advertisement in the play market, then nothing will work.