作成されたpython scriptをpyinstallerを用いてMacOSのアプリを作れます。
最初僕はpy2appを使用しましたが結果ファイルサイズが以下のように違いました。
- Py2appの結果:35MB
- Pyinstallerの結果:25MB
Pyinstallerを使わないわけがないでしょう。
インストールはPIPで可能になりまして。(昨年はできませんでした)
pip install pyinstaller
それで完了
pyinstallerの駆動は*.specファイルを通じてするのがお勧めです。
specファイルの基本構造は下のようです。
# -*- mode: python -*-
# filename = Main.spec
a = Analysis(['Main.py'],
pathex=['/Users/.../ProgramNameDir'],
hiddenimports=[],
hookspath=None,
runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='Main',
debug=False,
strip=None,
upx=True,
console=False , icon='mainIcon.ico')
app = BUNDLE(exe,
name='Main.app',
icon='mainIcon.ico')
この場合はmain.pyを読んでMain.appを作ります。iconはmainIcon.icoをかぶります。
Main.pyは ”/Users/.../ProgramNameDir”に存在し、その下の "./lib"のlibファイルを参考しています。なので *.specファイルが"./lib"を認識できるように少し修正します。
# -*- mode: python -*-
# filename = Main.spec
### 個人の./libsを認識するためのコード ###
import sys
myLibPath = './libs'
sys.path.append(myLibPath)
############################
a = Analysis(['Main.py'],
pathex=['/Users/.../ProgramNameDir'],
hiddenimports=[],
hookspath=None,
runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='Main',
debug=False,
strip=None,
upx=True,
console=False , icon='mainIcon.ico')
app = BUNDLE(exe,
name='Main.app',
icon='mainIcon.ico')
もう一つの問題があります。Main.pyでは /Users/.../ProgramNameDir/img内のイメージ・ファイルをつかいます。これはsys.path.appendで追加しても最終のアプリでは読めません。イメージ・ファイルをハンドリング仕組みが違うからです。
pyinstallerで作られたアプリが駆動する際、必要なファイル(イメージ・ファイルなど)は臨時フォルダ(temp folder)内「_MEIPASS」という場所でコピーします。だから*.pyコード内に「_MEIPASS」を認識させる必要があります。
Main.pyでこの関数を追加します。
def resource_path(relative):
if hasattr(sys, "_MEIPASS"):
return os.path.join(sys._MEIPASS, relative)
return os.path.join(relative)
そしてコード内のイメージ参照こどを変換します。
例え:
"./img/Title.png" --> resource_path("./img/Title.png")
*.specファイルにはTree()を追加します。
# -*- mode: python -*-
#filename = Main.spec
import sys
myLibPath = './libs'
sys.path.append(myLibPath)
a = Analysis(['Main.py'],
pathex=['/Users/.../ProgramNameDir'],
hiddenimports=[],
hookspath=None,
runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
Tree('img',prefix='img'), #<--追加するイメージがあるフォルダ名
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='Main',
debug=False,
strip=None,
upx=True,
console=False , icon='mainIcon.ico')
app = BUNDLE(exe,
name='Main.app',
icon='mainIcon.ico')
僕はMacBook proを使っています。即ちRetina Displayを使っています。pyinstallerで作られたアプリをそのまま作るとRetina Displayの上にはメッセージ・ボックスとかダイアログが滲んで見えるので醜いです。
それを解決するためBUNDLEにinfo_plistを追加します。
# -*- mode: python -*-
#filename = Main.spec
import sys
myLibPath = './libs'
sys.path.append(myLibPath)
a = Analysis(['Main.py'],
pathex=['/Users/.../ProgramNameDir'],
hiddenimports=[],
hookspath=None,
runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
Tree('img',prefix='img'),
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='Main',
debug=False,
strip=None,
upx=True,
console=False , icon='mainIcon.ico')
app = BUNDLE(exe,
name='Main.app',
info_plist={ 'NSHighResolutionCapable': 'True'}, #<-- Option for High Resolution
icon='mainIcon.ico')
これで大体におわりです。
pyinstaller Main.spec
でアプリができます。
py2exeとかpy2appの場合は事例がずいぶんあるけどpyinstallerの場合はあんまりないので整理のため記録しました。