简体   繁体   English

如何在 Mac 上为我的应用分配一种文件类型

[英]How do assign a type of file to my app on Mac

I try to assign a file type to my application.我尝试为我的应用程序分配文件类型。

In Info.plist I add:在 Info.plist 我添加:

<key>CFBundleDocumentTypes</key>
<array>
    <dict>
        <key>CFBundleTypeExtensions</key>
        <array>
            <string>type</string>
        </array>
        <key>CFBundleTypeIconFile</key>
        <string>icon</string>
        <key>CFBundleTypeName</key>
        <string>My Project</string>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>LSTypeIsPackage</key>
        <false/>
    </dict>
</array>

In Main.mm:在 Main.mm 中:

....
-(BOOL) application:(NSApplication *)sender openFile:(NSString *)filename {
  NSLog(@"Opened by file");
  return YES;
}
@end
int main(int argc, char* argv[]) {
  [NSApplication sharedApplication];
  [[[[Window alloc] init] autorelease] makeMainWindow];
  [NSApp run];
  return 0;
}

But when I try double click on the my file type, The app only open with the warn: could not be opened, MyApp cannot open file in format.但是当我尝试双击我的文件类型时,应用程序只打开警告:无法打开,MyApp 无法以格式打开文件。 Also the message from NSLog is not called at all.此外,根本不调用来自 NSLog 的消息。

There are several issues with the code you posted but I was able to get the desired behavior with a few modifications.您发布的代码存在几个问题,但我能够通过一些修改获得所需的行为。

I assume this is your window interface and implementation:我假设这是您的窗口界面和实现:

@interface Window : NSWindow <NSApplicationDelegate>

- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;

@end

@implementation Window

- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
    NSLog(@"Opened by file");
    return YES;
}

@end

This is extremely odd to be using a window object as an application delegate.将窗口对象用作应用程序委托是非常奇怪的。 Normally, you have a controller object that owns and manages the window and also acts as the application's delegate.通常,您有一个控制器对象,它拥有和管理窗口并充当应用程序的委托。

In any case, it's still possible to get... well, functional behavior by changing the main() function to the following:在任何情况下,仍然可以通过将main()函数更改为以下内容来获得......好吧,功能行为:

int main(int argc, const char * argv[]) {
    [NSApplication sharedApplication];
    Window *window = [[[Window alloc] init] autorelease];
    NSApp.delegate = window;
    [window makeKeyAndOrderFront:nil];
    [NSApp run];
    return 0;
}

There are two notable changes.有两个显着的变化。 First, your problem was that you didn't set the window instance to be the application delegate.首先,您的问题是您没有将窗口实例设置为应用程序委托。 Second, IIRC, you should never call -makeMainWindow directly;第二,IIRC, -makeMainWindow直接调用-makeMainWindow rather, that method exists so that you can override it if you wish.相反,该方法存在,因此您可以根据需要覆盖它。 If you want to display the window on screen, you call -makeKeyAndOrderFront: .如果要在屏幕上显示窗口,请调用-makeKeyAndOrderFront:

Opening a file should display the logged line in console (if you're using Xcode 12.5.1, resize the log window if needed to workaround the display bug).打开文件应该会在控制台中显示记录的行(如果您使用的是 Xcode 12.5.1,如果需要解决显示错误,请调整日志窗口的大小)。

Under manual reference counting, I believe this would leak memory, since no autorelease pool is created, but I didn't see any of the usual warnings in console.在手动引用计数下,我相信这会泄漏内存,因为没有创建自动释放池,但我没有在控制台中看到任何常见的警告。 Anyway, while this code works, it results in a fairly undesirable scenario.无论如何,虽然此代码有效,但会导致相当不理想的情况。 There is no main menu in the app so to quit it you have to use the Dock.应用程序中没有主菜单,因此要退出它,您必须使用 Dock。 The window created is also tiny and has no resizing capabilities, etc.创建的窗口也很小,没有调整大小等功能。

The following subclass of NSWindow should allow you to save a file with a unique '.jaf' extension and then reopen the file into the app by double clicking on it. NSWindow 的以下子类应该允许您使用唯一的“.jaf”扩展名保存文件,然后通过双击将文件重新打开到应用程序中。 The info.plist is not as critical as I initially thought; info.plist 并不像我最初想象的那么重要; I did not alter the one created by Xcode.我没有改变由 Xcode 创建的那个。 Most important for this non-Document based app seems to be the calling of NSApplicationDelegate method -(BOOL) application: openFile.对于这个非基于文档的应用程序来说,最重要的似乎是调用 NSApplicationDelegate 方法 -(BOOL) 应用程序:openFile。 The NSApplicationDelegate was added to the NSWindow subclass instead of having a separate AppDelegate as is usually the case. NSApplicationDelegate 被添加到 NSWindow 子类中,而不是像通常那样有一个单独的 AppDelegate。 When working correctly you should hear a beep when this method is called after a .jaf file is double-clicked;正常工作时,双击 .jaf 文件后调用此方法时,您应该会听到蜂鸣声; I couldn't find the NSLog output.我找不到 NSLog 输出。 To run the demo in Xcode first create an objc project and delete everything in the 'main.m' file and copy/paste the following source code into it.要在 Xcode 中运行演示,首先创建一个 objc 项目并删除“main.m”文件中的所有内容,然后将以下源代码复制/粘贴到其中。 Delete the pre-supplied AppDelegate class to avoid duplicate symbols.删除预先提供的 AppDelegate 类以避免重复符号。 In the entitlements set the App Sandbox to NO and set read-only to zero.在权利中将 App Sandbox 设置为 NO 并将只读设置为零。 After the JAF app has been made, use it to save a file to your desktop with the '.jaf' extension.制作 JAF 应用程序后,使用它以“.jaf”扩展名将文件保存到桌面。 Then make a copy of the app (shown in the Finder) and copy/paste it into the Applications folder.然后制作应用程序的副本(显示在 Finder 中)并将其复制/粘贴到应用程序文件夹中。 The next step is critical;下一步很关键; right click on the file that you just made and use either Get Info or Open With to set the file to always open with your newly made app.右键单击您刚刚创建的文件,然后使用“获取信息”或“打开方式”将文件设置为始终使用新创建的应用程序打开。 At this point you should be able to double click on the xxxx.jaf file and have it open into your app with an audible beep.此时,您应该能够双击 xxxx.jaf 文件,并在听到哔哔声的情况下将其打开到您的应用程序中。

#import <Cocoa/Cocoa.h>

@interface Window : NSWindow <NSApplicationDelegate> {
 NSTextView *txtView;
}
- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style backing:(NSBackingStoreType)backingStoreType defer:(BOOL)flag;
-(void) buildMenu;
-(void) openAction;
-(void) saveAction;
@end


@implementation Window

#define _wndW  700
#define _wndH  550

- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
 NSLog(@"This comes from JAF : filename = %@.",filename);
 NSBeep(); // Listen for this.

 NSError *error;
 NSURL *url = [NSURL fileURLWithPath:filename];
 NSString *fileStr = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
 if (!fileStr) {
    NSLog(@"Unable to open file %@", error);
  } else {
    [txtView setString:fileStr];
  }

 return YES;
}

-(void) buildMenu {
// **** Menu Bar **** //
 NSMenu *menubar = [NSMenu new];
 [NSApp setMainMenu:menubar];
// **** App Menu **** //
 NSMenuItem *appMenuItem = [NSMenuItem new];
 NSMenu *appMenu = [NSMenu new];
 [appMenu addItemWithTitle: @"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
 [appMenuItem setSubmenu:appMenu];
 [menubar addItem:appMenuItem];
}


-(void) openAction {
 NSOpenPanel *op = [NSOpenPanel openPanel];
[op setAllowedFileTypes:[NSArray arrayWithObjects: @"jaf", @"txt", nil]];
 [op beginSheetModalForWindow: self completionHandler: ^(NSInteger returnCode) {
 if (returnCode == NSModalResponseOK) {
  NSURL *url = [op URL];
  NSError *error;
  NSString *fileStr = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
  if (!fileStr) {
    NSLog(@"Unable to open file %@", error);
   } else {
    [self->txtView setString:fileStr];
   }
  }
 }];
}

-(void) saveAction {
 NSSavePanel *sp = [NSSavePanel savePanel];
 [sp setTitle:@"Save contents to file"];
 [sp setAllowedFileTypes:[NSArray arrayWithObjects: @"jaf", nil]];
 [sp setNameFieldStringValue: @".jaf"];
 [sp beginSheetModalForWindow: self completionHandler: ^(NSInteger returnCode) {
 if (returnCode == NSModalResponseOK) {
  NSURL *url = [sp URL];
     NSString *viewStr = [[self->txtView textStorage] string];
 NSError *err;
      BOOL fileSaved = [viewStr writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:&err];
      if (!fileSaved) { NSLog(@"Unable to save file due to error: %@", err);}
  }
 }];
}

- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style backing:(NSBackingStoreType)backingStoreType defer:(BOOL)flag {

 self = [super initWithContentRect:NSMakeRect(0, 0, _wndW, _wndH) styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable backing:NSBackingStoreBuffered defer:NO];
 [self setTitle: @"Test window"];
 [self center];
 [self makeKeyAndOrderFront: nil];

// ****** NSTextView with Scroll ****** //
NSScrollView *scrlView = [[NSScrollView alloc] initWithFrame:NSMakeRect( 10, 10, _wndW - 20, _wndH - 80 )];
[[self contentView] addSubview:scrlView];
[scrlView setHasVerticalScroller: YES];
[scrlView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
txtView = [[NSTextView alloc] initWithFrame:NSMakeRect( 0, 0, _wndW - 20, _wndH - 80 )];
[scrlView setDocumentView: txtView];

// **** Open Button **** //
NSButton *openBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 30, _wndH - 50, 95, 30 )];
[openBtn setBezelStyle:NSBezelStyleRounded ];
[openBtn setTitle: @"Open"];
[openBtn setAutoresizingMask: NSViewMinYMargin];
[openBtn setAction: @selector (openAction)];
[[self contentView] addSubview: openBtn];

// **** Save Button **** //
NSButton *saveBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 130, _wndH - 50, 95, 30 )];
[saveBtn setBezelStyle:NSBezelStyleRounded ];
[saveBtn setTitle: @"Save"];
[saveBtn setAutoresizingMask: NSViewMinYMargin];
[saveBtn setAction: @selector (saveAction)];
[[self contentView] addSubview: saveBtn];

 return self;
}

- (BOOL)windowShouldClose:(id)sender {
  [NSApp terminate:sender];
 return YES;
}


@end

int main() {
 NSApplication *application = [NSApplication sharedApplication];
 Window *window = [[Window alloc]init];
 [window buildMenu];
 [application setDelegate:window];
 [application activateIgnoringOtherApps:YES];
 [NSApp run];
 return 0;
}

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

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