I've created a prototype application for Android using kivy. It has compiled in buildozer and I've uploaded in to an Android device.
But I'm nor sure where to put app dependent files like the ini file, images database etc.
Any help greatly appreciated
[EDIT 2020 07 25]
When I asked this question (many moons ago) I was new to kivy and the whole idea of buildozer.
What I didn't realise and what isn't obvious to a beginner (witness the number of times this question has been viewed) and which #inclement's answer does not address, is that Buildozer wraps the whole python/kivy project into a single file which can include all of your static data. So you just need to make sure your buildozer spec picks them up.
You can arrange them to taste - as long as you tell buildozer to include them apk (i.e. by setting the file types, directories etc to be included) and access them with relative paths in your code, they will work the same way on the device.
The ini file may be an exception, I'm not sure offhand where kivy tries to load it from (but it may be somewhere in the external data dir). If putting it in the same directory as main.py doesn't work, maybe you could load it manually with a relative path, or if it has just a few values then you could set them in the main.py file.
It worked while I was using the pygame module, I haven't tried it with other modules, but maybe it works.
Folder where buildozer pulls files:
/data/data/package domain.package name /files/app/"
Example
buildozer.spec:
title = application
package.name = myapp
package.domain = org.test
main.py:
import os , sys
import pygame
path = "/data/data/org.test.myapp/files/app"
image = pygame.image.load(path+"image.jpg")
This command line does not work without converting to apk but it works fine when translated
The folder path will only be valid when running on android but... ----->
maybe this will help: ---->
https://youtu.be/XQTIllli6js
and this:
https://github.com/Sahil-pixel/Pygame-for-android/tree/main
Related
I have a quiz app with:
Video assets (over 1000 files, 750 MB) that can be downloaded using the download_assets package.
Image assets (also over 1000 files, 80 MB), bundled and deployed with the app.
Filenames are stored in a sqlite database.
I'm using Android Studio, macOS.
I wrote a function that takes filenames from a database and checks which files are on a device.
As it turned out, several of the video files are unavailable on Android devices (although they are visible in Device File Explorer). On iOS devices everything is OK.
Also some images are not available, but here on both iOS and Android devices.
I wrote Python script:
import os
import chardet
dir = '/path/to/directory/with/assets'
for n in os.listdir(dir):
if (chardet.detect(os.fsencode(n))['encoding'] != 'ascii'):
print ('{} => {} (confidence: {})'.format(n, chardet.detect(os.fsencode(n))['encoding'], chardet.detect(os.fsencode(n))['confidence']))
All files that work are encoded in ascii, the rest looks like this:
pięć5.mp4 => utf-8 (confidence: 0.7525)
JAZDA NOCĄorg.mp4 => ISO-8859-1 (confidence: 0.73)
Rowerzystę W17_2.mp4 => utf-8 (confidence: 0.505)
I tried renaming files in terminal. Then I tried to use the convmv utility. When I prepared a zip in terminal with only these 3 files it worked, but when I created a full archive, it turned out that two other files that worked fine before (and which had non-Latin characters in the name) stopped loading.
My final solution: I packed the two problem files in Finder (like the first archive). Then I added the rest of the files to the archive in the terminal:
zip assets.zip *.mp4
Now all video files load on both Android and iOS devices. But why?
I also solved the problem with the image files. I tried with mv and conmv in the terminal of course. I think it worked with at least one file (I'm not sure because I was in the dark and don't know what finally worked). I got stuck with a few files and that's when I found this link.
I used the Refactor->Rename option in Android Studio. I renamed the files to those that did not contain non-Latin characters (e.g. 313D12_a_org_światło.jpg to 313D12_a_org_swiatlo.jpg). I restarted the application. Then I renamed the files in Android Studio to the old ones. After restart all the files worked.
I am writing all this for two reasons:
Maybe someone will have similar problems and this description will be useful to him.
I am very curious what is causing this behavior. Especially, why files extracted from a zip will behave differently depending on how the zip is prepared and on which device it is used (Android or iOS).
I'm deeply sorry as I am not a professioanl programmer but I have my own simple application for Android, a-la "Hello world" that stopped working.
It used to work for half a year but when I came back to it to create new apk-file the application stopped working.
During troubleshooting process I found out that my application can't create directory in Android phone:
os.mkdir('/storage/emulated/0/MK_Eng')
The path is correct. Permissions are granted. All modules are imported. And it used to work!
I've lost several days to make it work again - unsuccessfully... Need your help! Thank you!
Here is an excerpt:
import os
if kivy.platform == 'win':
dirname='C:/MK_Eng/'
filename='C:/MK_Eng/eng-rus-new.txt'
elif kivy.platform == 'android':
from android.permissions import request_permissions, Permission
from android.storage import primary_external_storage_path
request_permissions([Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE])
dir = primary_external_storage_path()
dirname = os.path.join(dir, 'MK_Eng')
filename='/storage/emulated/0/MK_Eng/eng-rus-new.txt'
if not os.path.isdir(dirname):
# Create Directory
os.mkdir(dirname)
I tried to adjust some buildozer settings but still no luck.
#(list) Source files to include (let empty to include all the files)
source.include_exts = py,png,jpg,kv,atlas,txt
#(list) Application requirements
#comma separated e.g. requirements = sqlite3,kivy
requirements = python3,kivy,android.permissions
#(list) Permissions
android.permissions = INTERNET,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE
#(str) python-for-android branch to use, defaults to master
p4a.branch = develop
Yes on Android 11+ devices an app cannot create files and directories in root of external storage as you try to do.
Instead use one of the many public directories that are already there.
Like DCIM, Pictures, Documents, Download,...
I want write simple application in Python for Android using kivy. Sadly when I start example code I see only splash screen and few second later application finish work. There is a huge problem with debugging because adb on Linux Mint does not detect my device.
Can someone look at my code and tell my why?
To build application I use buildozer. You can also see create_env script to check all dependencies are there.
Best regards.
Draqun
EDIT:
I started debugging my application. Conclusion:
buildozer + python3 + kivy is a bad idea
if I use kivy.uix.button.Button when text attribute is str than I got exception "AttributeError: 'str' object has no attribute 'decode'"
if I use kivy.uix.button.Button when text attribute is bytes than I got exception "ValueError: Button.text accept only str"
It looks like loop with no solution. Some idea when I should report it?
Exception is in .buildozer/android/platform/build/build/python-installs/pad/android/init.py" file so it does not look like kivy and/or buildozer exception.
I've used python-for android tool and faced with the same errors. But in my case, app didn't run at all - crashed from splash screen. Finally, I've found a solution. You can try the same way.
So my pipeline was python3 + python-for-android (p4a tool, python-for-android, from master branch) + kivy (1.10.1)
There is a file "_android.pyx" for android building recipe (full list of avaliable p4a recipes you can see by command p4a recipes). This file is, possibly, used by Buildozer, and exactly used by P4A during APK building procedure. You need to fix it.
You may find it's location in Ubuntu (for example) via:
sudo updatedb
locate _android.pyx
It's path should be something like:
~/.local/lib/python3.6/site-packages/pythonforandroid/recipes/android/src/android/_android.pyx
There should be a string:
python_act = autoclass(JAVA_NAMESPACE.decode('utf-8') + u'.PythonActivity')
so you should change it - something like this:
python_act = autoclass(str(JAVA_NAMESPACE) + u'.PythonActivity'),
or just use some hardcode:
python_act = autoclass("org/kivy/android/PythonActivity")
Or there might be the other decode() usage in sources.
The reason: differences between Python2 and Python3 - the decode() method is usable on the equivalent binary data type in either Python 2 or 3, but it can’t be used by the textual data type consistently between Python 2 and 3 because str in Python 3 doesn’t have the method decode function has different realisation in Python3. More details are here:
pyporting features
issues p4a's github
Hope, it will help you somehow.
So I use chaquopy to get simple python programs functioning in an old (jelly bean) tablet (I replace the example console app's main.py in the src directory). Not bad for a beginner's start and I'm very happy.
But now for a test I try to display a matplotlib graph like this:
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
def main():
image = mpimg.imread("/storage/emulated/0/Documents/test.png")
plt.imshow(image)
plt.show()
The matplotlib library was installed from within android studio (albeit with a few missing elements, manual pip3 install and usage of local files). Now the build and program finish without errors, but there is no graph. Installation of pillow and use of other graph types no avail.
Can this be handled in python, or is a dive into android studio / java required?
Thanks for any advice
You'll have to include an ImageView in your app's layout, and then load the image file into it, as in this answer.
For an image which is generated dynamically by matplotlib, either save it to a file and then load from that file, or save it to a bytes object like this:
import io
bio = io.BytesIO()
plt.savefig(bio, format="png")
b = bio.getvalue()
... and then load that bytes object into the ImageView like in this app.
is there someone who has experience with pyqtdeploy and adding external modules? I am currently using pyqtdeploy (version 1.2) together with PyQt 5.5.1 to write an application that can be deployed to an Android device. Without any external modules, the freezing with pyqtdeploy works pretty well. However, I am not really sure how I can add external modules (not pure Python ones) to my application.
In particular, I want to add the external module pycrypto. Therefore, I downloaded the pycrypto sourcecode, compiled it with the Android toolchain (from the Android NDK) and now I have a bunch of *.py and *.so files. How can I add them to my application?
My initial attempt was to add the *.py and the *.so files (so basically the whole pycrypto module) to the "Other Packages" tab in pyqtdeploy.
But now, when I import something pycrypto related in my application (from Crypto.Cipher import AES) i get the following error message:
File: ":/Crypto/Cipher/_AES.py", line 20 in __bootstrap__
TypeError: 'NoneType' object is not callable
The _AES.py file where the error is thrown, looks like this:
def __bootstrap__():
global __bootstrap__, __loader__, __file__
import sys, pkgutil, imp
__file__ = pkgutil.get_data(__name__,'_AES.cpython-34m.so')
__loader__ = None; del __bootstrap__, __loader__
imp.load_dynamic(__name__,__file__)
__bootstrap__()
At first I thought, that the *.so filename was just wrong and therefore, I got the NoneType Error, so I changed the filename in _AES.py to something other like 'test.so'. Surprisingly, now, I get a different error message than before:
File ":/pkgutil.py" line 629, in get_data
ImportError: qrcimporter: error opening file :/Crypto/Cipher/test.so
Ok, so the filename should be fine, right? But why do i get the 'NoneType` error message? What am I doing wrong? Is this the right way to accomplish this?
Any help is highly appreciated. I am pretty sure, that i'm only one small step away from getting this thing to work, but I can't figure out what i'm doing wrong.
Thanks!