Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Associating file extension with Java JRE7 application for Mac

I would like to enable an opening of a file associated with my application by double-clicking on Mac. This question have been asked (many) times before, see for example Double click document file in Mac OS X to open Java application

However, it looks like the changes occurred since 2009 (when the solution was posted). That solution was effectively based on 2004 article https://today.java.net/pub/a/today/2004/01/05/swing.html and relied on two pieces of the puzzle:
1. Java program should register file opening event and act appropriately. This has been accomplished using com.apple.eawt Application and Application Adapters. 2. The OS needs to be familiar with the extension, which is done by using CFBundleDocumentTypes key in .plist of the package.

The constructions used in 2004 com.apple.eawt are depreciated, as mentioned in several discussions, including What's the alternative to using the now deprecated com.apple.eawt.ApplicationAdapter in Java Swing apps on the Mac? (Feb 11) It is noted there that OpenFilesHandler replaces depreciated constructions. The link to the API doc mentioned in the answer is not functioning anymore, so it is not immediately clear how to use this construction. I found the following reference that explains the reasons for the depreciation, but the link to the documentation is obsolete as well: http://lists.apple.com/archives/java-dev/2012/Jan/msg00101.html

I was not able to find any documentation online for the updated API. The Apple Developer site also refers to examples in X code that are not present in the version I have (5.0.2)

In the discussion in (2012) https://stackoverflow.com/questions/8857431/java-mac-jdk-7-beta-apple-application-listener-no-longer-works OpenFilesEvent was mentioned in the context of switching from jdk6 to jdk7-beta and the conclusion was the some errors attributed to jdk7-beta.

Finally, also in 2012 the following question was posed where the use of OpenFilesHandler was similar.

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

This is the most recent post that I was able to find, and I would like to revisit the questions posted there.

There were two answers in that thread: the first recommended switching to Java Web Start, which is not an option for me. The second answer was focused on the second part of the puzzle - registering proper info with .plist.

Specifically, the need for CFBundleDocumentTypes and UTExportedTypeDeclarations was indicated. The latter is needed to register a custom file extension.

Using app bundler does not provide the flexibility to include those keys in .plist, so I tried to include them after package is generated by editing .plist. Following the suggestions for the original post, I am including my 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>

This info.plist works to a point: files are indeed associated with the app, and I can open them by double-clicking.

The only remaining issue is that files don't show icons (of any size) associated with the files (regardless of how I choose to view the files). The application itself shows the icon. I generated a full set of icons using iconutil from a folder with png files as described https://apple.stackexchange.com/questions/59561/where-did-icon-composer-go-from-xcode A funny thing is that at some point those icons were showing up, and then they stopped. If I right click on the file, my application shows up with an image, but there is no image with the files itself. Any suggestions on how to get those images going will be highly appreciated.

The issue appears to be similar to OSX Custom extension icon Association The suggestion there is to use Jar Bundler, which is (to the best of my knowledge) is replaced with AppBundler.

I also tried to refresh the launchservices - http://www.tekrevue.com/tip/rebuild-launchservices-fix-duplicate-entries-os-xs-open-menu/ It did not help.

In summary, the issues described in Grabbing the openFileEvent on MacOSX (Can't get filename) are successfully resolved by utilizing OpenFilesHandler, and UTExportedTypeDeclarations are needed since a custom extension is introduced. Thanks to whiskeyspider for confirming that I was on the right track, as I was close to giving up. The only unresolved issue is actual images associated with files.

like image 651
PlutimusPaduster Avatar asked Nov 02 '22 02:11

PlutimusPaduster


1 Answers

This answer focuses on the use of OpenFilesHandler, and it assumes that CFBundleDocumentTypes and UTExportedTypeDeclarations definitions are included into Info.plist (see the text of the question).

It is useful to recall that there is a basic difference between the approaches for opening Java apps in Mac and PC. In the case of PC, one relies on the direct command line specification of the file to be open. The file name is an argument passed on to the Java program from the command line. So, the Java program needs to be written to take this argument and handle it appropriately. PC wrappers, such as Inno Setup, provide a means to invoke the Java program with the required argument by clicking on the file.

In contrast, for Macs we can utilize OpenFilesHandler to pass information about the file that needs to be open. Specific usage loosely follows: Grabbing the openFileEvent on MacOSX (Can't get filename)

In my implementation I have a class FileSaving that has a method readFile that takes an instance of class File as an argument, and does the actual job of reading the file. In the main part of the program I have the following relevant snippets of the code:

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) );
 }
 ……………

Here we call Class MacFiles that implements OpenFilesHandler:

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);  
}
}

This works, in a sense that double-clicking on the file opens it, but the issue of showing the custom made icons when browsing the files (as described in the question) remains unresolved.

like image 174
PlutimusPaduster Avatar answered Nov 11 '22 14:11

PlutimusPaduster