Skip to content

Instantly share code, notes, and snippets.

@pbk20191
Created May 16, 2025 00:17
Show Gist options
  • Save pbk20191/9e4df4b5db4e71f794098a02b356925c to your computer and use it in GitHub Desktop.
Save pbk20191/9e4df4b5db4e71f794098a02b356925c to your computer and use it in GitHub Desktop.
Post Notification using Apple NSNotificationCenter with Pure c# and CoreFoundation
using System;
using System.Runtime.InteropServices;
public static class AppleMessagesend {
#if UNITY_IOS || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX || UNITY_TVOS
const int kCFStringEncodingUTF8 = 0x08000100;
[DllImport("__Internal")]
static extern IntPtr CFStringCreateWithCString(IntPtr alloc, IntPtr cStr, int encoding);
[DllImport("__Internal")]
static extern void CFRelease(IntPtr cf);
[DllImport("__Internal")]
static extern void CFRetain(IntPtr cf);
[DllImport("__Internal")]
static extern IntPtr CFDataCreate(IntPtr allocator, byte[] bytes, long length);
[DllImport("__Internal")]
static extern void CFShow(IntPtr cfRef);
[DllImport("__Internal")]
static extern IntPtr CFPropertyListCreateWithData(
IntPtr allocator,
IntPtr data,
ulong options,
IntPtr format, // nullable
IntPtr* error // nullable
);
[DllImport("__Internal")]
static extern IntPtr CFNotificationCenterGetLocalCenter();
[DllImport("__Internal")]
static extern void CFNotificationCenterPostNotification(IntPtr center, IntPtr name, IntPtr obj, IntPtr userInfo, bool deliverImmediately);
[DllImport("__Internal")]
static extern ulong CFDictionaryGetTypeID();
[DllImport("__Internal")]
static extern ulong CFGetTypeID(IntPtr cf);
public static unsafe bool dispatchMessage(string @namespace, string plistString)
{
if (string.IsNullOrEmpty(@namespace) || string.IsNullOrEmpty(plistString))
return false;
IntPtr cfName = IntPtr.Zero;
IntPtr cfData = IntPtr.Zero;
IntPtr plist = IntPtr.Zero;
try
{
{
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(@namespace);
Array.Resize(ref utf8Bytes, utf8Bytes.Length + 1);
fixed (byte* pUtf8 = utf8Bytes)
{
cfName = CFStringCreateWithCString(IntPtr.Zero, (IntPtr)pUtf8, kCFStringEncodingUTF8);
if (cfName == IntPtr.Zero) return false;
}
}
// CFData for plist string
byte[] bytes = Encoding.UTF8.GetBytes(plistString);
cfData = CFDataCreate(IntPtr.Zero, bytes, bytes.Length);
if (cfData == IntPtr.Zero) return false;
// Parse plist
IntPtr* errorPtr = stackalloc IntPtr[1];
errorPtr[0] = IntPtr.Zero;
plist = CFPropertyListCreateWithData(IntPtr.Zero, cfData, 0, IntPtr.Zero, errorPtr);
if (plist == IntPtr.Zero)
{
#if UNITY_EDITOR
UnityEngine.Debug.LogWarning("[AppleMessagesend] Failed to parse plist.");
#endif
CFShow(*errorPtr);
CFRelease(*errorPtr);
return false;
} else if (CFGetTypeID(plist) != CFDictionaryGetTypeID())
{
#if UNITY_EDITOR
UnityEngine.Debug.LogWarning("[AppleMessagesend] plist is not a dictionary.");
#endif
CFShow(plist);
return false;
}
// Post
IntPtr center = CFNotificationCenterGetLocalCenter();
CFNotificationCenterPostNotification(center, cfName, IntPtr.Zero, plist, true);
return true;
}
finally
{
// Cleanup
if (cfName != IntPtr.Zero) CFRelease(cfName);
if (cfData != IntPtr.Zero) CFRelease(cfData);
if (plist != IntPtr.Zero) CFRelease(plist);
}
}
#else
public static bool dispatchMessage(string @namespace, string plistString)
{
Debug.LogWarning("[AppleMessagesend] dispatchMessage is not supported on this platform.");
return false;
}
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment