You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中如何设置仅可通过脚本删除的Android通知?

如何阻止用户删除Unity发送的Android通知(仅允许应用内操作删除)

核心原理

Android系统中,普通通知允许用户手动清除,要实现用户无法删除的效果,必须将通知与前台服务绑定。前台服务的通知属于系统级强制显示的通知,用户无法手动删除,只有当服务停止时,通知才会自动消失。

具体实现步骤

1. 修改通知渠道优先级

前台服务要求通知渠道的优先级至少为High,否则系统可能不允许将其设为前台通知。修改你的Start()方法中的渠道设置:

private void Start()
{
    var channel = new AndroidNotificationChannel()
    {
        Id = "channel_ID",
        Name = "Notifications Channel",
        Importance = Importance.High, // 必须改为High级别
        Description = "Reminder notifications",
        LockScreenVisibility = LockScreenVisibility.Public,
    };
    AndroidNotificationCenter.RegisterNotificationChannel(channel);
    if (!Permission.HasUserAuthorizedPermission("android.permission.POST_NOTIFICATIONS"))
    {
        Permission.RequestUserPermission("android.permission.POST_NOTIFICATIONS");
    }
}

2. 通过Android前台服务绑定通知

Unity的AndroidNotificationCenter本身不直接支持前台服务,需要通过Android原生API实现。以下是在Unity中调用原生API创建前台服务的代码:

添加启动前台服务的方法:

private void StartForegroundServiceWithNotification()
{
    AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
    AndroidJavaObject context = currentActivity.Call<AndroidJavaObject>("getApplicationContext");

    // 创建通知内容
    var notification = new AndroidNotification();
    notification.Title = "工单提醒";
    notification.Text = "请处理未关闭的游戏内工单";
    notification.ShouldAutoCancel = false;
    notification.SmallIcon = "icon_notification"; // 确保Android项目中有该图标资源

    // 转换为Android原生Notification对象
    AndroidJavaClass builderClass = new AndroidJavaClass("android.app.Notification$Builder");
    AndroidJavaObject builder = builderClass.CallStatic<AndroidJavaObject>("create", context, "channel_ID");
    builder.Call<AndroidJavaObject>("setContentTitle", notification.Title);
    builder.Call<AndroidJavaObject>("setContentText", notification.Text);
    
    int iconResId = context.Call<int>("getResources")
        .Call<int>("getIdentifier", notification.SmallIcon, "drawable", context.Call<string>("getPackageName"));
    builder.Call<AndroidJavaObject>("setSmallIcon", iconResId);
    
    builder.Call<AndroidJavaObject>("setAutoCancel", notification.ShouldAutoCancel);
    builder.Call<AndroidJavaObject>("setOngoing", true); // 标记为持续通知,防止用户手动清除

    AndroidJavaObject notificationObj = builder.Call<AndroidJavaObject>("build");

    // 启动前台服务
    AndroidJavaClass serviceClass = new AndroidJavaClass("com.yourpackage.NotificationForegroundService"); // 替换为你的服务包路径
    AndroidJavaObject intent = new AndroidJavaObject("android.content.Intent", context, serviceClass);
    intent.Call<AndroidJavaObject>("putExtra", "notification_id", 1); // 自定义通知ID
    intent.Call<AndroidJavaObject>("putExtra", "notification", notificationObj);

    // 适配Android版本(8.0+需用startForegroundService)
    if (GetAndroidOSVersion() >= 26)
    {
        context.Call("startForegroundService", intent);
    }
    else
    {
        context.Call("startService", intent);
    }
}

// 获取当前Android系统版本
private int GetAndroidOSVersion()
{
    AndroidJavaClass buildVersion = new AndroidJavaClass("android.os.Build$VERSION");
    return buildVersion.GetStatic<int>("SDK_INT");
}

3. 创建Android前台服务类

在Unity的Plugins/Android/src目录下创建NotificationForegroundService.java(替换包名为你的项目包名):

package com.yourpackage;

import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class NotificationForegroundService extends Service {
    private static final int DEFAULT_NOTIFICATION_ID = 1;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        int notificationId = intent.getIntExtra("notification_id", DEFAULT_NOTIFICATION_ID);
        Notification notification = intent.getParcelableExtra("notification");
        
        // 将服务设为前台服务,绑定通知
        startForeground(notificationId, notification);
        
        // 返回START_STICKY确保服务被杀死后可重启(可选,按需调整)
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 服务停止时,通知会自动移除
    }
}

4. 完成操作后停止服务(删除通知)

当用户关闭工单完成指定操作时,调用以下方法停止前台服务,通知会自动消失:

public void StopNotificationWhenTaskCompleted()
{
    AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
    AndroidJavaObject context = currentActivity.Call<AndroidJavaObject>("getApplicationContext");

    AndroidJavaClass serviceClass = new AndroidJavaClass("com.yourpackage.NotificationForegroundService");
    AndroidJavaObject intent = new AndroidJavaObject("android.content.Intent", context, serviceClass);
    context.Call("stopService", intent);
}

5. 配置AndroidManifest.xml

确保在AndroidManifest.xml中添加权限和服务声明:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<application ...>
    <service android:name="com.yourpackage.NotificationForegroundService" 
             android:foregroundServiceType="dataSync" /> <!-- 根据服务类型选择,如dataSync、mediaPlayback等 -->
</application>

关键注意事项

  • setOngoing(true):必须设置该属性,配合前台服务彻底阻止用户手动删除通知。
  • Android 12+要求指定foregroundServiceType,否则会触发系统报错。
  • 确保Android项目中存在指定的通知图标资源,否则通知无法正常显示。

内容的提问来源于stack exchange,提问作者Rafał Łojek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 14:57:48