How do I pass Parameters in Dynamic Links? - firebase

How to receive parameters from firebase dynamic links in flutter?
I created a short url:
https://subdomain.example.com/product
which points to
https://example.com/view-product
But I want to add a url query parameter like:
https://example.com/view-product?id=56
Note that "56" is variable and changes dynamically inside app flow. I am unable to receive this "id" parameter.
On browser I tried entering https://subdomain.example.com/product?id=56
I received the link: https://example.com/view-product
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
showModalBottomSheet(context: context, builder: (context){
return Container(
height: 100.0,
child: Text(deepLink.toString()),
);
});
if (deepLink != null) {
debugPrint("Link found on line: "+deepLink.queryParameters.toString());
}
}, onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
});

I finally figured it out!
I was understanding the concept totally wrong here.
There are 4 ways as of now to create dynamic links.
1) Firebase Console
2) Manually
3) Rest API
4) Dynamic Link Builder API on iOS and Android
What I was doing wrong here is was, I created https://subdomain.example.com/product a dynamic link from firebase console and was testing it against a manually created link.
2nd method(Manually) is much more powerful is you need to link dynamic content from your website links.
https://your_subdomain.page.link/?link=your_deep_link&apn=package_name[&amv=minimum_version][&afl=fallback_link]
The above mentioned is the standard manual procedure for creating dynamic links.
Lets break down the above link so that it looks less scary:
https://your_subdomain.page.link ==> This is simply your subdomain you registered on firebase console. In our case it's https://subdomain.example.com
link=your_deep_link ==> your_deep_link is basically your deep link(the link you want to open with that exists on your server, it can contain all the parameters you need). In our case its https://example.com/view-product?id=56. But note that this link is to be embedded inside an url so it needs to be urlencoded first. Use any url encoder for this purpose. The resulting encoded string becomes
https%3A%2F%2Fexample.com%2Fview-product%3Fid%3D56
apn=package_name ==> your respective package name for IOS or Android
[&amv=minimum_version] ==> "[]" represent this as an optional parameters. This parameter is the minimum version number of your app that you want your app should respond to this dynamic link (0 if you want all versions to support)
[&afl=fallback_link] ==> ==> "[]" represent this as an optional parameters. This is the fallback url, again url encoded. Could be your android play store link.
So our final dynamic link looks like:
https://subdomain.example.com/?link=https%3A%2F%2Fexample.com%2Fview-product%3Fid%3D56&apn=com.example&amv=0

Related

Flutter dynamic links test

Edited Question :
I have an issue with Firebase Dynamic Links Packag , My goal is getting know if new user installed and opend my app for first time to give him a rewards like 10 point . I tried to search everywhere but no answer,in firebase website there is option to know if user install for first time.
My Goal is : Getting value for first time install & how to debug this code ?
initDynamicLinks when app Lanched :
void initDynamicLinks() async {
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
}
},
onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
}
);
final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deepLink = data?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
}
}
.
You're mixing two things here.
The First-opens tab gives you the number of unique users who clicked on your Firebase Dynamic Link for the first time.
If you want to know how many unique users used your app, by clicking the Firebase Dynamic Link or not to get to your app, you have to implement the Firebase Analytics plugin to your app.
This way you'll get access to Dashboards showing you how many Unique users you have.
EDIT
Reading your comment, looks like your question is not related to your problem.
What you want here is to attribute rewards for users who invited their friends thanks to a referral link.
Since I never implemented this witout a dedicated backend, the only thing I can share is a use-case I used some time ago explaining the logic to follow to implement it.
https://firebase.google.com/docs/dynamic-links/use-cases/rewarded-referral
EDIT 2
The logic explained in the documentation is the following :
1- Generate a Dynamic Link for UserA.
2- UserA sends the Dynamic Link to someone (called UserB).
3- When UserB starts the app from a Dynamic Link, retrieve the referral informations in the app (to retrieve UserA's informations)
4- Call a route on your backend to attribute the reward to UserA (and check if UserB is really a new user in your database).
The point is, you shouldn't manage a referral/referrer relationship on the client's side (it would be way too easily abused/hacked).
It's the job of a backend (or cloud function) to manage this.
Once you have received the link clickthrough in your app use the google_analytics package to log an event.
Related thread here:
Flutter log event with google analytics
To be honest i have never used Firebase Dynamic Links , But if your Goal is to Achieve a first open or login token , you can always use the Sharedpreferences package , in my case iam using it to navigate to different pages passed on the first login value .
i think that Sharedpreferences is more reliable and easier than what you are trying to achieve with firebase
UPDATE:
what you actually want to do is make a firebase collection with IMEI numbers , when there is a new IMEI that means a new user , when that IMEI is in your collection that means that the app is not installed for the first time ,
you can use this package imei_plugin to get IMEI number and store it on firebase

Linking images from Firebase Storage to Firestore document and displaying them in React Native

Background
I'm trying to upload images to firebase storage manually (using the upload file button in the web page), however I have no clue how to later link them to a firestore document. What I have come up with (I'm unsure if it works) is copying the url for the image in the storage bucket and adding it to a string type field in the document called profilePicture. The reason I'm unable to get this to work is that I'm really new to React Native and I don't know how to properly require the images other than typing in the specific local route. Mind you also, the way I'm requiring user data such as a profile name is after logging in with email/password auth I pass the data as a param to react navigation and require it as extraData.
What I have tried
Once I've copied the image url and pasted it in the firestore document I'm doing this:
const profilePicture = props.extraData.profilePicture;
<Image source={require({profilePicture})}/>
I have also tried using backticks but that isn't working either. The error message I'm getting is:
TransformError src\screens\Profile\ProfileScreen.js: src\screens\Profile\ProfileScreen.js:Invalid call at line 27: require({
profilePicture: profilePicture
})
Note: this is an expo managed project.
Question
Is the problem in the code or in the way I'm linking both images? Maybe both? Should I require the document rather than relying on the data passed previously?
Thanks a lot in advance!
Edit 1:
I'm trying to get all info from the current user signed in, after a little research I've come to know about requiring images in this manner:
const ref = firebase.storage().ref('path/to/image.jpg');
const url = await ref.getDownloadURL();
and then I'd require the image as in <Image source={{uri: url}}/>
I get that this could be useful for something static, but I don't get how to update the ref for every single different user.
Edit 2:
Tried using the method mentioned in Edit 1, just to see what would happen, however It doesn't seem to work, the image just does not show up.
Maybe because my component is a function component rather than a class component (?
I understand that your goal is to generate, for each image that is uploaded to Cloud Storage, a Firestore document which contains a download URL.
If this is correct, one way is to use a Cloud Function that is triggered each time a new file is added to Cloud Storage. The following Cloud Function code does exactly that. You may adapt it to your exact requirements.
exports.generateFileURL = functions.storage.object().onFinalize(async object => {
try {
const bucket = admin.storage().bucket(object.bucket);
const file = bucket.file(object.name);
// You can check that the file is an image
const signedURLconfig = { action: 'read', expires: '08-12-2025' }; // Adapt as follows
const signedURLArray = await file.getSignedUrl(signedURLconfig);
const url = signedURLArray[0];
await admin.firestore().collection('profilePictures').add({ fileName: object.name, signedURL: url }) // Adapt the fields list as desired
return null;
} catch (error) {
console.log(error);
return null;
}
});
More info on the getSignedUrl() method of the Admin SDK here.
Also note that you could assign the Firestore document ID yourself, instead of having Firestore generating it as shown in the above code (with the add() method). For example, you can add to the image metadata the uid of the user and, in the Cloud Function,get this value and use this value as the Document ID.
Another possibility is to name the profile image with the user's uid.

Flutter Dynamic Links get added parameters

So, I am currently using Flutter to develop an IOS-App and added Firebase.
I am trying to use PayPal-Connect with the url_launcher package. As the PayPal-Connect link looks like this:
https://www.sandbox.paypal.com/connect?flowEntry=static&client_id=[<my_client_Id>]&scope=&redirect_uri=[<my_url>]
I am trying to use Firebase Dynamic Links for the redirect_uri to go back to the app and fetch the data I got from Pay-Pal as url parameters. The problem is that whenever I run this code:
Future<void> retrieveDynamicLink() async {
final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deepLink = data?.link;
if (deepLink != null) {
print(deepLink);
print(deepLink.queryParameters['code']);
}
}
The logs say:
flutter: https://domain.page.link/ppc
flutter: null
But I know from the Paypal-Connect Docs that they add a code=[<some_code>] parameter.
But is the thing I plan to do even possible with Dynamic Links? Or Am I doing something completely wrong?
Checking the implementation, it looks like you're trying to implement something similar to a reward referral use case. The reason why deepLink.queryParameters['code'] returns null is because there's no code parameter configured on the deep link of the Firebase Dynamic Link that has been handled.
To configure a query parameter for code, the deep link of your Dynamic Link should look something similar to https://example.com/?code={CODE}

Adding a button for google signin using f#/fable/asp.net/react

I'm working with the SAFE stack (https://safe-stack.github.io/) and through the example dojo. It's great so far.
I'd like to extend the example to include a button to login/auth via Google. So I looked at an example on the Google website (https://developers.google.com/identity/sign-in/web/build-button). And then I had a look how to do authentication using ASP.NET (https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins?view=aspnetcore-2.1&tabs=aspnetcore2x) As a result I ended up confused as to how to integrate this into a SAFE project. Can someone tell me what they would do? SHould I be trying to use ASP.NET Identity or should I be using the JWT approach? I don't even know if they are the same since I'm very new to web frameworks.....
The other question I have is how would one inject raw Javascript into the client side of a SAFE project. The google example above shows raw JS/CSS/HTML code? Should I be injecting that as is or should I look in React for some button that does this and map that idea back through Fable?
Setting up OAuth
The easiest way to use Google OAuth is to wait until the next release of Saturn, at which point Saturn will include the use_google_oauth feature that I just added. :-) See the source code if you're interested in how it works, though I'm afraid you can't implement this yourself with use_custom_oauth because you'll run into a type error (the underlying ASP.NET code has a GoogleOptions class, and use_custom_oauth wants an OAuthOptions class, and they aren't compatible).
To use it, add the following to your application CE:
use_google_oauth googleClientId googleClientSecret "/oauth_callback_google" []
The last parameter should be a sequence of string * string pairs that represent keys and values: you could use a list of tuples, or a Map passed through Map.toSeq, or whatever. The keys of that sequence are keys in the JSON structure that Google returns for the "get more details about this person" API call, and the values are the claim types that those keys should be mapped to in ASP.NET's claims system. The default mapping that use_google_oauth already does is:
id → ClaimTypes.NameIdentifier
displayName → ClaimTypes.Name
emails[] (see note) → ClaimTypes.Email
Those three are automatically mapped by ASP.NET. I added a fourth mapping:
avatar.url → `"urn:google:avatar:url"
There's no standard ClaimTypes name for this one, so I picked an arbitrary URN. Caution: this feature hasn't been released yet, and it's possible (though unlikely) that this string might change between now and when the feature is released in the next version of Saturn.
With those four claim types mapped automatically, I found that I didn't need to specify any additional claims, so I left the final parameter to use_google_oauth as an empty list in my demo app. But if you want more (say you want to get the user's preferred language to use in your localization) then just add them to that list, e.g.:
use_google_oauth googleClientId googleClientSecret "/oauth_callback_google" ["language", "urn:google:language"]
And then once someone has logged in, look in the User.Claims seq for a claim of type "urn:google:language".
Note re: the emails[] list in the JSON: I haven't tested this with a Google account that has multiple emails, so I don't know how ASP.NET picks an email to put in the ClaimTypes.Email claim. It might just pick the first email in the list, or it might pick the one with a type of account; I just don't know. Some experimentation might be needed.
Also note that third-party OAuth, including GitHub and Google, has been split into a new Saturn.Extensions.Authorization package. It will be released on NuGet at the same time that Saturn's next version (probably 0.7.0) is released.
Making the button
Once you have the use_google_oauth call in your application, create something like the following:
let googleUserIdForRmunn = "106310971773596475579"
let matchUpUsers : HttpHandler = fun next ctx ->
// A real implementation would match up user identities with something stored in a database, not hardcoded in Users.fs like this example
let isRmunn =
ctx.User.Claims |> Seq.exists (fun claim ->
claim.Issuer = "Google" && claim.Type = ClaimTypes.NameIdentifier && claim.Value = googleUserIdForRmunn)
if isRmunn then
printfn "User rmunn is an admin of this demo app, adding admin role to user claims"
ctx.User.AddIdentity(new ClaimsIdentity([Claim(ClaimTypes.Role, "Admin", ClaimValueTypes.String, "MyApplication")]))
next ctx
let loggedIn = pipeline {
requires_authentication (Giraffe.Auth.challenge "Google")
plug matchUpUsers
}
let isAdmin = pipeline {
plug loggedIn
requires_role "Admin" (RequestErrors.forbidden (text "Must be admin"))
}
And now in your scope (NOTE: "scope" will probably be renamed to "router" in Saturn 0.7.0), do something like this:
let loggedInView = scope {
pipe_through loggedIn
get "/" (htmlView Index.layout)
get "/index.html" (redirectTo false "/")
get "/default.html" (redirectTo false "/")
get "/admin" (isAdmin >=> htmlView AdminPage.layout)
}
And finally, let your main router have a URL that passes things to the loggedInView router:
let browserRouter = scope {
not_found_handler (htmlView NotFound.layout) //Use the default 404 webpage
pipe_through browser //Use the default browser pipeline
forward "" defaultView //Use the default view
forward "/members-only" loggedInView
}
Then your login button can just go to the /members-only route and you'll be fine.
Note that if you want multiple OAuth buttons (Google, GitHub, Facebook, etc) you'll probably need to tweak that a bit, but this answer is long enough already. When you get to the point of wanting multiple OAuth buttons, go ahead and ask another question.

Firebase storage with Ionic 2 SocialSharing plugin

My images are stored in firebase storage. I have noticed that if I store the image in a folder, I am no longer able to use it with the SocialSharing plugin from ionic native.
Anyone has found any workaround on this?
whatsappShare() {
let image = "https://firebasestorage.googleapis.com/v0/b/instagram-test-fe4a8.appspot.com/o/000.jpg?alt=media&token=64dd92cd-27c2-4c36-9c1d-2ab376ffd16c" //This is working
//let image = "https://firebasestorage.googleapis.com/v0/b/instagram-test-fe4a8.appspot.com/o/test%2F000.jpg?alt=media&token=2bc49648-cf1c-41fe-8e1f-071d54f56402" //This is failing because stored in test/ folder
//shareViaWhatsApp(message, image, url)
SocialSharing.shareViaWhatsApp("Checkout this picture!", image, "lycos.com/")
.then( () => {
alert("WhatsApp Success");
}, () => {
alert("WhatsApp failed")
})
}
I have found this github which seems related
https://github.com/EddyVerbruggen/SocialSharing-PhoneGap-Plugin/issues/696
It means the plugin can work in iOS and fail in android?
Any possible solution to this?
Yes. Finally I got a way to share images from Firebase Storage to any service. Just follow these two conditions:
Convert the image from the uri to a base64 string. You can find plenti of examples of that conversion out there.
Send the image data using shareWithOptions(). Other methods seem not to work with image data encoded that way.
I'm interested in any other updates regarding this issue. Hope that helps anyone.

Resources