Authoring macOS Help Books in 2020 (and beyond)

Updated for 2022

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 en.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:

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.

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

Your Help Book’s info plist must have these entries — most of which are specific to Help Books.

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 MyGreatApp.helpindex. Just know that there is a .helpindex file in each Help Book for indexing purposes that it needs a reference to.
  6. HPDBookCSIndexPath: This will be discussed more in detail later. For now, just name it MyGreatApp.cshelpindex. Just know that there is a .cshelpindex file in each Help Book for indexing purposes that it needs a reference to.
  7. 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.
  8. 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 en.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.

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. Use alternate words to your main keywords. (ex: include ‘track’ if ‘song’ is the main keyword used throughout your Help Topic page).
  2. Meta name Description: This is a brief 1-sentence description of this Help Topic. It displays under the Title for search results in the Help app.
  3. Meta name Robots: Tells the indexer what to index. Omit the ‘index’ in ‘contents’ if a page shouldn’t be index. If the page is supplementary (i.e. Terms & Conditions, Privacy Policy), you might not want to index. Typically, the landing page isn’t index either but for this example, we will index it.

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 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 use Terminal and hiutil to index your Help Book. Indexing allows your Help Book to surface pages in the Help menu’s search results and in the Help app search results.

To start, open Terminal and navigate to the en.lproj folder using the cd command.

cd '/Users/mario/Developer/My-Great-App/My Great App/MyGreatApp.help/Contents/Resources/en.lproj

Now we use hiutil to create two help index files. We referenced these earlier in this tutorial in the Info.plist file.

hiutil -I corespotlight -Caf MyGreatApp.cshelpindex -vv .

hiutil -I lsm  -Caf MyGreatApp.helpindex -vv .

You should now see two additional files next to your html files: MyGreatApp.cshelpindex and MyGreatApp.helpindex. Remember, these names should match the names listed in your Info.plist file. These are the files responsible for properly bringing up search results in your app’s Help menu and the Help app.

Thanks to Chris Davis and his Stack Overflow post for this!

Another nice tool is the verification options in hiutil so that you can see how and what was indexed from your Help Topics.

hiutil -I corespotlight -Tvf MyGreatApp.cshelpindex

Running the validator. Notice that the Titles, Descriptions, and Topics are listed for each page. Note that I have created 3 additional pages for this example named Topic 1, 2, and 3 respectively.

You will get a printout of all your pages. If a page has the title tag and correct meta tags (listed above), the values should appear each page entry after running this command. This helps you see what will be displayed to the user.

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!

Testing the Help Menu

Run your app and go to the Help menu. Usually, you’d just be able to search for all the commands across all your app’s menus to help you locate them. But now, with a properly indexed Help Book, it will also search and surface Help Topics from your Help Book!

The Help Menu will now search your Help Book and surface links to individual pages.

Open the Help app by going to Help > Your App Name Here Help.

It should take you to the landing page of your Help Book for your app. In the Search field in the toolbar of the Help app, search using a word you know you indexed and press Return. Help should bring up search results related to your app.

Using the Help app to Search for your Help Book’s content.

This is where you will see the brief descriptions you gave your pages. Make sure they’re short and succinct.

Please note that Help takes a very long time to update. The best way I have found to force new Help Book content is to use hiutil to restart the Help system, bring a copy of your app with the new Help Book into Applications, and Logout. Once you log out and log back in, it will take about 5 minutes to get your updates to appear. This is because Help Book content is cached and macOS resorts to that cached version.

Use hiutil -P to shutdown the helpd process and clear all caches the system may have created for your Help Book. Again, this process takes a while to restart and re-cache newly updated Help Books (that reside in your Applications folder). Sorry, I cannot stress this part enough. It requires much patience.

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.

Additionally, you may not want to index the landing page and informational pages (ex: Privacy Policy, Terms & Conditions). You may not want these to come up in search results because users typically only search Help to learn how to achieve something in your app.

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")

Developer Workflow

Wouldn’t it be nice if all you had to worry about was adding or updating the HTML pages in your Help Book and not have to mess with Terminal and manually creating the index files?

What I have done in my projects is to create a Run Script phase in the Build Phases section of your Project. Start by clicking the + button on the upper left and choosing Run Script. It will add this step to the button of the list, but drag it up to be the 2nd item in the list — right under the Dependencies phase.

First, you want your script to navigate over to your folder where the index files need to go — this would be your folder containing all the HTML files.

Then, simply call your hiutil commands to do all the heavy lifting.

This script will navigate to the correct location and create the help index files.

Notice that For install builds only is checked. This will only generate the help index files when you create an Archive of your app (to notarize, submit to the Mac App Store, etc.)

Also notice that I have a third hiutil command in this phase. This is to see the validation output of my index file. But where do you see this output you may ask?

In Xcode, go to the Report Navigator in the left-hand sidebar. Select the latest build and you’ll see all output from your script here. In the screenshot above, notice the selected item. Below it, you will see the validation output of hiutil including the details of my Help Book indexing.

With this in place, I never worry about having current index files for my Help Book. I just have to worry about making the Help Book (adding pages, removing pages, editing content, etc.).

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 macOS app, Music Widget.

The landing page to Music Widget’s Help Book
Search Results for “volume” in Music Widget’s Help Book

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

Advertisement

20 Comments

  1. Joss says:

    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. Sam says:

    “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. Enri says:

    Awesome Job. How do we get the table of contents sidebar?

    Like

  4. PartWood says:

    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. Mario Guzman says:

      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

  5. manndmd says:

    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

    1. Mario Guzman says:

      It was the same for me. Trial and error. Missing pieces. Etc. I hope this helps someone else so they’re not having to piece together from all corners of the internet. 😊 cheers!

      Liked by 1 person

  6. Виталий Ващенко says:

    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

  7. Michael says:

    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. Mario Guzman says:

      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

      1. Micahel says:

        Thanks Mario, but yes I have tried this several times. Unfortunately, it just isn’t loading. Anymore suggestions?

        Like

      2. Michael says:

        Perhaps I should mention my app isa SwiftUI app – Swift 5.4.

        Like

  8. Michael says:

    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

  9. Chris says:

    I’m able to get my help file to show in the help viewer, I just can’t seem to search it, either from inside the help viewer, or the search within my app :-/ Any ideas?

    Like

  10. Peter says:

    This tutorial helps me along some apps in the past. Updating to 12.0.1 all my help books are empty and white. All .help folders aren’t a bundle any more.

    Dies someone know how to do Help Books in 2021?

    Like

  11. Mark Erbaugh says:

    I worked through this, but when I got to the step about renaming MyGreatApp to MyGreatApp.help, the finder renamed it without a prompt and didn’t change the icon. Get Info still shows the type as Folder. This is with OSX Monterey

    Like

  12. Dirk says:

    This works great, thank you very much!

    Like

  13. eolcott12 says:

    Maybe this will help someone else: I can make changes in the HelpBook, run the app in Xcode and see the changes right away IF you change the build directory to be somewhere approved by the system for HelpBook to access.

    In my case, I didn’t have anything else in ~/Applications, so I set Preferences > Locations > Derived Data to “Custom” and selected my user’s Applications folder, and voila! Every time I launch my HelpBook is the latest and greatest.

    Liked by 1 person

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 )

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