简体   繁体   English

捆绑包中NSApplication委托的使用

[英]Use of NSApplication delegate in bundle

I am trying to create a plugin for Unity using Objective-C for an app running on Mac. 我正在尝试为在Mac上运行的应用程序使用Objective-C为Unity创建一个插件。 I need to get the URL when launching my app from a link using an url protocol. 从使用url协议的链接启动应用程序时,我需要获取URL。 I haven't used Objective-C before, so I am having trouble trying to make it work. 我以前没有使用过Objective-C,所以在尝试使其工作时遇到了麻烦。

I am using an example provided by Unity ( download example ) and changing the methods to the ones I need to get the URL, but my app crashes on the line nsApplication = [[NSApplication alloc] init]; 我正在使用Unity提供的示例( 下载示例 ),并将方法更改为获取URL所需的方法,但是我的应用程序在nsApplication = [[NSApplication alloc] init];行崩溃nsApplication = [[NSApplication alloc] init]; on the _GetUrl method. 在_GetUrl方法上。 I have no idea what I am missing/doing wrong. 我不知道我在想什么/做错了什么。 Also, _GetUrl is the method called from Unity when I want to ask for the url (which is called at the first frame), but I am afraid it might be called after applicationWillFinishLaunching. 另外,_GetUrl是我要询问url时从Unity调用的方法(在第一帧调用),但是我恐怕它可能在applicationWillFinishLaunching之后被调用。 So where should I actually set the delegate so that applicationWillFinishLaunching happens after the delegate is set? 那么我应该在哪里实际设置委托,以便在设置委托后发生applicationWillFinishLaunching?

I use an .h and a .m script and then compile the bundle and import it into Unity as a plugin. 我使用.h和.m脚本,然后编译捆绑软件并将其作为插件导入到Unity中。 This is my code: 这是我的代码:

PluginUrlHandler.h PluginUrlHandler.h

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>

@interface NSApplicationDelegate : NSObject
{
    NSString* urlString;
}

// NSApplication delegate methods
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification;
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;

//Other methods
- (NSString *)getUrl;
@end

PluginUrlHandler.m PluginUrlHandler.m

#import <Foundation/Foundation.h>
#import "PluginUrlHandler.h"

@implementation NSApplicationDelegate

- (id)init
{
    self = [super init];
    urlString = @"nourl";
    return self;
}

- (void)applicationWillFinishLaunching:(NSNotification *)aNotification
{
    NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
    [appleEventManager setEventHandler:self
                           andSelector:@selector(handleGetURLEvent:withReplyEvent:)
                         forEventClass:kInternetEventClass andEventID:kAEGetURL];

}

- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
    [event paramDescriptorForKeyword:keyDirectObject] ;

    NSString *urlStr = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];

    urlString = urlStr;
}

- (NSString *)getUrl
{
    return urlString;
}

@end

static NSApplicationDelegate* delegateObject = nil;
static NSApplication* nsApplication = nil;


// Helper method to create C string copy
char* MakeStringCopy (const char* string)
{
    if (string == NULL)
        return NULL;

    char* res = (char*)malloc(strlen(string) + 1);
    strcpy(res, string);
    return res;
}

#if c__plusplus
extern "C" {
#endif

    const char* _GetUrl ()
    {
        if (delegateObject == nil)
        delegateObject = [[NSApplicationDelegate alloc] init];

        if (nsApplication == nil)
            nsApplication = [[NSApplication alloc] init];

        [nsApplication setDelegate:delegateObject];

        return MakeStringCopy([[delegateObject getUrl] UTF8String]);
    }

#if c__plusplus
}
#endif

If your application is crashing, you need to provide some information, such as a stack trace or error message so we can best help. 如果您的应用程序崩溃了,则需要提供一些信息,例如堆栈跟踪或错误消息,以便我们提供最佳帮助。 I'm assuming the error you're receiving looks like this: 我假设您收到的错误如下所示:

2016-03-06 10:07:14.388 test[5831:230418] *** Assertion failure in -[NSApplication init], /Library/Caches/com.apple.xbs/Sources/AppKit/AppKit-1404.34/AppKit.subproj/NSApplication.m:1980
2016-03-06 10:07:14.391 test[5831:230418] An uncaught exception was raised
2016-03-06 10:07:14.391 test[5831:230418] Creating more than one Application

You shouldn't create your own NSApplication object. 您不应该创建自己的NSApplication对象。 Just use the system one by referencing [NSApplication sharedApplication] . 只需通过引用[NSApplication sharedApplication]使用系统。

Generally speaking, you shouldn't need an NSApplication (or NSApplicationDelegate ) for a plugin, though. 通常来说,您不需要为插件安装NSApplication (或NSApplicationDelegate )。 The program that's loaded you should already have one, and you don't want to mess with that. 加载的程序应该已经有一个,并且您不想弄乱它。 Just create a custom NSObject subclass to be your AppleEvent handler. 只需创建一个自定义NSObject子类作为您的AppleEvent处理程序即可。 You don't need NSApplication (or it's delegate) at all for this. 您完全不需要NSApplication (或它的委托)。 Any object can be the target of an AppleEvent. 任何对象都可以成为AppleEvent的目标。

You can't use things like applicationDidFinishLaunching:withOptions: from a plugin in any case. 在任何情况下,您都不能通过插件使用诸如applicationDidFinishLaunching:withOptions:类的东西。 It's too late. 太晚了。 The application has long since launched. 该应用程序自启动以来已久。 You'll need to add your AppleEvent handler in some function called from Unity. 您需要在从Unity调用的某些函数中添加AppleEvent处理程序。 I'm not particularly familiar with Unity's plugin engine, so I don't know if there's a particular "load" function that gets called automatically (I don't see one in the sample code). 我对Unity的插件引擎不是特别熟悉,所以我不知道是否有一个特定的“加载”函数会自动调用(示例代码中没有看到)。 You may have to call something yourself. 您可能必须自己打个电话。 It would have to occur after the plugin is loaded, but before the Get URL Apple Event happens (it's unclear what you expect to generate that). 它必须在加载插件之后但在“获取URL Apple事件”发生之前发生(尚不清楚您期望生成什么)。

Just curious what you're trying to pull off with this. 只是好奇您要尝试实现的目标。 I've never seen a protocol handler used this way. 我从未见过使用这种方式的协议处理程序。

Creation of NSApplication instance looks very suspicious. 创建NSApplication实例看起来非常可疑。 Normally you don't create it as it is a singleton by definition. 通常,您不会创建它,因为根据定义它是单例的。

So instead of this: 所以代替这个:

if (nsApplication == nil)
   nsApplication = [[NSApplication alloc] init];

you should have rather this (getting current NSApplication instance): 您应该这样做(获取当前的NSApplication实例):

if (nsApplication == nil)
   nsApplication = [NSApplication sharedApplication];

I made a tutorial on this, see Override app delegate in Unity for iOS and OSX (4/4) Inject code to Mach-O binary . 我对此做了一个教程,请参见在iOS和OSX的Unity中覆盖应用委托(4/4)将代码注入Mach-O二进制文件

It uses code injection to set an Objective-C class to respond the corresponding Apple Event. 它使用代码注入来设置一个Objective-C类来响应相应的Apple Event。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM