How to get version number of application from play store using xamarin forms - xamarin

I need to check current version of Installed Application and Playstore application version. If it is not same app should navigate to Playstore .
im using xam.Plugin.LatestVersion(2.1.0) To get the latestversion number of application from play console. unfortunately not getting latest version number of application from play store. The below code im using.
private async void ChekAppVersion()
{
try
{
latestVersionNumber = await CrossLatestVersion.Current.GetLatestVersionNumber();
installedVersionNumber = CrossLatestVersion.Current.InstalledVersionNumber;
if (installedVersionNumber != latestVersionNumber)
{
await DisplayAlert("New Version", "There is a new version of this app available. Please update now?", "Ok");
await CrossLatestVersion.Current.OpenAppInStore();
ChekAppVersion();
}
else
{
}
}
catch (Exception ex)
{
}
}
Im getting the installedVersionNumber, but im unable to get the latestVersionNumber(Playstore).
Please help on this.

They have removed the version from div, now it's displayed with js, but data is still there inside a <script> tag. My current fixed code is:
private bool _lockCheckUpdates;
public async Task<bool> CheckNeedUpdate()
{
if (Connectivity.NetworkAccess != NetworkAccess.Internet || _lockCheckUpdates)
return false;
_lockCheckUpdates = true;
try
{
HttpClient myClient = CreateClient();
if (Device.RuntimePlatform == Device.Android)
{
var bundle = "com.todo.app"; //ANDROID BUNDLE NAME HERE
string url = $"https://play.google.com/store/apps/details?id={bundle}&hl=en";
string raw = await myClient.GetStringAsync(new Uri(url));
var doc = new HtmlDocument();
doc.LoadHtml(raw);
var scripts = doc.DocumentNode.Descendants()
.Where(n => n.Name == "script" && n.InnerText.Contains("AF_initDataCallback({key: 'ds:4'"))
.ToArray();
var script = scripts.First().InnerText;
var engine = new Jurassic.ScriptEngine();
var eval = "(function() { var AF_initDataCallback = function(p) { return p.data[1][2][140][0][0][0]; }; return " + script + " })()";
var result = engine.Evaluate(eval);
//var json = JSONObject.Stringify(engine, result); //for debug, check in browser console with JSON.parse(json)
var remote = $"{result}".ToDouble();
var local = App.Version.ToDouble();
return local < remote;
}
else if (Device.RuntimePlatform == Device.iOS)
{
var bundle = "com.todo.app";//iOS BUNDLE NAME HERE
string url = $"http://itunes.apple.com/lookup?bundleId={bundle}";
string raw = await myClient.GetStringAsync(new Uri(url));
var dto = JsonConvert.DeserializeObject<AppStoreRecord>(raw);
double local = App.Version.ToDouble();
if (dto.ResultCount > 0)
{
double remote = dto.Results[0].Version.ToDouble();
return remote > local;
}
}
}
catch (Exception e)
{
Logger.Error("CheckNeedUpdate", e);
}
finally
{
_lockCheckUpdates = false;
}
return false;
}
Using nugets
Jurassic to evaluate the script on page,
HtmlAgilityPack to parse html,
Xamarin.Essentials to check if we are online,
and AppoMobi.Specials for .ToDouble() etc
I hope this could also be useful to fix https://github.com/edsnider/latestversionplugin/issues/43 :)

The plugin you are using no longer works for Android https://github.com/edsnider/latestversionplugin/issues/43
You will need to find a new way to get the desired information.

PR has been made on this plugin... it works again ;-)

Related

Download and open picture from url/http [Android Xamarin App]

Hello, would any of you send a working code to download a photo from a given http address on android Xamarin c #?
First, I need to create a new folder for my application files.
My goal is to download the file from the internet to my Android folder (saving this file with its original name is best).
The next step is to display the image from that folder in "ImageView". It is also important that there are permissions in android and I do not fully understand it.
Could any of you send it to me or help me understand it and explain the topic?
*Actually i have this code:
string address = "https://i.stack.imgur.com/X3V3w.png";
using (WebClient webClient = new WebClient())
{
webClient.DownloadFileCompleted += WebClient_DownloadFileCompleted;
webClient.DownloadFile(address, Path.Combine(pathDire, "MyNewImage1.png"));
//System.Net.WebException: 'An exception occurred during a WebClient request.'
}
Loading image from url and display in imageview.
private void Btn1_Click(object sender, System.EventArgs e)
{
var imageBitmap = GetImageBitmapFromUrl("http://xamarin.com/resources/design/home/devices.png");
imagen.SetImageBitmap(imageBitmap);
}
private Bitmap GetImageBitmapFromUrl(string url)
{
Bitmap imageBitmap = null;
using (var webClient = new WebClient())
{
var imageBytes = webClient.DownloadData(url);
if (imageBytes != null && imageBytes.Length > 0)
{
SavePicture("ImageName.jpg", imageBytes, "imagesFolder");
imageBitmap = BitmapFactory.DecodeByteArray(imageBytes, 0, imageBytes.Length);
}
}
return imageBitmap;
}
download image and save it in local storage.
private void SavePicture(string name, byte[] data, string location = "temp")
{
var documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
documentsPath = System.IO.Path.Combine(documentsPath, "Orders", location);
Directory.CreateDirectory(documentsPath);
string filePath = System.IO.Path.Combine(documentsPath, name);
using (FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate))
{
int length = data.Length;
fs.Write(data, 0, length);
}
}
you need to add permission WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE in AndroidMainfeast.xml, then you also need to Runtime Permission Checks in Android 6.0.
private void checkpermission()
{
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) == (int)Permission.Granted)
{
// We have permission, go ahead and use the writeexternalstorage.
}
else
{
// writeexternalstorage permission is not granted. If necessary display rationale & request.
}
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) == (int)Permission.Granted)
{
// We have permission, go ahead and use the ReadExternalStorage.
}
else
{
// ReadExternalStorage permission is not granted. If necessary display rationale & request.
}
}

Is there any plugin or way to show 'new version of app available' alert when user opens app

I have Xamarin.Android app, I want to show alert to user (when user opens app) that please download latest version. Like other apps. How can I do that?
I have tried few ways but didn't get succeed. I have tried this. This is quite different from Android. I need it for Xamarin.
I already asked this question but existing functionality broke down due to having some changes in play store policies, consequently I am not getting specific string "itemprop=\"softwareVersion\">" from play store so I asked new question. Thank you
Working answer. I have used plugin for that Plugin.LatestVersion for Xam.Android to get latest version of app from Google play store. below line of code was returning latest app version.
var appStoreVersionString = await CrossLatestVersion.Current.GetLatestVersionNumber();
Then this is the further implementation
private void CompareVersion()
{
double currentVersion = 0d;
double appStoreversion = 0d;
bool IsUpdateRequired = false;
if (Context.PackageName != null)
{
PackageInfo info = Context.PackageManager.GetPackageInfo(Context.PackageName, PackageInfoFlags.Activities);
string currentVersionStrig = info.VersionName;
currentVersion = Convert.ToDouble(currentVersionStrig);
}
try
{
if (IsUpdateRequired == false)
{
string appStoreVersionString = string.Empty;
if (CheckNetConnection.IsNetConnected())
{
Task.Run(async () => { appStoreVersionString = await CrossLatestVersion.Current.GetLatestVersionNumber();}).Wait();
if (!string.IsNullOrEmpty(appStoreVersionString))
{
appStoreversion = Convert.ToDouble(appStoreVersionString);
if ((appStoreversion.ToString() != currentVersion.ToString() && (appStoreversion > currentVersion)))
{
IsUpdateRequired = true;
}
}
}
}
if (IsUpdateRequired)
{
Activity.RunOnUiThread(() =>
{
AlertDialog dialog = null;
var Alertdialog = new Android.App.AlertDialog.Builder(Context);
Alertdialog.SetTitle("Update Available");
Alertdialog.SetMessage($"A new version of [" + appStoreversion + "] is available. Please update to version [" + appStoreversion + "] now.");
Alertdialog.SetNegativeButton("Cancel", (sender, e) =>
{
if (dialog == null)
{
dialog = Alertdialog.Create();
}
dialog.Dismiss();
});
Alertdialog.SetPositiveButton("Update", (sender, e) =>
{
string appPackage = string.Empty;
try
{
appPackage = Application.Context.PackageName;
Utilities.Logout(Activity);
var ints = new Intent(Intent.ActionView, Android.Net.Uri.Parse("market://details?id=" + appPackage));
ints.SetFlags(ActivityFlags.ClearTop);
ints.SetFlags(ActivityFlags.NoAnimation);
ints.SetFlags(ActivityFlags.NewTask);
Application.Context.StartActivity(ints);
}
catch (ActivityNotFoundException)
{
var apppack = Application.Context.PackageName;
Utilities.Logout(Activity);
var ints = new Intent(Intent.ActionView, Android.Net.Uri.Parse("market://details?id=" + appPackage));
ints.SetFlags(ActivityFlags.ClearTop);
ints.SetFlags(ActivityFlags.NoAnimation);
ints.SetFlags(ActivityFlags.NewTask);
Application.Context.StartActivity(ints);
}
//this kills the app?
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
System.Environment.Exit(1);
});
if (dialog == null)
dialog = Alertdialog.Create();
dialog.Show();
});
}
}
catch (Exception ex)
{
var objLog = new LogService();
objLog.MobileLog(ex, SISConst.UserName);
}
}

how to display pdf from url using pdfjs xamarin forms

I have worked with pdfjs and its working fine with local storage pdf, but I have another issue: I need to display pdf from WEB API, as I have stored binary data of pdf which I need to display?? this is my code
public pdfjsPage(string url)
{
InitializeComponent();
var localPath = string.Empty;
if (Device.RuntimePlatform == Device.Android)
{
var dependency = DependencyService.Get<ILocalFileProvider>();
if (dependency == null)
{
DisplayAlert("Error loading PDF", "Computer says no", "OK");
return;
}
var fileName = Guid.NewGuid().ToString();
// Download PDF locally for viewing
using (var httpClient = new HttpClient())
{
var pdfStream = Task.Run(() => httpClient.GetStreamAsync(url)).Result;
localPath =
Task.Run(() => dependency.SaveFileToDisk(pdfStream, $"{fileName}.pdf")).Result;
}
if (string.IsNullOrWhiteSpace(localPath))
{
DisplayAlert("Error loading PDF", "Computer says no", "OK");
return;
}
}
if (Device.RuntimePlatform == Device.Android)
PdfView.Source = $"file:///android_asset/pdfjs/web/viewer.html?file={WebUtility.UrlEncode(localPath)}";
else
PdfView.Source = url;
}
This is working with local pdf, but I have WEB API URL and I need to get pdf from there online.
This is the link from where I retrieve it: http://veezo2007pkk.somee.com/api/DiagnosticDetail/RetrieveFile/1
After saving your PDF to your device, pass the path to an Intent.
//Example
var fileName = "/storage/emulated/0/yourPDF.pdf"
Uri pdfPath = Uri.FromFile(new File(fileName));
Intent intent = new Intent(Intent.ActionView);
intent.SetDataAndType(pdfPath, "application/pdf");
intent.SetFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);

Best practice to send a lot of files (images) from your device to your server

I have a list of files to send from my device to my server.
List<myFiles> list = new List<myFiles>() { "[long list of files...]" };
For that I want to create a list of tasks: for each file I should invoke a function that sends to my webapi that file via PUT
public async Task<bool> UploadPhoto(byte[] photoBytes, int PropertyId, string fileName)
{
bool rtn = false;
if (CrossConnectivity.Current.IsConnected)
{
var content = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(photoBytes);
fileContent.Headers.ContentType =
MediaTypeHeaderValue.Parse("multipart/form-data");
fileContent.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName = fileName + ".jpg"
};
content.Add(fileContent);
string url = RestURL() + "InventoriesPicture/Put";
try
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("authenticationToken", SyncData.Token);
HttpResponseMessage response = await client.PutAsync(url, content);
if (response.IsSuccessStatusCode)
{
rtn = true;
Debug.WriteLine($"UploadPhoto response {response.ReasonPhrase}");
}
else
{
Debug.WriteLine($"UploadPhoto response {response.ReasonPhrase}");
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"UploadPhoto exception {ex.Message}");
}
Debug.WriteLine($"UploadPhoto ends {fileName}");
}
return rtn;
}
In a function I have a foreach that calls UploadPhoto. I think there are too many tasks at the same time then I want to send a file, wait the result from the webapi and then send next file and so on.
What can I do? What is the best practice for that? Or in any case how can I resolve my problem? :)
Thank you in advance

Azure Notification Hub and WP8 Intermitant notifications

This is a fairly long piece of code but I am getting nowhere with this and cannot see any issues, although I am new to using notification hubs. I am trying to register for targeted notifications (the logged on user) using the notification hub in Azure. After the registration, a test notification is sent.
The issue I am having is that sometimes the notification is sent to the device, and sometimes it is not. It mostly isn't but occasionally when I step through the code on the server, i will get the notification on the emulator come through. Once when I deployed the app to my phone the notification came though on the emulator! I cannot discover a pattern.
My Controller class looks like this;
private NotificationHelper hub;
public RegisterController()
{
hub = NotificationHelper.Instance;
}
public async Task<RegistrationDescription> Post([FromBody]JObject registrationCall)
{
var obj = await hub.Post(registrationCall);
return obj;
}
And the helper class (which is used elsewhere so is not directly in the controller) looks like this;
public static NotificationHelper Instance = new NotificationHelper();
public NotificationHubClient Hub { get; set; }
// Create the client in the constructor.
public NotificationHelper()
{
var cn = "<my-cn>";
Hub = NotificationHubClient.CreateClientFromConnectionString(cn, "<my-hub>");
}
public async Task<RegistrationDescription> Post([FromBody] JObject registrationCall)
{
// Get the registration info that we need from the request.
var platform = registrationCall["platform"].ToString();
var installationId = registrationCall["instId"].ToString();
var channelUri = registrationCall["channelUri"] != null
? registrationCall["channelUri"].ToString()
: null;
var deviceToken = registrationCall["deviceToken"] != null
? registrationCall["deviceToken"].ToString()
: null;
var userName = HttpContext.Current.User.Identity.Name;
// Get registrations for the current installation ID.
var regsForInstId = await Hub.GetRegistrationsByTagAsync(installationId, 100);
var updated = false;
var firstRegistration = true;
RegistrationDescription registration = null;
// Check for existing registrations.
foreach (var registrationDescription in regsForInstId)
{
if (firstRegistration)
{
// Update the tags.
registrationDescription.Tags = new HashSet<string>() {installationId, userName};
// We need to handle each platform separately.
switch (platform)
{
case "windows":
var winReg = registrationDescription as MpnsRegistrationDescription;
winReg.ChannelUri = new Uri(channelUri);
registration = await Hub.UpdateRegistrationAsync(winReg);
break;
case "ios":
var iosReg = registrationDescription as AppleRegistrationDescription;
iosReg.DeviceToken = deviceToken;
registration = await Hub.UpdateRegistrationAsync(iosReg);
break;
}
updated = true;
firstRegistration = false;
}
else
{
// We shouldn't have any extra registrations; delete if we do.
await Hub.DeleteRegistrationAsync(registrationDescription);
}
}
// Create a new registration.
if (!updated)
{
switch (platform)
{
case "windows":
registration = await Hub.CreateMpnsNativeRegistrationAsync(channelUri,
new string[] {installationId, userName});
break;
case "ios":
registration = await Hub.CreateAppleNativeRegistrationAsync(deviceToken,
new string[] {installationId, userName});
break;
}
}
// Send out a test notification.
await SendNotification(string.Format("Test notification for {0}", userName), userName);
return registration;
And finally, my SendNotification method is here;
internal async Task SendNotification(string notificationText, string tag)
{
try
{
var toast = PrepareToastPayload("<my-hub>", notificationText);
// Send a notification to the logged-in user on both platforms.
await NotificationHelper.Instance.Hub.SendMpnsNativeNotificationAsync(toast, tag);
//await hubClient.SendAppleNativeNotificationAsync(alert, tag);
}
catch (ArgumentException ex)
{
// This is expected when an APNS registration doesn't exist.
Console.WriteLine(ex.Message);
}
}
I suspect the issue is in my phone client code, which is here and SubscribeToService is called immediately after WebAPI login;
public void SubscribeToService()
{
_channel = HttpNotificationChannel.Find("mychannel");
if (_channel == null)
{
_channel = new HttpNotificationChannel("mychannel");
_channel.Open();
_channel.BindToShellToast();
}
_channel.ChannelUriUpdated += async (o, args) =>
{
var hub = new NotificationHub("<my-hub>", "<my-cn>");
await hub.RegisterNativeAsync(args.ChannelUri.ToString());
await RegisterForMessageNotificationsAsync();
};
}
public async Task RegisterForMessageNotificationsAsync()
{
using (var client = GetNewHttpClient(true))
{
// Get the info that we need to request registration.
var installationId = LocalStorageManager.GetInstallationId(); // a new Guid
var registration = new Dictionary<string, string>()
{
{"platform", "windows"},
{"instId", installationId},
{"channelUri", _channel.ChannelUri.ToString()}
};
var request = new HttpRequestMessage(HttpMethod.Post, new Uri(ApiUrl + "api/Register/RegisterForNotifications"));
request.Content = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json");
string message;
try
{
HttpResponseMessage response = await client.SendAsync(request);
message = await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
message = ex.Message;
}
_registrationId = message;
}
}
Any help would be greatly appriciated as I have been stuck on this now for days! I know this is a lot of code to paste up here but it is all relevant.
Thanks,
EDIT: The SubscribeToService() method is called when the user logs in and authenticates with the WebAPI. The method is here;
public async Task<User> SendSubmitLogonAsync(LogonObject lo)
{
_logonObject = lo;
using (var client = GetNewHttpClient(false))
{
var logonString = String.Format("grant_type=password&username={0}&password={1}", lo.username, lo.password);
var sc = new StringContent(logonString, Encoding.UTF8);
var response = await client.PostAsync("Token", sc);
if (response.IsSuccessStatusCode)
{
_logonResponse = await response.Content.ReadAsAsync<TokenResponseModel>();
var userInfo = await GetUserInfoAsync();
if (_channel == null)
SubscribeToService();
else
await RegisterForMessageNotificationsAsync();
return userInfo;
}
// ...
}
}
I have solved the issue. There are tons of fairly poorly organised howto's for azure notification hubs and only one of them has this note toward the bottom;
NOTE:
You will not receive the notification when you are still in the app.
To receive a toast notification while the app is active, you must
handle the ShellToastNotificationReceived event.
This is why I was experiencing intermittent results, as i assumed you would still get a notification if you were in the app. And this little note is pretty well hidden.
Have you used proper tag / tag expressions while register/send the message. Also, Where are you storing the id back from the notification hub. It should be used when you update the channel uri (it will expire).
I would suggest to start from scratch.
Ref: http://msdn.microsoft.com/en-us/library/dn530749.aspx

Resources