/* MessageHandler.cs */ using UnityEngine; using System.Runtime.InteropServices; public static class MessageHandler { // private delegate void MonoPMessageDelegate(string message, string data); // , // [AOT.MonoPInvokeCallback(typeof(MonoPMessageDelegate))] private static void OnMessage(string message, string data) { // MessageRouter.RouteMessage(message, data); } // Unity Engine [RuntimeInitializeOnLoadMethod] private static void Initialize() { // RegisterMessageHandler(OnMessage); } // , [DllImport("__Internal")] private static extern void RegisterMessageHandler(MonoPMessageDelegate messageDelegate); }
/* MessageHandler.mm */ #import <Foundation/Foundation.h> // , Unity typedef void (*MonoPMessageDelegate)(const char* message, const char* data); // . // - static MonoPMessageDelegate _messageDelegate = NULL; // , Unity FOUNDATION_EXPORT void RegisterMessageHandler(MonoPMessageDelegate delegate) { _messageDelegate = delegate; } // - , Unity, // void SendMessageToUnity(const char* message, const char* data) { dispatch_async(dispatch_get_main_queue(), ^{ if(_messageDelegate != NULL) { _messageDelegate(message, data); } }); }
/* MonoPCallback.cs */ using System; using System.Runtime.InteropServices; using UnityEngine; public static class MonoPCallback { // , Action // private delegate void MonoPCallbackDelegate(IntPtr actionPtr, string data); [AOT.MonoPInvokeCallback(typeof(MonoPCallbackDelegate))] private static void MonoPCallbackInvoke(IntPtr actionPtr, string data) { if(IntPtr.Zero.Equals(actionPtr)) { return; } // Action var action = IntPtrToObject(actionPtr, true); if(action == null) { Debug.LogError("Callaback not found"); return; } try { // , Action var paramTypes = action.GetType().GetGenericArguments(); // var arg = paramTypes.Length == 0 ? null : ConvertObject(data, paramTypes[0]); // Action , // var invokeMethod = action.GetType().GetMethod("Invoke", paramTypes.Length == 0 ? new Type[0] : new []{ paramTypes[0] }); if(invokeMethod != null) { invokeMethod.Invoke(action, paramTypes.Length == 0 ? new object[] { } : new[] { arg }); } else { Debug.LogError("Failed to invoke callback " + action + " with arg " + arg + ": invoke method not found"); } } catch(Exception e) { Debug.LogError("Failed to invoke callback " + action + " with arg " + data + ": " + e.Message); } } // public static object IntPtrToObject(IntPtr handle, bool unpinHandle) { if(IntPtr.Zero.Equals(handle)) { return null; } var gcHandle = GCHandle.FromIntPtr(handle); var result = gcHandle.Target; if(unpinHandle) { gcHandle.Free(); } return result; } // public static IntPtr ObjectToIntPtr(object obj) { if(obj == null) { return IntPtr.Zero; } var handle = GCHandle.Alloc(obj); return GCHandle.ToIntPtr(handle); } // , public static IntPtr ActionToIntPtr<T>(Action<T> action) { return ObjectToIntPtr(action); } private static object ConvertObject(string value, Type objectType) { if(value == null || objectType == typeof(string)) { return value; } return Newtonsoft.Json.JsonConvert.DeserializeObject(value, objectType); } // [RuntimeInitializeOnLoadMethod] private static void Initialize() { RegisterCallbackDelegate(MonoPCallbackInvoke); } [DllImport("__Internal")] private static extern void RegisterCallbackDelegate(MonoPCallbackDelegate callbackDelegate); }
/* MonoPCallback.h */ // Unity typedef const void* UnityAction; // , void SendCallbackDataToUnity(UnityAction callback, NSDictionary* data); /* MonoPCallback.mm */ #import <Foundation/Foundation.h> #import "MonoPCallback.h" // Objective C typedef void (*MonoPCallbackDelegate)(UnityAction action, const char* data); // , // static MonoPCallbackDelegate _monoPCallbackDelegate = NULL; FOUNDATION_EXPORT void RegisterCallbackDelegate(MonoPCallbackDelegate callbackDelegate) { _monoPCallbackDelegate = callbackDelegate; } // - void SendCallbackDataToUnity(UnityAction callback, NSDictionary* data) { if(callback == NULL) return; NSString* dataStr = nil; if(data != nil) { // json NSError* parsingError = nil; NSData* dataJson = [NSJSONSerialization dataWithJSONObject:data options:0 error:&parsingError]; if (parsingError == nil) { dataStr = [[NSString alloc] initWithData:dataJson encoding:NSUTF8StringEncoding]; } else { NSLog(@"SendCallbackDataToUnity json parsing error: %@", parsingError); } } // Unity () dispatch_async(dispatch_get_main_queue(), ^{ if(_monoPCallbackDelegate != NULL) _monoPCallbackDelegate(callback, [dataStr cStringUsingEncoding:NSUTF8StringEncoding]); }); }
/* Example.cs */ public class Example { public class ResultData { public bool Success; public string ValueStr; public int ValueInt; } [DllImport("__Internal", CharSet = CharSet.Ansi)] private static extern void GetSomeDataWithCallback(string key, IntPtr callback); public static void GetSomeData(string key, Action<ResultData> completionHandler) { GetSomeDataWithCallback(key, MonoPCallback.ActionToIntPtr<ResultData>(completionHandler); } }
/* Example.mm */ #import <Foundation/Foundation.h> #import "MonoPCallback.h" FOUNDATION_EXPORT void GetSomeDataWithCallback(const char* key, UnityAction callback) { DoSomeStuffWithKey(key); SendCallbackDataToUnity(callback, @{ @"Success" : @YES, @"ValueStr" : someResult, @"ValueInt" : @42 }); }
/* ApplicationStateListener.mm */ #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> #import "AppDelegateListener.h" @interface ApplicationStateListener : NSObject <AppDelegateListener> + (instancetype)sharedInstance; @end @implementation ApplicationStateListener // , // Unity Player static ApplicationStateListener* _applicationStateListenerInstance = [[ApplicationStateListener alloc] init]; + (instancetype)sharedInstance { return _applicationStateListenerInstance; } - (instancetype)init { self = [super init]; if (self) { // - // Notification Center UIApplicationDelegate, // Unity UnityRegisterAppDelegateListener(self); } return self; } - (void)dealloc { // . -, [[NSNotificationCenter defaultCenter] removeObserver:self]; } #pragma mark AppDelegateListener - (void)applicationDidFinishLaunching:(NSNotification *)notification { NSDictionary *launchOptions = notification.userInfo; // - launchOptions, // sdk } - (void)applicationDidEnterBackground:(NSNotification *)notification { // } - (void)applicationDidBecomeActive:(NSNotification *)notification { // } - (void)onOpenURL:(NSNotification*)notification { NSDictionary* openUrlData = notification.userInfo; // } @end
/* ApplicationExtension.m */ #import "UnityAppController.h" @implementation UnityAppController (ShortcutItems) - (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem completionHandler:(void (^)(BOOL succeeded))completionHandler { [[NSNotificationCenter defaultCenter] postNotificationName:@"UIApplicationPerformActionForShortcutItem" object:nil userInfo:@{ UIApplicationLaunchOptionsShortcutItemKey : shortcutItem }]; completionHandler(YES); } @end
Source: https://habr.com/ru/post/353088/
All Articles