The last time I had to build a brand new help file was some time ago — maybe even ten years ago — and in the world of software, that’s an age.
For the past few months I’ve been working hard on a new release of iDefrag, version 5, and as part of this I’m rewriting the documentation. Rather than using hand-written HTML like I did before, I’ve chosen this time around to use a documentation generator, Sphinx. The advantages of this approach include:
Built-in support for indexing and cross-referencing.
The ability to write the documententation in plain text.
Keeps the presentation details separate from the content (via theming and templates).
Supports multiple output formats, not just HTML.
The current version of Sphinx doesn’t directly support building Apple Help Books, but I’ve submitted a pull request to fix that so hopefully by the time you read this you’ll be able to do
fill in some fields and then do
$ make applehelp
to generate a help book.
(If you do do that, you’ll want to edit your
conf.py file quite a bit, and
you probably don’t want to use the default theme either.)
Anyway, all of the Sphinx related stuff was fine, and worked as documented. Unlike Apple Help, which doesn’t. I spent an entire day struggling to make a help book that actually worked, and most of that is because of problems with the documentation.
Let’s start with the Info.plist. Apple gives this not particularly helpful table:
|Key||Exact or sample value|
There are two serious problems with the table above. The first is that some of it is wrong(!), and the second is that it doesn’t indicate which values are sample values and which are required.
Here’s what you actually need:
|CFBundleIdentifier||your help bundle identifier|
|CFBundleShortVersionString||your short version string - e.g. 1.2.3 (108)|
|CFBundleVersion||your version - e.g. 108|
|HPDBookAccessPath||_access.html (see below)|
|HPDBookIndexPath||the name of your help index file|
|HPDBookTitle||the title of your help file|
The first thing to note is that
CFBundleDevelopmentRegion should have a
hyphen, not an underscore. Apple’s utilities generate this properly, but
the documentation is wrong.
The second thing to note is that in spite of the documentation implying that
you can use your help bundle identifier to refer to your help bundle (which
would, admittedly, make sense), you can’t. You need to use the
value. Oh, and ignore any references to
AppleTitle meta tags. You don’t
The third thing relates to
HPDBookAccessPath. The file referred to there
must be a valid XHTML file. In particular, it cannot be an HTML5 document
— that will simply not work, and the error messages you get on the system
console are completely uninformative.
The best solution I’ve come up with for this particular problem, as I want to
generate modern HTML output, is to make a file called
_access.html and put
the following in it:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Title Goes Here</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="robots" content="noindex" /> <meta http-equiv="refresh" content="0;url=index.html" /> </head> <body> </body> </html>
This means that both
helpd and the help indexer (
hiutil) are happy, and I
can write my index page using modern HTML. Incidentally, Apple appears to be
using a similar trick in the help for the current version of Mail. Obviously
you can change the
index.html in the above to whatever you need.
In your application bundle, you need to fill in the following keys
|CFBundleHelpBookFolder||The path of your help book relative to Resources - e.g. SurfWriter.help|
|CFBundleHelpBookName||The value from HPDBookTitle, above|
Note that while the
HPDBookTitle is displayed to the user, it can be
InfoPlist.strings. Note also that you absolutely cannot,
contrary to what the documentation implies, give a bundle ID here. It just
doesn’t work. You could however, if you wanted, write an
InfoPlist.strings file like this:
HPDBookTitle = "SurfWriter Help"
then put the bundle ID in as the
HPDBookTitle in the
Oh, and if you think you’re going to be able to double-click a help book to
preview it, think again. That won’t work. Instead, you need either to use it
from within your application, or you can put it in
~/Library/Documentation/Help (you might have to make that folder) and
double-click it in there. Why? Because help files are indexed and you can
only open them if they’re registered in the index.
One other thing that isn’t really documented at all is what exactly the
HPDBookRemoteURL will do for you. There’s some handwaving about being able
to offer remote content updates, but how the URL is used is skirted over.
Well, if you do set
HPDBookRemoteURL, Help Viewer will essentially expect
it to point at a copy of the
Resources folder of your bundle; so if you have
HPDBookRemoteURL set to
http://example.com/foo/bar/, then you’re going to
get requests like
http://example.com/foo/bar/en.lproj/index.html (and so