Automatorアプリケーションでシェルスクリプト+リソースを配りたい
macOS用のツールアプリケーションをインストールする方法がシェルスクリプトだった。ITエンジニア向けだったら良いんですけど、そうでない人が対象だったのでさすがにGUIが必要で、Automatorで手軽にできないかと思って調べてみました。
実行したいシェルスクリプトを用意する
シェルで実行したい内容を含めたものを、run.sh として作成します。
関連するリソースがある場合は、run.sh と同じ階層において参照できるようにしておきます。Automatorで直接シェルスクリプトを実行すると $0 が取れないが、既にファイルになっているスクリプトが実行されるので $0
も問題なく使えます。
Automatorアプリケーションを作る
Automatorで新規書類を作成するが、このときに「アプリケーション」を選びます。
次に「AppleScriptを実行」タスクを追加し、以下の内容を入力。
on run {input, parameters} set appPath to path to current application set appPOSIXPath to POSIX path of appPath set cmd to "sudo " & appPOSIXPath & "Contents/Commands/run.sh" do shell script cmd with administrator privileges end run
今回はツールインストール想定だったので管理者権限をとっています。こうしておくことで管理者権限のパスワード確認ダイアログが表示されますし、キャンセルすればそこで動作が止まります。
4行目から"sudo " &
を外して5行目からwith administrator privileges
を取れば一般権限にできます。
なお、Automator上から実行すると、Automator自体の実行パスが取れてしまうので、Automatorの実行ボタンを押しての動作確認はできません。ここまでできたら保存してAutomatorは閉じてOKです。
Automatorにコマンドを含める
保存したAutomatorアプリケーションを右クリックして「パッケージの内容を表示」します。
Contents/Commands の中に実行したい内容を含めた run.sh を入れます。
ダイアログを表示する
ユーザーに完了通知をするなどをでダイアログを表示する場合はosascriptコマンドでAppleScriptを書いて実現しますが、ユーザーセッションとは切り離されたところでコマンドが実行されてしまうので、実行しているユーザーのUIDをとってlaunchctl経由で実行する必要があります。こんな感じで関数にしておくと良いでしょう。
#!/bin/bash showDialog() { user=$(python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "\n");') uid=$(id -u "$user") launchctl asuser $uid osascript -e "display dialog \"$1\" buttons {\"OK\"}" } showDialog "hello"
コード署名をする
他のマシンで動かすにはコード署名をして、Notarizationしておく必要があります。
macOSアプリ開発相当の操作になるので、Apple Developer ProgramもしくはApple Developer Enterprise Programを契約して、Developer ID Application証明書を発行しておくことと、Xcodeのインストールが必要です。
まず、アプリのBundle Identifierを変えておくと良いと思います。「パッケージの内容を表示」して、Contents/Info.plistをXcodeで開き、CFBundleIdentifierを任意のものに変更します。
Bundle Identifierを変更したら、ターミナルでコードサインします。Automatorアプリの場合は、--deep
を付けるのがミソらしいです。
$ codesign -s "Developer ID Application: Iseteki Shinjyoushiki (XXXXXXXXXX)" \ --deep --force --timestamp -o runtime MyAutomatorApp.app
コードサインしたら、zipに圧縮します。なぜかzip -r
で圧縮するとNotarizationが失敗したので、Finderの右クリックから圧縮すると良いです。
最後に、Notary Service へ送信します。
$ xcrun altool --notarize-app \ --username <Apple ID> --password <Apple ID Password> \ --primary-bundle-id "net.iseteki.MyAutomatorApp" \ --file MyAutomatorApp.zip
ちなみに、Apple IDに複数のチームが登録されている場合は、--list-providers
で先に対象となるチームのProdiverShortNameを調べておいて、--asc-provider
引数で指定する必要があります。
$ xcrun altool --list-providers \ --username <Apple ID> --password <Apple ID Password> ProviderName ProviderShortname PublicID WWDRTeamID ------------------------- ----------------- ------------------------------------ ---------- Iseteki Shinjyoushiki XXXXXXXXXX xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx XXXXXXXXXX Shin ISE YYYYYYYYYY xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx YYYYYYYYYY $ xcrun altool --notarize-app \ --username <Apple ID> --password <Apple ID Password> \ --asc-provider XXXXXXXXXX \ --primary-bundle-id "net.iseteki.MyAutomatorApp" \ --file MyAutomatorApp.zip
しばらくすると、Notarizationの結果がApple IDのメールアドレスにメールで送られてきます。
※Notarizationについては、このブログでも過去に紹介したことがありますのであわせて読んでみてください。
iseebi.hatenablog.com iseebi.hatenablog.com
参考サイト
- Automator のシェルスクリプトで $0 を取得する - のき屋
- 【Mac】Apple Scriptのdisplay dialogの練習がてらじゃんけんアプリを作ってみる - Qiita
- 鳶嶋工房 / AppleScript / 入門 / ファイル指定を覚えよう
- User Interaction from bash Scripts – Scripting OS X
- Notarizing Automator applications | Der Flounder
- Notarization for Automator application - Apple Developer Forums
- Xcodeで実機実行する際にcode sign error resource fork, Finder information, or similar detritus not allowedで起動できない時の対処方法 – ダメ人間卒業研究所
Firestoreのフィールドにどうしても.を使いたい
Firebaseのフィールド、例えばマップのキーにメールアドレスを使いたいパターンはよくあると思う。例えばこういうの。
permissions: { "iseebi@example.com": "read", "admin@example.com": "admin" }
で、これをクエリしようとすると permissions.iseebi@example.com
のようになってしまうのだが、このままだとwhereのキーに入れることができない。
// NG firestore.collection("items") .where("permissions.iseebi@example.com", "in", ["read", "write", "admin"])
なんとかエスケープできないか、というのも試したけど、うまくいかず。
このような場合は、FieldPathを使うと良い。
// OK firestore.collection("items") .where(new firebase.firestore.FieldPath( "permissions", "iseebi@example.com"), "in", ["read", "write", "admin"])
ただ、そもそもこういうのはベストプラクティスに反するので、避けた方が良い。
参考:
Google Cloud SDK (gcloud) コマンドの設定切り替え
gcloudで取り扱うプロジェクトの切り替え方法。プロジェクト作るたびに調べてる気がするので。
続きを読む9年もののiOSアプリのプロダクト改善を1年ちょいやったのでまとめる
昨年の頭に転職して、ピリカという会社にお世話になっている*2。科学技術の力で環境問題を解決するという目標を元に、ごみ拾いSNS ピリカや、ITに限らず様々な技術を使った調査プロジェクトなどのプロダクト/プロジェクトを推進している会社だ。
ピリカとの出会いは、2011年5月のスマートフォン勉強会@関西#15。まだ立ち上がった当初に社長の小嶌さんに登壇してもらって、それ以後もFacebookで繋がっていて、途中クラウドファンディングの時に応援したり、ゆるくいいねを送りあう関係だった。前の会社で東京転勤した頃に一度お声かけしてもらって、1年後くらいに転職の機会が巡ってきて相談したところ、条件がうまくマッチしてお世話になることになった。
メインのお仕事は、ピリカSNS*3のiOSアプリ開発。正式入社からしばらくして、iOS版の開発をひとりで引き継ぐこととなった。
2011年5月にあったすまべんの頃はまだTitaniumで作られていたアプリは、gitのコミットログによると同年9月にネイティブ版の開発が開始されたらしい。ログの中にはTwitterのタイムラインで見たことがある方もいらっしゃったり、歴史の深さを感じる。
もちろんその時その時でのベスト選択をされてきたのだろうけど、時代も人も変わりながら開発が進んできていて、古いライブラリへの強い依存、新しい方式への移行が中途半端で同じ機能が複数実装されているといった状態だった。だからといって作り直しするというのは幾度となく大改築で苦労した身としては回避したかった。
幸いなことに、受託中心だったこれまでとは違い、長く継続的にアプリのプロダクトと向き合うことができるので、長期戦を見越して少しずつ改築していくことにした。
今回は、この1年でやってきた改善を紹介してみようと思う。
続きを読む