I am writing a App for a Open Source Conference.
Originally each attendees will receive different link via email or SMS like
https://example.com/?token=fccfc8bfa07643a1ca8015cbe74f5f17
then use this link to open app, we can know the user is which attendee by the token.
Firebase release a new feature Dynamic Links in I/O 2016, it provide better experience for users.
I had try that, but I can't find any way to pass the custom parameters (the token) in dynamic links, how to use the same link with different parameters to my users?
Thanks.
I don't think you can use the short url:
https://<my app>.app.goo.gl/Gk3m
unless you create one for each user, but you can use the long url:
https://<my app>.app.goo.gl/?link=https://example.com/?token=fccfc8bfa07643a1ca8015cbe74f5f17 ...(add other parameters as needed)
and set new token for each user.
I assume you generate the tokens automatically. In that case you can use this to shorten the links.
1) From https://console.firebase.google.com/ (no need for custom parameter here.)
2) Create link somewhere, f.e. on your confluence page (here we add our parameter):
https://PROJECTNAME.page.link/?link=https://PROJECTNAME.page.link/LINKNAME?PARAMETER=1&ofl=https://www.PROJECTNAME.com/
PARAMETER is your custom parameter.
ofl is a link where to go if click the link from another platform (PC, Mac).
3) Getting link data from android project Kotlin code:
Firebase.dynamicLinks
.getDynamicLink(intent)
.addOnSuccessListener { pendingDynamicLinkData ->
val parameter: String =
pendingDynamicLinkData?.link?.getQueryParameter("PARAMETER").orEmpty()
}
If you want to use dynamic links with custom arguments with REST, here is an example of a payload:
{
"dynamicLinkInfo": {
"dynamicLinkDomain": "example.app.goo.gl",
"link": "http://someurl.com?my_first_param=test&my_second_param=test2"
},
"suffix": {
"option":"UNGUESSABLE"
}
}
Make sure your remove 'https://' from your dynamicLinkDomain
Julien
Case A. If you want the short link to expand to a link with multiple parameters:
In the part where you setup a dynamic link, any parameter you append to the deep link URL will go on all platforms (web, iOS, android)
Case B. If you want to use dynamic parameters, you should use the api to create a short link
see documentation
Now you can create short links using the Firebase SDK through the FirebaseDynamicLinks.getInstance().createDynamicLink():
https://firebase.google.com/docs/dynamic-links/android/create
Sample code:
Task shortLinkTask = FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLink(Uri.parse("https://example.com/"))
.setDynamicLinkDomain("abc123.app.goo.gl")
// Set parameters
// ...
.buildShortDynamicLink()
.addOnCompleteListener(this, new OnCompleteListener() {
#Override
public void onComplete(#NonNull Task task) {
if (task.isSuccessful()) {
// Short link created
Uri shortLink = task.getResult().getShortLink();
Uri flowchartLink = task.getResult().getPreviewLink();
} else {
// Error
}
}
});
Create a dynamic link
Go to link details
Copy the long dynamic link and add your parameter in the link parameter of the URL, e.g., PARAMETER=132323
https://link.projectname.com/?link=https://link.projectname.com/LINK?PARAMETER=132323&apn=com.projectname.app&afl=https://link.projectname.com/LINK
1 First Change your Dynamic Link in firebase console from http://exampleandroid/test to http://exampleandroid/test?data 2. You send the query paramter data with this
DynamicLink dynamicLink = FirebaseDynamicLinks.getInstance().createDynamicLink()
// .setLink(dynamicLinkUri)
.setLink(Uri.parse("http://exampleandroid/test?data=dsads"))
.setDomainUriPrefix("https://App_Name.page.link")
// Open links with this app on Android
.setAndroidParameters(new DynamicLink.AndroidParameters.Builder().build())
// Open links with com.example.ios on iOS
.setIosParameters(new DynamicLink.IosParameters.Builder("com.appinventiv.ios").build())
.buildDynamicLink();
dynamicLinkUri = dynamicLink.getUri();
You can add extra parameter to your link to generate Short URL from Firebase.
Here I given example of Short URL generation using Firebase API.
Here ServiceRequestHelper(this).PostCall is my generic class to make API request
String url = "https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=YOUR_KEY";
try {
PackageManager manager = this.getPackageManager();
PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0);
JSONObject jsonObject = new JSONObject();
JSONObject androidInfoObject = new JSONObject();
androidInfoObject.put("androidPackageName", getApplicationContext().getPackageName());
androidInfoObject.put("androidMinPackageVersionCode",String.valueOf(info.versionCode));
JSONObject iosInfoObject = new JSONObject();
iosInfoObject.put("iosBundleId", "tettares.Test_ID");
JSONObject dynamicLinkInfoObj = new JSONObject();
dynamicLinkInfoObj.put("dynamicLinkDomain", "wgv3v.app.goo.gl");
dynamicLinkInfoObj.put("link", "https://test.in/?UserId=14&UserName=Naveen"); // Pass your extra paramters to here
dynamicLinkInfoObj.put("androidInfo", androidInfoObject);
dynamicLinkInfoObj.put("iosInfo", iosInfoObject);
JSONObject suffixObject = new JSONObject();
suffixObject.put("option" , "SHORT");
jsonObject.put("dynamicLinkInfo", dynamicLinkInfoObj);
jsonObject.put("suffix", suffixObject);
Log.d("JSON Object : " , jsonObject.toString());
new ServiceRequestHelper(this).PostCall(url, jsonObject, false, new CallBackJson() {
#Override
public void done(JSONObject result) throws JSONException {
try {
if (result.has("shortLink")) {
DEEP_LINK_URL = result.getString("shortLink"); }
} catch(Exception e)
{
e.printStackTrace();
}
}
});
} catch (JSONException | PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
In Your Receiving Activity:
boolean autoLaunchDeepLink = false;
AppInvite.AppInviteApi.getInvitation(mGoogleApiClient, this, autoLaunchDeepLink)
.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);
// Handle the deep link. For example, open the linked
// content, or apply promotional credit to the user's
// account.
// [START_EXCLUDE]
// Display deep link in the UI
Log.d(TAG, "deeplink URL: " + deeplink); // Here you get https://test.in/?UserId=14&UserName=Naveen
// [END_EXCLUDE]
} else {
Log.d(TAG, "getInvitation: no deep link found.");
}
}
});
I tried all above but none work. So I think you should change the link http://example.com/?userid=123tohttp://example.com/userid/123
No need of all the hustle
Don't shorten the url if you want to pass parameters
Write the links like this.
//APP_CODE is firebase link
String link = "https://APP_CODE.app.goo.gl/?refferer=" + userId;
Intent intent = new AppInviteInvitation.IntentBuilder(getString(R.string.invitation_title))
.setMessage(getString(R.string.invitation_custom_message)))
.setDeepLink(Uri.parse(link))
.setCustomImage(Uri.parse(getString(R.string.invitation_custom_image)))
.setCallToActionText(getString(R.string.invitation_cta))
.build();
startActivityForResult(intent, REQUEST_INVITE);
For web apps, which generating dynamic links..
const data = {
dynamicLinkInfo: {
domainUriPrefix: 'subdomain.page.link',
link: url,
},
suffix: {
option: 'SHORT'
}
};
return fetch(`https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=${environment.firebaseConfig.apiKey}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
}).then(res => res.json()).then(response => response.shortLink).catch(console.error);
Related
I would like to use Firebase Dynamic Links for Unity (Android/iOS) so users can invite friends and be rewarded with.
Each user gets a different Short Dynamic Link in the form of https://test.page.link/abcd
The user can share this Short DynamicLink with friends.
When the invited friend comes into the app, this callback is called.
private void OnDynamicLink(object sender, EventArgs args) {
var dynamicLinkEventArgs = args as ReceivedDynamicLinkEventArgs;
Debug.LogFormat("Received dynamic link {0}",
dynamicLinkEventArgs.ReceivedDynamicLink.Url.OriginalString);
}
Unfortunately, I only get back the base link that was necessary to create the short dynamic link.
Received dynamic link https://www.example.com/referral?xxxxxxxxxx
I get an additional native output in my iOS app:
IOSNative::Native->Unity callback data:
{"m_EventName":"continueUserActivity","m_Data":"https://test.page.link/?link=https://www.example.com/referral?xxxxxxxxxx&apn=de.test.testapp&isi=123456789&ibi=de.test.testapp&cid=1579347010984123886&_osl=https://test.page.link/abcd&_fpb=AB6327276CFGHT==&_cpt=cpit&_iumenbl=1&_iumchkactval=1&_plt=2076&_uit=2692&_cpb=1"}
2020-01-14 15:30:20.455009+0100 ambassador[315:8406]
IOSNative::Native->Unity callback data:
{"m_EventName":"applicationDidBecomeActive","m_Data":""}
Now my question is how do I get the generated short dynamic link that I have shared with a friend in OnDynamicLink callback( https://test.page.link/abcd)?
I need the value behind the parameter "&_osl" as seen in additional native output. But I only get the Base Url back in Unity (https://www.example.com/referral?xxxxxxxxxx).
My solution at the end was to shorten the BaseLink with the help of DynamicLinks.GetShortLinkAsync.
//unescape url
baseLink = UnityEngine.Networking.UnityWebRequest.UnEscapeURL(baseLink);
var components = new DynamicLinkComponents(
// The base Link.
new Uri(baseLink),
// The dynamic link URI prefix.
domainUriPrefix) {
IOSParameters = new IOSParameters(PackageName) {
AppStoreId = "XXXXXXXXX"
},
AndroidParameters = new AndroidParameters(PackeName)
};
string inviteLink = string.Empty;
await DynamicLinks.GetShortLinkAsync(components, options).ContinueWith((task) => {
if (task.IsCanceled) {
Debug.LogError("GetShortLinkAsync was canceled.");
return;
}
if (task.IsFaulted) {
Debug.LogError("GetShortLinkAsync encountered an error: " + task.Exception);
return;
}
// Short Link has been created.
inviteLink = task.Result.Url.ToString();
});
I am trying to upload a file from my angular code to an ASP.net backend.
My Angular code sends the object using FormData:
public uploadFiles(files) {
console.log(files);
if(files.length < 1) return;
const formData = new FormData();
files.forEach(file => {
console.log(file);
formData.append(file.name, file);
})
this._http.postFile('/order-processing/import-orders','application/x-www-form-urlencoded' ,formData).pipe(finalize(() => {
console.log("Finalized");
})).subscribe((val: any) => {
console.log('ORDER SUBMITTED', val);
}, error => {
console.log(error);
});
}
With the post file method looking like:
public postFile(path: string, contentType:string, body: FormData) : Observable<any> {
let headers = {
'Content-Type': contentType,
'Authorization': this.authToken
}
return this._http.post(environment.API_URL + path, body, {
headers
});
}
My ASP.net endpoint looks like:
[HttpPost, Route("hospitality/order-processing/import-orders")]
[RequestSizeLimit(2147483648)]
[DisableRequestSizeLimit]
public IActionResult UploadFile()
{
try
{
//var req = Request.Form.Files;
var file = Request.Form.Files;
string folderName = "Uploads";
string webRootPath = _hostingEnvironment.WebRootPath;
string newPath = Path.Combine(webRootPath, folderName);
if (!Directory.Exists(newPath))
{
Directory.CreateDirectory(newPath);
}
return Json("Upload Successful.");
}
catch (Exception e)
{
return Json("Failed:" + e);
}
}
If I check the network tab on my browser when I send the file, it says that my object is in the call, great, but for some reason it doesn't get picked up on the backend and when I step through the code it is not there.
I get different errors when I modify this code slightly. The error for the code in the state it is in now is "Form key or value length limit 2048 exceeded", however sometimes I get array out of bounds errors, or content boundary limit exceeded errors, it's enough to make you want to slam you face into your keyboard continually.
The whole point of this is to be able to upload an excel file to ASP.net code running in an AWS lambda, which then inserts rows in a RDS database. Am I going about this the right way? Is there a better way to achieve what I am trying to do? If not then what is wrong with my code that doesn't allow me to upload a file to a Web API?!
Thanks
It seems that you're trying to set the limit of the request but the message states that the problem is with form key or value length.
Try setting the RequestFormLimits and check if that helps.
[HttpPost, Route("hospitality/order-processing/import-orders")]
[RequestFormLimits(KeyLengthLimit = 8192, ValueLengthLimit = 8192)]
public IActionResult UploadFile()
When I create dynamic links which contain UTM parameters and share it, I was able to retrieve the data and encoded queries from the link. But when I try to create a short link of a dynamic link using firebase recommended method, I can only able to retrieve the path, but not the encoded queries. how do I solve it?
METHOD FOR CREATING DYNAMIC LINK :
public void buildReferral() {
DynamicLink dynamicLink = FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLink(Uri.parse("sample link"))
.setDynamicLinkDomain("sample domain")
.setAndroidParameters(
new DynamicLink.AndroidParameters.Builder("com.package.my")
.build())
.setGoogleAnalyticsParameters(
new DynamicLink.GoogleAnalyticsParameters.Builder()
.setSource("referral")
.setContent("content")
.setMedium("Android")
.build())
.buildDynamicLink();
buildShortUrl(dynamicLink);
}
METHOD FOR CREATING SHORT LINK :
public void buildShortUrl(DynamicLink dynamicLink) {
Task<ShortDynamicLink> shortLinkTask = FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLongLink(Uri.parse(dynamicLink.getUri().toString()))
.buildShortDynamicLink()
.addOnCompleteListener(this, new OnCompleteListener<ShortDynamicLink>() {
#Override
public void onComplete(#NonNull Task<ShortDynamicLink> task) {
if (task.isSuccessful()) {
// Short link created
Uri shortLink = task.getResult().getShortLink();
Uri flowchartLink = task.getResult().getPreviewLink();
} else {
// Error
// ...
}
}
});
}
You can use appendQueryParameter() to add multiple parameters to the link, and by using getQueryParameter() you can retrieve parameters from link. You can see this answer how you can achieve it.
I am trying to upload video on my YouTube channel using ASP.NET Web Form. I created developer account and tested it working using JavaScript based solution which requires login every-time to upload a video.
I want users of my website to upload video directly on my channel and every auth should be in code behind, user should not be prompted to login. For this I wrote following class:
public class UploadVideo
{
public async Task Run(string filePath)
{
string CLIENT_ID = "1111111111111111111111.apps.googleusercontent.com";
string CLIENT_SECRET = "234JEjkwkdfh1111";
var youtubeService = AuthenticateOauth(CLIENT_ID, CLIENT_SECRET, "SingleUser");
var video = new Video();
video.Snippet = new VideoSnippet();
video.Snippet.Title = "Default Video Title";
video.Snippet.Description = "Default Video Description";
video.Snippet.Tags = new string[] { "tag1", "tag2" };
video.Snippet.CategoryId = "22"; // See https://developers.google.com/youtube/v3/docs/videoCategories/list
video.Status = new VideoStatus();
video.Status.PrivacyStatus = "unlisted"; // or "private" or "public"
using (var fileStream = new FileStream(filePath, FileMode.Open))
{
var videosInsertRequest = youtubeService.Videos.Insert(video, "snippet,status", fileStream, "video/*");
videosInsertRequest.ProgressChanged += videosInsertRequest_ProgressChanged;
videosInsertRequest.ResponseReceived += videosInsertRequest_ResponseReceived;
await videosInsertRequest.UploadAsync();
}
}
void videosInsertRequest_ProgressChanged(Google.Apis.Upload.IUploadProgress progress)
{
switch (progress.Status)
{
case UploadStatus.Uploading:
//Console.WriteLine("{0} bytes sent.", progress.BytesSent);
break;
case UploadStatus.Failed:
//Console.WriteLine("An error prevented the upload from completing.\n{0}", progress.Exception);
break;
}
}
void videosInsertRequest_ResponseReceived(Video video)
{
Console.WriteLine("Video id '{0}' was successfully uploaded.", video.Id);
}
public static YouTubeService AuthenticateOauth(string clientId, string clientSecret, string userName)
{
string[] scopes = new string[] { YouTubeService.Scope.Youtube, // view and manage your YouTube account
YouTubeService.Scope.YoutubeForceSsl,
YouTubeService.Scope.Youtubepartner,
YouTubeService.Scope.YoutubepartnerChannelAudit,
YouTubeService.Scope.YoutubeReadonly,
YouTubeService.Scope.YoutubeUpload};
try
{
// here is where we Request the user to give us access, or use the Refresh Token that was previously stored in %AppData%
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets { ClientId = clientId, ClientSecret = clientSecret }
, scopes
, userName
, CancellationToken.None
, new FileDataStore("Daimto.YouTube.Auth.Store")).Result;
YouTubeService service = new YouTubeService(new YouTubeService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "YouTube Data API Sample",
});
return service;
}
catch (Exception ex)
{
//Console.WriteLine(ex.InnerException);
return null;
}
}
}
Now using this class into Page_Load() of default.aspx, as given below:
protected void Page_Load(object sender, EventArgs e)
{
try
{
string path = "C:/Users/abhi/Desktop/TestClip.mp4";
new UploadVideo().Run(path).Wait();
}
catch (AggregateException ex)
{
//catch exceptions
}
}
When I run this (default.aspx) page, i see http://localhost:29540/default.aspx spins, so I used them on Google Developer Console as given below:
Upon running http://localhost:29540/default.aspx opens a new tab which displays "redirect_uri_mismatch" error as given below:
At this point if I look in browser address, I see redirect_uri is set to http://localhost:37294/authorize and I just manually change this to http://localhost:29540/default.aspx which generates a token.
So, can you suggest where to make changes in above code so that request uri fills up correctly from my app side.
A day waste then I came to know below redirect URL is working for all localhost web applications. So you need to use below URL on google developer console web application's "Authorized redirect URIs".
http://localhost/authorize/
For anybody still having this issue in 2022, I figured out a solution. If you are using https://localhost:portnumb as your redirect uri, just use https://127.0.0.1:sameportnumb as your redirect uri. It ended up working for me
I'm trying to drag and drop file upload with a progress bar.
I have a div which is listening to files being dropped on which is working perfectly.
I'm then..
//Setting up a XmlHttpRequest
xhr = new XMLHttpRequest();
//Open connection
xhr.open("post", "api/ImageUpload", true);
// Set appropriate headers
xhr.setRequestHeader("Content-Type", "multipart/form-data");
xhr.setRequestHeader("X-File-Type", uf.type);
xhr.setRequestHeader("X-File-Name", uf.name);
xhr.setRequestHeader("X-File-Size", uf.size);
This sends fine, with the stream as the body of the request to the Web API (not async).
[System.Web.Mvc.HttpPost]
public string Post()
{
Stream stream = HttpContext.Current.Request.InputStream;
String filename = HttpContext.Current.Request.Headers["X-File-Name"];
FileModel file = uploadService.UploadFile(stream, filename);
return file.Id.ToString();
}
I'm trying to chance the request to "public async Task< string> Post(){ }
If the method was using a multipart form on the page instead of XmlHttpRequest I would have used "await Request.Content.ReadAsMultipartAsync(provider)" but this doesn't seem to be populated at the time I need it.
So what is the correct was to handle and an Async call from XmlHttpRequest on a Web API in order to record progress during the request with XHR's progress event?
I have looked at a great deal of pages so far to find a solution but this is the page I have used primarily.
http://robertnyman.com/html5/fileapi-upload/fileapi-upload.html
Thanks for any help
Oliver
It looks like someone else had the same question with you and got an answer yet. please have a look at ASP.NET MVC 4 Web Api ajax file upload.
And here is an example from microsoft http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2.
I combined the two above solution together and worked for me (just adjust a little bit)
one line change in Javascritp
xhr.open("post", "api/upload", true);
Save the file using stream
public class UploadController : ApiController
{
public async Task<HttpResponseMessage> PostFormData()
{
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var fileName = Path.Combine(root, Request.Headers.GetValues("X-File-Name").First());
try
{
var writer = new StreamWriter(fileName);
await Request.Content.CopyToAsync(writer.BaseStream);
writer.Close();
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
}