Android not finding .ini file

1,167 views
Skip to first unread message

Garrett Armstrong

unread,
Feb 11, 2015, 6:07:25 PM2/11/15
to kivy-...@googlegroups.com
A thumbnail of my app design is below for your reference.  The app works fine in linux, but fails in android.  

Specifically, the android app seems unable to find the myapp.ini.  I can see a file at /mnt/sdcard/.myapp.ini with all the correct config data.  It updates when you change the settings in the settings window - so kivy is writing to it.  However, i need to read from it, and cannot.  Specifically, the layout_x(RelativeLayout) needs to read it (cause it destroys its children, reads the config file, then recreates the appropriate children as instructed by the current config).  All this works in the linux OS -- linux makes as myapp.ini file in the project folder with the correct data & can read & write it.  In Android, the app can't seem to find the myapp.ini file (even when i point it to /mnt/sdcard/.myapp.ini specifically.)  

How do i read data from a ConfigParser()  myapp.ini file?

Any advice is welcome,
garrett


_______________________________________________________________________________

# File name: main.py
import kivy
kivy.require('1.8.0')

from kivy.app import App
from kivy.lang import Builder
from kivy.config import ConfigParser
from settingsjson import general_settings_json, fund_settings_json, melody_settings_json

from file_x import Layout_x

class myApp(App):
def build(self):
self.title = "MyApp"
self.use_kivy_settings = False
config = self.config
return RootWidget()

        def build_config(self, config):
config.setdefaults('Group1', {
'setting1': 1,
                        'setting2': 1})
config.setdefaults('Group2', {
'setting1': 1})

def build_settings(self, settings):
settings.add_json_panel('Group1', self.config, data=group1_settings_json)
settings.add_json_panel('Group2', self.config, data=group2_settings_json)

if __name__ == '__main__':
NoteGameApp().run()
_______________________________________________________________________

# File name: notegame.kv
#:kivy 1.8.0

<RootWidget>:
Layout_x:

_______________________________________________________________________

# File name: file_x.py
import kivy
import os
kivy.require('1.8.0')

from kivy.uix.relativelayout import RelativeLayout
from kivy.utils import platform

class Layout_x(RelativeLayout):
def __init__(self, **kwargs):
super(Layout_x, self).__init__(**kwargs)
                self.get_config_variables()
                self.redraw_layout()

def get_config_variables(self):
if platform=="android":
with open('mnt/sdcard/.myapp.ini', 'r') as g:                      # crashes as no file found
                              print type(g), dir(g)                                                      # (i'm trying different ways to get to myapp.ini                                               
settings = ConfigParser()
settings.read('mnt/sdcard/.myapp.ini' )
self.scale = settings.get('Group1', 'setting1')                      # if 'with open(...)... commented out, crashes as 
self.key = settings.get('Group1', 'setting2')                         # no Group 1 in settings
self.settings_list = settings.items('Groups2)
else:
settings = ConfigParser()                                                   # on linux, this command works
settings.read('notegame.ini')
print 'settings is:', dir(settings)
self.scale = settings.get('Group1', 'setting1')

        (... layout details ...)

Andrei Sima

unread,
Feb 12, 2015, 5:22:54 AM2/12/15
to kivy-...@googlegroups.com
When you 'compiled' the apk (with buildozer i guess) did you put the proper permissions there (line 49 - 50 )?

49  # (list) Permissions
50 android.permissions = INTERNET, SECOND_PERMISION, THIRD_PERMISION, etc

i think you need "WRITE_EXTERNAL_STORAGE"

Usually the app is force closed by android OS if she tries do do something that has no permission to do. I think this is a security issue.




--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

______________
random life

Andrei Sima

unread,
Feb 12, 2015, 5:25:01 AM2/12/15
to kivy-...@googlegroups.com
And also use log cat to see where and why your app is crashing. usually there is a good point to start debugging your app.

Sorry fot double post, i can not find the edit button :) 
--

______________
random life

Garrett Armstrong

unread,
Feb 12, 2015, 11:29:23 AM2/12/15
to kivy-...@googlegroups.com
The relevant adb logcat line is:  

I/python  (30919):    File "/home/user/Desktop/KivyProjects/myapp/myapp_step18_fixing_config/.buildozer/android/app/file_x.py", line 32, in get_config_variables
I/python  (30919):  IOError: [Errno 2] No such file or directory: 'mnt/sdcard/.notegame.ini'


I'll do the  "WRITE_EXTERNAL_STORAGE" and report back.  Thank you for your advice.  ~garrett.

Andrei Sima

unread,
Feb 12, 2015, 11:57:55 AM2/12/15
to kivy-...@googlegroups.com
"/home/user/Desktop/KivyProjects/myapp/myapp_step18_fixing_config/.buildozer/android/app/file_x.py"

If this path came up from logcat is no good. That path does not exist in Android Device as a matter a fact that path exists only i your machine.
I recommend to use another way to point to that file in to your code. You might consider a relative path not a absolute one.

Ex:

PROJECT FOLDER
    ASSETS
        1.png
        2.png
        3.png
    CLASSES
        myawesomeclass1.py
        myawesomeclass2.py
        myawesomeclass3.py
        ANOTHER RANDOM FOLDER
    UTILS
        HERE I WANT TO LAND
            file_x.py
    main.py

if you want to do something with file_x.py:

path = '/UTILS/HERE I WANT TO LAND/file_x.py'

also for further references read

OS class

SYS class


and





--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

______________
random life

Garrett Armstrong

unread,
Feb 12, 2015, 3:34:17 PM2/12/15
to kivy-...@googlegroups.com
The advice to add WRITE_EXTERNAL_STORAGE is spot-on.  I also added READ_EXTERNAL_STORAGE to android permissions in buildozer.spec, just for good measure.  

I don't know why kivy was defaulting to look for myapp.ini in /home/user/....  You're right that the android isn't the linux machine & shouldn't be looking for my linux's home directory.  

I haven't gotten the ConfigParser() to work with the myapp.ini on android, but the adb logcat shows i'm moving in the right direction to debugging it.  I'll reply with the solution (or whatever stumps me next) in a future response.

Thank you for the replies.
~garrett

Garrett Armstrong

unread,
Feb 12, 2015, 4:07:48 PM2/12/15
to kivy-...@googlegroups.com
Ok, problem solved.  

Adding the READ_EXTERNAL_STORAGE and/or WRITE_EXTERNAL_STORAGE fixed the issue. (i don't know whether one or both is necessary because i'm doing both right now.)  I also told buildozer.spec to include ini files along with kv,atlas,wav,png,whatevers. (this may also be unnecessary, since kivy builds the myapp.ini on start if no myapp.ini present.)

To test it, i added to some frequently called def in one of the layouts: 

                        f = 'myapp.ini'
settings = ConfigParser()
settings.read(f)
print 'cwd is', os.getcwd()
print 'dir of cwd is:', os.listdir('.')
print 'the settings' sections are:', settings.sections()
for i in settings.sections():
print 'the settings' items are:', i, settings.items(i)

i did 'buildozer --verbose android debug deploy run' -- 'adb logcat &> runtime.txt'  -- started the app on android --  'adb kill-server' in another bash shell  -- opened runtime.txt with a text editor.

It showed kivy on the android saw the right directory, it saw the right files (i.e., myapp.ini, etc) within that directory, it saw the right sections in the myapp.ini in that directory, and it saw the right items within the sections of the myapp.ini within that directory.

So it was just a buildozer permissions issue.  Thank you all for your help!
~garrett  

Andrei Sima

unread,
Feb 13, 2015, 5:39:17 AM2/13/15
to kivy-...@googlegroups.com
Glad i could help 

To f = open('myfile.ext', r) -> read argument  (r) open file in read only mode you need READ_EXTERNAL_STORAGE

To f = open('myfile.ext', w) -> write argument (w) open file in write mode you need WRITE_EXTERNAL_STORAGE

You need both if read and write a file, new or existing, append to existing file, etc.

You decide what you need and do not need. 

Also from my personal experience i get a little concern about an app that is asking me permissions to read my files. Personal Information Privacy is a must in my life.
Especially on Android devices where the permissions are asked by the app itself not passed thru Google Servers for approval. 
I advise you to keep it as clean as you can, with minimal permissions.

Unfortunately for Android (i do not know there is other way) the app files are treated the same (permission point of view) as user files (pictures, video, music).
I do not know why they are doing this but is a bit loose end here. I mean as a user when you give the app permissions to read / write you give that app some kind of admin permissions over your files. And that i find a bit disturbing.
I am not a fan boy or some brand soldier but i like more the way that Apple is looking at user privacy issue.
But this is another thread and is not the place here to elaborate :).

Have fun with your app.

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

______________
random life

ZenCODE

unread,
Feb 13, 2015, 8:24:55 PM2/13/15
to kivy-...@googlegroups.com
Hi

Thanks both. I just wanted to understand this as it might well be worth adding to the docs. We create and write to an sqlite db without adding any such permissions. We decide the folder as follows:

def get_user_path():
   
""" Return the folder to where user data can be stored """
    root
= getenv('EXTERNAL_STORAGE') or path.expanduser("~")
   
if __os != "ios":
       
return path.join(root, ".OurCompanyName")
   
else:
       
# iOS does not seems to allow for sub-folder creation here?
       
# "Documents" seems to be the the place to put it?
       
# https://groups.google.com/forum/#!topic/kivy-users/sQXAOecthmE
       
return path.join(root, "Documents")


Is it possible that you need this because the ini is copied with the install, so you need root privileges ? Or why would you need these permissions and not us?

@Andrei. If you're right, agreed about loose, but have you tried to access the files of other apps? As far as I recall, they handle permissions by making each app a separate user, so they cannot change  or see other apps files?

Thanks + Cheers

Andrei Sima

unread,
Feb 15, 2015, 3:56:44 AM2/15/15
to kivy-...@googlegroups.com
Hy,

@ zencode

No i did not try to acces other app data, and i think that is possible only if you know abbout the inside kitchen of the second app or if you design them both. 

Any way i was not talking about the inside app data, i was talking about the user data such as personal documents stored on sd/internal storage, pictures, etc. 

I do not know how google is reviewing the apps before approving them to the store, but i think you can pass some "bad app behavior" without the user even noticing what is going on under the hood. 

I do not know if it is a urban legend or the true story, but there is/was an app in the store that had the permission to read contacts (name, phone nr, mail etc). This data latter was used to spam commercial  mail/sms to the contacts. Also was using the sms function to sms the contacts from the user device  (on his costst) to "noify them that the user is using this amazing app". Any way legend or true storry, we know that this app can be made, and there is a chance for it to pass the revision.

I totally think that Google should revise the permission manifest, or to do a more deep revision for the apps.

Again i am not a fan boy i just look at things and try to analyze them from my personal point of view. Also this post is just my personal opinion.

Have fun.
--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--

______________
random life

Garrett Armstrong

unread,
Feb 16, 2015, 12:22:14 PM2/16/15
to kivy-...@googlegroups.com
I haven't solved the problem as i thought. 

The App class was still using /sdcard/.myapp.ini  while the Layout_x class was using (app_directory)/myapp.ini.  I'll respond when i find how to point Layout_x to the /sdcard/.myapp.ini  or how to point the App to (app_directory)/myapp.ini.

Garrett Armstrong

unread,
Feb 16, 2015, 3:47:08 PM2/16/15
to kivy-...@googlegroups.com
ok, solution found.

(Note: i'm using 'myapp.ini' as shorthand for the app's specific ini file.  For an app named ThisAwesomeApp, the file will be thisawesome.ini, not actually myapp.ini.)

In andoid, kivy is written to put the myapp.ini at /sdcard/.myapp.ini.  On linux, it will be (app_directory)/myapp.ini.  On OsX or iOs, another place.  The good news is kivy keeps track of it's myapp.ini location despite OS.

So, to access the myapp.ini:   From the MyAwesomeApp(App) class, you can just execute the normal defs (i.e., build_config(), build_settings(), on_config_change(), etc).  However, to access it from another class (E.g., Widget_X), you can do:

from kivy.config import COnfigParser
from kivy.app import App

#load the myapp.ini file
settings = ConfigParser()
my_awesome_ini = App.get_running_app().get_application_config()
settings.read(my_awesome_ini)

# then manipulate it like a normal ConfigParser object.    
print settings.sections()
for i in settings.sections():
    print i, settings.items(i)

Here is the advantage:  You don't need to do buildozer.spec "android.permissions = READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE" !!  You also don't have to do "source.include_exts = ini" because kivy makes the ini on first build_config().  I'm assuming this is the reason kivy mangles the myapp.ini & places it at /sdcard/.myapp.ini. 

Andrei Sima

unread,
Feb 17, 2015, 2:25:41 AM2/17/15
to kivy-...@googlegroups.com
Thank you for sharing this solution.
I will be in this situation in 2 weeks if everything goes as planned. 

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--

______________
random life
Reply all
Reply to author
Forward
0 new messages