Implementing an Apple Help Book in OS X Snow Leopard and Lion
Sunday, 23 October 2011
The documentation at Apple regarding help book implementation leaves a lot to be desired. It seems that updates have been added here and there, and overall the documentation is fragmented. Add to that the fact that Apple is no longer providing sample code for it makes the process of creating a help book a royal pain.
With that in mind, here is a brief overview of the process with some notes that hopefully may help someone, or at least serve as a reminder to myself the next time I have to do this.
The Process
- Start by creating a directory structure for the helpbook. The finished product will have a suffix of .help, which is reserved for helpbooks much like .app is reserved for applications. But for now I’d suggest just using a regular folder named something like MyAppHelp to avoid the difficulty of most apps accessing files in .help bundles
The basic structure should like so:Note that the Images, Scripts and Style directories are optional and can be named anything. Similarly, page1.html and page2.html, files which would ostensibly contain additional help info, are optional – it can all be put in MyAppHelp.html if you wish (MyAppHelp.html is the start, or access, page). As well, you can have localized stylesheets/images/etc. in subdirectories under English.lproj if you wish, and you can obviously have other language localizations. But this shows the basic layout.
Also note that MyAppHelp.helpindex is created with the Help Indexer app after you’ve created your content. And that Info.plist is located in the Contents directory along with Resources. Finally, the MyAppIcon16x16.png is the icon that will display itself in the Help Viewer. - Edit Info.plist in Property List Editor. You should have values that look something like this (all entries are strings):
CFBundleDevelopmentRegion - en-us CFBundleIdentifier - com.MyCompany.MyApp.help CFBundleInfoDictionaryVersion - 6.0 CFBundleName - MyApp CFBundlePackageType - BNDL CFBundleShortVersionString - 1 CFBundleSignature - hbwr CFBundleVersion - 1 HPDBookAccessPath - MyAppHelp.html HPDBookIconPath - Images/MyAppIcon16x16.png HPDBookIndexPath - MyAppHelp.helpindex HPDBookKBProduct - MyApp1 HPDBookKBURL - nil HPDBookRemoteURL - nil HPDBookTitle - MyApp Help HPDBookType - 3 HPDBookTopicListCSSPath - Style/MyStyleSheet.css HPDBookTopicListTemplatePath - nil
(Some of these values are optional)
- Edit MyApp.html to look something like this:
<?xml version="1.0" encoding="utf-8"?> <!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" XML:LANG="en" LANG="en"> <HEAD> <LINK REL="stylesheet" HREF="../style/MyStyleSheet.css" MEDIA="all" /> <META HTTP-EQUIV="X-UA-Compatible" content="IE=edge" /> <META name="AppleTitle" content="MyApp Help"/> <TITLE>MyApp Help</TITLE> </HEAD> <BODY> <h1>Here is where our info goes!</h1> </BODY> </HTML>
We won’t get into the details of writing the html, but one thing to note is that for any page (or section) that contains data that you want to link to you should add an anchor. You then simply link to the anchor with <a help:anchor=TheNameOfTheAnchor bookID=com.MyCompany.MyApp.help> links”> Typically the main file would be an index that you’d start up on, with links to other pages with the actual topics.
So, just to clarify – you don’t have to specifically reference the file(eg. page1.html) to access an anchor in it from another file (eg. MyAppHelp.html). The index takes care of knowing where you want to go. So the only thing that should change in that <a> link is TheNameOfTheAnchor part. - Once done writing the help files you can index them by opening Help Indexer and dragging the English.lproj folder onto it, then generate the index. Note that you will have to rename the resulting file it spits out (it will default to English.lproj.helpindex)
- Rename MyAppHelp to MyAppHelp.help
- Open your app in XCode. Right click Supporting Files (or wherever) and choose “Add Files to MyApp”. Select MyAppHelp.help. Make sure “Create folder references for any added folders” is selected. You don’t have to copy the files into location if you don’t want to. Click Add.
- Still in XCode open the file MyApp-Info.plist. Make sure Bundle Identifier is set to com.MyCompany.MyApp Add 2 new key/values – Help Book Directory Name (MyAppHelp.help) and Help Book Identifier (com.MyCompany.MyApp.help).
- In Interface Builder link your Help menu item (or buttons) to File’s Owner’s showHelp method.
on «event helphdhp» (passedLocation) -- First, get rid of any %20's we may have passed set astid to AppleScript's text item delimiters set AppleScript's text item delimiters to "%20" set passedLocation to passedLocation's text items set AppleScript's text item delimiters to " " set passedLocation to passedLocation as string set AppleScript's text item delimiters to astid -- localizable text set cancelBtn to "OK" set errorTxt to "The item can't be opened at this time." --end localizable text set locationURL to POSIX file expandTilde(passedLocation) as Unicode text try tell application "Finder" activate open locationURL end tell on error errMsg number errNum display dialog errMsg buttons {cancelBtn} default button 1 with icon 0 return end try end «event helphdhp» on expandTilde(thePath) if thePath starts with "~/" then set homeAddress to POSIX path of (path to home folder) set delim to text item delimiters set text item delimiters to "~/" set thePath to thePath's text items set text item delimiters to homeAddress set thePath to thePath as string set text item delimiters to delim return thePath else return thePath end if end expandTilde
This script adds the app to the list of startup items for the user:
if appIsRunning("MyApp") then set thePath to (POSIX path of (path to application "MyApp.app")) tell application "System Events" make login item at end with properties {path:thePath, hidden:false} end tell display dialog "MyApp has been added to your startup items." buttons {"OK"} cancel button "OK" else display alert "Error - MyApp is not currently running!" message "In order to ensure that the correct version of MyApp is added to your start up items, please start MyApp before running this command." as warning buttons {"OK"} cancel button "OK" end if on appIsRunning(appName) tell application "System Events" to (name of processes) contains appName end appIsRunning