Override app delegate in Unity for iOS and OSX (4/4)
Inject code to Mach-O binary

In the previous part of the tutorial series – Override app delegate in Unity for iOS and OSX (3/4) Method swizzling – we override app delegate in Unity iOS player using method swizzling. While it has countless advantages on iOS, on OSX method swizzling is the only option to override app delegate in OSX Unity standalone player.

At the time of this writeup, the Unity OSX player source code is closed, so extend / override app delegate behaviour is simply not supported in Unity for OSX players. Once Unity has loaded, you can do a lot of stuff, but not before. Without having access to the application events making OSX productivity applications in Unity is quiet unthinkable. Examples of this can be working with Documents, Drag and Drop, Printing, URL handling, Scripting (Apple Events in general).

In this tutorial-ish writeup I share my findings on how I managed to work this issue around by eventually hack my own Unity OSX player executable.

TL;DR

You may get the example project immediately by heading to GitHub (in that case you should really be aware of the folder structure at the end of the article, as there are numerous sub-projects can be found all around). However, I strongly recommend to take the next 15 minutes to understand what is going on, and read along (so the prerequisites).

See Unity.Blog.Override_App_Delegate at

OSX Plugin architecture in Unity

Unity OSX plugins – per documentation at Building a Plugin for Mac OS X – are to be packed into bundles. They are quiet useful stuff (applications themselves are bundles as well), but in OSX Unity player they get loaded after Unity, only around when the first scene starts (using an [NSBundle load] class presumably). It means that, by using this plugin structure, we cannot load our method swizzle class to override app delegate, like we did previously Override app delegate in Unity for iOS and OSX (3/4) Method swizzling.

We can inject the swizzling code using dynamic libraries (OSX frameworks), but first let’s build up the plugin itself, using almost entirely the same codebase we have build at Override app delegate in Unity for iOS and OSX (3/4) Method swizzling (also, I recommend to walk through the previous parts of the tutorial series). The main difference will be that we are gonna use AppKit instead UIKit.

Unity OSX standalone player architecture

I tried to get my hands on a Unity OSX standalone player Xcode project in numerous ways, without any success. As I really left with no options to move forward, I decided to start reverse engineering the built Unity OSX player. Fortunately there is a great tool called class-dump (by Steve Nygard), by which I managed to get the Objective-C headers of the Unity OSX player.

See Unity.Labs.OSX_Unity_Player_Headers at

Amongst a whole lot of insights, you can conclude that the Unity OSX player Xcode project probably contains a class called PlayerAppDelegate, that is responsible to orchestrate the application states between OSX and the Unity player application. It could be seen also in MainWindow.nib interface builder file of the Unity OSX Player, as there is an object setup having that class PlayerAppDelegate (it is hooked as the delegate of PlayerApplication). There is also a class called PlayerWindowDelegate (that is explicitly conforms to NSWindowDelegate protocol) which seemingly manages window events. Having these informations we can easily pick the actual classes / methods we want to override. For the sake of this tutorial, as we are about to override app delegate, let’s override applicationDidFinishLaunching: of PlayerAppDelegate.

Create an OSX framework to override app delegate

Create Cocoa Framework ProjectCreate Cocoa Framework Project Product Name

Create a new Cocoa Framework project using the same conventions we already setup in the previous parts of the tutorial series (use Override_OSX as the Product Name, and put it in a folder called OSX beside Assets).

You can drag every file from the Override_iOS plugin project created in the previous article, then make the following modifications. Rename Override_iOS to Override_OSX using refactor tools, and replace every UIKit to AppKit and every UIApplication to NSApplication even using Find and Replace. Remove UnityString_C++.mm from Build Phases / Compile Sources (it seems to get built already along DeepLink_C++.mm where it has imported).

Create Cocoa Application TargetCreate Cocoa Application Target Product Name

It is convenient to create a sandbox application to the framework as well, so you can see your framework working in a sandbox environment before inject it directly into the Unity OSX player. Create an Application target called Override_OSX_Sandbox.

Add Target Dependencies Link Binary with Libraries

Then hook up Override_OSX.framework as Target Dependencies as well as Link Binary With Libraries in Build Phases. Also, create an URL Scheme called overridesandbox at the Info tab. Rename AppDelegate class to PlayerAppDelegate to mimic the presence of Unity OSX player app delegate class.

You can now run the sandbox application (with the framework), however, most of the swizzlings will fail, as there are no methods present we specified for iOS (adding the placeholder methods will be succeeded anyway).

Back to our framework, we only want to override applicationDidFinishLaunching:, so you can gently remove any additional placeholder methods from OverrideAppDelegate, as well as the corresponding swizzlings from Override_OSX accordingly.

#import 
#import 
#import "Override_OSX.h"
#import "DeepLink.h"


@interface OverrideAppDelegate : NSObject


-(void)applicationDidFinishLaunching:(NSNotification*) notification;
-(void)_original_saved_by_Override_applicationDidFinishLaunching:(NSNotification*) notification;


@end
See OverrideAppDelegate.h at
#import "OverrideAppDelegate.h"


@implementation OverrideAppDelegate


#pragma mark Override implementations

-(void)applicationDidFinishLaunching:(NSNotification*) notification
{
    NSLog(@"[OverrideAppDelegate applicationDidFinishLaunching:%@]", notification);
    return [self _original_saved_by_Override_applicationDidFinishLaunching:notification];
}


#pragma mark Original implementation placeholders

-(void)_original_saved_by_Override_applicationDidFinishLaunching:(NSNotification*) notification
{ return; }


@end
See OverrideAppDelegate.m at
...
+(void)swizzle
{
    NSLog(@"[Override_OSX swizzle]");
    [self replaceAppDelegateMethod:@selector(applicationDidFinishLaunching:)
                         fromClass:OverrideAppDelegate.class
                  savingOriginalTo:@selector(_original_saved_by_Override_applicationDidFinishLaunching:)];
}
...
See Override_OSX.m at

To get a grasp on how these method works, read the previous part of the tutorial series Override app delegate in Unity for iOS and OSX (3/4) Method swizzling. After that you can run the sandbox application without any swizzling errors in Xcode.

Add features to capture URL scheme deep link data

To have the Unity application working later on, we should capture (and provide) URL scheme deep link data (so we can see outputs int the application instead of the console log only).

To obtain the URL scheme deep link payload we should register to the corresponding Apple Event using NSAppleEventManager. We could add the event handling code to our app delegate, but as we already have a singleton instantiated of our DeepLink class (details in Override app delegate in Unity for iOS and OSX (3/4) Method swizzling), we can set the DeepLink instance as the handler for the event as soon as the class gets loaded, also we can implement the handling in that class as well.

#import "DeepLink.h"


__strong DeepLink *_instance;


@implementation DeepLink


+(void)load
{
    NSLog(@"[DeepLink load]");
    _instance = [DeepLink new];
    [[NSAppleEventManager sharedAppleEventManager] setEventHandler:_instance
                                                       andSelector:@selector(handleGetURLEvent:withReplyEvent:)
                                                     forEventClass:kInternetEventClass
                                                        andEventID:kAEGetURL];
}

+(DeepLink*)instance
{ return _instance; }

-(instancetype)init
{
    self = [super init];
    if (self) [self reset];
    return self;
}

-(void)reset
{
    self.URL = [NSString new];
    self.sourceAppliaction = [NSString new];
    self.annotation = [NSDictionary new];
}

-(void)handleGetURLEvent:(NSAppleEventDescriptor*) event withReplyEvent:(NSAppleEventDescriptor*) replyEvent
{
    NSLog(@"[DeepLink handleGetURLEvent:%@ withReplyEvent:%@]", event, replyEvent);
    self.URL = [event paramDescriptorForKeyword:keyDirectObject].stringValue;
}

@end
See DeepLink.m at

Test Sandbox Application URL scheme OSX Safari

Great! To test the sandbox application on your system, simply open up Safari (!), then open up a link with the URL scheme: overridesandbox://Hello!. Make sure that the sandbox application is running (!) in Xcode.

But if you stop / quit the sandbox app, and open link as the application was not started before, it will crash, as it won’t find Override_OSX.framework.

Provide framework along Application bundle

This may seems annoying at first, but this crashlog holds a key information piece on how we can inject code to Unity OSX player soon.

Crash Report Dynamic Library Image Not Found

Reveal the crash log (click Report… / Show Details) to see the details. The framework image is being expected at a location @rpath/Override_OSX.framework/Versions/A/Override_OSX.

Copy Framework Build Phase

You can easily fix this in Xcode by add a new Copy Files Phase to Build Phases of the sandbox application, drag Override_OSX.framework from the Products group into, and set the Destination to Frameworks (stands for @rpath). If you make a build this way, you can open it via Safari even if the application was quit before. If you open up Console application, you can see all the log messages from our framework.

Application Product Show In FinderFramework Deployed Into Application Bundle

Right click on Override_OSX_Sandbox.app in your Products group, and click Show in Finder to locate it in Finder. If you reveal the application bundle contents (right click, Show Package Contents) you can see our framework is now located in the application bundle indeed.

Application Build Settings Runpath Search Paths

That @rpath is literally means that folder you seen before. If you inspect Override_OSX_Sandbox Build Settings, you can find an entry called Runpath Search Paths with the value @executable_path/../Frameworks (see Run-Path Dependent Libraries for more). The very same folder where our framework now resides.

Inspect dynamic libraries in OSX Mach-O binary executables

New Terminal at Folder

As there comes some terminal focused block below, I recommend to setup a keybord shortcut to open up a terminal window at a given folder. You can easily setup a shortcut in System Preferences / Keyboard / Shortcuts / Services / Files and Folders / New Terminal at Folder.

In the application bundle folder, beside the framework, you can find the application itself as a Mach-O binary executable file (in MacOS folder). You can see how the framework has hooked up using otool (it comes with Xcode). Fire up terminal, navigate to the MacOS folder containing application bundle, and type otool -L Override_OSX_Sandbox. It gives you a list of all linked frameworks (either system frameworks or bundled frameworks along application).

$ otool -L Override_OSX_Sandbox
Override_OSX_Sandbox:
	@rpath/Override_OSX.framework/Versions/A/Override_OSX (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1258.0.0)
	/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1404.46.0)

There you can see our plugin framework hooked up to be loaded when the executable launches. Unlike static libraries (covered in more details in Override app delegate in Unity for iOS and OSX (1/4) Plugin workflow), frameworks (dynamic libraries) gets loaded upon the application launch. That means that every code we put into our load methods will be invoked right there. It means that our DeepLink instance will be created and set as event handler for URL scheme Apple Events.

You can even see what @rpath contains. If you list all segments in the binary using otool -l Override_OSX_Sandbox, you can see a segment called LC_RPATH holding a value of @executable_path/../Frameworks. It is the very same value that has been setup in the framework Runpath Search Paths in the Build Settings from above.

$ otool -l Override_OSX_Sandbox
...
Load command 17
          cmd LC_RPATH
      cmdsize 48
         path @executable_path/../Frameworks (offset 12)
...

Now you have some understanding how frameworks are hooked up in Mach-O binary executables, we can start processing the Unity OSX player Mach-O binary itself.

Inject dynamic library into Unity OSX player Mach-O binary executable

In short, we can workaround override app delegate on OSX simply by adding our framework to the Unity OSX player executable (the only thing we have access to at the time of this writing).

So create an OSX build of our Unity project (see project details in the previous parts of the tutorial). For easier later reference, use the naming / folder convention we used in the previous chapter, so make the build into the Build/OSX folder in the Unity project root folder beside Assets, and call it simply Override.

Now you can inspect the content of Override.app with the same tools we used before. It already has a Frameworks folder, but only contains Mono dynamic libraries. If you list the load commands of the executable in MacOS folder using otool -L Override, you can see how the Mono framework linked there, using the relative path @executable_path/../Frameworks. It is directly uses @executable_path, because the executable has no any segment containing Runpath Search Paths definition. If you list all the segments using otool -l Override, you can see that there is no LC_RPATH segment present in the binray.

$ otool -L Override
Override:
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 728.9.0)
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 22.0.0)
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo (compatibility version 1.2.0, current version 1.5.0)
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon (compatibility version 2.0.0, current version 157.0.0)
	/System/Library/Frameworks/AVFoundation.framework/Versions/A/AVFoundation (compatibility version 1.0.0, current version 2.0.0)
	/System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
	/System/Library/Frameworks/Security.framework/Versions/A/Security (compatibility version 1.0.0, current version 57337.40.83)
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore (compatibility version 1.2.0, current version 1.11.0)
	@executable_path/../Frameworks/MonoEmbedRuntime/osx/libmono.0.dylib (compatibility version 1.0.0, current version 1.0.0)
	/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 104.1.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1404.46.0)
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices (compatibility version 1.0.0, current version 48.0.0)
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1258.1.0)
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1258.0.0)
	/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)

Framework Deploy Copy Files Phase Into Unity OSX Player Application Bundle

Great. Now to put our framework there, is should simply copied into place (near Mono libraries). Make Xcode copy this for us, add a Copy Files Phase, and use an absolute path for the sake of simplicity. You can double check inside Override.app (right click, Show Package Contents) that the framework has been deployed properly.

Code injection to Unity OSX player Mach-O binary executables

The framework is in place, not we have to load it upon application launch. Fortunately, there is a great tool to manipulate load commands of OSX Mach-O binaries out there called optool, so install in to an accessible location, like usr/bin. It’s usage is straightforward, among some other features, you can insert load commands into Mach-O binaries. If you take a look at its source, you can see where the actual code injection happens at line 481 of operations.m (it is surprisingly readable as it is written in Objective-C).

Now you can compose the command with all the paths we explored before. We gonna use the same relative framework path that the embedded Mono library uses, namely @executable_path/../Override_OSX.framework/Versions/A/Override_OSX. The Unity OSX player executable location is also known, (using the folder convention above, it will reside at Build/OSX/Override.app/Contents/MacOS/Override relative to the Unity project root. The command and the output will look something like below.

$ optool install -c load -p "@executable_path/../Frameworks/Override_OSX.framework/Versions/A/Override_OSX" -t ~/Projects/Unity/Blog/Override_App_Delegate/Build/OSX/Override.app/Contents/MacOS/Override
Found thin header...
Inserting a LC_LOAD_DYLIB command for architecture: x86_64
Successfully inserted a LC_LOAD_DYLIB command for x86_64
Writing executable to /Users/eppz/Projects/Unity/Blog/Override_App_Delegate/Build/OSX/Override.app/Contents/MacOS/Override...

There you go! Our framework is embedded in Unity OSX player, and gets loaded right at startup. Before running the application, you can (you should) double check the results using otool. You can see the framework injection in the last line of the output.

$ otool -L Override
Override:
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 728.9.0)
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 22.0.0)
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo (compatibility version 1.2.0, current version 1.5.0)
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon (compatibility version 2.0.0, current version 157.0.0)
	/System/Library/Frameworks/AVFoundation.framework/Versions/A/AVFoundation (compatibility version 1.0.0, current version 2.0.0)
	/System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
	/System/Library/Frameworks/Security.framework/Versions/A/Security (compatibility version 1.0.0, current version 57337.40.83)
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore (compatibility version 1.2.0, current version 1.11.0)
	@executable_path/../Frameworks/MonoEmbedRuntime/osx/libmono.0.dylib (compatibility version 1.0.0, current version 1.0.0)
	/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 104.1.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1404.46.0)
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices (compatibility version 1.0.0, current version 48.0.0)
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1258.1.0)
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1258.0.0)
	/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
	@executable_path/../Frameworks/Override_OSX.framework/Versions/A/Override_OSX (compatibility version 0.0.0, current version 0.0.0)

Unity OSX Player Injected Framework Console Log

Fire up the Console application, then if you run the application, you can see the logs from our injected code. It is truly awesome. now you can swizzle the hell out off every Unity OSX player class of your choice.

New Run Script Phase

Unity OSX Player Framework_Injection Run Script Phase

To have this step integrated in our workflow, you can simply put the optool command we used previously into a Run Script Phase in the framework Xcode project.

Register URL scheme via code in Unity OSX player

To be able to test the application without keep using the console, we should implement the URL scheme registration to the Unity OSX player as well. For some reason, Unity does not provide URL scheme option to standalone player, so we have to add the necessary Info.plist values.

UnityEngine have an extremely useful class to manipulate plist files called PlistDocument, so we can add the Info.plist entries in our BuildPostProcessor.cs we used to add -ObjC linker flag to iOS project.

...
    [PostProcessBuildAttribute(1)]
    public static void OnPostProcessBuild(BuildTarget target, string path)
    {
        if (target == BuildTarget.iOS)
        {
            // Read.
            string projectPath = PBXProject.GetPBXProjectPath(path);
            PBXProject project = new PBXProject();
            project.ReadFromString(File.ReadAllText(projectPath));
            string targetName = PBXProject.GetUnityTargetName();
            string projectTarget = project.TargetGuidByName(targetName);

            AddFrameworks(project, projectTarget);

            // Write.
            File.WriteAllText(projectPath, project.WriteToString());
        }

        if (target == BuildTarget.StandaloneOSXIntel ||
            target == BuildTarget.StandaloneOSXIntel64 ||
            target == BuildTarget.StandaloneOSXUniversal)
        {
            // Read.
            string plistDocumentPath = path + "/Contents/Info.plist";
            PlistDocument plistDocument = new PlistDocument();
            plistDocument.ReadFromString(File.ReadAllText(plistDocumentPath));
            PlistElementDict rootElement = plistDocument.root;
       
            // Add scheme.
            PlistElementDict urlSchemeArrayElement = rootElement.CreateArray("CFBundleURLTypes").AddDict();
            urlSchemeArrayElement.SetString("CFBundleURLName", "");
            urlSchemeArrayElement.CreateArray("CFBundleURLSchemes").AddString("override");

            // Write.
            File.WriteAllText(plistDocumentPath, plistDocument.WriteToString());
        }
    }
See BuildPostProcessor.cs at

So again, we managed to avoid any additional manual Xcode project post processing. The very last thing need to remember is to make our managed part of our plugin code to run on OSX as well beside iOS. Find the corresponding preprocessor directives, and add UNITY_STANDALONE_OSX as well to DeepLink.cs.

...
#if !UNITY_EDITOR && (UNITY_IOS || UNITY_STANDALONE_OSX)
...
See DeepLink.cs at

Now you build the Unity OSX player, then build the framework project in Xcode, then you can see the whole thing working using Safari. much uplifting.

Using code injection to Mach-O binaries in Production

While this solution feels a bit hacky indeed, it actually does really the same that Unity and Xcode do under the hood. However, an important thing is not covered in this tutorial, is the code signing.

To put this solution to production, you have to code sign both the framework, and the modified executable. The framework code signing identity can be setup right in the framework Xcode project, the executable should be signed manually anyway. See the corresponding official documentation How to port to Apple Mac Store.

What’s next

First of all, congrats! If you have read all the 4 parts of this tutorial series, then you’ve earned the badge of the curious mind for sure, Yay! It is lengthy indeed, tightly packed with information, but the article will be here for ages as a reference, probably me myself will also use it on an annual basis or so. Until Unity does not open up the OSX standalone player code, this Mach-O binary hack is the best option we got.

For the next part. As I go along with the products I’m working on, I’ll probably have more and more workflow goodie, like direct invocation between iOS and Unity (instead UnitySendMessage), but I also drafted a series about image compositing (understanding blend modes, image effects), general application architecture considerations, and more (the bottleneck is time, the upcoming tutorial series should be probably funded by Patreon or something similar), so stay tuned!

DISCLAIMER. THE INFORMATION ON THIS BLOG (INCLUDING BUT NOT LIMITED TO ARTICLES, IMAGES, CODE SNIPPETS, SOURCE CODES, EXAMPLE PROJECTS, ETC.) IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE INFORMATION ON THIS BLOG (INCLUDING BUT NOT LIMITED TO ARTICLES, IMAGES, CODE SNIPPETS, SOURCE CODES, EXAMPLE PROJECTS, ETC.).

  • Tim R

    Great articles thanks for sharing, the Android stuff was great too, side stepping Unity is awesome 🙂

    • Thanks! 🙏
      The best would be if I had time to work out direct method calling between Unity and iOS runtime (using Mono runtime).

  • Alex

    Good job on that! Thanks. I am trying to do the same way for open file function, but it wasn’t successful, it keeps saying the app cannot open this file type. I’ve added keys to playlist, to register app for filetime and i’ve added – (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename
    to OverrideAppDelegate.m , also replaced it in Override_OSX. Do you have any idea how to handle it?

    • Hey, thanks!

      I suggest to break it down to smaller steps.

      First you should make sure that it works in a simple OSX app built in Xcode. Make a proof of concept in Override_OSX_Sandbox target using the official docs or some corresponding tutorial. After that you can extract it to Override_OSX, but you should still test / link against it the standalone Override_OSX_Sandbox app.

      Once everything is proved to be fine, you can inject it to a Unity player according this tutorial.