5

我想知道如何使用我用 Objective-C 编写的 OS X 应用程序打开文件。我在 Info.plist 中注册了文件类型,并且application:openFile:在我的代码中。我通过这篇文章做了所有事情,它被标记为已解决。

问题是,只有当我在应用程序运行时将文件拖放到应用程序上时,这才有效。但如果我只是双击我的文件,它就不起作用。它会启动我的应用程序,但不会像我拖放那样启动。因此,其中的代码application:openFile:在双击时不会运行,但只有在我拖放文件时才会运行。

编辑:

关于我的代码的更多细节,以及我想要实现的目标。我为另一个应用程序创建了一个包装应用程序。我们将另一个应用程序称为“HelperApp.app”。这个 HelperApp 位于/Contents/我的包装应用程序的文件夹中。使用包装应用程序,我指定了一个新的文件类型,我们在 Info.plist 文件中将其称为“.ha”。该文件包含一些参数命令。我试图实现的目标是,当用户单击“.ha”文件时,我的包装应用程序会从该文件中读取参数并将其设置为 HelperApp,然后启动 HelperApp。这个 HelperApp 根据它得到的参数打开不同的东西。您可以在下面查看我的代码。

我有一个AppDelegate.h和一个AppDelegate.mm默认情况下最新的 Xcode 如何创建它。我将此行添加到我的AppDelegate.h,就在“@end”之前:

- (BOOL)processFile:(NSString *)file;

我在我的有这些功能AppDelegate.mm

#import "AppDelegate.h"
#import "ArgumentParser.h"

@implementation AppDelegate

- (void)dealloc
{
    [super dealloc];
}

- (BOOL)application:(NSApplication *)WrapperApp openFile:(NSString *)filename
{
    return [self processFile:filename];
}

- (BOOL)processFile:(NSString *)file
{
    NSLog(@"The following file has been dropped or selected: %@",file);

    std::string path = [file cStringUsingEncoding:[NSString defaultCStringEncoding]];

    ArgumentParser parser = ArgumentParser();
    parser.getArgumentfromFile(path);
    parser.setArgumentinFile();     // <== This is the "corrupted" function

    NSBundle *mainBundle = [NSBundle mainBundle];
    NSString *helperAppPath = [[mainBundle bundlePath]
                           stringByAppendingString:@"/Contents/HelperApp.app"];
    [[NSWorkspace sharedWorkspace] launchApplication:helperAppPath];

    return  YES;
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
   // Insert code here to initialize your application
}

损坏的功能 - setArgumentinFile()

void ArgumentParser::setArgumentinFile() {
    std::string content = ""; // The file content
    std::fstream file;

    file.open("HelperApp.app/Contents/Wrapper/HelperApp.app/Contents/Info.plist");

    // Open the file and modify the arguments
    if(file.is_open()) {
        std::stringstream stream;
        stream << file.rdbuf();

        std::string line = "";
        bool isIt = false;

        while(getline(stream, line)) {
            // This line is the argument list, which needs to be modifyed
            if(isIt) {
                int index = (int)line.find_last_of("<");
                std::string start = line.substr(0, index);
                std::string end = line.substr(index, std::string::npos);
                std::string argument_list = start + " " + _argument + end;
                content += argument_list + '\n';
                isIt = false;
            }
            // Save the rest of the file so we can overwrite it
            else {
                content += line + '\n';
            }
            // Next line is the argument list
            if(line.find("WineProgramArguments") != std::string::npos) {
                isIt = true;
            }
        }

        file.flush();
        file.close();
    }
    else {
        file.flush();
        file.close();
        throw std::runtime_error("File isn't opened");
    }


    file.open("HelperApp.app/Contents/Wrapper/HelperApp.app/Contents/Info.plist", std::ios::out);

    // Open the file and overwrite it with the modifyed argument
    if(file.is_open()) {
        file << content;

        file.flush();
        file.close();
    }
    else {
        file.flush();
        file.close();
        throw std::runtime_error("File isn't opened");
    }
}

processFile如果我从in 函数中注释掉上述函数AppDelegate,那么一切都会“顺利”运行。我的意思是包装应用程序启动并使用默认参数启动 HelperApp。所以这里应该是错误...

4

4 回答 4

4

如果你已经实现-application:openFile:了,它应该在你双击你注册的类型的文件时被调用。您说应用程序已启动,因此操作系统正在尝试使用您的应用程序打开文件。这是文档中的有用注释:

如果用户通过双击文件启动应用程序,则委托会在收到 applicationDidFinishLaunching: 之前收到 application:openFile: 消息。(applicationWillFinishLaunching: 在 application:openFile: 之前发送。)

因此,如果您在-applicationDidFinishLaunching:打开任何文件之前要做的任何事情都必须完成,那可能是您的问题。考虑将您的应用初始化代码移动到-applicationWillFinishLaunching:.

于 2013-05-23T06:33:12.233 回答
1

我已经想通了。当您双击文件图标时,应用程序将自行启动,其他操作正确完成。但是响应您的操作的应用程序不一定是您最后一次构建的应用程序。您的应用程序的旧副本可能正在响应。查看库 > 开发人员 > Xcode > DrivedData。您应该会看到您的应用程序的许多文件夹。您可以通过右键单击并在构建后选择 Shown In Finder 来找到您的应用程序文件夹。将它们全部丢弃,然后构建一个新的应用程序。然后双击,看看现在发生了什么。

于 2013-05-24T05:54:15.917 回答
1

问题是,我在函数中给出了错误的路径。如果我从 Xcode 启动应用程序,则此路径有效,但如果我自己启动应用程序则无效。

这是解决我问题的帖子!

于 2013-05-25T10:13:07.697 回答
1

右键单击与双击打开文件的行为不同!

苹果文档:

如果用户通过双击文件启动应用程序,则委托会在收到 applicationDidFinishLaunching: 之前收到 application:openFile: 消息。(applicationWillFinishLaunching: 在 application:openFile: 之前发送。)

Apple Docs 遗漏了一条重要的信息……我曾假设 Finder 中的右键单击->“打开方式”操作与双击相同。它不是!

application:openFile: 发生在 applicationDidFinishLaunching: 在这种情况下!

在这个问题上我挠了一个小时。

于 2014-09-18T20:27:57.367 回答