将文件扩展名与Mac的Java JRE7应用程序相关联

时间:2014-03-28 05:41:31

标签: java macos file-io plist

我想通过双击Mac来启用与我的应用程序关联的文件。这个问题之前曾被问过(很多次),例如参见 Double click document file in Mac OS X to open Java application

然而,看起来自2009年(解决方案发布后)发生了变化。 该解决方案实际上基于2004年的文章 https://today.java.net/pub/a/today/2004/01/05/swing.html 并依赖于两个难题:
1. Java程序应该注册文件打开事件并采取适当的行动。这是使用com.apple.eawt应用程序和应用程序适配器完成的。 2.操作系统需要熟悉扩展,这是通过使用来完成的 CFBundleDocumentTypes包的.plist中的键。

2004 com.apple.eawt中使用的构造是折旧的,正如在几个讨论中提到的那样,包括 What's the alternative to using the now deprecated com.apple.eawt.ApplicationAdapter in Java Swing apps on the Mac? (2月11日) 需要注意的是,OpenFilesHandler取代了折旧的结构。答案中提到的API文档的链接不再起作用,因此不能立即清楚如何使用此构造。 我找到了以下参考资料来解释折旧的原因,但是文档的链接也已经过时了: http://lists.apple.com/archives/java-dev/2012/Jan/msg00101.html

我无法在线找到任何更新的API文档。 Apple Developer站点还引用了X代码中的示例,这些示例在我的版本(5.0.2)

中不存在

在(2012)的讨论中 https://stackoverflow.com/questions/8857431/java-mac-jdk-7-beta-apple-application-listener-no-longer-works 在从jdk6切换到jdk7-beta的上下文中提到了OpenFilesEvent,结论是归因于jdk7-beta的一些错误。

最后,同样在2012年,提出了以下问题,其中OpenFilesHandler的使用类似。

Grabbing the openFileEvent on MacOSX (Can't get filename)

这是我能找到的最新帖子,我想重温那里发布的问题。

该线程中有两个答案:第一个建议切换到Java Web Start,这对我来说不是一个选项。第二个答案集中在拼图的第二部分 - 用.plist注册正确的信息。

具体而言,指出了对CFBundleDocumentTypes和UTExportedTypeDeclarations的需求。注册自定义文件扩展名需要后者。

使用app bundler无法灵活地将这些密钥包含在.plist中,因此我尝试在编译.plist生成包之后包含它们。 按照原始帖子的建议,我包括我的info.plist  info.plist中:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-  1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>JavaAppLauncher</string>
<key>CFBundleIconFile</key>
<string>myIcons.icns</string>
<key>CFBundleIdentifier</key>
<string>mypackage.MainClass</string>
<key>CFBundleDisplayName</key>
<string>MyProgram</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>ProgramName</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSHumanReadableCopyright</key>
<string>NOTICES.txt</string>
<key>JVMRuntime</key>
<string>jdk1.7.0_21.jdk</string>
<key>JVMMainClassName</key>
<string>mypackage.MainClass</string>
<key>JVMOptions</key>
<array/>
<key>JVMArguments</key>
<array/>
<key>UTExportedTypeDeclarations</key>
<dict>
            <key>UTTypeIdentifier</key>
    <string>com.myCompany.xxx</string>
    <key>UTTypeReferenceURL</key>
    <string>http://myCompany.com/xxx.html</string>
    <key>UTTypeDescription</key>
    <string>My program file</string>
    <key>UTTypeIconFile</key>
            <array>
    <string>myIcons.icns</string>
            </array>
    <key>UTTypeConformsTo</key>
            <array>
    <string>com.apple.package</string>
             </array>
    <key>UTTypeTagSpecification</key>
    <dict>
        <key>public.filename-extension</key>
        <string>apn</string>
    </dict>
</dict>
<key>CFBundleDocumentTypes</key>
<dict>
    <key>CFBundleTypeName</key>
    <string>y program file</string>
    <key>CFBundleTypeIconFiles</key>
            <array>
    <string>myIcons.icns</string>
             </array>
            <key>CFBundleTypeRole</key>
             <string>Editor</string>
    <key>LSHandlerRank</key>
    <string>Owner</string>
    <key>LSItemContentTypes</key>
    <string>com.myCompany.xxx</string>
</dict>
</dict>
</plist>

这个info.plist工作到一定程度:文件确实与应用程序相关联,我可以通过双击打开它们。

唯一剩下的问题是文件不显示与文件关联的图标(任何大小)(无论我如何选择查看文件)。应用程序本身显示图标。我使用生成了一整套图标 iconutil来自png文件的文件夹,如上所述 https://apple.stackexchange.com/questions/59561/where-did-icon-composer-go-from-xcode 有趣的是,在某些时候,这些图标出现了,然后他们停了下来。如果我右键单击该文件,我的应用程序会显示一个图像,但文件本身没有图像。任何关于如何获得这些图像的建议都将受到高度赞赏。

问题似乎与此类似 OSX Custom extension icon Association 建议使用Jar Bundler,这是(据我所知)用AppBundler取代。

我也尝试刷新启动服务 - http://www.tekrevue.com/tip/rebuild-launchservices-fix-duplicate-entries-os-xs-open-menu/ 它没有帮助。

总之,描述的问题 Grabbing the openFileEvent on MacOSX (Can't get filename) 通过使用OpenFilesHandler成功解决,并且由于引入了自定义扩展,因此需要UTExportedTypeDeclarations。 感谢whiskeyspider确认我在正确的轨道上,因为我接近放弃了。唯一未解决的问题是与文件关联的实际图像。

2 个答案:

答案 0 :(得分:2)

本回答重点介绍OpenFilesHandler的使用,并假设CFBundleDocumentTypes和UTExportedTypeDeclarations定义包含在Info.plist中(参见问题文本)。

回想一下,在Mac和PC中打开Java应用程序的方法之间存在基本差异,这很有用。在PC的情况下,一个依赖于要打开的文件的直接命令行规范。文件名是从命令行传递给Java程序的参数。因此,需要编写Java程序来接受这个参数并适当地处理它。 PC包装器,例如Inno Setup,提供了一种通过单击文件来调用带有所需参数的Java程序的方法。

相比之下,对于Mac,我们可以利用OpenFilesHandler传递有关需要打开的文件的信息。具体用法如下: Grabbing the openFileEvent on MacOSX (Can't get filename)

在我的实现中,我有一个FileSaving类,它有一个方法readFile,它将类File的实例作为参数,并完成读取文件的实际工作。在程序的主要部分,我有以下代码的相关片段:

public final static boolean SYSTEMISMAC=(System.getProperty("os.name")).startsWith("M"); //   treating Mac separately
static protected FileSaving initialFiling;
........
initialFiling = new FileSaving(); // Initializing  
if(SYSTEMISMAC){
     Application a = Application.getApplication();
     a.setOpenFileHandler(new MacFiles(initialFiling) );
 }
 ……………

这里我们称之为实现OpenFilesHandler的Class MacFiles:

import java.io.File;
import java.util.List;
import com.apple.eawt.AppEvent.OpenFilesEvent;
import com.apple.eawt.Application;
import com.apple.eawt.OpenFilesHandler;
public class MacFiles implements OpenFilesHandler{
private List<File> files;
private FileSaving myFiling;
public MacFiles(FileSaving filing) {//
    Application.getApplication().setOpenFileHandler(this);
    myFiling=filing;
}
public List<File> getFiles() {
    return files;
}
@Override
public void openFiles(OpenFilesEvent event) {
  files = event.getFiles();
  File myFile=new File(files.get(0).getAbsolutePath());
  myFiling.readFile(myFile,true);  
}
}

从某种意义上说,双击文件会打开它,但是在浏览文件时显示自定义图标的问题(如问题中所述)仍未解决。

答案 1 :(得分:0)

在您提供的Info.plist中,似乎不再支持CFBundleTypeIconFiles的条目。而是尝试使用以下CFBundleTypeIconFile条目替换它,该条目只是一个字符串值而不是数组。

<dict>
<key>CFBundleTypeName</key>
    <string>y program file</string>
<key>CFBundleTypeIconFile</key>
    <string>myIcons.icns</string>
<key>CFBundleTypeRole</key>
    <string>Editor</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
    <array>
        <string>com.myCompany.xxx</string>
    </array>
</dict>

我能够使文件关联和自定义图标显示工作,但是,当用户双击相关文件时,我仍然无法获得OpenFilesEvent。它只是将我的应用程序放在前面,尽管设置了所有相关的处理程序,但应用程序没有收到任何事件。

无论如何,我希望我的建议适合你。