I'm using dynamic links for my app.
I've followed the tutorial step-by-step and I'm able to open the app by clicking on the link posted on facebook.
But when I invoke getInvitation, I always have CANCELED as status of AppInviteInvitationResult.
AppInvite.AppInviteApi.getInvitation(mGoogleApiClient, this, false).setResultCallback(
new ResultCallback<AppInviteInvitationResult>() {
#Override
public void onResult(#NonNull AppInviteInvitationResult result) {
if (result.getStatus().isSuccess()) {
// Extract deep link from Intent
Intent intent = result.getInvitationIntent();
String deepLink = AppInviteReferral.getDeepLink(intent);
// [END_EXCLUDE]
} else {
Log.d("StartActivity", "getInvitation: no deep link found.");
}
}
});
Into debug, I can see that result.getStatus() returns CANCELED, but the click on lick open the app correctly.
Where I'm wrong?
EDIT: The link that I'm using is:
https://wft4z.app.goo.gl/?link=https://aqld.it/testlink/112972&al=aqld://test/about?params%3D17363&apn=com.project.mydeeplink
The filter on manifest:
The status is canceled when no intent has been received. I was wondering the same thing and it turned out that my links created in firebase web page were wrong. I wrote some ideas on how to debug the url problem as an answer to another question. If you have the same problem as I did, they should be helpful:
https://stackoverflow.com/a/37615175/4025606
Doesn't directly answer your question but you could eliminate badly formed urls as a root cause by using this page to create firebase dynamic links for both ios and Android: http://fdl-links.appspot.com/
Just double-check if you have added the SHA-1 in the firebase console and the added SHA-1 matches the SHA1 of the generated APK. I was seeing the same issue - result.getStatus() returning CANCELED prior to this, but after adding the SHA-1 on firebase console, it started working fine. :)
Related
Thanks again to Cbroe who answered my original question. I implemented his suggestion and although the URL returned by GraphRequest.newMeRequest looks valid, when I followed it, I got a "Content not found" error:
reachOut.setOnClickListener(new View.OnClickListener(){
public void onClick(View view) {
// Navigate to person's Facebook page to send a message.
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(linkArray[selectedPosition]));
startActivity(intent);
}
});
BTW, in the above, I did confirm that linkArray[selectedPosition] contained the correct value.
I had previously (back in 2018!) successfully completed an app review for user_link, so I doubt that that's the problem.
Looks like I had to resubmit my app for approval because now it's working again.
I have created a dynamic link in Firebase console. It has a short url that directs the user to an Activity inside the application.
I have done the same in iOS, using the code:
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool
{
if let incomingUrl = userActivity.webpageURL
{
print(incomingUrl) //Here I get the url that the user clicked on
}
}
I'm trying to get the exact output in Android when the user clicks on the dynamic short link.
Currently, I have :
FirebaseDynamicLinks.getInstance()
.getDynamicLink(getIntent())
.addOnSuccessListener(this, new OnSuccessListener<PendingDynamicLinkData>() {
#Override
public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
// Get deep link from result (may be null if no link is found)
Uri deepLink = null;
if (pendingDynamicLinkData != null)
{
deepLink = pendingDynamicLinkData.getLink();
}
// Handle the deep link. For example, open the linked
// content, or apply promotional credit to the user's
// account.
// ...
// ...
}
})
.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "getDynamicLink:onFailure", e);
}
});
Here, I can get the deep link, I have no clear idea of fetching the short link in Android.
Thank you.
You are misunderstanding the way platforms like Dynamic Links and Branch.io (full disclosure: I'm on the Branch team) work. Your Android implementation is correct — the iOS one is wrong. You'll want to review the Dynamic Links setup guide for iOS to make sure you're all set.
One of the major benefits of using hosted deep links is you don't need the actual URL the user clicked. There are two good reasons for this:
The URL is never available for the deferred deep link use case (when the app isn't already installed).
The URL arrives differently when the app is opened via Universal Links/App Links than via custom URI scheme.
The hosted link platform abstracts those technical details away, so that you can implement your own functionality without worrying about them. If you try to bypass the intended usage, it actually makes things much harder.
When using Firebase invites and accessing the dynamic links at the startup of the app on Android, is there a way to know whether the user just installed the app thanks to the invite or whether it was already installed?
Many thanks,
Borja
EDIT: Thanks to Catalin Morosan for the answer
It turns out that you can find this out using method AppInviteReferral.isOpenedFromPlayStore(result.getInvitationIntent()). In the activity that runs when you click on the invitation:
// Create an auto-managed GoogleApiClient with access to App Invites.
mGoogleApiClientInvite = new GoogleApiClient.Builder(this)
.addApi(AppInvite.API)
.enableAutoManage(this, this)
.build();
// Check for App Invite invitations and launch deep-link activity if possible.
// Requires that an Activity is registered in AndroidManifest.xml to handle
// deep-link URLs.
boolean autoLaunchDeepLink = false;
AppInvite.AppInviteApi.getInvitation(mGoogleApiClientInvite, this, autoLaunchDeepLink)
.setResultCallback(
new ResultCallback<AppInviteInvitationResult>() {
#Override
public void onResult(AppInviteInvitationResult result) {
if (result.getStatus().isSuccess()) {
// Extract information from the intent
Intent intent = result.getInvitationIntent();
String invitationId = AppInviteReferral.getInvitationId(intent);
boolean alreadyUser = AppInviteReferral.isOpenedFromPlayStore(result.getInvitationIntent());
if (alreadyUser) {
// Do stuff...
} else {
// Do other stuff...
}
}
}
});
Based on this Google product form post, the Firebase Dynamic Links library will only check for incoming deep links once per app lifetime, meaning you'd need to uninstall and reinstall the app for it to check again. This feeds into the behavior of the getInvitation() method, and it appears you can imply whether the app was previously installed based on the results of this method.
To me, this seems awfully confusing. At Branch.io we do it completely differently: your link data object will always contain an is_first_session boolean, which you can programmatically handle in any way you choose.
Facebook's Sharing on Android documentation tells us to show the ShareDialog with the following code snippet:
if (ShareDialog.canShow(ShareLinkContent.class)) {
ShareLinkContent linkContent = new ShareLinkContent.Builder()
.setContentTitle("Hello Facebook")
.setContentDescription(
"The 'Hello Facebook' sample showcases simple Facebook integration")
.setContentUrl(Uri.parse("http://developers.facebook.com/android"))
.build();
shareDialog.show(linkContent);
}
My question is why do we need to check ShareDialog.canShow()? In what scenarios would this possibly return false and do we need to handle this scenario? The example code would just fail silently not tell the user anything.
I spent a lot of time yesterday trying to debug an error related to this. Facebook's docs are poor in this sense and when there is an error related to this canShow() method, it just fails silently, no logging at all.
So, to answer your question:
My question is why do we need to check ShareDialog.canShow()? In what
scenarios would this possibly return false and do we need to handle
this scenario?
Based on the scenario I faced: when the user doesn't have the Facebook app installed on their device and you want to share photos (SharePhotoContent) or videos (ShareVideoContent), canShow() will return false. The reason is that Facebook SDK's WebView version doesn't support sharing this kind of content.
I found this out debugging their FacebookActivity class, on the handlePassThroughError() method. The (not logged) error message is:
"Unable to show the provided content. This typically means that the Facebook app is not installed or up to date. If showing via the Web, this could mean that the content has properties that are not supported via this channel."
So, what should we do when canShow() returns false?
It depends on your scenario. Possible solutions would be:
Show a dialog (or SnackBar) telling the user that they need to install the Facebook app to be able to share this kind of content;
Request an authentication token, log the user using the Facebook SDK, and share the content using your own dialog and calling Facebook API directly.
Possible solutions for Facebook would be include this on their documentation or log this error on LogCat.
Hope it helps!
this answer for someone facing the same problem.
#leocadiotine was great.
From the facebook sdk sample, when the ShareDialog.canShow() return false you should use ShareApi.share function.
In AndroidManifest.xml, add:
<queries>
<provider android:authorities="com.facebook.katana.provider.PlatformProvider" />
</queries>
// for facebook
callbackManager = CallbackManager.Factory.create();
shareDialog = new ShareDialog(this);
// this part is optional
shareDialog.registerCallback(callbackManager, new FacebookCallback<Sharer.Result>() {
#Override
public void onSuccess(Sharer.Result result) {
}
#Override
public void onCancel() {
}
#Override
public void onError(FacebookException e) {
}
});
I've been playing around with Parse on Android for a few days, I have a problem with ParseUser.logOut() => it actually doesn't log the current user out.
Here's what I do :
private void onClickOnDisconnect() {
ParseUser.logOut();
currentUser = ParseUser.getCurrentUser(); // should be null but isn't...
invalidateOptionsMenu();
Toast.makeText(getApplicationContext(), "Disconnected...", Toast.LENGTH_LONG).show();
}
After the call to ParseUser.logOut(), ParseUser.getCurrentUser() should return null (says the documentation). Still it returns the previously logged in user.
Even though I restart the app the user is still considered as connected.
I use parse framework v1.3.8 (downloaded a 3 days ago). I don't use Facebook SDK, as I've seen a few questions for that specific case.
Thanks in advance
Somewhere in your app, probably the appDelegate you most likely send this message to the PFUserClass
[PFUser enableAutomaticUser];
in this case the
[PFUser currentUser];
will never return nil;
I had the same issue while incorporating logout functionality with facebook login. The error turned out to quite simple and a basic mistake on my part. I had written the following piece of code in my Application class
ParseUser.enableAutomaticUser();
This creates the user every time you run your application even if you have logged out the last time around. Removing this solved my problem.
As I said in the comments above, I got it to work by :
uninstalling the app
deleting the user on the Parse dashboard
reinstalling the app and signing up again
Then the signout/signin mechanism worked miraculously :|
The only reason I can imagine is that I had previously signed up with this user having Automatic user creation enabled, and it somehow stuck to the user entity in Parse.
Experiencing same bug. Now instead of only checking ParseUser as null, I check username too:
ParseUser currentUser=ParseUser.getCurrentUser()
if(currentUser==null)
{
//user doesn't exist
}
else
{
if(currentUser.getUserName()==null)
{
//user oesn't exist
}
}
Try
ParseUser.getCurrentUser().logOut();
I had the same problem. Actually it was a bug in parse sdk and the problem was solved without changing any of my code, just by installing the latest parse android sdk(1.8.1 at the time of writing).
I had the same issue it was because i has automatic user enabled which causes a new anonymous user to be created, it is also explained here
https://www.parse.com/questions/issues-with-parseuserlogout-on-android
Try to logout the current user object, not the class.
ParseUser.getCurrentUser().logout();
and make sure to delete
ParseUser.enableAutomaticUser();
Edit:
When you logout, the User instance will still available, but with null fields. Parse changes all the user's fields into nulls.
So, if you want to check whether the user is logged in or out, just do the following
if(ParseUser.getCurrentUser().getUsername() == null)
{ // user is out
} else {
// user is in }