application:openFile: 尝试打开自己的文件类型时确实报错
application:openFile: did report error when trying to open own file type
我的应用程序有自己独特的文件类型。当用户双击该文件时,应用程序不是运行,应用程序启动但报如下错误:
我的申请基于 Chromium
(CEF)。我既不对任何设置部分使用 application:applicationWillFinishLaunching
也不使用 application:applicationDidFinishLaunching
,但似乎 application:openFile 在应用程序完全启动之前确实被调用了。
问题
- 有没有办法等到应用程序完全初始化后才能正确open/handle文件
- 是否还有其他方法可以在应用完全初始化后调用
我的 AppDelegate 实现如下:
// ****************************************************************************
// application:openFile
// ****************************************************************************
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
return [self processFile:filename];
}
// ****************************************************************************
// processFile
// ****************************************************************************
- (BOOL)processFile:(NSString *)file
{
std::string fileName([file UTF8String]);
au::arcwork::Handler* handler = au::arcwork::Handler::GetInstance();
handler->OnOpenFile(fileName);
return YES;
}
不要直接在application:openFile:
方法中调用[self processFile:filename]
,而是尝试将其存储到ivar中,并在应用程序完全初始化时调用processFile:
。
@property NSString *filenameToOpen;
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
self.filenameToOpen = filename;
return YES;
}
// You should use other method, that will indicate that your app is finished initialization, if you had one
- (void)applicationDidFinishLaunching:(NSApplication *)theApplication {
if (self.filenameToOpen) {
[self processFile:self.filenameToOpen];
}
}
经过大量研究和调试,我想出了一个解决方案,即如何在 OS X 上为基于 Chromium 的应用程序实施 application:openFile
。首先,有 3 个 parts/layers 必须解决。
- Cocoa 部分与
application:openFile
- 带有浏览器初始化代码的 Chromium 部分
- JavaScript 部分及其初始化部分
开始于 1:
application:openFile
中的 application:openFile already describes in the Discussion part, that application:openFile
is called before applicationDidFinishLaunching
. This means, that If you rely on a full initialized client (I can't imagine how's not?), you have to store the URL of the file somewhere, e.g. ivar/property 的 Apple 文档,或者像下面我的 Chromium handler
中的 std::vector
示例。只有当应用程序完全初始化并显示浏览器 window 时,您才能直接调用 Chromium handler method
,后者又会调用相应的 JavaScript 函数!
// ***
// application:openFile
// ***
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename {
AUApplication * clientApp = (AUApplication *)theApplication;
NSWindow* targetWindow = [clientApp findTargetWindow];
//Check if browser window is up and running
if (targetWindow) {
[self processFile:filename];
}
else {
//This method saves the file URL to open the file
//when the application+JavaScript is fully initialized
au::test::Handler* handler = au::test::Handler::GetInstance();
handler->AddPendingFile([filename UTF8String]);
}
return YES;
}
// ***
// processFile
// ***
- (BOOL)processFile:(NSString *)file
{
//This method calls the JavaScript function to open the file
std::string fileName([file UTF8String]);
au::test::Handler* handler = au::test::Handler::GetInstance();
handler->OnOpenFile(fileName);
return YES;
}
2部分:
在 Chromium side
上,您必须将文件 URL 存储在适当的结构中。我为此使用 std::vector
。文件URL 保存在Chromium 方法OnLoadEnd
中。 Chromium 已在浏览器中加载了您的 HTML+JavaScript 部分。不过要小心。 JavaScript 的初始化还没有完成!在我下面的示例中,我必须分配一个 JavaScript 属性 来存储文件 URL.
// ***
// Handler::OnLoadEnd
// ***
void Handler::OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) {
if (!m_pendingOpenFiles.empty()) {
std::string file(m_pendingOpenFiles[0]);
std::cout << "Pending file for later opening: " << file << std::endl;
//This method below is calling a JavaScript function to assign
//a property `pendingFile`
OnPendingFile(file);
//Don't forget to pop the file URL afterwards
//or use another store container instead of `std::vector`
//if you don't plan to implement `application:openFiles` as well!!!
m_pendingOpenFiles.pop_back();
}
}
3部分:
在 JavaScript 方面,您必须在应用程序初始化后检查 属性 pendingFile
是否已分配或未正确打开文件。
我的应用程序有自己独特的文件类型。当用户双击该文件时,应用程序不是运行,应用程序启动但报如下错误:
我的申请基于 Chromium
(CEF)。我既不对任何设置部分使用 application:applicationWillFinishLaunching
也不使用 application:applicationDidFinishLaunching
,但似乎 application:openFile 在应用程序完全启动之前确实被调用了。
问题
- 有没有办法等到应用程序完全初始化后才能正确open/handle文件
- 是否还有其他方法可以在应用完全初始化后调用
我的 AppDelegate 实现如下:
// ****************************************************************************
// application:openFile
// ****************************************************************************
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
return [self processFile:filename];
}
// ****************************************************************************
// processFile
// ****************************************************************************
- (BOOL)processFile:(NSString *)file
{
std::string fileName([file UTF8String]);
au::arcwork::Handler* handler = au::arcwork::Handler::GetInstance();
handler->OnOpenFile(fileName);
return YES;
}
不要直接在application:openFile:
方法中调用[self processFile:filename]
,而是尝试将其存储到ivar中,并在应用程序完全初始化时调用processFile:
。
@property NSString *filenameToOpen;
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
self.filenameToOpen = filename;
return YES;
}
// You should use other method, that will indicate that your app is finished initialization, if you had one
- (void)applicationDidFinishLaunching:(NSApplication *)theApplication {
if (self.filenameToOpen) {
[self processFile:self.filenameToOpen];
}
}
经过大量研究和调试,我想出了一个解决方案,即如何在 OS X 上为基于 Chromium 的应用程序实施 application:openFile
。首先,有 3 个 parts/layers 必须解决。
- Cocoa 部分与
application:openFile
- 带有浏览器初始化代码的 Chromium 部分
- JavaScript 部分及其初始化部分
开始于 1:
application:openFile
中的 application:openFile already describes in the Discussion part, that application:openFile
is called before applicationDidFinishLaunching
. This means, that If you rely on a full initialized client (I can't imagine how's not?), you have to store the URL of the file somewhere, e.g. ivar/property 的 Apple 文档,或者像下面我的 Chromium handler
中的 std::vector
示例。只有当应用程序完全初始化并显示浏览器 window 时,您才能直接调用 Chromium handler method
,后者又会调用相应的 JavaScript 函数!
// ***
// application:openFile
// ***
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename {
AUApplication * clientApp = (AUApplication *)theApplication;
NSWindow* targetWindow = [clientApp findTargetWindow];
//Check if browser window is up and running
if (targetWindow) {
[self processFile:filename];
}
else {
//This method saves the file URL to open the file
//when the application+JavaScript is fully initialized
au::test::Handler* handler = au::test::Handler::GetInstance();
handler->AddPendingFile([filename UTF8String]);
}
return YES;
}
// ***
// processFile
// ***
- (BOOL)processFile:(NSString *)file
{
//This method calls the JavaScript function to open the file
std::string fileName([file UTF8String]);
au::test::Handler* handler = au::test::Handler::GetInstance();
handler->OnOpenFile(fileName);
return YES;
}
2部分:
在 Chromium side
上,您必须将文件 URL 存储在适当的结构中。我为此使用 std::vector
。文件URL 保存在Chromium 方法OnLoadEnd
中。 Chromium 已在浏览器中加载了您的 HTML+JavaScript 部分。不过要小心。 JavaScript 的初始化还没有完成!在我下面的示例中,我必须分配一个 JavaScript 属性 来存储文件 URL.
// ***
// Handler::OnLoadEnd
// ***
void Handler::OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) {
if (!m_pendingOpenFiles.empty()) {
std::string file(m_pendingOpenFiles[0]);
std::cout << "Pending file for later opening: " << file << std::endl;
//This method below is calling a JavaScript function to assign
//a property `pendingFile`
OnPendingFile(file);
//Don't forget to pop the file URL afterwards
//or use another store container instead of `std::vector`
//if you don't plan to implement `application:openFiles` as well!!!
m_pendingOpenFiles.pop_back();
}
}
3部分:
在 JavaScript 方面,您必须在应用程序初始化后检查 属性 pendingFile
是否已分配或未正确打开文件。