Control iTunes on Mac OS X #82
Chapter 11, Native Integration and Packaging
|
419
HACK
so what better way to show off the power of Java than by taking control of
iTunes directly from your own Java app!
The task of dealing with native applications is, by nature, platform specific.
For example, though Apple ships identical looking copies of iTunes for both
Windows and Mac, the integration APIs couldn’t be more different.
Apple Events
Most well-written Mac OS X applications support an API called Apple
Events. Apple Events let a programmer send commands and requests to a
running application from another program, through a process often called
scripting. The application must be written to support Apple Events and
every scriptable feature must be defined explicitly when the program is writ-
ten. Since it was Apple that wrote iTunes, they did a very good job of expos-
ing virtually every feature through Apple Events. All you need to do is tap
into these events.
Apple Events is an API, and you need a programming language to support it.
There are a variety of languages to choose from, but the easiest one to start
with is AppleScript, as the syntax is simple and OS X ships with a command-
line interpreter. There are also direct Java bindings available, but for the
kinds of simple things you are likely to want to do with iTunes,
exec( )ing
the interpreter will be much easier. All you have to do is call
osascript with
the AppleScript commands you want to run, and OS X will do the rest.
AppleScript is a simple language with a somewhat natural language feel to it.
If you want to tell iTunes to toggle the Play/Pause button, you can call this
script from the command line:
osascript -e 'tell app "iTunes" to playpause'
Now that’s the kind of simple integration I like! Because you can directly
execute command-line programs from inside your code, the Java equivalent
would look like this:
String[] args = { "osascript", "-e",
"tell app \"iTunes\" to playpause" };
Process proc = rt.exec(args);
That’s it. You can make iTunes do virtually anything you want with simple
commands like this. One caveat to remember is that iTunes must be run-
ning as the same user for this to work. This usually isn’t a program for desk-
top applications, but if you made a web application with this technique, you
might need a workaround like a
chown script or a daemon that runs next to
iTunes. Example 11-5 is the code for a simple program with one button that
will toggle the iTunes Play/Pause button.
420
|
Chapter 11, Native Integration and Packaging
#82 Control iTunes on Mac OS X
HACK
This code creates a JFrame with one button. The button’s action listener cre-
ates a new
java.lang.Runtime object, sets up the command-line arguments,
and finally calls
osascript to control iTunes. When you click on the button
in the Swing application, iTunes will start playing. If you press the button a
second time, iTunes will pause. Virtually any feature in iTunes can be
scripted this way.
Sometimes you don’t want to tell iTunes to do something, but instead want
to get information from it.
osascript can handle this, too. When you call a
function that returns a value,
osascript will write the value to standard out,
which you can pick up from the process’s input stream. For example, if you
wanted to get the name of the currently playing track, you could change the
action listener code to look like this:
public void actionPerformed(ActionEvent evt) {
try {
Runtime rt = Runtime.getRuntime( );
String[] args = { "osascript", "-e",
"tell app \"iTunes\" to artist of current track as string"};
Process proc = rt.exec(args);
InputStream in = proc.getInputStream( );
String str = new DataInputStream(in).readLine( );
System.out.println("got: " + str);
Example 11-5. Controlling iTunes on the Mac
public class MacITunes implements ActionListener {
public static void main(String[] args) {
JFrame frame = new JFrame("Mac iTunes Hack");
JButton button = new JButton("Play/Pause");
button.addActionListener(new MacITunes( ));
frame.getContentPane( ).add(button);
frame.pack( );
frame.setVisible(true);
}
public void actionPerformed(ActionEvent evt) {
try {
Runtime rt = Runtime.getRuntime( );
String[] args = { "osascript",
"-e","tell app \"iTunes\" to playpause"};
Process proc = rt.exec(args);
} catch (IOException ex) {
System.out.println("exception : " + ex.getMessage( ));
ex.printStackTrace( );
}
}
}

Get Swing Hacks now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.