How to create a Firebase short dynamic link - java

I'm successfully creating a Firebase dynamic link in Java on Android. My code to do so is in a button click listener.
shareButton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
DynamicLink dynamicLink = FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLink(Uri.parse("https://www.mycompany.com/"))
.setDomainUriPrefix("https://mycompany.page.link/test")
.setAndroidParameters(
new DynamicLink.AndroidParameters.Builder("com.mycompany.app")
.setFallbackUrl(Uri.parse("https://www.mycompany.com/"))
.setMinimumVersion(1)
.build())
.buildDynamicLink();
Uri dynamicLinkUri = dynamicLink.getUri();
shareDynamicLink(dynamicLinkUri);
}
});
public void shareDynamicLink(Uri dynamicLink)
{
Intent shareIntent = new Intent();
String msg = "Check this out: " + dynamicLink;
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, msg);
shareIntent.setType("text/plain");
startActivity(shareIntent);
}
This sends a LONG dynamic link that works just fine. Now I'd like to shorten the link, so I replaced the 'shareDynamicLink' method with this code.
public void shareDynamicLink(Uri dynamicLink)
{
Task<ShortDynamicLink> shortLinkTask = FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLongLink(dynamicLink)
.buildShortDynamicLink()
.addOnCompleteListener(Objects.requireNonNull(this.getActivity()), new OnCompleteListener<ShortDynamicLink>()
{
#Override
public void onComplete(#NonNull Task<ShortDynamicLink> task)
{
if (task.isSuccessful())
{
// Short link created
Uri shortLink = Objects.requireNonNull(task.getResult()).getShortLink();
Uri flowchartLink = task.getResult().getPreviewLink();
Log.e("DynamicLink", "shortLink: " + shortLink + System.lineSeparator());
Log.e("DynamicLink", "flowChartLink: " + flowchartLink + System.lineSeparator());
Intent shareIntent = new Intent();
String msg = "Check this out: " + shortLink;
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, msg);
shareIntent.setType("text/plain");
startActivity(shareIntent);
}
else
{
Toast.makeText(context, "Failed to share event.", Toast.LENGTH_SHORT).show();
}
}
});
}
This second method produces an error that I don't understand.
"400: Cannot shorten a short Dynamic Link:
https://mycompany.page.link/test?afl=https%3A%2F%2Fwww.mycompany.com%2F&amv=1
&apn=com.mycompany.app&ibi=com.mycompany.app&ifl=https%3A%2F%2F
www.mycompany.com%2F&isi=963543827&ipfl=https%3A%2F%2F
www.mycompany.com%2F&link=https%3A%2F%2Fwww.mycompany.com%2F
[https://firebase.google.com/docs/dynamic-links/rest#create_a_short_link_from_parameters]
What am I missing here? This seems like it should work.
Note: I don't need the long dynamic link, just the short one. I tried changing the onClickListener as follows.
shareButton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Task<ShortDynamicLink> dynamicLink = FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLink(Uri.parse("https://www.mycompany.com/"))
.setDomainUriPrefix("https://mycompany.page.link/test")
.setAndroidParameters(
new DynamicLink.AndroidParameters.Builder("com.mycompany.app")
.setFallbackUrl(Uri.parse("https://www.mycompany.com/"))
.setMinimumVersion(1)
.build())
.buildShortDynamicLink()
.addOnCompleteListener(Objects.requireNonNull(getActivity()), new OnCompleteListener<ShortDynamicLink>()
{
#Override
public void onComplete(#NonNull Task<ShortDynamicLink> task)
{
if (task.isSuccessful())
{
Uri shortLink = Objects.requireNonNull(task.getResult()).getShortLink();
Uri flowchartLink = task.getResult().getPreviewLink();
Log.e("DynamicLink", "shortLink: " + shortLink + System.lineSeparator());
Log.e("DynamicLink", "flowChartLink: " + flowchartLink + System.lineSeparator());
}
else
{
Log.e("DynamicLink", "Link failed: " + task.getException().getMessage() + System.lineSeparator());
}
}
});
}
});
But I still get the same 400 error.
400: Cannot shorten a short Dynamic Link:
https://mycompany.page.link/test?afl=https%3A%2F%2Fwww.mycompany.com%2F&amv=1
&apn=com.mycompany.app&ibi=com.mycompany.app&ifl=https%3A%2F%2F
www.mycompany.com%2F&isi=963543827&ipfl=https%3A%2F%2Fwww.mycompany.com%2F
&link=https%3A%2F%2Fwww.mycompany.com%2F
[https://firebase.google.com/docs/dynamic-links/rest#create_a_short_link_from_parameters]

For anyone who finds this, my problem stemmed from a misunderstanding of how programmatically generated links work vs. predefined links. In my case I was trying to use a pre-defined link from the Firebase console ("https://mycompany.page.link/test") as the PREFIX for my generated link. That caused some sort of confusion on the back end when I tried to shorten it. I still don't understand exactly what it didn't like, but point is it failed.
So the solution for generating links was to use only the base prefix from the Firebase console - .setDomainPrefix("https://mycompany.page.link/"). Using that I can create either ".buildShortDynamicLink()" or "buildDynamicLink()".
The link I created in the Firebase console ("http://mycompany.page.link/test") can only be used verbatim -- no need to generate anything. Just put it in a text message literally and you're done.

Are you going to use the longer version at all, or only the short one? If so, does it work if you use .buildShortDynamicLink() instead of .buildDynamicLink() in your onClick(...) method without the conversion in shareDynamicLink(...)?

Related

Get value from deeplink parameter rather than dynamic link in android java

I made an application in which users can send links to their friends. With the link, I added some parameters, So when the user clicks on the link the page with the given parameter will open.
The deep link user sends to his friends is:
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
String shareBody = "https://shareemotion.page.link/mood?mood=Sad&bottomneg=2";
sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Subject Here");
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, shareBody);
context.startActivity(Intent.createChooser(sharingIntent, "Share via"));
While the dynamic link in firebase is:
https://www.myapp.com/?mood=Happy&bottomneg=2
And the code for getting data from link is :
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();
}
if(deepLink!=null)
{
String mood = deepLink.getQueryParameter("mood");
String bottomId = deepLink.getQueryParameter("bottomneg");
NewActivity(mood, bottomId);
}
}
})
.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e( "getDynamicLink", " "+e);
}
});
So Now when I share the link with mood=Sad the app run but at the fetching point it fetches "Happy"(which is present in the dynamic link) but I want to fetch mood=Sad from the link that sends to another user.
Note
mood=Sad will replace by variable, for now, it uses for testing purposes.

Not getting the correct Firebase String Android

I am trying to get a String reference from a nested Collection but it generates a random String instead, I don't understand why because i have it set up in another class and it works correctly (but that is atop level collection.
I am saving as follows:
String folderFirebaseString;
-----------------------
folderFirebaseString = collectionReference.document("User_" + JournalApi.getInstance().getUserId()).collection("Created_Folders").document().getId();
final FolderJournal folderJournal = new FolderJournal();
folderJournal.setTitle(title);
folderJournal.setUserId(currentUserId);
folderJournal.setFolderId(folderFirebaseString);
Log.d(TAG, "folderFireBaseString: " + folderFirebaseString);
//Collection Reference --> Journal <-- document --> unique userID + username entered at registration <-- Collection for Titles --> titleTextView
db.collection("Journal").document("User_" + JournalApi.getInstance().getUserId()).collection("Created_Folders").document().set(folderJournal).addOnSuccessListener(new OnSuccessListener<Void>() {
public void onSuccess(Void aVoid) {
Log.d(TAG, "onSuccess FULL PATH: "+ db.collection("Journal").document("User_" + JournalApi.getInstance().getUserId()).collection("Created_Folders").document().getId());
progressBar.setVisibility(View.INVISIBLE);
Intent intent = new Intent(FolderCreation.this, FoldersActivity.class);
startActivity(intent);
finish();
}
})
My folderFirebaseString returns a random String as wel as the LogD i have set up returns a different random string but the db.collection...(etc...) random generated string in firebase is actually something else.
In another class I have this set up but just as collectionReference = db.collection("CollectionNameHere").getDocument().getId(); and this works and gets the correct String. what am i doing wrong?
I managed to solve this by pre-generating a firebase string and then passing it to its self.
String folderFirebaseString;
-----------------------
folderFirebaseString = collectionReference.document("User_" + JournalApi.getInstance().getUserId()).collection("Created_Folders").document().getId();
final FolderJournal folderJournal = new FolderJournal();
folderJournal.setTitle(title);
folderJournal.setUserId(currentUserId);
folderJournal.setFolderId(folderFirebaseString);
//Collection Reference --> Journal <-- document --> unique userID + username entered at registration <-- Collection for Titles --> titleTextView
db.collection("Journal").document("User_" + JournalApi.getInstance().getUserId()).collection("Created_Folders").document(**folderFirebaseString**).set(folderJournal).addOnSuccessListener(new OnSuccessListener<Void>() {
public void onSuccess(Void aVoid) {
Log.d(TAG, "onSuccess FULL PATH: "+ db.collection("Journal").document("User_" + JournalApi.getInstance().getUserId()).collection("Created_Folders").document(*###folderFirebaseString###*).getId());
progressBar.setVisibility(View.INVISIBLE);
Intent intent = new Intent(FolderCreation.this, FoldersActivity.class);
startActivity(intent);
finish();
}
})

Why does the command transaction.update is executed before the carrelloAttuale.prodotti.add() command

I'm trying to get a product from a document form the cloud firestore and then put that product in the shopping cart. When i read (successfully) the product, i try to put it in an arraylist that is declared outside but it doesnt work unless i put final to the variable.
Doing so, when I run the code below, I successfully retrieve the data, but the operation carrelloAttuale.prodotti.add(prod) is executed after the command transaction.update(), so the update doesn't upload nothing different from the start.
//prendo l'utente
FirebaseAuth auth= FirebaseAuth.getInstance();
//mi salvo il codice del prodotto scannerizzato
final String codiceProdottoScannerizzato=String.valueOf(intentData);
final FirebaseFirestore db = FirebaseFirestore.getInstance();
final DocumentReference docRef = db.collection("carrelli").document(auth.getUid());
final DocumentReference docrefprodotti = db.collection("prodotti").document(codiceProdottoScannerizzato);
db.runTransaction(new Transaction.Function<Void>() {
#Override
public Void apply(Transaction transaction) throws FirebaseFirestoreException {
DocumentSnapshot snapshot = transaction.get(docRef);
final Carrello carrelloAttuale = snapshot.toObject(Carrello.class);
docrefprodotti.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
Prodotti prod=document.toObject(Prodotti.class);
prod.id=codiceProdottoScannerizzato;
prod.totalePezziCarrello=1;
carrelloAttuale.prodotti.add(prod);
Log.d(TAG, "PRODOTTO: " + prod.toString());
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
}
});
Log.d(TAG, "CARRELLO FB: " + carrelloAttuale.size());
transaction.update(docRef, "prodotti", carrelloAttuale.getProdotti());
// Success
return null;
}
}).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "Transaction success!");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "Transaction failure.", e);
}
});
I expect that the command update is executed after the carrelloAttuale.prodotti.add(prod)
in the debug log the order of tags are:
CARRELLO FB: 0
PRODOTTO: Nome: latte
Data is loaded from Firestore asynchronously, since it may have to be retrieved from the server. To prevent blocking the app, the main code continues while the data is being retrieved. Then when the data is available, your onComplete gets called.
This means that any code that needs the data from the data, must be inside the onComplete method, or be called from there. So something like:
docrefprodotti.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
Prodotti prod=document.toObject(Prodotti.class);
prod.id=codiceProdottoScannerizzato;
prod.totalePezziCarrello=1;
carrelloAttuale.prodotti.add(prod);
Log.d(TAG, "PRODOTTO: " + prod.toString());
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
Log.d(TAG, "CARRELLO FB: " + carrelloAttuale.size());
transaction.update(docRef, "prodotti", carrelloAttuale.getProdotti());
}
});
Also see:
How to return a DocumentSnapShot as a result of a method?
Firebase Firestore get data from collection
"the command update" is executed before "carrelloAttuale.prodotti.add(prod)" is called because the onComplete() method has an asynchronous behaviour and returns immediately. This means that listener will not get invoked until some time later, after the database update operation is complete. There is no guarantee how long it will take. Depending on your connection speed and the state, it may take from a few hundred milliseconds to a few seconds for the update operation to complete.
If you want to use some logic with that data, you must wait until the asynchronous Firebase database operation is complete. This means that you can only use the prod object inside the listener callback itself.
For more informarions, I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.

Doucment.getString not giving an output (Firestore)

I just wrote a basic code to get multiple documents from Firestore database. The task is getting successful and you could see the document.getId() & document.getData() value in Log, but after that when I use document.getString(), it gives a blank output. I have been trying to find my error but I am unable to and I have a project submission due tomorrow. Ignore all the textview declaration in the given code below:
private FirebaseFirestore db;
private int month,year;
private Calendar calendar;
private String email;
private String name,points;
private int i,j;
private String q,p,r;
public String[][] data= new String[10][10];
private TextView rankingTextView,a,b;
public TextView t01,t02,t03,t10,t11,t12,t20,t21,t22,t30,t31,t32,t40,t41,t42,t50,t51,t52,t60,t61,t62,t70,t71,t72,t80,t81,t82,t90,t91,t92;
private static final String TAG = "MyApp";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_leaderboard);
calendar=Calendar.getInstance();
t01=(TextView)findViewById(R.id.t00);
t02=(TextView)findViewById(R.id.t01);
t03=(TextView)findViewById(R.id.t02);
t10=(TextView)findViewById(R.id.t10);
t11=(TextView)findViewById(R.id.t11);
t12=(TextView)findViewById(R.id.t12);
t20=(TextView)findViewById(R.id.t20);
t21=(TextView)findViewById(R.id.t21);
t22=(TextView)findViewById(R.id.t22);
t30=(TextView)findViewById(R.id.t30);
t31=(TextView)findViewById(R.id.t31);
t32=(TextView)findViewById(R.id.t32);
t40=(TextView)findViewById(R.id.t40);
t41=(TextView)findViewById(R.id.t41);
t42=(TextView)findViewById(R.id.t42);
t50=(TextView)findViewById(R.id.t50);
t51=(TextView)findViewById(R.id.t51);
t52=(TextView)findViewById(R.id.t52);
t60=(TextView)findViewById(R.id.t60);
t61=(TextView)findViewById(R.id.t61);
t62=(TextView)findViewById(R.id.t62);
t70=(TextView)findViewById(R.id.t70);
t71=(TextView)findViewById(R.id.t71);
t72=(TextView)findViewById(R.id.t72);
t80=(TextView)findViewById(R.id.t80);
t81=(TextView)findViewById(R.id.t81);
t82=(TextView)findViewById(R.id.t82);
db= FirebaseFirestore.getInstance();
email = getIntent().getStringExtra("email");
month = calendar.get(Calendar.MONTH);
month = month + 1;
year = calendar.get(Calendar.YEAR);
i=0;
j=0;
dothis();
Toast.makeText(this, "MO", Toast.LENGTH_SHORT).show();
t01.setText(data[0][0]);
t02.setText(data[0][1]);
t11.setText(data[1][0]);
t12.setText(data[1][1]);
t21.setText(data[2][0]);
t22.setText(data[2][1]);
t31.setText(data[3][0]);
t32.setText(data[3][1]);
t41.setText(data[4][0]);
t42.setText(data[4][1]);
t51.setText(data[5][0]);
t52.setText(data[5][1]);
}
private void dothis()
{i=0;
j=0;
db.collection("users")
// .whereGreaterThanOrEqualTo("points" + Integer.toString(month) + Integer.toString(year), "0")
.orderBy("points" + Integer.toString(month) + Integer.toString(year)).limit(10)
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
if(document.exists()) {
Log.d(TAG, document.getId() + " => " + document.getData() + " ");
data[i][j] = document.getString("username");
data[i][j + 1] = document.getString("points" + Integer.toString(month) + Integer.toString(year));
i++;
Toast.makeText(Leaderboard.this, "OK", Toast.LENGTH_SHORT).show();
}
}
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
}
});
}
}
Please don't duplicate my question. I searched a lot before putting.
According to your comment, you say that when are you calling the following line of code:
t01.setText(data[0][0]);
Nothing is set to your t01 TextView and this is the normal behaviour since the data that is coming from the Firebase database is asynchronous. This means that the onComplete() method returns immediately after it's invoked, and the callback from the Task it returns, will be called some time later.
There are no guarantees about how long it will take. So it may take from a few hundred milliseconds to a few seconds before that data is available. Because this method returns immediately, the value of your data[0][0] variable you're trying to use outside the onComplete() method, will not have been populated from the callback yet.
Basically, you're trying to use a value synchronously from an API that's asynchronous. That's not a good idea. You should handle the APIs asynchronously as intended.
A quick solve for this problem would be set all those texts to your TextViews only inside the onComplete() method. If you need to set them outside, I recommend dive into the asynchronous worlds and see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.

Getting one Activity from another within If case condition

I am trying to insert data using the Retrofit library. The data has been inserted successfully and I am also receiving the response from the API, but my error is that I am not getting the intent Activity (AdminActivity.class) after the Toast. Can anyone help me on this??
private void createUserResponse() {
ApiInterface apiInterface = ApiClient.getClient().create(ApiInterface.class);
CreateUserRequest createUserRequest = new CreateUserRequest(editTextUserId.getText().toString().trim(),
editTextPassword.getText().toString().trim(),
editTextUserName.getText().toString().trim(),
editTextProfileImage.getText().toString().trim(), editTextSchoolId.getText().toString().trim(),editTextRole.getText().toString().trim());
Call<CreateUserResponse> createUserResponseCall = apiInterface. createUserCall(createUserRequest);
createUserResponseCall.enqueue(new Callback<CreateUserResponse>() {
#Override
public void onResponse(Call<CreateUserResponse> call, Response<CreateUserResponse> response) {
Log.d("CreateUser" , "onResponse: " + response.body().getMessage());
String status = response.body().getStatus();
if (status.equals("sucess")){
String message = response.body().getMessage();
Toast.makeText(getActivity(),"User Created Successfully" + message,Toast.LENGTH_SHORT).show();
Intent i = new Intent(getActivity(), AdminActivity.class);
startActivity(i);
} else{
String message = response.body().getMessage();
Toast.makeText(getActivity(),"" + message, Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<CreateUserResponse> call, Throwable t) {
}
});
}
You have a typo within your if-else condition, so your code do not execute the if statement even if you get a successful response.
Fix the following typo and try again:
if (status.equals("success")) // fixed typo on "sucess" word

Categories

Resources