Packaging kivy applications can be quite daunting. The documentation can be pretty confusing at times. This guide will walk you through how to package a kivyMD application for windows using pyinstaller through the use of an simple example.
Let's get right into it!🙂
I assume that you already have kivy and kivyMD installed in a virtual environment.
The first step is to install pyinstaller with pip. Open up the command prompt terminal, activate your virtual environment and type in the following:
pip install pyinstaller
Create two files:
-
main.py
- which is going to contain the main code. -
main.kv
- which is going to contain the code written in kivy lang
Note: These files should be in the same directory.
Inside main.py
, enter the following code:
import os, sys
from kivy.resources import resource_add_path, resource_find
from kivymd.app import MDApp
class MainApp(MDApp):
def build(self):
self.theme_cls.primary_palette = "DeepPurple"
if __name__ == '__main__':
try:
if hasattr(sys, '_MEIPASS'):
resource_add_path(os.path.join(sys._MEIPASS))
app = MainApp()
app.run()
except Exception as e:
print(e)
input("Press enter.")
The above code is very crucial when it comes to packaging our application. The try-catch statement helps us identify errors in our program and the input("Press enter.")
stops the console from closing before we want it to.
Edit main.kv
:
MDRectangleFlatButton:
text: "Hello World"
pos_hint: {'center_x': .5, 'center_y': .5}
We are just going to display a simple button.
Save the files then open the command prompt terminal, activate your environment and navigate to the folder containing the two files.
Now, before you even start the packaging process, make sure when you run your application you are not getting any console errors.
Type pyinstaller --onefile main.py
in command prompt and press enter.
When execution is complete, two folders should have been created in the directory containing main.py
; dist
and build
and a file named main.spec
.
Navigate into the dist
folder. Inside it, there is an executable file, main.exe
. If you double click it, a terminal will open and close very quickly.
To solve this issue, add the following lines to the top of main.spec
:
from kivy_deps import sdl2, glew
from kivymd import hooks_path as kivymd_hooks_path
Note: If you are not packaging a kivyMD application, there is no need for the second import or modifying hookspath
as shown shortly below.
Add in Analysis
the lines:
a = Analysis(
#...
datas=[('main.kv', '.')],
hookspath=[kivymd_hooks_path],
#...
)
datas
is made up of a list of tuples where the first item in the tuple is the file name and the second item is the directory that is going to be used to store the file. If for example, you had a folder named images in the same directory as main.py
, you would add them as follows:
datas=[('main.kv', '.'), ('./images/*.png', 'images')],
The above line is basically saying, 'Get all the png images in the images folder and save them to a folder named images in the final application.'
Next, edit EXE
:
exe = EXE(
#...
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
#....
)
The final main.spec file looks like this:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
from kivy_deps import sdl2, glew
from kivymd import hooks_path as kivymd_hooks_path
a = Analysis(['main.py'],
pathex=['C:\\Users\\path\\to\\file'],
binaries=[],
datas=[('main.kv', '.')],
hiddenimports=[],
hookspath=[kivymd_hooks_path],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True )
Now save and run: pyinstaller main.spec
in the terminal.
After it has finished executing, try executing main.exe
again.
And that's it! You have successfully packaged your application.
Errors you may encounter
You may encounter import errors when running pyinstaller. I encountered errors importing pyenchant and cv2. These can easily be fixed by running the following commands in your terminal:
pip install pyenchant
pip install opencv-python
After the installation is complete, run pyinstaller main.spec
in your terminal and try executing the main.exe
again.
Final thoughts
I hope this guide can prove useful to you. It is by no means a complete guide covering all the aspects of packaging kivy application for windows but I hope you can learn something from it.
For more information, check out:
- This post on stackoverflow.
- Kivy documentation.
- Pyinstaller
Top comments (20)
i get an error if i do console= false
Error:
Hi,
If you are using pyinstaller 5.7.0, try building your app with version 5.6.2
Doesn't work... wich Versions should i Take from kivymd or kivy?
I'm using kivy==2.1.0 and kivymd==1.1.1.
Did you try running it with
--noconsole
?That is,
pyinstaller --onefile --noconsole main.py
Yes, that is the problem. With console it worked, but without console It doesn't.
Please share your spec file
The Standard Hook from the KIVYMD webside,
i think i must Import hidden modules, but i don't know how i do it correctly...
`# -- mode: python ; coding: utf-8 --
import sys
import os
from kivy_deps import sdl2, glew
from kivymd import hooks_path as kivymd_hooks_path
path = os.path.abspath("E:\Programmieren\Python\KivyMD\CreateApp")
a = Analysis(
["main.py"],
pathex=[path],
hookspath=[kivymd_hooks_path],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=None,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=None)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
debug=False,
strip=False,
upx=True,
name="Main",
console=False,
)`
I used your spec file and it built the app successfully. I faced the same issue before and solved it by simply changing the version of pyinstaller I was using to version 5.6.2.
Are getting that error from building the app in this tutorial or your own application?
i did it with pyinstaller==5.6.2 and it worked!! thank you so much!!!!
You're welcome. Glad it worked
Greetings, I am currently attempting to transform my python code into an APK, however, after converting it and installing the file, it unfortunately crashes right after the kivy logo appears. I am using google collab to convert my code into APK.
![Image description](https://res.cloudinary.com/practicaldev/image/fetch/s--cWJvormW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/84yavuffoq3mozk0x6b7.png)
Spec file
main.py
The problem you're experiencing might be due to a number of reasons, including missing dependencies, issues with your
buildozer.spec
file, or problems with the build process itself.Here are a few steps you can follow to help debug and solve the problem:
Check the Logs: After running the application and it crashes, check the logs for any error messages. On an Android device, you can view the logs by connecting the device to your computer and running
adb logcat
in a terminal. This should provide some information about why the application is crashing.Check the
Buildozer.spec
File: Ensure that all necessary requirements are mentioned in thebuildozer.spec
file. You can use the requirements field in the spec file to specify all Python modules that your app depends on.Permissions: Some functionalities might require certain permissions to be set in the
buildozer.spec
file. If your app is trying to access a feature it does not have permission for, it could cause the app to crash.Resource Files: If your application uses any resources such as images, audio files, etc., make sure that these files are being included in the APK. In your
buildozer.spec
file, thesource.include_exts
option can be used to specify the file types to include in the package.Python Version: Make sure you're using a Python version that's compatible with KivyMD.
Share the log with the errors showing, it will be helpful to debug!
That's completely nice and worked for me. thank you very much.
The question is why the above solution is not in pyinstaller by default?
You're welcome. Glad it worked for you!
Hi, your code did help me. Thank you. But can you please show me how to include a text file or a JSON file as a database. I wanna make a kivy desktop application in onefile. It's giving me error. Please help me out.
Hi,
So the best I can do is give you an example using json. You'll need two file,
main.py
andmain.kv
. I'm going to be using code from this article to demonstrate.main.kv
remains the same as in the article but inmain.py
I am going to add code to save and extract data from a json file so in the end it will look like this:When you add an item, it will be added to the listbox and saved to the json file as well. When you start the app, data is loaded from the json file and added to the listbox.
Hope that helps.
Hi, when I run pyinstaller --onefile main.py with your example, I get an empty dist folder with no executable file in it. I have python==3.10.8, kivy==2.1.0, kivymd==1.1.1.
I even tried changing pyinstaller version to 5.6.2 and the hello world program runs normally.
I am not sure how to proceed from here.
Thanks, it worked!
thanks bro it worked for me
for linux:
just skip the
kivy_deps import ..
and*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
steps