I'm trying to get google firebase dynamic link work on my .net core project my code is as below
public static async Task<string> GetShortLink(string longLink)
{
var service = AuthenticateServiceAccount("[email protected]", "Opt/Keys/quallogi-keys.json", new[] { "https://www.googleapis.com/auth/firebase" });
var request = service.ManagedShortLinks.Create(new CreateManagedShortLinkRequest
{
DynamicLinkInfo = new DynamicLinkInfo
{
//DynamicLinkDomain = "https://quallogi.page.link",
DomainUriPrefix = "quallogi.page.link",
AnalyticsInfo = new AnalyticsInfo(),
IosInfo = new IosInfo(),
Link = "https://github.com/distriqt/ANE-Firebase/wiki/DynamicLinks---Create-Dynamic-Links",
},
Suffix = new Suffix { Option = "SHORT" },
Name = "shortlink",
});
var response = await request.ExecuteAsync();
return response.PreviewLink;
}
public static FirebaseDynamicLinksService AuthenticateServiceAccount(string serviceAccountEmail, string serviceAccountCredentialFilePath, string[] scopes)
{
try
{
if (string.IsNullOrEmpty(serviceAccountCredentialFilePath))
throw new Exception("Path to the service account credentials file is required.");
if (!File.Exists(serviceAccountCredentialFilePath))
throw new Exception("The service account credentials file does not exist at: " + serviceAccountCredentialFilePath);
if (string.IsNullOrEmpty(serviceAccountEmail))
throw new Exception("ServiceAccountEmail is required.");
if (Path.GetExtension(serviceAccountCredentialFilePath).ToLower() == ".json")
{
GoogleCredential credential;
using (var stream = new FileStream(serviceAccountCredentialFilePath, FileMode.Open, FileAccess.Read))
{
credential = GoogleCredential.FromStream(stream)
.CreateScoped(scopes);
}
return new FirebaseDynamicLinksService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Firebasedynamiclinks Service account Authentication Sample",
});
}
else if (Path.GetExtension(serviceAccountCredentialFilePath).ToLower() == ".p12")
{
var certificate = new X509Certificate2(serviceAccountCredentialFilePath, "notasecret", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = scopes
}.FromCertificate(certificate));
return new FirebaseDynamicLinksService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Firebasedynamiclinks Authentication Sample",
});
}
else
{
throw new Exception("Unsupported Service accounts credentials.");
}
}
catch (Exception ex)
{
throw new Exception("CreateServiceAccountFirebasedynamiclinksFailed", ex);
}
}
but when i run the code google throws exception
Google.Apis.Requests.RequestError Internal error encountered. [500] Errors [ Message[Internal error encountered.] Location[ - ] Reason[backendError] Domain[global] ]
what was the issue ?
Dynamic Links are smart URLs that allow you to send existing and potential users to any location within your iOS or Android app. They survive the app install process, so even new users see the content they're looking for when they open the app for the first time. Dynamic Links are no-cost forever, for any scale.
To receive Dynamic Links in your app, see the documentation for iOS, Android, C++, and Unity. Requests are limited to 5 requests/IP address/second, and 200,000 requests/day.
Firebase Dynamic Links records events related to your Dynamic Links' performance, including events that happen outside of your apps, such as the number of times someone clicks on one of your short Dynamic Links. This data can be viewed in the Dynamic Links section of the Firebase console and retrieved using a REST API.
I'm a little surprised you got as far as you did. Currently, this library has two issues:
ETag
members are undecorated, and get serialized as is. You will see an error like so:Google.Apis.Requests.RequestError
Invalid JSON payload received. Unknown name "ETag" at 'dynamic_link_info.android_info': Cannot find field.
Invalid JSON payload received. Unknown name "ETag" at 'dynamic_link_info.ios_info': Cannot find field.
Invalid JSON payload received. Unknown name "ETag" at 'dynamic_link_info': Cannot find field.
Invalid JSON payload received. Unknown name "ETag" at 'suffix': Cannot find field.
Invalid JSON payload received. Unknown name "ETag": Cannot find field. [400]
I haven't found a way around ManagedShortLinks. However, ShortLinks
will work. I'll show you how I did it.
public async Task<string> GetDeepLink(Invitation inv)
{
var playId = _configurationProvider.GetSetting(AppSettingNames.GooglePlayAppId);
var iosId = _configurationProvider.GetSetting(AppSettingNames.AppleAppStoreAppId);
var domain = _configurationProvider.GetSetting(AppSettingNames.GoogleFirebaseDynamicLinkDomain);
NameValueCollection queryString = System.Web.HttpUtility.ParseQueryString(string.Empty);
queryString["Key1"] = "value1";
var mslReq = new CreateShortDynamicLinkRequest();
mslReq.DynamicLinkInfo = new DynamicLinkInfo();
mslReq.DynamicLinkInfo.AndroidInfo = new AndroidInfo() { AndroidPackageName = playId };
mslReq.DynamicLinkInfo.IosInfo = new IosInfo() { IosAppStoreId = iosId, IosBundleId = playId };
mslReq.DynamicLinkInfo.DomainUriPrefix = $"https://{domain}";
mslReq.DynamicLinkInfo.Link = $"https://www.example.com/?{queryString}";
mslReq.Suffix = new Suffix() { Option = "SHORT" };
var json = JsonConvert.SerializeObject(mslReq, Formatting.Indented, new CreateShortDynamicLinkRequestConverter());
var request = _firebaseDynamicLinksService.ShortLinks.Create(new CreateShortDynamicLinkRequest());
request.ModifyRequest = message =>
message.Content = new StringContent(json, Encoding.UTF8, "application/json");
var res = await request.ExecuteAsync();
return res.ShortLink;
}
This depends upon CreateShortDynamicLinkRequestConverter
:
public class CreateShortDynamicLinkRequestConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.NullValueHandling = NullValueHandling.Ignore;
var t = JToken.FromObject(value);
var modified = t.RemoveFields("ETag");
modified.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
return true;
}
public override bool CanRead => false;
}
which in turn depends upon RemoveFields
:
// source: https://stackoverflow.com/a/31581951/773673
public static JToken RemoveFields(this JToken token, params string[] fields)
{
JContainer container = token as JContainer;
if (container == null) return token;
List<JToken> removeList = new List<JToken>();
foreach (JToken el in container.Children())
{
JProperty p = el as JProperty;
if (p != null && (fields.Contains(p.Name)))
{
removeList.Add(el);
}
el.RemoveFields(fields);
}
foreach (JToken el in removeList)
{
el.Remove();
}
return token;
}
At the end of the day, the big problem here is the lack of decoration of the ETag
members. We need to work around that. I believe that customizing BaseClientService.Initializer.Serializer
when the service is instantiated with the public NewtonsoftJsonSerializer(JsonSerializerSettings settings)
constructor will allow you to specify the Converters
to use, but I stopped when I got it working. The real fix for this is to simply decorate the ETag members to not participate in serialization (providing that doesn't break anything else!).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With