Download Progress stopped on Screen lock in iOS - xamarin

I have developed an Xamarin forms application. Provided download option to download file in our application. I have clicked download file and download progress show in app itself. If lock the iphone while download is in progress and unlock it again download stopped. How can I process download even locked phone?. This occurs only in iOS and works properly in Android.
I have used webclient DownloadFileTaskAsync process to download a file and maintain progress value in it.
WebClient client = new WebClient();
client.DownloadFileTaskAsync(new Uri(DownloadUrl), FileName);
Updated Query:
I have implemented the back-grounding process into my source. I have used "Creating Background-Safe Tasks" concept for my download process. I can download more than one file, so put this process in Task itself previously. Now, I have used BeginBackgroundTask in my download process but download process not carried to UI, even BeginBackgroundTask code doesn't hit while debug the code.
Below function put in native and called this function from forms when click download button.
public async Task DownloadFile(string DownloadUrl, string FileName)
{
var taskID = UIApplication.SharedApplication.BeginBackgroundTask(async() =>
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
client.DownloadFileTaskAsync(new Uri(DownloadUrl), FileName);
});
UIApplication.SharedApplication.EndBackgroundTask(taskID);
}
Also registered the app into Background fetch registration categories and now also progress not carried out while lock screen or minimize the app.
Am I missing any process in background techniques? Could you please help me to resolve this or suggest some simple sample as my scenario?
Please help me on this to resolve it.
Regards,
Cheran

You will need to use NSURLSession instead and create a background session for it. You can read how to do this in the official Xamarin Documentation.
You might get away with using WebClient in a background session, but only for a very short time span by using the pattern described in the "Handle iOS Background Limits" docs:
Task.Factory.StartNew(() =>
{
//expirationHandler only called if background time allowed exceeded
var taskId = UIApplication.SharedApplication.BeginBackgroundTask(() => {
Console.WriteLine("Exhausted time");
UIApplication.SharedApplication.EndBackgroundTask(taskId);
});
while(myFlag == true)
{
Console.WriteLine(UIApplication.SharedApplication.TimeRemaining);
myFlag = SomeCalculationNeedsMoreTime();
}
//Only called if loop terminated due to myFlag and not expiration of time
UIApplication.SharedApplication.EndBackgroundTask(taskId);
});
Where you would replace the while with your WebClient code.
However, as mentioned you really need to use Background Transfers for this to work properly.

Related

How do I deal with a possible exception in a Xamarin Forms application deployed to iOS or Android?

I have a finished application which I would like to make available to run on the iOS and Android platforms.  I have tested the application as much as possible and it works without problem.  But I know there is always the chance that something might go wrong and I could get an exception.
My question is how can I deal with this or what should I do. What happens on the phone, if a Forms application is deployed and there is an exception.
Would appreciate any advice or even links as to how this is handled.
If an exception is thrown and not handled by your code, the app will stop working (i.e. crash).
In order to handle these crashes we are using MS AppCenter (the successor to HockeyApp/Xamarin AppInsights).
You'll have to create a project there (one for each platform), and add the NuGet package to your projects. Afterwards you can initialize it with
AppCenter.Start("ios={Your App Secret};android={Your App Secret}",
typeof(Crashes)); // you'll get the app secrets from appcenter.ms
Crashes will be logged to AppCenter now and you'll be informed whenever there is a new crash.
Please note that it's best practice (if not required by law), that you ask the user for consent before sending the crash report (see here). You are using the delegate Crashes.ShouldAwaitUserConfirmation for that matter. You could for example show an action sheet with Acr.UserDialogs
private bool AwaitUserConfirmation()
{
// you should of course use your own strings
UserDialogs.Instance.ActionSheet(
new ActionSheetConfig
{
Title = "Oopsie",
Message = "The app crashed. Send crash to developers.",
Options = new List<ActionSheetOption>
{
new ActionSheetOption("Sure", () => Crashes.NotifyUserConfirmation(UserConfirmation.Send)),
new ActionSheetOption("Yepp, and don't bug be again.", () => Crashes.NotifyUserConfirmation(UserConfirmation.AlwaysSend)),
new ActionSheetOption("Nope", () => Crashes.NotifyUserConfirmation(UserConfirmation.DontSend))
}
});
return true;
}

App Center in-app updates not showing up in Xamarin Android app

I'm attempting to configure AppCenter.Distribute for in-app updates within my Xamarin Android app. Here is the very basic setup code, which I have in my main launcher activity's OnCreate method (AFTER the base.OnCreate call):
AppCenter.Start (Resources.GetString (Resource.String.appcenter_app_secret), typeof (Analytics), typeof (Crashes), typeof (Distribute));
I was able to get the in-app updates to supposedly initialize. When I first install and open the app, it shows a browser window for one second that says "In-app updates enabled! Returning to app in 1...", then it redirects back to my app. Unfortunately, when I then bump the version name and code and distribute a new build, I don't get a dialog within the app prompting me to update to the new version.
I even tried handling the Distribute.ReleaseAvailable action and showing a custom dialog, and that action isn't invoked either:
Distribute.ReleaseAvailable = OnReleaseAvailable;// Called before AppCenter.Start
private bool OnReleaseAvailable(ReleaseDetails releaseDetails)
{
// Show custom dialog.
Droid.ApplicationContext.Activity.CustomDialogBuilder().Show(new NotificationArgs
{
Title = "New update available!",
Message = "A new version of RPR Mobile, {0} ({1}) is available. Release notes: {2}"
.WithFormat(releaseDetails.ShortVersion, releaseDetails.Version, releaseDetails.ReleaseNotes),
PositiveButtonText = "Update",
PositiveAction = () =>
{
// Notify SDK that user selected to update...
Distribute.NotifyUpdateAction(UpdateAction.Update);
},
HideNegativeButton = releaseDetails.MandatoryUpdate,
NegativeButtonText = "Postpone Update",
NegativeAction = () =>
{
// Notify SDK that user selected to postpone (for 1 day)...
// Note that this method call is ignored by the SDK if the update is mandatory.
Distribute.NotifyUpdateAction(UpdateAction.Postpone);
}
});
// Return true if you are using your own dialog, false otherwise.
return true;
}
I'm wondering what I'm missing. Some questions that may or may not be relevant...
Does it matter whether the AppCenter.Start code executes before or after the base.OnCreate call?
Does it matter whether the activity that AppCenter.Start is called from is running or finished? Because in our case, the main launcher is just a splash screen that closes after a couple seconds.
Is the App Center SDK supposed to poll every few seconds for an update? Or does it check only when opening and closing activities?
It turns out that you have to close and relaunch your app for it to check for new updates. The documentation could be more clear on this...

Opening the uri from background tasks in Universal windows apps

I know this sounds weird. Is there any way we can open a URI from background tasks in Windows 10 Apps?
I have 2 requirements,
Talk to cortana and it will show you results based on the speech recognition, when user clicks on it, we cannot open the links in browser directly. Instead I am passing the Launch Context to the Foreground app and then using LauchUri I am opening the url in default browser.
Send toast notifications from the App, when user clicks on it, I have requirement to open a url instead opening an app. So, did the same, by passing the launch context to foreground app and then opening the url.
Both scenarios, it just opening url in browser. Here user experience is very poor that user seeing the app open for each action and then opening browser. Please throw some ideas if any possibilities.
thanks in advance.
For your second requirement, you can make Toast Notifications launch a URL!
If you're using the Notifications library (the NuGet package that we suggest you use), just set the Launch property to be a URL, and change the ActivationType to Protocol. You can also do this with raw XML, but that's error-prone.
You can also make buttons on the toast launch a URL too, since they also support ActivationType of Protocol.
Show(new ToastContent()
{
Visual = new ToastVisual()
{
BindingGeneric = new ToastBindingGeneric()
{
Children =
{
new AdaptiveText() { Text = "See the news" },
new AdaptiveText() { Text = "Lots of great stories" }
}
}
},
Launch = "http://msn.com",
ActivationType = ToastActivationType.Protocol
});

How can I test the background scan and launch the application in background with iBeacon-Android?

I am using the pro library.
But I just found doc for free library
I cannot find any doc for pro version.
Also, I don't know how to implement the background mode even using the pro sample.
Here are the steps:
Build the pro sample project
start the iBeacon source(using iPad) and it can be detected
start the application and then press home button the make it in
background
Turn off the iBeacon source
Turn on the iBeacon source
However, more than 5 minutes, the application does not launch
So, can anyone verify the step I did?
How can I test the background mode more easily?
Also, for the BootstrapNotifier, is it just work only first time when the device reboot?
After that, even I put application in background, the application will not launch when it detect iBeacon?
Your testing method sounds fine. I think the issue is that the reference app for the pro library only auto launches the app on the first detection after boot. After that, it sends a notification instead, and tapping on that notification launches the app.
This is purely for demonstration purposes. You can change it to auto launch on every detection if you wish. Simply alter the haveDetectedIBeaconsSinceBoot logic in this code:
#Override
public void didEnterRegion(Region arg0) {
// In this example, this class sends a notification to the user whenever an iBeacon
// matching a Region (defined above) are first seen.
Log.d(TAG, "did enter region.");
if (!haveDetectedIBeaconsSinceBoot) {
Log.d(TAG, "auto launching MainActivity");
// The very first time since boot that we detect an iBeacon, we launch the
// MainActivity
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Important: make sure to add android:launchMode="singleInstance" in the manifest
// to keep multiple copies of this activity from getting created if the user has
// already manually launched the app.
this.startActivity(intent);
haveDetectedIBeaconsSinceBoot = true;
} else {
// If we have already seen iBeacons and launched the MainActivity before, we simply
// send a notification to the user on subsequent detections.
Log.d(TAG, "Sending notification.");
sendNotification();
}
}
The javadoc link was missing from the main documentation page when you posted this question. That is fixed now.

Google service object for Google Calendar API

I am trying to use the Google Calendar API in .NET, specifically I am trying to get a list of events. According to the examples here, in different programming languages I need to create a 'service' object and an 'event' object. However, I can't find a clear explanation of what either of these objects is or how to initiate them. Does anyone have an explanation? Or can anyone provide any information or give me a link to where this is explained? It doesn't necessarily have to be in .NET
Here is the example in Java:
String pageToken = null;
do {
events = service.events().list('primary').setPageToken(pageToken).execute();
List<Event> items = events.getItems();
for (Event event : items) {
System.out.println(event.getSummary());
}
pageToken = events.getNextPageToken();
} while (pageToken != null);
Following the advice answered, I am getting the following error:
Could not load file or assembly 'Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.16.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
Here is the code, the error occurs on the credentials = Await... line
Dim credential As UserCredential
Dim clientSecretsPath As String = Server.MapPath("~/App_Data/client_secret.json")
Dim scopes As IList(Of String) = New List(Of String)()
scopes.Add(CalendarService.Scope.Calendar)
Using stream = New System.IO.FileStream(clientSecretsPath, System.IO.FileMode.Open, System.IO.FileAccess.Read)
credential = Await GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets, scopes, "user", CancellationToken.None)
End Using
The problem with GoogleWebAuthorizationBroker is that it tries to launch a new instance of a web browser to go and get authorization where you have to click the "Grant" button.
Obviously if you're running a MVC project under IIS it's just going to get confused when the code tries to execute a web browser!
My solution:
Download the .net sample projects: https://code.google.com/p/google-api-dotnet-client/source/checkout?repo=samples
Build and run one of the projects relevant to you (Eg Calendar or Drive). Dont forget to include your client_secret.json file downloaded from the cloud console.
Run the project and it will open a new browser on your computer where you will have to click the "Grant" button. Do this once and then your MVC code will work because it will not try to open a web browser to grant the permissions.
I'm not aware of any other way to grant this permission to the SDK but it worked for me just great!
Good luck. This took me a good 5 hours to figure out.
Just had the same issue running VS2013 (using .net45 for my project):
After fetching the CalendarV3 API via NuGet you just have to manually add the reference to:
...packages\Microsoft.Bcl.Async.1.0.165\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll
to the project (because it is not inserted automatically via the NuGet-Script)!
That's it! Maybe #peleyal is correcting the script somewhen in future ;)
Remember that this sample is for Java. My recommendation is to do the following:
Take a look in our VB sample for the Calendar API which is available here
You should take a look also in other sample for C#, let's say Tasks API sample
Start a new project and add a NuGet reference to Google.Apis.Calednar.v3. Remember that it's prerelease version.
Your code should look like the following:
It's based on the 2 samples above, I didn't compile or test it but it should work.
UserCredential credential;
using (var stream = new System.IO.FileStream("client_secrets.json",
System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { CalendarService.Scope.Calendar },
"user", CancellationToken.None);
}
// Create the service.
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "YOUR APP NAME HERE",
});
var firstCalendar = (await service.CalendarList.List().ExecuteAsync()).Items().FirstOrDefault();
if (firstCalendar != null)
{
// Get all events from the first calendar.
var calEvents = await service.Events.List(firstCalendar.Id).ExecuteAsync();
// DO SOMETHING
var nextPage = calEvents.NextPage;
while (nextPage != null)
{
var listRequest = service.Events.List(firstCalendar.Id);
// Set the page token for getting the next events.
listRequest.PageToken = nextPage;
calEvents = await listRequest.EsecuteAsync();
// DO SOMETHING
nextPage = calEvents.NextPage;
}
}
I had the same error, and it was due to the app trying to launch the accept screen.
I first tried to get the vb.net example from google and ran that, which I did get to work, and change to my secret info, ran and got the accept screen. I then tried my app, and it still did not work.
I noticed that the dll was found here under my project installed from the nuget packages.
...packages\Microsoft.Bcl.Async.1.0.165\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll
but was not in the net45 dir. So I uninstalled the nuget packages (have to if changing the .net version) then changed my .net version for my project to 4.0 instead of 4.5, reinstalled the nuget packages, and then it worked!!

Resources