2016-03-06 38 views
2

我正在嘗試爲在Mac上運行的應用使用Objective-C爲Unity創建一個插件。我需要從使用url協議的鏈接啓動我的應用時獲取URL。我之前沒有使用過Objective-C,所以我在嘗試使它工作時遇到了麻煩。在包中使用NSApplication委託

我正在使用Unity提供的示例(download example)並將方法更改爲我需要的URL,但我的應用在_GetUrl方法上的行nsApplication = [[NSApplication alloc] init];上崩潰。我不知道我在想什麼/做錯了什麼。另外,_GetUrl是我想要求URL(在第一幀被調用)時從Unity調用的方法,但恐怕可能會在applicationWillFinishLaunching之後調用。那麼我應該在哪裏設置委託,以便在委派設置後發生applicationWillFinishLaunching?

我使用.h和.m腳本,然後編譯捆綁包並將其作爲插件導入Unity。這是我的代碼:

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

#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 
+0

「我之前沒有使用Objective-C」!!!!!!!!你會發現它非常困難,至少需要3年的時間才能掌握Xcode/OSX版本的基本知識。 :O – Fattie

+0

3年?!來吧!但是我發現OP沒有關於委託和應用程序實例的線索。我建議先寫一個OS X的應用程序,並採取一些教程,直到你瞭解基本架構 –

+0

找到這個,這幫助我,實際上http://stackoverflow.com/a/2154666 –

回答

0

如果您的應用程序崩潰,您需要提供一些信息,如堆棧跟蹤信息或錯誤信息所以我們可以提供最佳幫助我假設的錯誤您收到這樣的容貌:

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 

你不應該創建自己的NSApplication對象。通過參考[NSApplication sharedApplication]來使用系統。

不過一般來說,你不應該需要一個NSApplication(或NSApplicationDelegate)插件。加載你的程序應該已經有了,而你不想搞砸這個。只需創建一個自定義NSObject子類作爲您的AppleEvent處理程序。你完全不需要NSApplication(或它的代表)。任何對象都可以成爲AppleEvent的目標。

在任何情況下,您都不能使用插件等applicationDidFinishLaunching:withOptions:之類的東西。太晚了。該應用程序早已推出。您需要在Unity調用的某個函數中添加AppleEvent處理程序。我對Unity的插件引擎並不是特別熟悉,所以我不知道是否有自動調用的特定「加載」函數(我在示例代碼中沒有看到)。你可能需要自己打電話。它必須在插件加載後,但在獲取URL Apple事件發生之前發生(目前尚不清楚您期望生成的內容)。

只是好奇你試圖與此拉開。我從來沒有見過這種方式使用的協議處理程序。

+0

嘿羅布,感謝您的答案。我想要做的是在用戶點擊一個鏈接時啓動我的應用程序,所以我在info.plist上聲明瞭一個url協議。現在我需要從該鏈接獲取一些值,因此請獲取啓動該應用的網址。我無法從Unity中完成,因此需要一個處理該數據的本機插件。我發現這樣做的方式是使用handleGetURLEvent。那麼如何在我的插件中使用該事件?我應該只使用Unity調用的方法而不是applicationWillFinishLaunching創建appleEventManager? – Sandra

+0

我不太瞭解Unity來回答這個問題。這取決於Unity如何在Mac上運行。如果它沒有給你一個啓動時間鉤子,那麼它可能無法響應該事件。如果是這樣的話,一個常見的解決方案是創建一個單獨的Cocoa啓動器應用程序來處理這個協議,並在需要時啓動你的Unity應用程序(但即使如此,你需要一些方法來將你的URL傳遞給Unity應用程序,是可能的,但我不知道Unity是否有內置的任何支持它的東西)。我對Unity的瞭解不夠多,無法說明在啓動時如何實現OS集成。 –

0

創建NSApplication實例看起來非常可疑。通常情況下,你不會創建它,因爲它是一個單例定義。

因此,不是這樣的:

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

你應該有相當這(獲取當前的NSApplication實例):

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