Místní oznámení v Xamarin.Forms
Místní oznámení jsou výstrahy odesílané aplikacemi nainstalovanými v mobilním zařízení. Místní oznámení se často používají pro funkce, jako například:
- Události kalendáře
- Připomínky
- Triggery založené na poloze
Každá platforma zpracovává vytváření, zobrazování a spotřebu místních oznámení odlišně. Tento článek vysvětluje, jak vytvořit abstrakci pro různé platformy pro odesílání, plánování a příjem místních oznámení pomocí nástroje Xamarin.Forms .
Vytvoření rozhraní pro různé platformy
Xamarin.FormsAplikace by měla vytvářet a využívat oznámení bez obav pro základní implementace platforem. Následující INotificationManager rozhraní je implementováno ve sdílené knihovně kódu a definuje rozhraní API pro různé platformy, které aplikace může použít pro interakci s oznámeními:
public interface INotificationManager
{
event EventHandler NotificationReceived;
void Initialize();
void SendNotification(string title, string message, DateTime? notifyTime = null);
void ReceiveNotification(string title, string message);
}
Toto rozhraní bude implementováno v každém projektu platformy. NotificationReceivedUdálost umožňuje aplikaci zpracovávat příchozí oznámení. InitializeMetoda by měla provést jakoukoli nativní logiku platformy potřebnou pro přípravu oznamovacího systému. SendNotificationMetoda by měla v případě potřeby odeslat oznámení DateTime . ReceiveNotificationMetoda by měla být volána základní platformou při přijetí zprávy.
Využití rozhraní v Xamarin.Forms
Po vytvoření rozhraní je možné jej spotřebovat ve sdíleném projektu i v případě, že Xamarin.Forms implementace platformy ještě nebyly vytvořeny. Ukázková aplikace obsahuje ContentPage s názvem ContentPage následující obsah:
<StackLayout Margin="0,35,0,0"
x:Name="stackLayout">
<Label Text="Click the button below to create a local notification."
TextColor="Red"
HorizontalOptions="Center"
VerticalOptions="Start" />
<Button Text="Create Notification"
HorizontalOptions="Center"
VerticalOptions="Start"
Clicked="OnSendClick" />
<Label Text="Click the button below to schedule a local notification for in 10 seconds time."
TextColor="Red"
HorizontalOptions="Center"
VerticalOptions="Start" />
<Button Text="Create Notification"
HorizontalOptions="Center"
VerticalOptions="Start"
Clicked="OnScheduleClick" />
</StackLayout>
Rozložení obsahuje Label prvky, které vysvětlují pokyny a Button prvky, které odesílají nebo naplánovaly oznámení v případě klepnutí.
MainPageKód třídy na pozadí zpracovává odesílání a příjem oznámení:
public partial class MainPage : ContentPage
{
INotificationManager notificationManager;
int notificationNumber = 0;
public MainPage()
{
InitializeComponent();
notificationManager = DependencyService.Get<INotificationManager>();
notificationManager.NotificationReceived += (sender, eventArgs) =>
{
var evtData = (NotificationEventArgs)eventArgs;
ShowNotification(evtData.Title, evtData.Message);
};
}
void OnSendClick(object sender, EventArgs e)
{
notificationNumber++;
string title = $"Local Notification #{notificationNumber}";
string message = $"You have now received {notificationNumber} notifications!";
notificationManager.SendNotification(title, message);
}
void OnScheduleClick(object sender, EventArgs e)
{
notificationNumber++;
string title = $"Local Notification #{notificationNumber}";
string message = $"You have now received {notificationNumber} notifications!";
notificationManager.SendNotification(title, message, DateTime.Now.AddSeconds(10));
}
void ShowNotification(string title, string message)
{
Device.BeginInvokeOnMainThread(() =>
{
var msg = new Label()
{
Text = $"Notification Received:\nTitle: {title}\nMessage: {message}"
};
stackLayout.Children.Add(msg);
});
}
}
MainPageKonstruktor třídy používá Xamarin.FormsDependencyService k načtení instance specifické pro platformu INotificationManager . OnSendClickMetody a OnScheduleClicked používají INotificationManager instanci pro posílání a naplánování nových oznámení. ShowNotificationMetoda je volána z obslužné rutiny události připojené k NotificationReceived události a Label při vyvolání události vloží novou stránku do stránky.
NotificationReceivedObslužná rutina události přenese argumenty události do NotificationEventArgs . Tento typ je definovaný ve sdíleném Xamarin.Forms projektu:
public class NotificationEventArgs : EventArgs
{
public string Title { get; set; }
public string Message { get; set; }
}
Další informace o naleznete v Xamarin.FormsDependencyService tématu Xamarin.Forms DependencyService .
Vytvoření implementace rozhraní Android
Aby Xamarin.Forms aplikace mohla odesílat a přijímat oznámení v Androidu, aplikace musí poskytnout implementaci INotificationManager rozhraní.
Vytvoření třídy AndroidNotificationManager
AndroidNotificationManagerTřída implementuje INotificationManager rozhraní:
using System;
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.OS;
using AndroidX.Core.App;
using Xamarin.Forms;
using AndroidApp = Android.App.Application;
[assembly: Dependency(typeof(LocalNotifications.Droid.AndroidNotificationManager))]
namespace LocalNotifications.Droid
{
public class AndroidNotificationManager : INotificationManager
{
const string channelId = "default";
const string channelName = "Default";
const string channelDescription = "The default channel for notifications.";
public const string TitleKey = "title";
public const string MessageKey = "message";
bool channelInitialized = false;
int messageId = 0;
int pendingIntentId = 0;
NotificationManager manager;
public event EventHandler NotificationReceived;
public static AndroidNotificationManager Instance { get; private set; }
public AndroidNotificationManager() => Initialize();
public void Initialize()
{
if (Instance == null)
{
CreateNotificationChannel();
Instance = this;
}
}
public void SendNotification(string title, string message, DateTime? notifyTime = null)
{
if (!channelInitialized)
{
CreateNotificationChannel();
}
if (notifyTime != null)
{
Intent intent = new Intent(AndroidApp.Context, typeof(AlarmHandler));
intent.PutExtra(TitleKey, title);
intent.PutExtra(MessageKey, message);
PendingIntent pendingIntent = PendingIntent.GetBroadcast(AndroidApp.Context, pendingIntentId++, intent, PendingIntentFlags.CancelCurrent);
long triggerTime = GetNotifyTime(notifyTime.Value);
AlarmManager alarmManager = AndroidApp.Context.GetSystemService(Context.AlarmService) as AlarmManager;
alarmManager.Set(AlarmType.RtcWakeup, triggerTime, pendingIntent);
}
else
{
Show(title, message);
}
}
public void ReceiveNotification(string title, string message)
{
var args = new NotificationEventArgs()
{
Title = title,
Message = message,
};
NotificationReceived?.Invoke(null, args);
}
public void Show(string title, string message)
{
Intent intent = new Intent(AndroidApp.Context, typeof(MainActivity));
intent.PutExtra(TitleKey, title);
intent.PutExtra(MessageKey, message);
PendingIntent pendingIntent = PendingIntent.GetActivity(AndroidApp.Context, pendingIntentId++, intent, PendingIntentFlags.UpdateCurrent);
NotificationCompat.Builder builder = new NotificationCompat.Builder(AndroidApp.Context, channelId)
.SetContentIntent(pendingIntent)
.SetContentTitle(title)
.SetContentText(message)
.SetLargeIcon(BitmapFactory.DecodeResource(AndroidApp.Context.Resources, Resource.Drawable.xamagonBlue))
.SetSmallIcon(Resource.Drawable.xamagonBlue)
.SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate);
Notification notification = builder.Build();
manager.Notify(messageId++, notification);
}
void CreateNotificationChannel()
{
manager = (NotificationManager)AndroidApp.Context.GetSystemService(AndroidApp.NotificationService);
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var channelNameJava = new Java.Lang.String(channelName);
var channel = new NotificationChannel(channelId, channelNameJava, NotificationImportance.Default)
{
Description = channelDescription
};
manager.CreateNotificationChannel(channel);
}
channelInitialized = true;
}
long GetNotifyTime(DateTime notifyTime)
{
DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(notifyTime);
double epochDiff = (new DateTime(1970, 1, 1) - DateTime.MinValue).TotalSeconds;
long utcAlarmTime = utcTime.AddSeconds(-epochDiff).Ticks / 10000;
return utcAlarmTime; // milliseconds
}
}
}
assemblyAtribut nad oborem názvů registruje INotificationManager implementaci rozhraní s DependencyService .
Android umožňuje aplikacím definovat více kanálů pro oznámení. InitializeMetoda vytvoří základní kanál, který ukázková aplikace používá k odesílání oznámení. SendNotificationMetoda definuje logiku specifickou pro platformu nutnou k vytvoření a odeslání oznámení. ReceiveNotificationMetoda je volána operačním systémem Android při přijetí zprávy a vyvolá obslužnou rutinu události.
SendNotificationMetoda vytvoří místní oznámení okamžitě nebo přesně DateTime . Oznámení lze naplánovat přesně DateTime pomocí AlarmManager třídy a oznámení bude přijato objektem, který je odvozen od BroadcastReceiver třídy:
[BroadcastReceiver(Enabled = true, Label = "Local Notifications Broadcast Receiver")]
public class AlarmHandler : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
if (intent?.Extras != null)
{
string title = intent.GetStringExtra(AndroidNotificationManager.TitleKey);
string message = intent.GetStringExtra(AndroidNotificationManager.MessageKey);
AndroidNotificationManager manager = AndroidNotificationManager.Instance ?? new AndroidNotificationManager();
manager.Show(title, message);
}
}
}
Důležité
Ve výchozím nastavení nebudou oznámení naplánovaná pomocí této AlarmManager třídy zachována při restartu zařízení. Můžete ale navrhnout aplikaci tak, aby automaticky znovu naplánovala oznámení v případě, že se zařízení restartuje. Pokud chcete získat další informace, Spusťte alarm, když se zařízení restartuje , a Naplánujte opakované alarmy na Developer.Android.com a ukázku. Informace o zpracování na pozadí v Androidu najdete v tématu Průvodce zpracováním na pozadí na Developer.Android.com.
Další informace o přijímačích všesměrového vysílání najdete v tématu přijímače všesměrového vysílání v Xamarin. Android.
Zpracování příchozích oznámení v Androidu
MainActivityTřída musí detekovat příchozí oznámení a informovat o AndroidNotificationManager instanci. ActivityAtribut MainActivity třídy by měl zadat LaunchMode hodnotu LaunchMode.SingleTop :
[Activity(
//...
LaunchMode = LaunchMode.SingleTop]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
// ...
}
SingleTopRežim zabraňuje spuštění více instancí, Activity když je aplikace v popředí. To LaunchMode nemusí být vhodné pro aplikace, které v složitějších scénářích oznámení spouštějí více aktivit. Další informace o LaunchMode hodnotách výčtu najdete v tématu věnovaném LaunchMode.
Ve MainActivity třídě je upraven pro příjem příchozích oznámení:
protected override void OnCreate(Bundle savedInstanceState)
{
// ...
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
CreateNotificationFromIntent(Intent);
}
protected override void OnNewIntent(Intent intent)
{
CreateNotificationFromIntent(intent);
}
void CreateNotificationFromIntent(Intent intent)
{
if (intent?.Extras != null)
{
string title = intent.GetStringExtra(AndroidNotificationManager.TitleKey);
string message = intent.GetStringExtra(AndroidNotificationManager.MessageKey);
DependencyService.Get<INotificationManager>().ReceiveNotification(title, message);
}
}
CreateNotificationFromIntentMetoda extrahuje data oznámení z intent argumentu a poskytne je AndroidNotificationManagerReceiveNotification metodě pomocí metody. CreateNotificationFromIntentMetoda je volána jak z OnCreate metody, tak z OnNewIntent metody:
- Když je aplikace spuštěna pomocí dat oznámení,
Intentdata budou předánaOnCreatemetodě. - Pokud je aplikace již v popředí,
Intentdata budou předánaOnNewIntentmetodě.
Android nabízí řadu pokročilých možností pro oznámení. Další informace najdete v tématu oznámení v Xamarin. Android.
Vytvoření implementace rozhraní iOS
Aby Xamarin.Forms aplikace mohla odesílat a přijímat oznámení v iOS, musí aplikace poskytnout implementaci INotificationManager .
Vytvoření třídy iOSNotificationManager
iOSNotificationManagerTřída implementuje INotificationManager rozhraní:
using System;
using Foundation;
using UserNotifications;
using Xamarin.Forms;
[assembly: Dependency(typeof(LocalNotifications.iOS.iOSNotificationManager))]
namespace LocalNotifications.iOS
{
public class iOSNotificationManager : INotificationManager
{
int messageId = 0;
bool hasNotificationsPermission;
public event EventHandler NotificationReceived;
public void Initialize()
{
// request the permission to use local notifications
UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert, (approved, err) =>
{
hasNotificationsPermission = approved;
});
}
public void SendNotification(string title, string message, DateTime? notifyTime = null)
{
// EARLY OUT: app doesn't have permissions
if (!hasNotificationsPermission)
{
return;
}
messageId++;
var content = new UNMutableNotificationContent()
{
Title = title,
Subtitle = "",
Body = message,
Badge = 1
};
UNNotificationTrigger trigger;
if (notifyTime != null)
{
// Create a calendar-based trigger.
trigger = UNCalendarNotificationTrigger.CreateTrigger(GetNSDateComponents(notifyTime.Value), false);
}
else
{
// Create a time-based trigger, interval is in seconds and must be greater than 0.
trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(0.25, false);
}
var request = UNNotificationRequest.FromIdentifier(messageId.ToString(), content, trigger);
UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) =>
{
if (err != null)
{
throw new Exception($"Failed to schedule notification: {err}");
}
});
}
public void ReceiveNotification(string title, string message)
{
var args = new NotificationEventArgs()
{
Title = title,
Message = message
};
NotificationReceived?.Invoke(null, args);
}
NSDateComponents GetNSDateComponents(DateTime dateTime)
{
return new NSDateComponents
{
Month = dateTime.Month,
Day = dateTime.Day,
Year = dateTime.Year,
Hour = dateTime.Hour,
Minute = dateTime.Minute,
Second = dateTime.Second
};
}
}
}
assemblyAtribut nad oborem názvů registruje INotificationManager implementaci rozhraní s DependencyService .
V systému iOS musíte požádat o oprávnění používat oznámení před pokusem o naplánování oznámení. InitializeMetoda požaduje autorizaci k používání místních oznámení. SendNotificationMetoda definuje logiku potřebnou k vytvoření a odeslání oznámení. ReceiveNotificationMetoda bude volána systémem iOS při přijetí zprávy a vyvolá obslužnou rutinu události.
Poznámka
SendNotificationMetoda vytvoří místní oznámení hned pomocí UNTimeIntervalNotificationTrigger objektu nebo přesnou hodnotu DateTime pomocí UNCalendarNotificationTrigger objektu.
Zpracování příchozích oznámení v iOS
V systému iOS je nutné vytvořit delegáta, který podtřídy UNUserNotificationCenterDelegate zpracovávají příchozí zprávy. Ukázková aplikace definuje iOSNotificationReceiver třídu:
public class iOSNotificationReceiver : UNUserNotificationCenterDelegate
{
public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
ProcessNotification(notification);
completionHandler(UNNotificationPresentationOptions.Alert);
}
void ProcessNotification(UNNotification notification)
{
string title = notification.Request.Content.Title;
string message = notification.Request.Content.Body;
DependencyService.Get<INotificationManager>().ReceiveNotification(title, message);
}
}
Tato třída používá DependencyService pro získání instance iOSNotificationManager třídy a poskytuje data příchozích oznámení do ReceiveNotification metody.
AppDelegateTřída musí iOSNotificationReceiver během spuštění aplikace určovat objekt jako UNUserNotificationCenter delegáta. K tomu dochází v FinishedLaunching metodě:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
UNUserNotificationCenter.Current.Delegate = new iOSNotificationReceiver();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
iOS nabízí spoustu pokročilých možností pro oznámení. Další informace najdete v tématu oznámení v Xamarin. iOS.
Testování aplikace
Jakmile projekty platformy obsahují registrovanou implementaci INotificationManager rozhraní, může být aplikace testována na obou platformách. Spusťte aplikaci a kliknutím na kteroukoli z tlačítek vytvořit oznámení vytvořte oznámení.
V Androidu se oznámení zobrazí v oznamovací oblasti. Po klepnutí na oznámení aplikace obdrží oznámení a zobrazí zprávu:

V systému iOS jsou příchozí oznámení automaticky přijímána aplikací bez nutnosti zásahu uživatele. Aplikace obdrží oznámení a zobrazí zprávu:

Stažení ukázky