当应用程序收到某些推送通知时,我尝试实现自定义呼叫屏幕。当我拥有所有可用数据时,我尝试在应用程序仍在后台时发出本地通知。注意......
当应用程序收到某些推送通知时,我尝试实现自定义呼叫屏幕。当我拥有所有可用数据时,我尝试在应用程序仍在后台时发出本地通知。
注意:它是 MAUI 的 .NET 代码,但它基本上是 Android API 的完全模仿者,因此 Java 程序员应该是可读的。
void RegisterNotification(string cid, string title){
.......
var clickIntent = new Intent(context, typeof(MainActivity));
clickIntent.AddFlags(ActivityFlags.SingleTop | ActivityFlags.ClearTop);
clickIntent.PutExtra("field1thatneeded", "abcde");
var pendingIntentFlags = (Build.VERSION.SdkInt >= BuildVersionCodes.S) ? PendingIntentFlags.UpdateCurrent | PendingIntentFlags.Immutable : PendingIntentFlags.UpdateCurrent;
var pendingIntent = PendingIntent.GetActivity(context, activityId, clickIntent, pendingIntentFlags);
.......
var notificationBuilder = new Notification.Builder(this, AppConstants.CallChannelID)
.SetAutoCancel(false)
.SetOngoing(true)
.SetContentTitle("Incoming call")
.SetContentText(title)
.SetContentIntent(pendingIntent)
.SetStyle(Notification.CallStyle.ForIncomingCall(incomingCaller, rejectPendingIntent, answerPendingIntent))
.SetCategory(Notification.CategoryCall);
var notification =notificationBuilder.Build();
#if ANDROID29_0_OR_GREATER
StartForeground(notificationID, notification, Android.Content.PM.ForegroundService.TypePhoneCall);
#else
StartForeground(notificationID, notification );
#endif
}
在附加任何活动之前无法立即创建本地通知,我无法获取 PendingIntent( 尝试在空对象引用上调用虚拟方法“android.os.UserHandle android.content.Context.getUser()” )或使用所需资源的供稿生成器( 尝试在空对象引用上调用虚拟方法“android.content.res.Resources android.content.Context.getResources()” / Java.Lang.NullPointerException:尝试在空对象引用上调用虚拟方法“android.os.UserHandle android.content.Context.getUser()” )
我发现的唯一解决方案是创建一个服务:
[Service(ForegroundServiceType = Android.Content.PM.ForegroundService.TypePhoneCall, Exported = false)] //this attribute fills up AndroidManifest
internal class DroidCallService: Service
{
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
if (intent.Action == "START_SERVICE")
{
var callID = intent.GetStringExtra("call_id");
var name = intent.GetStringExtra("call_title");
RegisterNotification(callID, name);
}
else if (intent.Action == "STOP_SERVICE")
{
StopForeground(StopForegroundFlags.Remove);
StopSelfResult(startId);
}
return StartCommandResult.NotSticky;
}
}
当应用程序卸载时,所有这些在 Android 11 及更早版本上运行良好,但由于运行前台服务的新限制,我在启动服务时收到错误:
Intent startService = new Intent(ctx, typeof(DroidCallService));
startService.SetAction("START_SERVICE");
startService.PutExtra("call_id", callID);
startService.PutExtra("call_title", name);
#if ANDROID26_0_OR_GREATER
ctx.StartForegroundService(startService); // ERROR!
#else
ctx.StartService(startService);
#endif
Android.App.ForegroundServiceStartNotAllowedException:由于 mAllowStartForegroundfalse 而不允许 startForegroundService()
和
Android.App.BackgroundServiceStartNotAllowedException:不允许启动服务 Intent { act=START_SERVICEcmp=com.company.app/crc646332b1bcddc0e22c.DroidCallService(has extras) }:应用程序在后台
我看到过多种建议,例如要求用户跳过电池优化、使用闹钟或日历等,但这些都像是“古怪的”解决方案。
任务很简单 :后台实例需要创建前台通知。正确的做法是什么?如何做?