我正在使用Xamarin来创建和使用Android应用程序,但我一直停留在通知中。
我想实现的目标:
问题:
出现通知,我关闭了应用程序(只需将其从最近的应用程序屏幕上滑开),然后点击通知按钮-没有任何反应。如果我点击通知正文-应用将打开,但我需要使用这些按钮执行一些操作。
这是我的一些源文件:
MainActivity.cs
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
AnswerReciever receiver;
public static long reminderInterval = 30 * 1000; //every 30 seconds for test
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
CreateNotificationFromIntent(Intent);
receiver = new AnswerReciever();
//trying to schedule notification for specific time of the day
var alarmIntent = new Intent(this, typeof(AlarmReceiver));
var pending = PendingIntent.GetBroadcast(this, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
var alarmManager = GetSystemService(AlarmService).JavaCast<AlarmManager>();
alarmManager.SetInexactRepeating(AlarmType.RtcWakeup, FirstReminder(), reminderInterval, pending);
}
public static long FirstReminder()
{
var dt = DateTime.Now;
//dt = dt.Date.AddHours(22).AddMinutes(00).AddSeconds(0);
//TODO set from user settings
var timestamp = (long)(dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1))).TotalMilliseconds;
return timestamp;
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
protected override void OnNewIntent(Intent intent)
{
CreateNotificationFromIntent(intent);
}
protected override void OnResume()
{
try
{
UnregisterReceiver(receiver);
}
catch (IllegalArgumentException) { }
RegisterReceiver(receiver, new IntentFilter(Constants.ANDROID_NOTIFICATION_ACTION));
base.OnResume();
}
protected override void OnDestroy()
{
UnregisterReceiver(receiver);
base.OnDestroy();
}
protected override void OnPause()
{
base.OnPause();
}
void CreateNotificationFromIntent(Intent intent)
{
if (intent?.Extras != null)
{
string title = intent.Extras.GetString(AndroidNotificationManager.TitleKey);
string message = intent.Extras.GetString(AndroidNotificationManager.MessageKey);
DependencyService.Get<INotificationManager>().ReceiveNotification(title, message);
}
}
}
AlarmReceiver.cs
[BroadcastReceiver]
public class AlarmReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
DependencyService.Get<INotificationManager>().ScheduleNotification(Constants.NOTIFICATION_TITLE, Constants.NOTIFICATION_TEXT);
}
}
AnswerReciever.cs
[BroadcastReceiver(Enabled = true, Exported = true)]
[IntentFilter(new[] { Constants.ANDROID_NOTIFICATION_ACTION })]
public class AnswerReciever : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
var manager = (NotificationManager)AndroidApp.Context.GetSystemService(AndroidApp.NotificationService);
var result = intent.GetBooleanExtra(Constants.ANDROID_NOTIFICATION_EXTRA_ACTION, false);
var date = intent.GetStringExtra(Constants.ANDROID_NOTIFICATION_EXTRA_DATE);
var id = intent.GetIntExtra(Constants.ANDROID_NOTIFICATION_EXTRA_ID, -1);
manager.Cancel(id);
//do something with data
}
}
AndroidNotificationManager.cs
public class AndroidNotificationManager : INotificationManager
{
const int mainActivityPendingIntentId = 0;
const int firstActionPendingIntentId = 1;
const int secondActionPendingIntentId = 2;
bool channelInitialized = false;
int messageId = -1;
NotificationManager manager;
public static string TitleKey => "Title";
public static string MessageKey => "Message";
public event EventHandler NotificationReceived;
public void Initialize()
{
CreateNotificationChannel();
}
public int ScheduleNotification(string title, string message)
{
if (!channelInitialized)
{
CreateNotificationChannel();
}
messageId++;
var mainActivityIintent = new Intent(AndroidApp.Context, typeof(MainActivity));
var mainActivityPendingIntent = PendingIntent.GetActivity(AndroidApp.Context, mainActivityPendingIntentId, mainActivityIintent, PendingIntentFlags.OneShot);
var firstActionIntent = new Intent(Constants.ANDROID_NOTIFICATION_ACTION);
firstActionIntent.PutExtra(Constants.ANDROID_NOTIFICATION_EXTRA_ACTION, false);
firstActionIntent.PutExtra(Constants.ANDROID_NOTIFICATION_EXTRA_DATE, DateTime.Now.Date.ToString("s"));
firstActionIntent.PutExtra(Constants.ANDROID_NOTIFICATION_EXTRA_ID, messageId);
var pFirstActionIntent = PendingIntent.GetBroadcast(AndroidApp.Context, firstActionPendingIntentId, firstActionIntent, PendingIntentFlags.OneShot);
var secondActionIntent = new Intent(Constants.ANDROID_NOTIFICATION_ACTION);
secondActionIntent.PutExtra(Constants.ANDROID_NOTIFICATION_EXTRA_ACTION, true);
secondActionIntent.PutExtra(Constants.ANDROID_NOTIFICATION_EXTRA_DATE, DateTime.Now.Date.ToString("s"));
secondActionIntent.PutExtra(Constants.ANDROID_NOTIFICATION_EXTRA_ID, messageId);
var pSeconActionIntent = PendingIntent.GetBroadcast(AndroidApp.Context, secondActionPendingIntentId, secondActionIntent, PendingIntentFlags.OneShot);
var builder = new NotificationCompat.Builder(AndroidApp.Context, Constants.ANDROID_NOTIFICATION_DEFAULT_CHANNEL_ID)
.SetContentIntent(mainActivityPendingIntent)
.SetContentTitle(title)
.SetContentText(message)
.AddAction(Resource.Drawable.navigation_empty_icon, Constants.ANDROID_NOTIFICATION_ANSWER_NO, pFirstActionIntent)
.AddAction(Resource.Drawable.navigation_empty_icon, Constants.ANDROID_NOTIFICATION_ANSWER_YES, pSeconActionIntent)
.SetAutoCancel(true)
.SetLargeIcon(BitmapFactory.DecodeResource(AndroidApp.Context.Resources, Resource.Drawable.navigation_empty_icon))
.SetSmallIcon(Resource.Drawable.navigation_empty_icon)
.SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate);
var notification = builder.Build();
manager.Notify(messageId, notification);
return messageId;
}
public void ReceiveNotification(string title, string message)
{
var args = new NotificationEventArgs()
{
Title = title,
Message = message,
};
NotificationReceived?.Invoke(null, args);
}
void CreateNotificationChannel()
{
manager = (NotificationManager)AndroidApp.Context.GetSystemService(AndroidApp.NotificationService);
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var channelNameJava = new Java.Lang.String(Constants.ANDROID_NOTIFICATION_DEFAULT_CHANNEL_NAME);
var channel = new NotificationChannel(Constants.ANDROID_NOTIFICATION_DEFAULT_CHANNEL_ID, channelNameJava, NotificationImportance.Default)
{
Description = Constants.ANDROID_NOTIFICATION_DEFAULT_CHANNEL_DESC
};
manager.CreateNotificationChannel(channel);
}
channelInitialized = true;
}
}
我创建了一个示例项目来重现我的问题,如果有帮助的话:https://github.com/Immelstorn/NotificationsTest
MyService.cs:
[Service(Enabled = true)]
public class MyService : Service
{
private Handler handler;
private Action runnable;
private bool isStarted;
private int DELAY_BETWEEN_LOG_MESSAGES = 5000;
private int NOTIFICATION_SERVICE_ID = 1001;
private int NOTIFICATION_AlARM_ID = 1002;
private string NOTIFICATION_CHANNEL_ID = "1003";
private string NOTIFICATION_CHANNEL_NAME = "MyChannel";
public override void OnCreate()
{
base.OnCreate();
handler = new Handler();
//here is what you want to do always, i just want to push a notification every 5 seconds here
runnable = new Action(() =>
{
if (isStarted)
{
DispatchNotificationThatAlarmIsGenerated("I'm running");
handler.PostDelayed(runnable, DELAY_BETWEEN_LOG_MESSAGES);
}
});
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
if (isStarted)
{
// service is already started
}
else
{
CreateNotificationChannel();
DispatchNotificationThatServiceIsRunning();
handler.PostDelayed(runnable, DELAY_BETWEEN_LOG_MESSAGES);
isStarted = true;
}
return StartCommandResult.Sticky;
}
public override void OnTaskRemoved(Intent rootIntent)
{
//base.OnTaskRemoved(rootIntent);
}
public override IBinder OnBind(Intent intent)
{
// Return null because this is a pure started service. A hybrid service would return a binder that would
// allow access to the GetFormattedStamp() method.
return null;
}
public override void OnDestroy()
{
// Stop the handler.
handler.RemoveCallbacks(runnable);
// Remove the notification from the status bar.
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Cancel(NOTIFICATION_SERVICE_ID);
isStarted = false;
base.OnDestroy();
}
private void CreateNotificationChannel()
{
//Notification Channel
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationImportance.Max);
notificationChannel.EnableLights(true);
notificationChannel.EnableVibration(true);
notificationChannel.SetVibrationPattern(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 });
NotificationManager notificationManager = (NotificationManager)this.GetSystemService(Context.NotificationService);
notificationManager.CreateNotificationChannel(notificationChannel);
}
//start a foreground notification to keep alive
private void DispatchNotificationThatServiceIsRunning()
{
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.SetDefaults((int)NotificationDefaults.All)
.SetSmallIcon(Resource.Drawable.Icon)
.SetVibrate(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 })
.SetSound(null)
.SetChannelId(NOTIFICATION_CHANNEL_ID)
.SetPriority(NotificationCompat.PriorityDefault)
.SetAutoCancel(false)
.SetContentTitle("Mobile")
.SetContentText("My service started")
.SetOngoing(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.From(this);
StartForeground(NOTIFICATION_SERVICE_ID, builder.Build());
}
//every 5 seconds push a notificaition
private void DispatchNotificationThatAlarmIsGenerated(string message)
{
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.OneShot);
Notification.Builder notificationBuilder = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
.SetSmallIcon(Resource.Drawable.Icon)
.SetContentTitle("Alarm")
.SetContentText(message)
.SetAutoCancel(true)
.SetContentIntent(pendingIntent);
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Notify(NOTIFICATION_AlARM_ID, notificationBuilder.Build());
}
}
2。您的活动:
protected override void OnResume()
{
base.OnResume();
StartMyRequestService();
}
public void StartMyRequestService()
{
var serviceToStart = new Intent(this, typeof(MyService));
StartService(serviceToStart);
}