表題についてまとめていきたい
作り方
PackageMakerは止めて、pkgbuild, productbuildでinstallerを作るのがよさそう
http://stackoverflow.com/questions/11487596/making-os-x-installer-packages-like-a-pro-xcode4-developer-id-mountain-lion-re
基本方針は上記linkと同じ
- pkgbuild pkgつくる
- productbuild distribution(といってもextensionは同じpkg)つくる
- productsign signする
ここまでで ship可能な pkg をつくるところまで。
ここから、さらに 1. dmg をつくり、2. Notary Service に upload して公称をうけ、3. offline時でのinstallのための staple を貼る。ところまでmemoを残します。
4) dmg をつくる
5) Apple Notary Service に upload して公称してもらう。
6) staple をはる
1) pkgをつくる
.pkgファイルをつくります。.pkgには、installされるfileや、install時に走るscriptなどを入れます。また、どのようにinstallするのかについてのoptionを付けることも出来ます。
そのようなことを記述するplistファイルをまず用意する必要があります。
それにはanalyzeコマンドでひな形を作ってあげるのが楽です。
1.1) pkgbuild で plist(設定file)のひな形をつくる
pkgbuild --analyze --root root-path plist-output-path
このコマンドでまず、pkgを作るのに必要なplistのひな形をつくります。
rootで指定するdirにinstallするappなどを、"所定の位置に"おきます。
たとえば、Applications以下にFoo.appをinstallするつもりなら
/path/to/root/以下に、
Applications という擬似的なdir構造を作って、そこにFoo.appを置きます。
そして
pkgbuild --analyze --root /path/to/root foo.plistを実行すると
以下のようなplistが得られます。
<dict>
<key>BundleHasStrictIdentifier</key>
<true/>
<key>BundleIsRelocatable</key>
<false/>
<key>BundleIsVersionChecked</key>
<true/>
<key>BundleOverwriteAction</key>
<string>upgrade</string>
<key>RootRelativeBundlePath</key>
<string>Applications/Foo.app</string>
<key>BundlePostInstallScriptPath</key>
<string></string>
<key>BundlePreInstallScriptPath</key>
<string></string>
</dict>
dictはbundle(app, vst など) 毎に用意されます。
以下、key/valueについて;
Relocatableはfalseがいいと思います。developerの環境でこれをtrueにしてinstallかけると、install場所としてbuild dirが勝手に指定されちゃったりして困ることになると思います。
BundlePostInstallScriptPath, BundlePreInstallScriptPathはないのなら削除してください(その意味で上のは悪い例です)。削除しないとcurrent position が scriptだとinstallerに思われてしまうようです。このScriptPathはpkgのscriptとは別に走らせたい場合において記述します。
くわしくは
man pkgbuild
してください(darwin manpage は公式からは手繰れなくなってしまった)。
さてでは実際にpkgを作ります。
1.2) pkgbuildでpkgファイルをつくる
pkgbuild --root rootDir --component-plist plistPath --scripts scriptDir --identifier id --version version --install-location location Foo.pkg
root はanalyzeしたときのrootと同じです。
component-plistはさっき作ったplist
scripts は script が入っているfolderを指定します。plist で ScriptPathを指定してる場合はこのfolderにscriptを置きます。また、implicit に このfolderに置いたpre/postInstall は pkgが走らせるものと決まっている模様。
identifier は installer/pkg の jp.co.somewhere... みたいなやつです。
versionはinstaller/pkg のversionです
これで flat pkgが出来上がります。
出来上がった後、中身を操作したい場合は
pkgutil --expand xx.pkg out で展開。のち、packageする場合は
pkgutil --flatten で出来ます。 .svnとか不必要に入ってたら 展開して削除してもよいかも。(root以下の.svnなどはpkgbuildがやってくれるのだが(--filter optionの解説を見よ), script folder とかはやってくれない。
2) 次に pkg を distibution形式にします。
distribution形式とはmpkgみたいな、中に1つ以上のpkgをもったpkgです。
pkgがひとつであっても、必ず包むと考えるべき。
まずは distributionを定義するxmlを作るところからstart。
2.1) 設定ファイル(xml)のひな形をつくる
productbuild --synthesize --package Foo.pkg Distribution.xml
こんな感じ。これで出来たxmlをひな形にして、titleやbg, versionなどを適宜変更する。逆に言うと さっきつくったpkgにはbgやtitleを独自に入れるinterfaceがなかった(=公開用のpkgではない)ってことです!
で実際にdistribution形式にパッケージする。
2.2) pkgをdistribution形式にする
productbuild --distribution "Distribution.xml" --package-path /path/to/pkgDir --resources "/path/to/rsrcDir" "Bar.pkg"
こんな感じ。parameterについてはみれば分かると思うので、割愛します。
ここで分かるのはscriptを指定する方法がdistributionにはないということですね。つまり、scriptは個別のpkgで持つしかない、です。
mpkgと比較していえば、mpkgにつけてたscriptどうすんの?てのがあるんですけど、1)使わないで何とかする, 2)裏技としてpayload=0 つまり、実際には何もinstallしないpkgをつくってこれにscriptだけを持たせるという方法があります。
僕のケースでいえば、使わないようにしました。
3)最後にsignしておわり
productsign --sign "Developer ID Installer: Somewhere Inc." "Bar.pkg" "Installer.pkg"
4)dmg をつくる
実際にuserに配るときにはdmgにするのが、macOSだと基本でしょうか。ということでつくったpkgをdmgに入れます。
hdiutil create -srcfolder "/path/to/folder" -fs HFS+ -format UDZO -volname "name_you_see_when_mounting_the_volume" "/path/to/filename.dmg"
このコマンドの前に、 srcfolder に必要なfileを入れておきます。 pkg とか readme とかそういうやつです。.DS_Storeを用意しておくと、imageをmountしたときに見える風景を調整できるのでぜひしましょう。(実際に finder で そのfolderをひらいて、fileをよい場所において、できる.DS_Storeを何らか保存しておき、それを /path/to/folderに配置する)
-fs とか -format は好きなものにしましょう。ここはなんかtipsあったかもなので、追記するかも。
5) 公称をうける。
#比較的新しい方法
notarytool submit --keychain-profile TOKEN_IN_KEYCHAIN --wait "/path/to/file.dmg"
- tokenのkeychain への登録などは、こちらなどを参照https://qiita.com/spc_gmorimoto/items/6b31d82ab28202eff603
#少し古い方法
xcrun altool --notarize-app -f "/path/to/file.dmg" --primary-bundle-id "jp.mycompany.myappname" -u me@mail.jp -p @keychain:PWD_IN_KEYCHAIN
- primary-bundle-idはここでしか使われないidentifier。適宜名前をつけましょう。
- Upload には AppleID が必要です。さらに2step validationしてる場合、tokenが必要になるので、appleid.apple.comにいってtokenをgetしましょう。
- このtoken を keychain にて PWD_IN_KEYCHAIN (名前はもちろん自由) として store すれば、上記のような形式で呼び出し可能です。
notarization で error が出た場合
まずは、どんなerrorが出ているか調べます。
xcrun altool --notarization-info MAGIC_NUMBER_DISTRIBUTED_BY_APPLE -u me@mail.jp -p @keychain:PWD_IN_KEYCHAIN
- app の場合、hardened してないから、と言われることがあります。xcodeで Hardened Runtime を on にします
- code_sign してないから、といわれることがあります。Xcodeで Code Sign するように組みましょう (Developer ID Application)
- 有効なtimestamp がついてないから、と言われることがあります。 Archive から、Exportするときには timestampが付くようですが、Release build して、それをpackagingするようになってたりする場合、
OTHER_CODE_SIGN_FLAGS
に--timestamp
をつけます - The executable requests the com.apple.security.get-task-allow entitlement. の場合は、release時のみ、
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO
などして、回避しましょう
6) stapleをはります。
appなどを起動する際、初めての場合は公称を受けているのかappleのサーバーに確認に行くのですが、offlineの場合はできません。なので、package自体にラベルを貼って、公称済みかどうかを知らせます。これが staple です。
xcrun stapler staple /path/to/dmg
これは、Appleから公称を受けた後に行います。以上で作成された dmg を distribute します。
その他メモ
pkgbuildでつくったpkgのpayloadも開きたい。
pkgutil --expand-full [pkg] [dir]
pkgの内容物をunarchiveせずに閲覧したい
lsbom [options] /path/to/BOM
uninstaller をつくりたい
pkgutil --files ${PKG_ID}
でinstallしたfileリストはでるので、あとはお好みで削除してください