きりかノート 3冊め

おあそびプログラミング

productbuildによるインストーラ作成

この記事は、2011年12月の「packagemakerコマンドでインストーラをつくる」の改訂版です。

Package MakerがDEPRECATEDになってしまったので、こないだRubyCocoaのインストーラ作成をproductbuildに移行しました。ついでなので、その際に調べたことなどをまとめておきます。

インストーラを使う理由(前回のコピペ)

通常のアプリケーションはインストーラでなく、ディスクイメージなどの中に.appファイルを入れておき、ユーザが自由に配置できるようにしておくのが一般的です。インストーラを使用したインストールが適しているのは、「決められた位置にファイルをインストールする」ことが求められる場合です。たとえば、

  • 環境設定パネル(.prefPane) - Library/PreferencePanes/
  • かな漢字変換などのインプットメソッド(.app) - Library/Input Methods/
  • サービス(.app, .service) - Library/Services/
  • 汎用のフレームワーク(.framework) - Library/Frameworks/
  • 多数のファイルをそれぞれ配置する(Xcode, MacPortsなど)

などです。これらを配布するときは、ユーザに適切な場所にコピーするよう依頼するよりも、インストーラで自動的に決められた場所に配置されるようになっているほうが親切ってもんです。

インストーラファイルの中身

インストーラファイル(.pkg)がどのようになっているかを見てみます。旧来の.pkgはディレクトリでその中にさまざまなファイルが配置されていましたが、現在では単一のファイルになっています。

   % ls -la RubyCocoa-1.0.7-OSX10.9.pkg
   -rw-r--r--@ 1 kimuraw  staff  1614451 Oct 26 20:52 RubyCocoa-1.0.7-OSX10.9.pkg

最近ではこの手のファイルは単一ファイルと見せかけてzipでパッケージしたものが多かったりしますが、これはどうでしょう。

   % file RubyCocoa-1.0.7-OSX10.9.pkg
   RubyCocoa-1.0.7-OSX10.9.pkg: xar archive version 1, SHA-1 checksum

xarで固めたファイルのようですね。じゃあxarコマンドを使って中身を見てみましょう。

   % xar -tvf RubyCocoa-1.0.7-OSX10.9.pkg
   drwx------      root/wheel             0 1970-01-01 00:00:00 RubyCocoa-1.0.7-OSX10.9.pkg
   -rw-r--r--   kimuraw/staff        250682 2013-10-26 11:52:18 RubyCocoa-1.0.7-OSX10.9.pkg/Bom
   -rw-r--r--   kimuraw/staff       1548524 2013-10-26 11:52:18 RubyCocoa-1.0.7-OSX10.9.pkg/Payload
   ??????????  unknown/unknown        7664 1970-01-01 00:00:00 RubyCocoa-1.0.7-OSX10.9.pkg/PackageInfo
   drwx------      root/wheel             0 1970-01-01 00:00:00 Resources
   drwx------      root/wheel             0 1970-01-01 00:00:00 Resources/en.lproj
   ??????????  unknown/unknown        2817 1970-01-01 00:00:00 Resources/en.lproj/ReadMe.html
   drwx------      root/wheel             0 1970-01-01 00:00:00 Resources/ja.lproj
   ??????????  unknown/unknown        3932 1970-01-01 00:00:00 Resources/ja.lproj/ReadMe.html
   ??????????  unknown/unknown        2552 1970-01-01 00:00:00 Resources/License.txt
   ??????????  unknown/unknown        5434 1970-01-01 00:00:00 Distribution

概ね以前の形式と同じようなものが入っていますね。Payloadが配布物の実体で、Bomにファイルリストが入っているのでしょう。

productbuildによる.pkg作成

DEPRECATED: Package Maker app.
Use the productbuild command to create installer packages

と、Xcodeのリリースノートあるように、productbuildコマンドが新しいインストーラ作成ツールになります。

こういったApple独自のツール(xcodebuildやibtoolとか)はmanの最後に"EXAMPLES"として使用例が書いてあることが多いので、そこをまず見るのがおすすめです。

   EXAMPLES
        productbuild --component build/Release/Sample.app /Applications Product.pkg

                Build the archive Product.pkg to install Sample.app under
                /Applications, synthesizing a distri-bution. distribution.
                bution. This is typical for building a Mac App Store archive.

        productbuild --product def.plist --component \
                build/Release/Sample.app /Applications Product.pkg
          :
        productbuild --distribution Product.dist --resources Resources Product.pkg
          :

オプションを指定して、最後に出力する(もしくは更新する)Product.pkgファイル名を書くということのようです。ちょっと試しにやってみましょう。アプリを用意するのもめんどうなので、テキストエディットをパッケージしちゃいましょう。

   % productbuild --component /Applications/TextEdit.app TextEdit.pkg
   productbuild: Adding component at /Applications/TextEdit.app
   productbuild: Inferred install-location of /Applications
   productbuild: Wrote product to TextEdit.pkg
   productbuild: Supported OS versions: [10.8, )
   % ls -la TextEdit.pkg
   -rw-r--r--  1 kimuraw  staff  7147430 Oct 29 19:59 TextEdit.pkg
   % xar -tvf TextEdit.pkg
   drwx------      root/wheel             0 1970-01-01 00:00:00 com.apple.TextEdit.pkg
   -rw-r--r--   kimuraw/staff        186384 2013-10-29 10:59:13 com.apple.TextEdit.pkg/Bom
   -rw-r--r--   kimuraw/staff       7102446 2013-10-29 10:59:13 com.apple.TextEdit.pkg/Payload
   ??????????  unknown/unknown         934 1970-01-01 00:00:00 com.apple.TextEdit.pkg/PackageInfo
   drwx------      root/wheel             0 1970-01-01 00:00:00 Resources
   drwx------      root/wheel             0 1970-01-01 00:00:00 Resources/ar.lproj
   ??????????  unknown/unknown          25 1970-01-01 00:00:00 Resources/ar.lproj/Localizable.strings
     :
   % xar -xvf TextEdit.pkg com.apple.TextEdit.pkg/Bom
   com.apple.TextEdit.pkg/Bom
   % lsbom com.apple.TextEdit.pkg/Bom
   .	0	0/0
   ./TextEdit.app	40755	0/0
   ./TextEdit.app/Contents	40755	0/0
   ./TextEdit.app/Contents/Info.plist	100644	0/0	7868	477219676
   ./TextEdit.app/Contents/MacOS	40755	0/0
   ./TextEdit.app/Contents/MacOS/TextEdit	100755	0/0	174640	1115714015
   ./TextEdit.app/Contents/PkgInfo	100644	0/0	8	842486447
     :

ちゃんと、TextEdit.appのインストーラが作成されたようですね。あとはEXAMPLESとmanを見ながらほしいオプションを足していけばお好みのインストーラが作成できます。

たとえば、--product オプションで指定したplistファイルでは

などを指定することができます。詳細はmanの"PRE-INSTALL REQUIREMENTS PROPERTY LIST"を参照してください。

また、Macのバンドル形式(.appなど)でないファイルはproductbuildではパッケージすることはできません。

   % productbuild --component ~/.vim vimdir.pkg
   productbuild: error: The component at "/Users/kimuraw/.vim" is not a bundle.

そういったファイルをインストーラとして作成したい場合は、pkgbuildコマンドの--rootオプションを使います。

   % pkgbuild --root ~/.vim --identifier kimuraw vimdir.pkg
   pkgbuild: Inferring bundle components from contents of /Users/kimuraw/.vim
   pkgbuild: Wrote package to vimdir.pkg
   % xar -tvf vimdir.pkg
   -rw-r--r--   kimuraw/staff       1049333 2013-10-29 11:23:17 Bom
   -rw-r--r--   kimuraw/staff      12038167 2013-10-29 11:23:18 Payload
   ??????????  unknown/unknown         452 1970-01-01 00:00:00 PackageInfo
   %

これで配布ファイルを.pkgにまとめて、productbuildで仕上げていくという手順になります。

XMLでの各種設定

productbuildの--distributionオプションに渡すXMLファイルでは、productbuildの各オプションや--productオプションのplistより多くの指定を行うことができます。

その設定内容はAppleDistribution XML Referenceで説明されています。項目は一部、--productのplistと重複しています。

RubyCocoaでは、次の設定を使用しています。

  • "allowed-os-versions" インストール可能なOSバージョンの設定
    • こちらでは対象バージョンの上限(未満)も指定することができます。
  • "readme" 「大切な情報」として表示されます。
  • "license" 「使用許諾契約」として表示されます。

productbuildコマンドの--synthesizeオプションで最小限設定されたXMLファイルを生成することができます。初回はこれで生成して、そこに設定を追加したファイルを使う、というのが便利ではないかと思います。

署名

Mac OS X 10.7.5から導入されたGatekeeperの初期設定では、AppleのDeveloper IDで署名されていないインストーラからインストールすることができません。

MacのDeveloper Programに加入していれば、必要な証明書を用意できるのでそれを利用して署名することができます。先日のRubyCocoa 1.0.7では私のIDで署名したので、Gatekeeperが有効でもインストールすることができるはずです。

証明書を準備する手順は次のとおりです。

  1. MacのDeveloper Programに加入する。
  2. XcodeのAccounts > View Detailsの[+]ボタンで"Developer ID Install Distribution"を選択する。
  3. キーチェーンにインストーラ用の証明書が追加されているので確認する。

これで、productbuildの--signオプションを使って署名することができます。

まとめ

productbuildによるインストーラ作成手法を紹介しました。productbuildはSnow Leopardなど古い環境でも利用可能です。

また、Package Makerで提供されていた機能も、私が把握している範囲ではひととおり利用可能なようです。今でもPackage Makerを使っている方がいたら、この期に移行を検討してみてはいかがでしょうか。