hacomono TECH BLOG

フィットネスクラブやスクールなどの顧客管理・予約・決済を行う、業界特化型SaaS「hacomono」を提供する会社のテックブログです!

PythonでMacアプリつくってみた


はじめに


こんにちは、IoTチームの組み込みソフトウェアエンジニアのとりーです。

1年に1回くらいカッとなってなにか作ったりするのですが、先日は某ゲームに出てくるロボットをつくりました。
画用紙とマスキングテープと水糊で作ったのですが、紙に水糊はだめですね…

水糊でひっつけたところがたわんでしまいました。
3Dプリンタがほしい、かも。


さて今回はまたまたツールアプリについて書こうと思います。

PythonでMacアプリをつくる


これまでは非エンジニア向けのアプリを作る場合、Xcodeを使ってMacアプリをつくっていました。

が、今回は事情がちょっと違うところがありまして。

具体的には下記のような感じです。

  • これまで:非エンジニア向けにアプリを1 からつくる
  • 今回:すでにエンジニア向けの Python コードがあり、それを非エンジニアでも触れるようにアプリ化する。

最初は脳死で Xcode でつくるか!と思ったのですが、

  • すでにPythonであるものをもう一度Xcodeで作り直すのが面倒
  • もし修正が入れば両方に手を入れないといけなくなるので嫌
  • Pythonの資産は使いたい
  • そういえばPythonのGUIアプリ作ったことないので良い機会では

という4点で Python でアプリをつくることにしました。


どのツールを使おうか


まずは Python 標準ライブラリである Tkinter を使ってみました。

まずはサンプルアプリを使って、どんな感じのものかを確認してみたのですが、なんだかうまく表示されない…

ぐぐってみたところ、MacOSで Tkinter8.5系は表示バグの致命的欠陥があるそうな。

>>> tkinter.Tcl().eval('info patchlevel')
'8.5.9'

うーん。

特に Tkinterにこだわりもなかったので、早速諦めて別のツールに。
(ちょっと前に試してたのですが詳細をメモしておらず、どこがうまく表示されなかったのかは忘れちゃいました。ごめんなさい。)

次は PyQt を使ってみることにしました。
ガッツリつかったことはないですが、他の人がつくったものを少し触ったことがあったので「とっつきやすいかも?」と思ったことが主な理由です。

こちらはサンプルアプリをつくったところ、表示・ボタンアクションなど一通り意図通りに動くことを確認できました。やったぜ。

以降はアプリを粛々と作成。
詳細は割愛しますが、かなり直感的に実装できました。
iOS や MacOS 開発で得た GUI まわりのノウハウを割とそのまま流用できたような気がします。

ただ今回は大したアプリではないので、ひたすら画面パーツを作って上から順に配置して終わりという感じになりました…😂

画面パーツをつくる

        self.title_style = 'color:#4169e1;font-size: 15pt;;'

        self.label_aaa = QLabel('XXXXXXX')
        self.label_aaa.setStyleSheet(self.title_style)
        self.qle_bbb = QLineEdit(placeholderText='アクセスキーを入力')
        self.qle_ccc = QLineEdit(placeholderText='シークレットキーを入力')
        (略)

ひたすら上から順に配置

        layout = QVBoxLayout()
        layout.addWidget(self.label_aaa)
        layout.addWidget(self.qle_bbb)
        layout.addWidget(self.qle_ccc)
        layout.addWidget(QLabel()) # スペース確保用                                                                                                                                        
        layout.addWidget(self.label_ddd)
        layout.addWidget(self.qle_eee)
        layout.addWidget(QLabel()) # スペース確保用                                                                                                                                        
        layout.addWidget(self.label_fff)
        layout.addWidget(self.qle_ggg)
        layout.addWidget(self.btn_hhh)
        layout.addWidget(self.label_iii)
        layout.addWidget(self.qte_jjj)
        layout.addStretch()
        self.setGeometry(200, 200, 600, 400)

        self.setLayout(layout)

できたアプリ

配布するためにアプリ化する


アプリができたぞ!ということで、次は配布するためにアプリ化をしました。
主にやったことは 2 つです。

  1. Python のパッケージを venv を使って管理する
  2. アプリ化する

1 については特に変わったこともなく、つまずきもなかったので割愛します。
2 について 2 点ほどはまったので、そちらについて記載したいと思います。


はまったこと、その①


アプリ化には pyinstaller を使いました。
使い方を調べていると  --onefile というオプションで 1 つのファイルにまとめられるようです。

さっそく指定してみたのですが、1 つ問題が…

このアプリの仕様として、テキストフィールドに入力した情報を保持しておき、次回起動時に反映した状態で表示したい、というのがあります。
しかし、1 つのファイルにまとめているとどうにもそれがうまく動かないようです。
1 つのバイナリファイルになっちゃってるんだし、そりゃそうかという気もします。

--onefile をつけないと期待通りの動作をしたので、今回は 1 ファイル化はあきらめました。


はまったこと、その②


いざ配布用のアプリができたぞ!ということで、チームメンバーに協力いただき実際に動かしてもらうことにしました。

が、下記のようなメッセージが出て動かない。

はじめてみるメッセージです。

インターネット経由でダウンロードしたので、セキュリティ的に実行不可になっているのか?と設定アプリから確認しましたが、問題ありません。

困り果てていたところ、情シスのえんどぅーから「拡張ファイル属性では…?」と神のアドバイスが。

結論、拡張ファイル属性でした。
下記コマンドで拡張ファイル属性を消したら無事動きました。

% xattr -cr ./

えんどぅーありがとう!!

拡張ファイル属性とは…?となった方へ。

簡単に説明すると、Chromeなどを使ってファイルをダウンロードすると MacOSがいろいろ情報を付与してくれます。
それが悪さをしてアプリを実行できなかったようです。

こちら↓のリンク先を参考にさせていただきました。 qiita.com


おわりに


はじめて PyQt でアプリを作りましたが、ボタンなどのアクション部分や Layer の概念など良く出来てるなぁと思いました。
(わたしがあまり知ってないだけで当たり前なのかもしれませんが…)

もっと触ってみたいなと思いつつ、やはり実行環境を選ばないツールを作ろうと思うと、次トライするなら Web アプリかなと思ってます。

組み込み屋さんなので Web アプリはほぼさわったことがないのですが、社内ツールだし!動けばいいし!というところで、なんとか頑張ってみたいと思います。


株式会社hacomonoでは一緒に働く仲間を募集しています。
採用情報や採用ウィッシュリストもぜひご覧ください!