2025-05-18 01:04:31 +08:00

476 lines
17 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using AOT;
using UnityEngine;
#pragma warning disable 162
namespace Unity.Notifications.iOS
{
internal struct iOSNotificationWithUserInfo
{
internal iOSNotificationData data;
internal Dictionary<string, string> userInfo;
internal List<iOSNotificationAttachment> attachments;
}
internal class iOSNotificationsWrapper : MonoBehaviour
{
#if DEVELOPMENT_BUILD
[DllImport("__Internal")]
private static extern int _NativeSizeof_iOSNotificationAuthorizationData();
[DllImport("__Internal")]
private static extern int _NativeSizeof_iOSNotificationData();
[DllImport("__Internal")]
private static extern int _NativeSizeof_NotificationSettingsData();
#endif
[DllImport("__Internal")]
private static extern void _RequestAuthorization(IntPtr request, Int32 options, bool registerForRemote);
[DllImport("__Internal")]
private static extern void _ScheduleLocalNotification(iOSNotificationData data);
[DllImport("__Internal")]
private static extern void _SetNotificationReceivedDelegate(NotificationReceivedCallback callback);
[DllImport("__Internal")]
private static extern void _SetRemoteNotificationReceivedDelegate(NotificationReceivedCallback callback);
[DllImport("__Internal")]
private static extern void _SetAuthorizationRequestReceivedDelegate(AuthorizationRequestCallback callback);
[DllImport("__Internal")]
private static extern iOSNotificationSettings _GetNotificationSettings();
[DllImport("__Internal")]
private static extern IntPtr _GetScheduledNotificationDataArray(out Int32 count);
[DllImport("__Internal")]
private static extern IntPtr _GetDeliveredNotificationDataArray(out Int32 count);
[DllImport("__Internal")]
internal static extern void _RemoveScheduledNotification(string identifier);
[DllImport("__Internal")]
internal static extern void _RemoveAllScheduledNotifications();
[DllImport("__Internal")]
internal static extern void _RemoveDeliveredNotification(string identifier);
[DllImport("__Internal")]
private static extern void _SetApplicationBadge(Int32 badge);
[DllImport("__Internal")]
private static extern Int32 _GetApplicationBadge();
[DllImport("__Internal")]
private static extern bool _GetAppOpenedUsingNotification();
[DllImport("__Internal")]
internal static extern void _RemoveAllDeliveredNotifications();
[DllImport("__Internal")]
private static extern IntPtr _GetLastNotificationData();
[DllImport("__Internal")]
private static extern string _GetLastRespondedNotificationAction();
[DllImport("__Internal")]
private static extern string _GetLastRespondedNotificationUserText();
[DllImport("__Internal")]
private static extern void _FreeUnmanagediOSNotificationDataArray(IntPtr ptr, int count);
[DllImport("__Internal")]
internal static extern IntPtr _AddItemToNSDictionary(IntPtr dict, string key, string value);
[DllImport("__Internal")]
internal static extern IntPtr _AddAttachmentToNSArray(IntPtr atts, string id, string url, out IntPtr error);
[DllImport("__Internal")]
private static extern void _ReadNSDictionary(IntPtr handle, IntPtr nsDict, ReceiveNSDictionaryKeyValueCallback callback);
[DllImport("__Internal")]
private static extern void _ReadAttachmentsNSArray(IntPtr handle, IntPtr nsArray, ReceiveUNNotificationAttachmentCallback callback);
[DllImport("__Internal")]
internal static extern IntPtr _CreateUNNotificationAction(string id, string title, int options);
[DllImport("__Internal")]
internal static extern IntPtr _CreateUNTextInputNotificationAction(string id, string title, int options, string buttonTitle, string placeholder);
[DllImport("__Internal")]
private static extern void _ReleaseNSObject(IntPtr obj);
[DllImport("__Internal")]
private static extern string _NSErrorToMessage(IntPtr error);
[DllImport("__Internal")]
private static extern IntPtr _AddActionToNSArray(IntPtr actions, IntPtr action, int capacity);
[DllImport("__Internal")]
private static extern IntPtr _CreateUNNotificationCategory(string id, string hiddenPreviewsBodyPlaceholder, string summaryFormat, int options, IntPtr actions, IntPtr intentIdentifiers);
[DllImport("__Internal")]
private static extern IntPtr _AddCategoryToCategorySet(IntPtr categorySet, IntPtr category);
[DllImport("__Internal")]
private static extern void _SetNotificationCategories(IntPtr categorySet);
[DllImport("__Internal")]
private static extern IntPtr _AddStringToNSArray(IntPtr array, string str, int capacity);
[DllImport("__Internal")]
internal static extern void _OpenNotificationSettings();
private delegate void AuthorizationRequestCallback(IntPtr request, iOSAuthorizationRequestData data);
private delegate void NotificationReceivedCallback(iOSNotificationData notificationData);
private delegate void ReceiveNSDictionaryKeyValueCallback(IntPtr dict, string key, string value);
private delegate void ReceiveUNNotificationAttachmentCallback(IntPtr array, string id, string url);
#if UNITY_IOS && !UNITY_EDITOR && DEVELOPMENT_BUILD
static iOSNotificationsWrapper()
{
VerifyNativeManagedSize(_NativeSizeof_iOSNotificationAuthorizationData(), typeof(iOSAuthorizationRequestData));
VerifyNativeManagedSize(_NativeSizeof_iOSNotificationData(), typeof(iOSNotificationData));
VerifyNativeManagedSize(_NativeSizeof_NotificationSettingsData(), typeof(iOSNotificationSettings));
}
static void VerifyNativeManagedSize(int nativeSize, Type managedType)
{
var managedSize = Marshal.SizeOf(managedType);
if (nativeSize != managedSize)
throw new Exception(string.Format("Native/managed struct size missmatch: {0} vs {1}", nativeSize, managedSize));
}
#endif
public static void RegisterAuthorizationRequestCallback()
{
#if UNITY_IOS && !UNITY_EDITOR
_SetAuthorizationRequestReceivedDelegate(AuthorizationRequestReceived);
#endif
}
public static void RegisterOnReceivedRemoteNotificationCallback()
{
#if UNITY_IOS && !UNITY_EDITOR
_SetRemoteNotificationReceivedDelegate(RemoteNotificationReceived);
#endif
}
public static void RegisterOnReceivedCallback()
{
#if UNITY_IOS && !UNITY_EDITOR
_SetNotificationReceivedDelegate(NotificationReceived);
#endif
}
[MonoPInvokeCallback(typeof(AuthorizationRequestCallback))]
public static void AuthorizationRequestReceived(IntPtr request, iOSAuthorizationRequestData data)
{
#if UNITY_IOS && !UNITY_EDITOR
AuthorizationRequest.OnAuthorizationRequestCompleted(request, data);
#endif
}
[MonoPInvokeCallback(typeof(NotificationReceivedCallback))]
public static void RemoteNotificationReceived(iOSNotificationData data)
{
#if UNITY_IOS && !UNITY_EDITOR
iOSNotificationCenter.OnReceivedRemoteNotification(NotificationDataToDataWithUserInfo(data));
#endif
}
[MonoPInvokeCallback(typeof(NotificationReceivedCallback))]
public static void NotificationReceived(iOSNotificationData data)
{
#if UNITY_IOS && !UNITY_EDITOR
iOSNotificationCenter.OnSentNotification(NotificationDataToDataWithUserInfo(data));
#endif
}
static iOSNotificationWithUserInfo NotificationDataToDataWithUserInfo(iOSNotificationData data)
{
iOSNotificationWithUserInfo ret;
ret.data = data;
ret.data.userInfo = IntPtr.Zero;
ret.userInfo = NSDictionaryToCs(data.userInfo);
ret.attachments = AttachmentsNSArrayToCs(data.attachments);
return ret;
}
[MonoPInvokeCallback(typeof(ReceiveNSDictionaryKeyValueCallback))]
private static void ReceiveNSDictionaryKeyValue(IntPtr dict, string key, string value)
{
GCHandle handle = GCHandle.FromIntPtr(dict);
var dictionary = (Dictionary<string, string>)handle.Target;
if (dictionary == null)
return;
dictionary[key] = value;
}
[MonoPInvokeCallback(typeof(ReceiveUNNotificationAttachmentCallback))]
private static void ReceiveUNNotificationAttachment(IntPtr array, string id, string url)
{
GCHandle handle = GCHandle.FromIntPtr(array);
var list = (List<iOSNotificationAttachment>)handle.Target;
if (list == null)
return;
list.Add(new iOSNotificationAttachment()
{
Id = id,
Url = url,
});
}
public static void RequestAuthorization(IntPtr request, int options, bool registerRemote)
{
#if UNITY_IOS && !UNITY_EDITOR
_RequestAuthorization(request, options, registerRemote);
#endif
}
public static iOSNotificationSettings GetNotificationSettings()
{
#if UNITY_IOS && !UNITY_EDITOR
return _GetNotificationSettings();
#else
return new iOSNotificationSettings();
#endif
}
public static void ScheduleLocalNotification(iOSNotificationWithUserInfo data)
{
#if UNITY_IOS && !UNITY_EDITOR
data.data.userInfo = iOSNotificationsWrapper.CsDictionaryToObjC(data.userInfo);
data.data.attachments = iOSNotificationsWrapper.CsAttachmentsToObjc(data.attachments);
_ScheduleLocalNotification(data.data);
#endif
}
public static iOSNotificationWithUserInfo[] GetDeliveredNotificationData()
{
#if UNITY_IOS && !UNITY_EDITOR
int count;
var ptr = _GetDeliveredNotificationDataArray(out count);
return MarshalAndFreeNotificationDataArray(ptr, count);
#else
return null;
#endif
}
public static string GetLastRespondedNotificationAction()
{
#if UNITY_IOS && !UNITY_EDITOR
return _GetLastRespondedNotificationAction();
#else
return null;
#endif
}
public static string GetLastRespondedNotificationUserText()
{
#if UNITY_IOS && !UNITY_EDITOR
return _GetLastRespondedNotificationUserText();
#else
return null;
#endif
}
public static iOSNotificationWithUserInfo[] GetScheduledNotificationData()
{
#if UNITY_IOS && !UNITY_EDITOR
int count;
var ptr = _GetScheduledNotificationDataArray(out count);
return MarshalAndFreeNotificationDataArray(ptr, count);
#else
return null;
#endif
}
#if UNITY_IOS && !UNITY_EDITOR
static iOSNotificationWithUserInfo[] MarshalAndFreeNotificationDataArray(IntPtr ptr, int count)
{
if (count == 0 || ptr == IntPtr.Zero)
return null;
var dataArray = new iOSNotificationWithUserInfo[count];
var structSize = Marshal.SizeOf(typeof(iOSNotificationData));
var next = ptr;
for (var i = 0; i < count; ++i)
{
dataArray[i].data = (iOSNotificationData)Marshal.PtrToStructure(next, typeof(iOSNotificationData));
dataArray[i].userInfo = NSDictionaryToCs(dataArray[i].data.userInfo);
dataArray[i].attachments = AttachmentsNSArrayToCs(dataArray[i].data.attachments);
next = next + structSize;
}
_FreeUnmanagediOSNotificationDataArray(ptr, count);
return dataArray;
}
#endif
public static IntPtr CsDictionaryToObjC(Dictionary<string, string> userInfo)
{
#if UNITY_IOS && !UNITY_EDITOR
if (userInfo == null)
return IntPtr.Zero;
IntPtr dict = IntPtr.Zero;
foreach (var item in userInfo)
dict = _AddItemToNSDictionary(dict, item.Key, item.Value);
return dict;
#else
return IntPtr.Zero;
#endif
}
public static IntPtr CsAttachmentsToObjc(List<iOSNotificationAttachment> attachments)
{
#if UNITY_IOS && !UNITY_EDITOR
if (attachments == null || attachments.Count == 0)
return IntPtr.Zero;
var atts = IntPtr.Zero;
foreach (var attachment in attachments)
{
IntPtr error;
atts = _AddAttachmentToNSArray(atts, attachment.Id, attachment.Url, out error);
if (error != IntPtr.Zero)
{
if (atts != IntPtr.Zero)
_ReleaseNSObject(atts);
var msg = _NSErrorToMessage(error);
throw new Exception(msg);
}
}
return atts;
#else
return IntPtr.Zero;
#endif
}
public static Dictionary<string, string> NSDictionaryToCs(IntPtr dict)
{
#if UNITY_IOS && !UNITY_EDITOR
var ret = new Dictionary<string, string>();
var handle = GCHandle.Alloc(ret);
_ReadNSDictionary(GCHandle.ToIntPtr(handle), dict, ReceiveNSDictionaryKeyValue);
handle.Free();
return ret;
#else
return new Dictionary<string, string>();
#endif
}
public static List<iOSNotificationAttachment> AttachmentsNSArrayToCs(IntPtr array)
{
#if UNITY_IOS && !UNITY_EDITOR
if (array == IntPtr.Zero)
return null;
var ret = new List<iOSNotificationAttachment>();
var handle = GCHandle.Alloc(ret);
_ReadAttachmentsNSArray(GCHandle.ToIntPtr(handle), array, ReceiveUNNotificationAttachment);
handle.Free();
return ret;
#else
return null;
#endif
}
public static void SetApplicationBadge(int badge)
{
#if UNITY_IOS && !UNITY_EDITOR
_SetApplicationBadge(badge);
#endif
}
public static int GetApplicationBadge()
{
#if UNITY_IOS && !UNITY_EDITOR
return _GetApplicationBadge();
#else
return 0;
#endif
}
public static bool GetAppOpenedUsingNotification()
{
#if UNITY_IOS && !UNITY_EDITOR
return _GetAppOpenedUsingNotification();
#else
return false;
#endif
}
public static iOSNotificationWithUserInfo? GetLastNotificationData()
{
#if UNITY_IOS && !UNITY_EDITOR
if (_GetAppOpenedUsingNotification())
{
IntPtr ptr = _GetLastNotificationData();
if (ptr != IntPtr.Zero)
{
iOSNotificationWithUserInfo data;
data.data = (iOSNotificationData)Marshal.PtrToStructure(ptr, typeof(iOSNotificationData));
data.userInfo = NSDictionaryToCs(data.data.userInfo);
data.data.userInfo = IntPtr.Zero;
data.attachments = AttachmentsNSArrayToCs(data.data.attachments);
data.data.attachments = IntPtr.Zero;
_FreeUnmanagediOSNotificationDataArray(ptr, 1);
return data;
}
}
#endif
return null;
}
public static void SetNotificationCategories(IEnumerable<iOSNotificationCategory> categories)
{
var allActions = new Dictionary<string, IntPtr>();
foreach (var category in categories)
{
foreach (var action in category.Actions)
{
if (string.IsNullOrEmpty(action.Id))
throw new ArgumentException("Action must have a valid and unique ID");
if (!allActions.ContainsKey(action.Id))
allActions[action.Id] = action.CreateUNNotificationAction();
}
}
#if UNITY_IOS && !UNITY_EDITOR
IntPtr categorySet = IntPtr.Zero;
foreach (var category in categories)
{
IntPtr actions = IntPtr.Zero;
int count = category.Actions.Length;
foreach (var action in category.Actions)
actions = _AddActionToNSArray(actions, allActions[action.Id], count);
IntPtr intentIdentifiers = IntPtr.Zero;
count = category.IntentIdentifiers.Length;
foreach (var idr in category.IntentIdentifiers)
intentIdentifiers = _AddStringToNSArray(intentIdentifiers, idr, count);
var cat = _CreateUNNotificationCategory(category.Id, category.HiddenPreviewsBodyPlaceholder, category.SummaryFormat, (int)category.Options,
actions, intentIdentifiers);
categorySet = _AddCategoryToCategorySet(categorySet, cat);
}
_SetNotificationCategories(categorySet);
foreach (var act in allActions)
_ReleaseNSObject(act.Value);
#endif
}
}
}
#pragma warning restore 162