標籤:

Kivy中文編程指南:打包為 Windows 系統可執行文件

英文原文

特別注意

本文檔僅適用於1.9.1以及更新版本的 Kivy。

要打包 Windows 平台的應用程序,只能在 Windows 操作系統下完成。另外一定要注意,本文後續內容中都是在 wheels 安裝的 Kivy 下通過測試的,如果你用其他安裝方法,參考結尾部分吧。

打包出來的程序是 32 位還是 64 位只取決於你打包使用的 Python,而不取決於 Windows 操作系統的版本。

依賴包

  • 最新版本的Kivy (參考安裝指南 Installation on Windows)
  • PyInstaller 3.1或者更新的版本 (pip install --upgrade pyinstaller)。

(譯者註:PyInstaller 目前(2017年03月01日)還不支持 Python 3.6 哦~,好多朋友都坑到這裡了,所以推薦使用 3.5.2。)

PyInstaller 的基本用法

本節內容是要讓 PyInstaller(3.1或者更新版本)包含 Kivy 的 Hook(鉤子, Windows 消息處理機制的一個平台)。要覆蓋默認的 Hook ,下面的樣例代碼需要稍微修改一下。參考 覆蓋默認 Hook。

打包一個簡單的 APP

這個例子裡面,咱們要把樣例中的 touchtracer 這個項目進行打包,並且添加一個自定義圖標。這裡 Kivy 的樣例目錄要注意,如果是用 wheels 安裝的,在 pythonsharekivy-examples 這個位置,如果從 github 上面下載的,就在 kivyexamples 這個位置。為了避免混亂,這裡就用 examples-path 來指代這個目錄的完整路徑。然後 touchtracer 這個樣例在 examples-pathdemotouchtracer 這個文件夾里,代碼文件是 main.py。

1 確保 Python

打開命令行確保 Python 包含在環境變數內,也就是說,輸入 python 會出現解釋器提示符。(譯者註:cmd 或者 powershell 都可以,更推薦用後者,語法和 Bash 比較相似。)

2 創建文件夾

在要打包 APP 的位置創建一個文件夾。比如咱們這次就創建一個名字為 TouchApp 的文件夾,然後用類似 cd TouchApp 這樣的命令進入到這個新建目錄內。之後輸入:

python -m PyInstaller --name touchtracer examples-pathdemotouchtracermain.pyn

還可以增加一個 icon.ico 文件到這個應用目錄,這樣就可以讓程序有自己的圖標了。如果沒有自己的 .ico 圖標文件,可以把你的 icon.png 文件轉換成 ico,用這個 ConvertICO 在線的應用就可以了。保存 icon.ico 到 touchtracer 這個目錄裡面,然後輸入:

python -m PyInstaller --name touchtracer --icon examples-pathdemotouchtracericon.ico examples-pathdemotouchtracermain.pyn

更多其它選項,請參考 PyInstaller 官方說明。

3 編輯配置文件

在 TouchApp 裡面會有一個配置文件 touchtracer.spec。咱們需要編輯修改一下這個文件,在裡面增加一些依賴包的 hook,這樣才能保證正確創建 exe。接下來就是打開編輯器了,愛用啥都行,然後在配置文件的開頭添加上下面這句:(這裡是假設用的是 sdl2, 現在 Kivy 默認使用這個)

from kivy.deps import sdl2, glewn

然後,用搜索,找到 COLLECT() 這個位置,添加上 touchtracer 用到的其他文件(touchtracer.kv, particle.png,等等):修改示例中的行位置,添加一個 Tree() 對象,例如這裡的是 Tree(examples-pathdemotouchtracer)。這個 Tree() 會搜索在當前這個 touchtracer 文件夾的所有文件,並添加到你最終打包的程序中。

要添加額外的依賴包,就要在 COLLECT 的第一個關鍵詞參數的前面,為每一個依賴包的路徑添加一個 Tree 對象。例如下面的就是以 *[Tree(p) for p in(sdl2.dep_bins + glew.dep_bins)] 為例:

coll = COLLECT(exe, Tree(examples-pathdemotouchtracer),n a.binaries,n a.zipfiles,n a.datas,n *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],n strip=False,n upx=True,n name=touchtracer)n

4 進行構建

接下來就用 TouchApp 裡面這個 spec 配置文件來進行構建了:

python -m PyInstaller touchtracer.specn

5 生成位置

編譯好的包會在 TouchAppdisttouchtracer 這個目錄。

使用 gstreamer 創建一個視頻應用

接下來就是修改一下上面的這個樣例了,這回要打包的 APP 是一個使用了 gstreamer 的視頻應用。咱們這回用樣例中的視頻播放器的例子 videoplayer,代碼在examples-pathwidgetsvideoplayer.py。另外創建一個名字為 VideoPlayer 的文件夾,然後在命令行中進入到這個文件夾,之後操作如下:

python -m PyInstaller --name gstvideo examples-pathwidgetsvideoplayer.pyn

這回要修改 gstvideo.spec 這個文件。跟上文的方法類似,也就是把 gstreamer 的依賴包放進去:

from kivy.deps import sdl2, glew, gstreamern

然後就是增加 Tree() 來包含好要用的視頻文件,Tree(examples-pathwidgets) 和 gstreamer 依賴都得弄好,大概如下所示:

coll = COLLECT(exe, Tree(examples-pathwidgets),n a.binaries,n a.zipfiles,n a.datas,n *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins + gstreamer.dep_bins)],n strip=False,n upx=True,n name=gstvideo)n

接下來就是使用 VideoPlayer 文件夾中的這個 spec 配置文件來進行構建了:

python -m PyInstaller gstvideo.specn

然後你就能在 VideoPlayerdistgstvideo 這個位置找到 gstvideo.exe 這個文件了,運行一下就能播放視頻了。

特別注意

如果你用了 Pygame,或者你打包的程序需要 Pygame,那在你的 spec 文件裡面就還得添加如下的代碼,在 import 導入語句的後面添加(詳情參考 kivy issue #1638):

def getResource(identifier, *args, **kwargs):n if identifier == pygame_icon.tiff:n raise IOError()n return _original_getResource(identifier, *args, **kwargs)nnimport pygame.pkgdatan_original_getResource = pygame.pkgdata.getResourcenpygame.pkgdata.getResource = getResourcen

覆蓋默認 Hook

包含/移除視頻音頻以及縮小應用體積

PyInstallers 默認會將 Kivy 用到的所有核心模塊和這些模塊的依賴包,全部都添加成 hook,比如音頻,視頻,拼寫等等(然而 gstreamer 的 dll 還是需要你用 Tree() 來手動添加,參考上文)。有的 Hook 並沒有用到或者想要縮小應用的體積,就都可以嘗試著移除一些模塊,比如如果沒有用到音頻和視頻,就可以用自定義的 Hook了。

Kivy 在hookspath() 提供了可選的 Hook。

此外,當且僅當 PyInstaller 沒有默認的 hook 的時候,就必須得提供一個runtime_hooks()。 覆蓋 hook的時候,這個runtime_hooks() 不需要覆蓋。

可選自定義的hookspath() hook不包含任何 Kivy 的 provider。要添加電話,就要用get_deps_minimal() 或者 get_deps_all()來添加。可以看看相關的文檔以及pyinstaller_hooks來了解更多信息。不過get_deps_all()跟默認的 hook一樣,都是把所有 provider 都添加進去;而get_deps_minimal() 只添加在應用程序運行的時候載入了的內容。

這兩個方法都提供了一個 Kivy 隱藏導入列表,以及排除的導入,可以傳遞出來給 Analysis。

還可以生成一個自定義 hook,一個個列出每一個 kivy 的 provider 模塊,然後把其中用不上的就注釋掉就行了。

參考 pyinstaller_hooks.

要在上面的例子中使用自定義 hook,要按照下面給出的範例來修改,以hookspath() 和 runtime_hooks(必要情況下),然後是**get_deps_minimal() 或者 **get_deps_all()來制定好各種 provider。

例如,增加了導入語句 from kivy.tools.packaging.pyinstaller_hooks import get_deps_minimal, get_deps_all, hookspath,runtime_hooks ,然後按照如下方式修改Analysis:

a = Analysis([examples-pathdemotouchtracermain.py],n ...n hookspath=hookspath(),n runtime_hooks=runtime_hooks(),n ...n **get_deps_all())n

上面這個實際上跟默認 hook 一樣包含全部了。或者可以:

a = Analysis([examples-pathdemotouchtracermain.py],n ...n hookspath=hookspath(),n runtime_hooks=runtime_hooks(),n ...n **get_deps_minimal(video=None, audio=None))n

這樣就是移除了聲音視頻的 provider,這就只載入了用到的核心模塊了。

關鍵就是要提供自定義的 hookspath(),這個默認並不會列出全部的 kivy provider,而是手動的來設定隱藏導入的模塊和需要用的 provider,通過get_deps_minimal()來移除用不上的模塊 (比如上面的是聲音影像)。

其他安裝方式

前面的這些例子都用到了 *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins + gstreamer.dep_bins)], 這樣的語句來保證 PyInstaller 把所有依賴包用到的 dll 都添加進去。如果不是用 wheel 的方法安裝的 Kivy,那麼這些命令就很可能失敗,比如 kivy.deps.sdl2 可能就無法導入。這時候,你就必須得找到這些 dll 文件的位置,然後手動地一個個傳遞給 Tree 類,傳遞方法和上面說的基本差不多了。

(譯者註:Windows 平台還是推薦用 wheel 二進位安裝,省心多了。)


推薦閱讀:

Matplotlib的大新聞
基於bs4庫的HTML內容查找方法

TAG:Python | Kivy |