Reputation: 67
I started using xamarin a few months ago, and, until now, I didn't have the need of doing something like this. I'm developing an app that, once a day, should run a WCF web service and verify if an information is true. If it is true, it should show a notification on the device. My problem is that I don't know how to perform it, i've read about backgrounding and schedule tasks, but I didn't understand well how can I perform this. How can I do it using Xamarin.Forms?
Thank you!
Upvotes: 3
Views: 2511
Reputation: 3169
In this case for Android you can use you can use JobScheduler, see this class
[Service(Name = "com.xamarin.samples.downloadscheduler.DownloadJob",
Permission = "android.permission.BIND_JOB_SERVICE")]
public class DownloadJob : JobService
{
public override bool OnStartJob(JobParameters jobParams)
{
Task.Run(() =>
{
//Your periodic task here
});
return true;
}
public override bool OnStopJob(JobParameters jobParams)
{
//true so we re-schedule the task
return true;
}
}
Then you can create a Factory to call this service.
public static class ReadLocationSchedulerFactory
{
public static JobInfo.Builder CreateJobBuilderUsingJobId<T>(this Context context, int jobId) where T : JobService
{
var javaClass = Java.Lang.Class.FromType(typeof(T));
var componentName = new ComponentName(context, javaClass);
return new JobInfo.Builder(jobId, componentName);
}
}
Then in your Main Activity you have to call the Factory.
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App172S.App());
#region Scheduler
var jobBuilder = this.CreateJobBuilderUsingJobId<ReadLocationScheduler>(152);
//This means each 20 mins
jobBuilder.SetPeriodic(20 * 60 * 1000);
//Persists over phone restarts
jobBuilder.SetPersisted(true);
//If Fails re-try each 2 mins
jobBuilder.SetBackoffCriteria(120 * 1000, BackoffPolicy.Linear);
var jobInfo = jobBuilder.Build();
var jobScheduler = (JobScheduler)GetSystemService(JobSchedulerService);
jobScheduler.Cancel(152);
var scheduleResult = jobScheduler.Schedule(jobInfo);
if (JobScheduler.ResultSuccess == scheduleResult)
{
//If OK maybe show a msg
}
else
{
//If Failed do something
}
#endregion
}
Upvotes: 2
Reputation: 106
For Android, a solution needs 4 components:
AlarmManager
to set daily check scheduleBroadCastReceiver
to receive the daily trigger and call the IntentServiceIntentService
to execute awaitable callsOnBootReceiver
to ensure alarms are set again after a device reboot For iOS, you will most likely need remote push notifications.
Some sample code below for the Android components:
AlarmManager - Setting the Alarm
[assembly: Dependency(typeof(AlarmHelper))] // above the namespace
...
class AlarmHelper: IAlarm
{
var now = Calendar.Instance;
var alarmTime = Calendar.Instance;
alarmTime.Set(CalendarField.HourOfDay, settings.AlarmHour); // Set Alarm start Hour
alarmTime.Set(CalendarField.Minute, settings.AlarmMinutes); // Set Alarm Start Minutes
if (alarmTime.Before(now))
{
alarmTime.Add(CalendarField.Hour, 24);
}
var intent = new Intent(Android.App.Application.Context, typeof(ScheduledAlarmHandler));
var pendingIntent = PendingIntent.GetBroadcast(Android.App.Application.Context, 0, intent, PendingIntentFlags.CancelCurrent);
var alarmManager = Android.App.Application.Context.GetSystemService(Context.AlarmService) as AlarmManager;
alarmManager.SetRepeating(AlarmType.RtcWakeup, alarmTime.TimeInMillis, AlarmManager.IntervalDay, pendingIntent);
}
BroadCastReceiver - Receiving the Alarm
[BroadcastReceiver]
class ScheduledAlarmHandler : WakefulBroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Console.WriteLine("ScheduledAlarmHandler", "Starting service @" + SystemClock.ElapsedRealtime());
Intent service = new Intent(context, typeof(WakefulAPIService));
StartWakefulService(context, service);
}
}
IntentService - Executing awaitable calls
[Service]
[IntentFilter(new String[] { "com.test.testApp.WakefulAPIService" })]
class WakefulAPIService : IntentService
{
protected override void OnHandleIntent(Intent intent)
{
// Your API Call code here
Console.WriteLine("WakefulAPIService", "Completed service @ " + SystemClock.ElapsedRealtime());
Android.Support.V4.Content.WakefulBroadcastReceiver.CompleteWakefulIntent(intent);
}
}
OnBootReceiver - Ensuring alarms are set again after a device reboot
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { "android.intent.action.BOOT_COMPLETED", "android.intent.action.QUICKBOOT_POWERON" })]
class OnBootReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Console.WriteLine("On Boot Reveiver", "Alarm Set Again after Reboot");
var alarmHelper = new AlarmHelper();
alarmHelper.SetAlarm();
}
}
The required permissions for this to work are 'RECEIVE_BOOT_COMPLETED' and 'WAKE_LOCK'
Upvotes: 5