|
|
@@ -0,0 +1,459 @@
|
|
|
+#unity/日常积累
|
|
|
+#安卓
|
|
|
+#ios
|
|
|
+
|
|
|
+消息通知权限,和安卓版本的关系:
|
|
|
+https://developer.android.com/develop/ui/views/notifications/notification-permission
|
|
|
+
|
|
|
+![[Pasted image 20250813141852.png]]
|
|
|
+
|
|
|
+## 安卓和ios移动端,主动申请权限相关,参考
|
|
|
+
|
|
|
+``` cs
|
|
|
+ /// <summary>
|
|
|
+ /// 主动申请通知权限
|
|
|
+ /// </summary>
|
|
|
+ private static void RequestNotificationPermission()
|
|
|
+ {
|
|
|
+#if !UNITY_EDITOR
|
|
|
+#if UNITY_ANDROID
|
|
|
+ // 检查Android版本
|
|
|
+ if (GetAndroidVersion() >= 33) // Android 13+
|
|
|
+ {
|
|
|
+ // 检查是否已经有通知权限
|
|
|
+ if (!CheckNotificationPermissionStatus())
|
|
|
+ {
|
|
|
+ Debug.Log("请求通知权限...");
|
|
|
+ // 请求通知权限
|
|
|
+ Permission.RequestUserPermission("android.permission.POST_NOTIFICATIONS");
|
|
|
+
|
|
|
+ // 添加权限回调
|
|
|
+ PermissionCallbacks callbacks = new PermissionCallbacks();
|
|
|
+ callbacks.PermissionGranted += (permissionName) => {
|
|
|
+ Debug.Log($"通知权限已授予: {permissionName}");
|
|
|
+ };
|
|
|
+ callbacks.PermissionDenied += (permissionName) => {
|
|
|
+ Debug.LogWarning($"通知权限被拒绝: {permissionName}");
|
|
|
+ };
|
|
|
+ callbacks.PermissionDeniedAndDontAskAgain += (permissionName) => {
|
|
|
+ Debug.LogWarning($"通知权限被拒绝且不再询问: {permissionName}");
|
|
|
+ };
|
|
|
+
|
|
|
+ Permission.RequestUserPermission("android.permission.POST_NOTIFICATIONS", callbacks);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Debug.Log("已有通知权限");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Debug.Log("Android版本低于13,无需申请通知权限");
|
|
|
+ }
|
|
|
+#elif UNITY_IOS
|
|
|
+ // 使用iOSNotificationPermission类处理iOS通知权限
|
|
|
+ if (!iOSNotificationPermission.CheckPermission())
|
|
|
+ {
|
|
|
+ Debug.Log("请求iOS通知权限...");
|
|
|
+ iOSNotificationPermission.RequestPermission();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Debug.Log("已有iOS通知权限");
|
|
|
+ }
|
|
|
+#else
|
|
|
+ Debug.Log("其他平台,无需申请通知权限");
|
|
|
+#endif
|
|
|
+#else
|
|
|
+ Debug.Log("Unity编辑器模式,跳过通知权限申请");
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取Android版本
|
|
|
+ /// </summary>
|
|
|
+ private static int GetAndroidVersion()
|
|
|
+ {
|
|
|
+#if !UNITY_EDITOR && UNITY_ANDROID
|
|
|
+ try
|
|
|
+ {
|
|
|
+ using (AndroidJavaClass buildVersion = new AndroidJavaClass("android.os.Build$VERSION"))
|
|
|
+ {
|
|
|
+ return buildVersion.GetStatic<int>("SDK_INT");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ Debug.LogError($"获取Android版本失败: {e.Message}");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+#else
|
|
|
+ return 0; // 非Android平台返回0
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 检查通知权限状态
|
|
|
+ /// </summary>
|
|
|
+ private static bool CheckNotificationPermissionStatus()
|
|
|
+ {
|
|
|
+#if !UNITY_EDITOR && UNITY_ANDROID
|
|
|
+ if (GetAndroidVersion() >= 33)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
|
|
|
+ using (AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
|
|
|
+ using (AndroidJavaObject context = currentActivity.Call<AndroidJavaObject>("getApplicationContext"))
|
|
|
+ using (AndroidJavaClass notificationManager = new AndroidJavaClass("android.app.NotificationManager"))
|
|
|
+ using (AndroidJavaObject notificationService = context.Call<AndroidJavaObject>("getSystemService", "notification"))
|
|
|
+ {
|
|
|
+ // 直接调用areNotificationsEnabled方法,因为Android 13+肯定支持这个方法
|
|
|
+ return notificationService.Call<bool>("areNotificationsEnabled");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ Debug.LogError($"检查通知权限状态失败: {e.Message}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true; // 低版本默认返回true
|
|
|
+#elif !UNITY_EDITOR && UNITY_IOS
|
|
|
+ // 使用iOSNotificationPermission类检查iOS通知权限状态
|
|
|
+ return iOSNotificationPermission.CheckPermission();
|
|
|
+#else
|
|
|
+ // Unity编辑器或其他平台,默认返回true
|
|
|
+ return true;
|
|
|
+#endif
|
|
|
+ }
|
|
|
+```
|
|
|
+
|
|
|
+## iOSNotificationPermission.cs
|
|
|
+
|
|
|
+``` cs
|
|
|
+using UnityEngine;
|
|
|
+using System.Runtime.InteropServices;
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// iOS通知权限处理
|
|
|
+/// </summary>
|
|
|
+public class iOSNotificationPermission
|
|
|
+{
|
|
|
+#if !UNITY_EDITOR && UNITY_IOS
|
|
|
+ // iOS原生方法声明
|
|
|
+ [DllImport("__Internal")]
|
|
|
+ private static extern void RequestNotificationPermission();
|
|
|
+
|
|
|
+ [DllImport("__Internal")]
|
|
|
+ private static extern bool CheckNotificationPermission();
|
|
|
+#endif
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 请求通知权限
|
|
|
+ /// </summary>
|
|
|
+ public static void RequestPermission()
|
|
|
+ {
|
|
|
+#if !UNITY_EDITOR && UNITY_IOS
|
|
|
+ Debug.Log("请求iOS通知权限...");
|
|
|
+ RequestNotificationPermission();
|
|
|
+#else
|
|
|
+ Debug.Log("非iOS平台,跳过通知权限请求");
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 检查通知权限状态
|
|
|
+ /// </summary>
|
|
|
+ public static bool CheckPermission()
|
|
|
+ {
|
|
|
+#if !UNITY_EDITOR && UNITY_IOS
|
|
|
+ return CheckNotificationPermission();
|
|
|
+#else
|
|
|
+ return true; // 非iOS平台默认返回true
|
|
|
+#endif
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## iOSNotificationPermission.mm
|
|
|
+
|
|
|
+``` cpp
|
|
|
+#import <Foundation/Foundation.h>
|
|
|
+#import <UserNotifications/UserNotifications.h>
|
|
|
+#import <UIKit/UIKit.h>
|
|
|
+
|
|
|
+extern "C" {
|
|
|
+
|
|
|
+ // 请求通知权限
|
|
|
+ void RequestNotificationPermission() {
|
|
|
+ if (@available(iOS 10.0, *)) {
|
|
|
+ UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
|
|
+ [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge)
|
|
|
+ completionHandler:^(BOOL granted, NSError * _Nullable error) {
|
|
|
+ if (granted) {
|
|
|
+ NSLog(@"iOS通知权限已授予");
|
|
|
+ } else {
|
|
|
+ NSLog(@"iOS通知权限被拒绝: %@", error.localizedDescription);
|
|
|
+ }
|
|
|
+ }];
|
|
|
+ } else {
|
|
|
+ // iOS 10以下版本的处理
|
|
|
+ UIUserNotificationType types = UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge;
|
|
|
+ UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
|
|
|
+ [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查通知权限状态
|
|
|
+ bool CheckNotificationPermission() {
|
|
|
+ if (@available(iOS 10.0, *)) {
|
|
|
+ UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
|
|
+ __block bool hasPermission = false;
|
|
|
+
|
|
|
+ dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
|
+ [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
|
|
|
+ hasPermission = (settings.authorizationStatus == UNAuthorizationStatusAuthorized);
|
|
|
+ dispatch_semaphore_signal(semaphore);
|
|
|
+ }];
|
|
|
+
|
|
|
+ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
|
+ return hasPermission;
|
|
|
+ } else {
|
|
|
+ // iOS 10以下版本
|
|
|
+ UIUserNotificationSettings *settings = [[UIApplication sharedApplication] currentUserNotificationSettings];
|
|
|
+ return (settings.types != UIUserNotificationTypeNone);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## iOSNotificationSetup.cs
|
|
|
+ios的出包配置相关,也要处理一下,放到Editor目录下
|
|
|
+
|
|
|
+``` cs
|
|
|
+#if UNITY_IOS
|
|
|
+using System;
|
|
|
+using System.IO;
|
|
|
+using UnityEditor;
|
|
|
+using UnityEditor.Callbacks;
|
|
|
+using UnityEditor.iOS.Xcode;
|
|
|
+using UnityEngine;
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// iOS通知权限编辑器工具(基于官方API)
|
|
|
+/// </summary>
|
|
|
+public class iOSNotificationSetup
|
|
|
+{
|
|
|
+ [PostProcessBuild(999)]
|
|
|
+ public static void OnPostprocessBuild(BuildTarget buildTarget, string buildPath)
|
|
|
+ {
|
|
|
+ if (buildTarget != BuildTarget.iOS)
|
|
|
+ return;
|
|
|
+
|
|
|
+ Debug.Log("开始配置iOS推送通知...");
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 1. 检查iOS版本
|
|
|
+ CheckiOSVersion();
|
|
|
+
|
|
|
+ // 2. 配置PBX项目
|
|
|
+ ConfigurePBXProject(buildPath);
|
|
|
+
|
|
|
+ // 3. 配置Info.plist
|
|
|
+ ConfigureInfoPlist(buildPath);
|
|
|
+
|
|
|
+ // 4. 配置entitlements
|
|
|
+ ConfigureEntitlements(buildPath);
|
|
|
+
|
|
|
+ Debug.Log("iOS推送通知配置完成!");
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ Debug.LogError($"iOS推送通知配置失败: {e.Message}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 检查iOS版本
|
|
|
+ /// </summary>
|
|
|
+ private static void CheckiOSVersion()
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var requiredVersion = new Version(10, 0);
|
|
|
+ var currentVersion = new Version(PlayerSettings.iOS.targetOSVersionString);
|
|
|
+
|
|
|
+ if (currentVersion < requiredVersion)
|
|
|
+ {
|
|
|
+ Debug.LogWarning($"UserNotifications framework需要iOS 10.0+,当前设置为: {currentVersion}。请在Player Settings中设置正确的Target minimum iOS Version。");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Debug.Log($"iOS版本检查通过: {currentVersion}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ Debug.LogWarning($"无法检查iOS版本: {e.Message}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 配置PBX项目
|
|
|
+ /// </summary>
|
|
|
+ private static void ConfigurePBXProject(string buildPath)
|
|
|
+ {
|
|
|
+ var pbxProjectPath = PBXProject.GetPBXProjectPath(buildPath);
|
|
|
+ var pbxProject = new PBXProject();
|
|
|
+ pbxProject.ReadFromString(File.ReadAllText(pbxProjectPath));
|
|
|
+
|
|
|
+ // 获取目标GUID
|
|
|
+ string mainTarget = GetMainTargetGuid(pbxProject);
|
|
|
+ string unityFrameworkTarget = GetUnityFrameworkTargetGuid(pbxProject);
|
|
|
+
|
|
|
+ bool needsToWriteChanges = false;
|
|
|
+
|
|
|
+ // 添加UserNotifications.framework
|
|
|
+ if (!pbxProject.ContainsFramework(unityFrameworkTarget, "UserNotifications.framework"))
|
|
|
+ {
|
|
|
+ pbxProject.AddFrameworkToProject(unityFrameworkTarget, "UserNotifications.framework", true);
|
|
|
+ needsToWriteChanges = true;
|
|
|
+ Debug.Log("添加UserNotifications.framework到UnityFramework目标");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Debug.Log("UserNotifications.framework已存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置iOS部署目标
|
|
|
+ var currentDeploymentTarget = pbxProject.GetBuildPropertyForAnyConfig(mainTarget, "IPHONEOS_DEPLOYMENT_TARGET");
|
|
|
+ if (string.IsNullOrEmpty(currentDeploymentTarget) || Version.Parse(currentDeploymentTarget) < Version.Parse("10.0"))
|
|
|
+ {
|
|
|
+ pbxProject.SetBuildProperty(mainTarget, "IPHONEOS_DEPLOYMENT_TARGET", "10.0");
|
|
|
+ needsToWriteChanges = true;
|
|
|
+ Debug.Log("设置iOS部署目标为10.0");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 禁用Bitcode
|
|
|
+ var currentBitcode = pbxProject.GetBuildPropertyForAnyConfig(mainTarget, "ENABLE_BITCODE");
|
|
|
+ if (currentBitcode != "NO")
|
|
|
+ {
|
|
|
+ pbxProject.SetBuildProperty(mainTarget, "ENABLE_BITCODE", "NO");
|
|
|
+ needsToWriteChanges = true;
|
|
|
+ Debug.Log("禁用Bitcode");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置正确的架构
|
|
|
+ var currentArchs = pbxProject.GetBuildPropertyForAnyConfig(mainTarget, "ARCHS");
|
|
|
+ if (string.IsNullOrEmpty(currentArchs) || currentArchs != "$(ARCHS_STANDARD)")
|
|
|
+ {
|
|
|
+ pbxProject.SetBuildProperty(mainTarget, "ARCHS", "$(ARCHS_STANDARD)");
|
|
|
+ needsToWriteChanges = true;
|
|
|
+ Debug.Log("设置架构为$(ARCHS_STANDARD)");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (needsToWriteChanges)
|
|
|
+ {
|
|
|
+ File.WriteAllText(pbxProjectPath, pbxProject.WriteToString());
|
|
|
+ Debug.Log("PBX项目配置完成");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 配置Info.plist
|
|
|
+ /// </summary>
|
|
|
+ private static void ConfigureInfoPlist(string buildPath)
|
|
|
+ {
|
|
|
+ var plistPath = Path.Combine(buildPath, "Info.plist");
|
|
|
+ var plist = new PlistDocument();
|
|
|
+ plist.ReadFromString(File.ReadAllText(plistPath));
|
|
|
+
|
|
|
+ var rootDict = plist.root;
|
|
|
+ bool needsToWriteChanges = false;
|
|
|
+
|
|
|
+ // 添加推送通知权限描述
|
|
|
+ if (!rootDict.values.ContainsKey("NSUserNotificationUsageDescription"))
|
|
|
+ {
|
|
|
+ rootDict.SetString("NSUserNotificationUsageDescription", "This app needs push notification permission to send important messages");
|
|
|
+ needsToWriteChanges = true;
|
|
|
+ Debug.Log("添加推送通知权限描述");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加后台模式
|
|
|
+ PlistElementArray backgroundModes = rootDict.CreateArray("UIBackgroundModes");
|
|
|
+ var remoteNotificationElement = new PlistElementString("remote-notification");
|
|
|
+ if (!backgroundModes.values.Contains(remoteNotificationElement))
|
|
|
+ {
|
|
|
+ backgroundModes.values.Add(remoteNotificationElement);
|
|
|
+ needsToWriteChanges = true;
|
|
|
+ Debug.Log("添加remote-notification后台模式");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (needsToWriteChanges)
|
|
|
+ {
|
|
|
+ File.WriteAllText(plistPath, plist.WriteToString());
|
|
|
+ Debug.Log("Info.plist配置完成");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 配置entitlements
|
|
|
+ /// </summary>
|
|
|
+ private static void ConfigureEntitlements(string buildPath)
|
|
|
+ {
|
|
|
+ var pbxProjectPath = PBXProject.GetPBXProjectPath(buildPath);
|
|
|
+ var pbxProject = new PBXProject();
|
|
|
+ pbxProject.ReadFromString(File.ReadAllText(pbxProjectPath));
|
|
|
+
|
|
|
+ string mainTarget = GetMainTargetGuid(pbxProject);
|
|
|
+
|
|
|
+ // 获取entitlements文件名
|
|
|
+ var entitlementsFileName = pbxProject.GetBuildPropertyForAnyConfig(mainTarget, "CODE_SIGN_ENTITLEMENTS");
|
|
|
+ if (string.IsNullOrEmpty(entitlementsFileName))
|
|
|
+ {
|
|
|
+ var bundleIdentifier = PlayerSettings.GetApplicationIdentifier(BuildTargetGroup.iOS);
|
|
|
+ entitlementsFileName = $"{bundleIdentifier.Substring(bundleIdentifier.LastIndexOf(".") + 1)}.entitlements";
|
|
|
+
|
|
|
+ // 添加entitlements文件引用到项目
|
|
|
+ pbxProject.AddBuildProperty(mainTarget, "CODE_SIGN_ENTITLEMENTS", entitlementsFileName);
|
|
|
+ File.WriteAllText(pbxProjectPath, pbxProject.WriteToString());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用ProjectCapabilityManager配置推送通知能力
|
|
|
+ var capManager = new ProjectCapabilityManager(pbxProjectPath, entitlementsFileName, "Unity-iPhone");
|
|
|
+ capManager.AddPushNotifications(true); // true表示使用开发环境
|
|
|
+ capManager.WriteToFile();
|
|
|
+
|
|
|
+ Debug.Log($"Entitlements配置完成: {entitlementsFileName}");
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取主目标GUID
|
|
|
+ /// </summary>
|
|
|
+ private static string GetMainTargetGuid(PBXProject pbxProject)
|
|
|
+ {
|
|
|
+ var unityMainTargetGuidMethod = pbxProject.GetType().GetMethod("GetUnityMainTargetGuid");
|
|
|
+ if (unityMainTargetGuidMethod != null)
|
|
|
+ {
|
|
|
+ return (string)unityMainTargetGuidMethod.Invoke(pbxProject, null);
|
|
|
+ }
|
|
|
+ return pbxProject.TargetGuidByName("Unity-iPhone");
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取UnityFramework目标GUID
|
|
|
+ /// </summary>
|
|
|
+ private static string GetUnityFrameworkTargetGuid(PBXProject pbxProject)
|
|
|
+ {
|
|
|
+ var unityFrameworkTargetGuidMethod = pbxProject.GetType().GetMethod("GetUnityFrameworkTargetGuid");
|
|
|
+ if (unityFrameworkTargetGuidMethod != null)
|
|
|
+ {
|
|
|
+ return (string)unityFrameworkTargetGuidMethod.Invoke(pbxProject, null);
|
|
|
+ }
|
|
|
+ return GetMainTargetGuid(pbxProject);
|
|
|
+ }
|
|
|
+}
|
|
|
+#endif
|
|
|
+```
|
|
|
+
|