Authoring macOS Help Books in 2020 (and beyond)

Updated for 2021.

Apple Help is old. Really old. Sometimes I wonder if new developers even know what Apple Help is since it’s not really used as much these days. Most applications in 2020 just open the support page from the developer’s website in Safari. However, Apple’s own applications and some big-name developers still make use of Apple Help by shipping the necessary resources in their app!

It’s probably not worth writing a Help Book anymore these days but it certainly doesn’t hurt to include one. I mean, it definitely has some advantages. For example, your Help Book can be viewed offline since it’s just a collection of HTML pages stored within your app’s bundle. Other advantages include anchors, which is a mechanism to link the Help button in AppKit to specific pages within your Help Book.

You may also want to include a Help Book with your app for the sake of completeness …and to be old school. I often feel those long-time Mac OS X developers appreciate the little things — such as Apple Help Books. So, what do we need to get started?

Well unfortunately, a ton of time. And even more patience. Apple’s own documentation for Apple Help has moved to the documentation archive on their developer site. You’ll find tons of questions on Stack Overflow and other… more questionable sites. Apple did do a minor revision to their documentation back in 2013. 2013!!!

By now, 2020, Apple Help is neglected and well, crusty. Very crusty (no, not that Crusty). It still works but certain parts of it don’t seem to work as well anymore. Not sure why it’s neglected. They advise you include a Help Book in their HIG that was recently published — and they link to the documentation (from 2013). Personally, I think they have a lot of potential and a lot to offer. I just wish this was a component at Apple that would get some attention in both development and documentation.

Before I continue, I want to make sure that you understand some things just don’t work. I don’t know if either I am doing something wrong or it the issue truly is a bug Apple never got around to fixing. For example, only Apple seems to have access to the sidebar button in Apple Help’s toolbar to open a sidebar in their HTML pages.

But at the end of the day, a Help Book is better than No Help Book. So, let’s get started on a simple Help Book for your awesome Mac OS X… errr… macOS app!

One last thing before we continue. Why are we spending time going over a complicated process and why am I spending time writing this article? Well, when I was developing PDX Transit for macOS, I wanted to make sure it included a Help Book to make it feel more native and more OG. I spent countless hours and days trying to piece together all the information from all corners of the internet to build a Help Book. It was super frustrating and excruciatingly time consuming. I don’t want anyone else to feel this way so I hope this speeds things up for the next Mac Developer who wants to include a Help Book with their awesome app!

Getting Started

A Help Book is nothing more than a bundle that resides in your app’s Resources folder. It’s accessible from the Help menu of your app’s menu bar. In fact, any new project will already be set up with this Help menu item but it’s your responsibility to include the Help Book and register it.

In this example, the name of both the project and app is My Great App. In the Finder, go to your project and open your project’s source code folder. Your project’s root folder is where you will add your Help Book’s folder containing all of its necessary resources.

Xcode project files in the Finder.

Create a new folder with the name of your app removing any spaces. In our case, we would make it MyGreatApp. Your folder should now look similar to this:

Newly created MyGreatApp folder in the Xcode project files.
Newly created MyGreatApp folder in the Xcode project files.

Now we need to create a very specific file structure for a Mac OS X bundle that will later constitute as our Help Book bundle.

Open your newly created Folder (MyGreatApp in this example) and copy the following file structure.

  1. Create a Contents folder.
  2. Open the Contents folder and create a Resources folder.
  3. Open the Resources folder and create an English.lproj folder.
Help Book bundle initial file structure.

Your Help Book’s bundle file structure should be as shown above. Go back up to the Contents folder’s contents. You will need an info.plist file as a sibling to the Resources folder. You can copy your app’s info.plist or just download my info.plist from my project:

Download my base Info.plist

This info.plist will include vital information unique to your Help Book. So, if you copied your app’s info.plist (which is fine), you will need to delete all of its entries since they don’t pertain to Help Book files.

Your Help Book’s bundle file structure should now look like this:

Help Book bundle file structure with info.plist.
Help Book bundle file structure with info.plist.

Open your info.plist file and remove any entries it may have. We will add the following items into it:

Help Book specific info.plist. Red dots indicate values that you define specific for your app.
Help Book specific info.plist. Red dots indicate values that you define specific for your app.

Let’s go over what these key/value pairs mean and how to fill them in with information specific to your app.

  1. Bundle identifier: This is the bundle identifier specific to your app’s Help Book, not the app itself. The easiest thing you can do here is copy your app’s bundle identifier and append .help to it. In our case, it is com.mycompany.mygreatapp.help.
  2. Bundle name: This is just the name for your Help Book. It will appear as the title of your Help Book in the Apple Help viewer app. The easiest thing you can do is have it be your app’s name. In our case, it is just My Great App.
  3. Bundle version string (short) and Bundle version: Same as your app, Help Books have a Version and Build number. The easiest thing you can do is just copy into it the values you use for your app. You can also just use whatever mechanism you use for revving version and build numbers.
  4. HPDBookAccessPath: This is the initial or landing page to your HTML files which we will create later. For websites, this would normally be index.html but we will just go with our app’s name for this. In our case, it will be MyGreatApp.html. Remember this name.
  5. HPDBookIndexPath: This will be discussed more in detail later. For now, just name it English.lproj.helpindex. Just know that there is a .helpindex file in each Help Book for indexing purposes that it needs a reference to.
  6. HPDBookKBProduct: This is just a KB tag code to identify this product. Name it whatever you’d like. In our case, it is simply mygreatapp1.
  7. HPDBookTitle: This will be the title shown in the Title bar of the Apple Help book viewer app. The easiest thing you can do is give it your app’s name and append Help. In our case, it’s My Great App Help.

You must include all other key/value pairs not described above but shown in the screenshot with the same values shown in the screenshot. These are unique to Help Books but the same for all Help Books.

Creating your Help Book Content

Apple Help content is nothing more than standard HTML. The help viewer is nothing more than a standard web view so you’re welcome to use basic HTML, CSS, Scripts, etc. However, there are some specific meta tags and other elements you must use or include in order to have the content work a bit more tightly with Apple Help and your App.

Your HTML files go in their respective localized folder. In this case, the HTML files will go into the English.lproj folder (shown above).

I’d also advise to include style sheets and scripts with your Help Book rather than loading them remotely. If you want your users to be able to access everything even when they’re offline, they shouldn’t be loaded from your web server.

Let’s begin by creating the initial/landing page to your Help Book. This is the first page page your users will see when opening your Help Book from the Help menu of the app. You must name this html file with the name selected in your info.plist’s HPDBookAccessPath‘s value. In our case, we named it MyGreatApp.html. You can name it whatever you’d like so long it matches your value for HPDBookAccessPath in your Help Book’s info.plist.

Example HTML for our initial/landing page.
Example HTML for our initial/landing page.

The HTML above is essentially boiler plate for any Help Book page. For simplicity, we’re not including any style sheets or scripts. Let’s go over some things unique or required by Apple Help in your HTML pages.

If you look at the HEAD section, notice the meta tags.

  1. Meta name Keywords: This is a list of comma delimited words with themes for this help page. This would be different for each HTML page you include in your help book and is used by the Indexer app we will be using later.
  2. Meta name Description: This is a short summary for the help content in this page. This is used in the search results of Apple Help to provide extra content on search results.
  3. Meta name Robots: This is a helper tag to let the indexer know what it should index, if anything. In this case we want it to index both anchors and keywords. If your page shouldn’t be index, set the content tag to noindex.

If you look at the BODY section, notice the anchor tag with a name. This is a very awesome feature of Help Books: anchors. Give each page a unique anchor name. AppKit has support to open your Help Book to specific anchors to give your app better support for contextual help. We will go more into this later.

In this case, we gave it an anchor name of Welcome since it’s our landing page.

Now, add all the HTML files you want to your Help Book and link them however you want. You can see in the sample HTML code above that we link to 3 other pages inside the Body tag. Make sure that each page has:

  1. a keywords meta tag
  2. a description meta tag
  3. a robot(s) meta tag(s)
  4. a anchor with a specific name

Tired yet? Sorry… we’re not completely done yet. Let’s keep going…

Indexing your Help Book

You’re going to need to download a very old Mac OS X app to index your Help Book. Indexing allows for things such as your anchors to work properly. Unfortunately this app is not included in current versions of Xcode but it’s easy to get from the Apple Developer website.

Apple Developer: Download: More

On the left-hand side, locate the Search field and type in: Additional Tools. Download the version that closely matches your installed version of Xcode.

Apple Downloads: Additional Tools
Apple Downloads: Additional Tools

Once the download is complete, open the Disk Image but don’t move its contents quite yet.

Open your Applications folder and drill into your Utilities folder. In side the Utilities folder, create a folder called Additional Tools. Open this new folder.

Now, we can move over the contents from the Disk Image you just downloaded into your Additional Tools folder you just created. You should be looking at something similar to the following screenshot:

Additional Tools where Help Indexer.app resides.
Additional Tools where Help Indexer.app resides.

Go ahead and open Help Indexer and click on the Show Details button in the lower left.

Begin by placing a checkmark for the following items:

  • Index anchor information in all files
  • Warnings (under Log these)
  • Status messages (under Log these)

Next, go back to your Help Book folder and drill until you see your English.lproj folder but do not open it. We’re going to drag this folder into the path field at the top of the Help Indexer app. Make sure your options appear as they do in the screenshot below.

Using Help Indexer to generate our .helpindex file.
Using Help Indexer to generate our .helpindex file.

Complete this process by clicking on Create Index in the lower right of the Help Indexer app. You will get a window with results that will display the pages that were indexed and will also display any errors/warnings should any arise. Fix any warnings and/or errors and repeat these steps again to generate a valid .helpindex file.

If you open your English.lproj folder, you will notice that there is now a new file: English.lproj.helpindex. This is used by the system to make sure search results work in Apple Help as well as an index for your anchors. Repeat this process any time you add, remove, or update your Help Book HTML files.

Finalizing your Help Book

Go back to the root of all of your Help files. In this case, it was named “MyGreatApp” and resides at the root of the project folder. If it helps, it’s the folder containing the “Contents” folder.

Select the folder and rename it by appending .help. The Finder will confirm if you want to add the extension. You will notice that the icon will change from a blue Finder folder to either a white document page or a white document page with an orange Question mark icon. This is normal.

Appending .help makes it a Help Book bundle
Appending .help makes it a Help Book bundle

Refrain from double-clicking this file. We don’t want to open this just yet with Apple Help. If you must go into its contents once more before we continue (or to edit the content in the future), you must right-click and choose Show Package Contents. This is now a bundle.

Additionally, you want to make sure this Help Book goes out with your app when you build it. To do this, make sure that your .help bundle is listed under “Copy Bundle Resources” under “Build Phases” in your project’s settings.

The Help Book should be added to "Copy Bundle Resources" for your App.
The Help Book should be added to “Copy Bundle Resources” for your App.

Tell your app about it

Your application doesn’t know anything about your Help Book just yet. To advise your app and the Finder that your app contains a Help Book, you must add two new items to your app’s info.plist (not your Help Book’s info.plist).

Add the following two keys to your app’s info.plist and enter their values as described:

  1. Help Book directory name: This is going to be the name of your Help Book file, the one we just renamed by appending .help. In our case, it will be MyGreatApp.help.
  2. Help Book identifier: This will be the Bundle identifier you chose for your Help Book’s info.plist. Remember, this is the one where we basically copied our app’s bundle identifier and appended .help. So, in our case, it will be com.mycompany.mygreatapp.help. You can copy the value for Bundle identifier in your Help Book’s plist.

Test it!

From Xcode, build and run your application. Once it is up and running, go to the Help menu and open your app’s Help Book. In our case, it will be Help > My Great App Help.

Uh oh. You might not get what you expect. I know you were expecting to see your landing HTML page from your Help Book but instead you got “The selected content is currently unavailable.” Right?

The selected content is currently unavailable.
The selected content is currently unavailable.

This is because Apple Help hasn’t had a chance to register your Help Book and doesn’t know anything about it. Apple Help seems to like to cache things and works off that cache. So, how do we force it to begin tracking our Help Book but also update subsequent updates of our HTML files?

To do this, we want to run this app from our Applications folder. Placing an app with an updated Help Book in Applications seems to trigger an update to Apple Help.

Let’s begin by quitting our Application or pressing the Stop button in Xcode.

  1. In the Xcode Project Navigator, right-click on your app that resides in your Products folder.
  2. Select Show in Finder.
  3. From the Finder window, drag this app into your Applications folder.
  4. Go into your Applications folder and open your app.

Now we can go into the Help menu and try again. You should now see your Help Book’s landing page. In our case, using the sample HTML above, should appear like this:

Our Help Book's landing page.
Our Help Book’s landing page.

You did it! Your awesome Mac OS X… errr, macOS app now has a Help Book!

Checkpoint!

Now that you have a working Help Book, you might want to go back and start adding more HTML pages for all topics of your app. Maybe you want to add additional content to existing pages. This is going to be pretty common going forward so lets go over some things you must remember.

  1. Any updates you want to see during development won’t reflect in Apple Help until you drag your debug output of the app into Applications.
  2. Always remember to update the .helpindex file whenever you update your Help Book content.
  3. And finally, remember to keep your Help Index app up-to-date. Apple always seems to include an updated Additional Tools disk image for each Xcode update (including Betas!). Download this from the Downloads page on Apple’s Developer website.

Writing an Effective Help Book

I know I haven’t given you any instruction on how to write or structure your Help Book specific content. That’s really up to you but Apple does offer some guidance here. I’m going to refer you to that because that part is actually quite good.

What I did for my own app was to break down each section of my app into a topic and then into further sub-topics. I also added additional information such as a page dedicated to keyboard shortcuts and system-related features such as Handoff, Dock Menu Items, Touch Bar Support, etc.

For more guidance, check out Apple’s Developer Documentation which is complete with illustration and examples.

More work to be done…

Remember our discussion on Anchors? I mentioned that anchors can give your app more contextual help because it opens your Help Book to a specific page. Here’s an example from System Preferences’ Desktop and Screensaver pane:

System Preferences opening to a specific topic in Apple Help.
System Preferences opening to a specific topic in Apple Help.

For reference, each HTML page in your Help Book should have a blank anchor tag with a name as such:

<a name="Welcome"></a>

Each name should also be unique so that Apple Help only has one page to open to. No ambiguity!

AppKit gives you two ways to access a specific topic of your Help Book. The first is using the Help styled NSButton and calling up the page programmatically. First, use this Cocoa control:

Help-styled NSButton in AppKit.
Help-styled NSButton in AppKit.

Set its action or IBOutlet to the following code:

@IBAction func helpButtonAction(_ sender: Any)
{
    if  let bookName = Bundle.main.object(forInfoDictionaryKey: "CFBundleHelpBookName") as? String {
        NSHelpManager.shared.openHelpAnchor("MY_ANCHOR", inBook: bookName)
    }
}

The other hook AppKit has into Apple Help is in NSAlert. NSAlert has a showsHelp property which you can set to true and then set the helpAnchor property to your anchor string. AppKit will take care of the rest by displaying the Help button and opening the anchor when clicked.

Help Button in NSAlert
Help Button in NSAlert
let alert = NSAlert()
alert.messageText = ""
alert.informativeText = ""
alert.alertStyle = .warning
alert.addButton(withTitle: "")
alert.addButton(withTitle: "")
alert.showsHelp = true
alert.helpAnchor = NSHelpManager.AnchorName("MY_ANCHOR")

That’s it!

You’ve successfully constructed a Help Book for Apple Help! That’s super exciting in my opinion but the road ahead is still long and arduous. Maintaining a Help Book is tedious and there isn’t much Help on the web. At this point, I’d like to share with you some things I still encounter till this day with no way around them.

  1. Help Books don’t update automatically. While developing a Help Book, remember to keep moving your debug output into your Applications folder to force Apple Help to update its cached contents. (At least I think it has a caching mechanism.)
  2. Anchors take much longer to begin working or update. If your anchor doesn’t work right away, give it time. Yes, I know that sounds weird but just give it time. It will eventually work.
  3. Unless you want to reverse engineer Apple Help, forget about the sidebar button. Maybe if you know or figure it out, please let me know!

I’d like to leave you with an example of the Help Book for my Mac OS X app, PDX Transit.

PDX Transit for macOS Help Book

If you have any questions or wish to reach out to me, contact me via Twitter @marioguzman.

13 Comments

  1. I wonder: will .help bundles anywhere on your volume always be automatically registered with macOS, and thereby be available for access in HelpViewer, even standalone .help bundles? Or do they have to be nested in an app’s Resources folder? If the latter is the case, is there maybe a macOS built-in way to manually register a standalone (i.e. not nested) .help bundle with macOS in Terminal? Reason: I’m sometimes creating Platypus apps or (shell) scripts that run in BitBar, and while I could always just include a button or menu command that runs `open -a HelpViewer /foo/myApp.help`, it would be nice to have the help available in HelpViewer by default with something like `helpregister ~/Library/Application\ Support/myApp/myApp.help`. Do you by chance have any information on that? PS: I will definitely ask the Platypus developer to include support for .help in Resources, but that wouldn’t cover standalone or BitBar scripts.

    Like

  2. “Unless you want to reverse engineer Apple Help, forget about the sidebar button. Maybe if you know or figure it out, please let me know!”

    Google “window.HelpViewer.showTOCButton”.

    Like

  3. This is a great article covering Mac Help, well written and easy to follow, I really appreciate your sharing. Thanks to this, I was finally able to get help working in my own Mac App.

    However there are still a few gaps that I had to figure out with the archived Apple documentation. You show an example of your html file, but you don’t mention what directory it exists in (in the English case it goes in the English.lproj directory). Also, you didn’t mention if you put the resources in Xcode and if so what directory structure you used (in the simple case I added the .help bundle directory to the root of my product branch, which automatically added it as a product resource. Later I figured out I could put the whole directory structure in so I could edit the files within Xcode). Hopefully that will help others who missed a few steps.

    Thanks Again!

    Liked by 1 person

    1. Thanks! I guess in my head I figured that the screenshots were enough to show where the Help bundle should go but you’re right in that it should be explicitly called out. I have updated that. I have also called out where your HTML files should go (in your localized folders).

      Like

  4. This is a great post. I went through adding a help book to a macOS app years ago and had to figure out a lot of this by trial and error, and even with that I couldn’t get everything to work like I wanted. I wish I had been able to read this post back then!

    Like

  5. Great tutorial!
    Maybe you can point me into the right direction. I have an app with an extension and need to share the help file between both. So, I have a shared framework and want it to include the help file. But how can I share it to both apps? Whatever I write into the Info.plist file of my apps, Help isn’t working.

    Like

  6. This is the nearest I’ve got to implementing a help book and I’m truly gratefull. I’ve followed your instructions and double checked my efforts several times. but it’s not working for me. Could this be because something has changed in Xcode 12.5 or macOS 11.4? I’ve even deleted the entire ~/Library/Caches/ contents, rebooted, re-built, plus several other ideas – all without success. The Help App loads OK and displays a blank page for a few millisecond, but then the “The selected content is currently unavailable” page takes over. Please can you offer a solution?

    Like

    1. When you run from Xcode, the app shows up in your Dock. Right-click on it and say “show in Finder.”

      Take that and drag it to your main Applications folder and open the app. Not sure if you tried this. It takes a least one time doing this for it actually work in my experience. Have you tried this?

      Like

  7. I seem to have found a solution and think it has to do with localisation and that the ‘English.lproj’ is depreciated. Simply rename this folder to ‘Base.lproj’. As I’m only planning for my English language, it doesn’t appear to matter if ‘Use Base Internationalization’ is checked or not. P.S. I looked into contents folder of several apps, including the Apple one, and all are using different methods – probably much more modern.

    Like

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s