Android Kivy JsonStore data.json does not persist across upgrades - android

I'm using the JsonStore with a Kivy app
from kivy.storage.jsonstore import JsonStore
stored_data = JsonStore('data.json')
On my PC, the store is preserved even if I rebuild the program.
On my android phone, reloading the same apk file keeps the data, but any change to the program (and rebuild) seems to wipe the stored data.
Am I doing something wrong, how can I keep the data through upgrades?

That's because you write your files to the folder where your app is located. You should write them to /sdcard and also give the write permissions:
from jnius import autoclass
from android.permissions import request_permissions, Permission
...
# request a permission from user
request_permissions([Permission.WRITE_EXTERNAL_STORAGE, Permission.READ_EXTERNAL_STORAGE])
...
# path to sdcard (external storage that user have access to)
Environment = autoclass('android.os.Environment')
sdpath = Environment.getExternalStorageDirectory().getAbsolutePath()
So, after that you can make your folder there, something like:
if not os.path.exists(sdpath + '/yourappname'):
os.makedirs(sdpath + '/yourappname')
And save your files there, they won't be deleted while reinstalling the app anymore.
P.S. don't forget to add pyjnius to requirements in the buildozer spec file!

Related

Can't create directory in Android with apk created with with Python/Kivy and Buildozer in Colab

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,...

APK made by buildozer not making CSV file on android mobile

I made an APK with the help of KivyApp. APK generated successfully and my APK also runs on my mobile. The problem is that I didn't give any specific path for the CSV file, which stored the output generated by the app. Initially, I run python code in the pydroid3 app and it automatically generated the CSV file at the same location, where my code was stored. My question is if I want to store the data in the internal storage of my mobile, what path should I enter?
import csv
csvfile = "Discrete_pos.csv"
with open(csvfile, "a") as fp:
wr = csv.writer(fp, dialect='excel')
wr.writerow(csvRow)
Well, I suppose you mean the path of External Storage (which can be accessed by any app, one you see in your mobile file explorer) As it's already storing in your internal storage path. Now to access external storage there are 2 methods. But first of all you need storage permission for that. To get storage permission use the following code:
from android.permissions import request_permissions, Permission
request_permissions([Permission.WRITE_EXTERNAL_STORAGE, Permission.READ_EXTERNAL_STORAGE])
Now after you have access to external storage you can use the following code to get external storage path:
from android.storage import primary_external_storage_path
external_storage = primary_external_storage_path()
Sometimes this doesn't work on some android devices so if you are getting that issue then you can also use os.getenv:
external_storage = os.getenv('EXTERNAL_STORAGE')
Also, don't forget to write READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE in the permissions of your buildozer.spec file

Kivy - get the path to DCIM folder on any android device

I would like to know exactly how to get the path to the DCIM folder on android using just Kivy.
PyJinus is not an option as it currently doesn't work with Python 3.5
What i tried so far is:
DATA_FOLDER = os.getenv('EXTERNAL_STORAGE') if platform is 'android' else os.path.expanduser("~")
But this will only get me the user area. Any ideas?
Use user_data_dir and go up if you intend to use the sdcard as a storage for your app (the usage of user_data_dir variable creates a folder):
from kivy.app import user_data_dir
from os.path import dirname, join
join(dirname(user_data_dir), 'DCIM')
or just use its code directly:
DCIM = join('/sdcard', 'DCIM')
I think /sdcard is only a symlink to the real folder (wherever it is), so a usage of this path just gets the value when accessed e.g. to /storage/sdcard0 (symlink) or rather directly to the real path.
Except those solutions, android has the path in the environment as you've noticed in:
EXTERNAL_STORAGE (/storage/emulated/legacy) again symlink to sdcard
SECONDARY_STORAGE (/storage/extSdCard) i.e. for the external card if you store photos there
EMULATED_STORAGE_TARGET (/storage/emulated) basically a parent folder for your sdcard, where the real sdcard (for me) is in /storage/extSdCard/emulated/0
use this path PATH for where you have to save your file. I would like this way to access android storage.
First, import platform from kivy.utils
from kivy.utils import platform
Second, use this banch of code to get the path of DCIM
PATH = '.'
if platform == 'android':
from android.permissions import request_permissions, Permission
request_permissions([Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE])
app_folder = os.path.dirname(os.path.abspath(__file__))
PATH = "/storage/emulated/0/DCIM"

Why can't I create a file on android using python

I can't run my python program on my android device using qpython3.
The first step in he program is to create a text file to save data to it. But I get an I/O error (file system read only)
This is the function used to create / or be sure that the file exists easily.
def filecreate(file): # creates the text file
f = open(file, 'a')
print('file created successfully\n')
print()
f.close()
How to overcome this problem in android ?
QPython by default runs your programs from the root directory which is not writable by non-root users. If you check the ftp utility (under About menu) you will find the name of the directory that is writable by QPython. On my HTC it is:
/storage/emulated/0/com.hipipal.qpyplus
So you need to do something along the lines of:
RootPath='/storage/emulated/0/com.hipipal.qpyplus'
...
import os
f = open(file, os.path.join(RootPath,'a'))
...
Example of a similar problem with QPython and SQLite3
Just create the file with QPython before use in your script.
You can create an txt file with QPython.
In My case I create the file whith name "pontoText.txt"
Inside folder "MyPythonScripts" (Im create that folder to put my python files)
so the file is in the same folder of the script and are created in QPython
Now an example code im make ton test:
import time
import os
a = input("1 to save date on file or 2 too see records on file. ")
folder= '/storage/emulated/0/MyPythonScripts'
if(a == "1"):
pontoTxt=open(os.path.join(folder,'pontoText.txt'),'w')
pontoTxt.write(time.strftime("%I %M %p on %A, %B %e, %Y"))
if(a == "2"):
pontoTxt=open(os.path.join(folder,'pontoText.txt'),'r')
exibe = pontoTxt.read()
print(exibe)
Your app may not have required permission to manage that file. Check your manifest, specify Android version and file path. Check documentation: http://developer.android.com/training/basics/data-storage/files.html
You have to actually find the file path, as it doesn't infer the directory that the file is in as the destination directory, unlike in Python on the PC.
Use what they're changed.
The file you have is inside /accounts/mastercard root and the file you're inside is /accounts/main.py you only need to use is this
/mastercard/xxxxx like my code
from django.shortcuts import render
from django.http import HttpResponse
from . import models
# Create your views here.
def index(request):
return render(request,"mastercard/Templates/mastercard/Base.html")
def about(request):
return render(request,"mastercard/Templates/mastercard/index.html")

Running Py4A script from external SD card?

I need to run the Python script from external SD card, which in the target device is mounted as /mnt/sdcard/_ExternalSD.
I've succeeded to accomplish that in a quick&dirty way by preparing the "proxy" script ExtSDRun.py in the standard SL4A scripts directory, which in case of my target device is /mnt/sdcard/sl4a/scripts
import android
droid = android.Android()
import os
import sys
# Add directory with the scripts to the Python path
sys.path.append("/mnt/sdcard/_ExternalSD/scripts")
# Start the script located in the external SD card
# in the script_to_run.py file
import script_to_run
# You can also do:
# from script_to_run import *
Is there any better and more elegant way to achieve this goal?
I'm pretty sure you can run a script from an external SD card. Try this. It's a simple Python function that launches any script SL4A has an installed interpreter for, given an arbitrary path to the script. I don't have an external card to test it on, but see no reason for it to fail.
Short answer: you can't. A better way to do what you're doing is to put a main function is script_to_run. i.e. if script_to_run contained this:
import sys
sys.stdout.write('Hi!\n') #Technically I should use print, but I'm trying
#to make the program longer.
you'd do this:
import sys
def main():
sys.stdout.write('Hi!\n')
Then, when you import it, use:
import script_to_run
script_to_run.main() #This is what runs the script
Also, see https://stackoverflow.com/a/4463726/2097780. I wouldn't recommend doing that, but it might be an option if you can't call main the other way.
Good luck!

Categories

Resources