Android runtime permissions

834 views
Skip to first unread message

Dark Knight

unread,
Nov 10, 2018, 8:09:38 AM11/10/18
to Kivy users support
How can I set runtime permission for android using buildozer? When I run my app on android it crashes because I don't have runtime permission for internet or external storage.

build information:
sdk = 23
api = 26
ndk = 16b

Boca Valentin

unread,
Nov 10, 2018, 3:12:56 PM11/10/18
to kivy-...@googlegroups.com
Often it crashes due to the lack of libraries.
For internet permissions you have just to uncomment for getting this: 
# (list) Permissions
android.permissions = INTERNET  
What libraries do you use? For mysql.connector, for example, I had to use another 6 - 7 dependencies.
If it still crashes the you should use adb logcat or OptimusGreen's recommandation: https://github.com/JakeWharton/pidcat

--
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.
To post to this group, send email to kivy-...@googlegroups.com.
Visit this group at https://groups.google.com/group/kivy-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/c7b3e53f-57b1-41e7-a6e3-5f8a6602b80d%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

T. Kuam

unread,
Nov 11, 2018, 6:26:38 PM11/11/18
to Kivy users support
As of the new (not so new at this point...) API 26 requirement for android apps permissions need to be requested at runtime and unless an official solution has been implemented recently, I'm not aware of a way to do that strictly from buildozer.  Ensuring you have the permissions listed in your buildozer.spec (e.g. android.permissions = WRITE_EXTERNAL_STORAGE,READ_EXTERNAL_STORAGE, etc....) is a first step (which you've probably done?) and will get those permissions in the androidmanifest.xml, but assuming you're running into the issue I was, that's not enough anymore for android devices running 6.0 or higher.  I managed to get runtime permissions working for my app (at least on the one device I've tested it on), but it required some delving into this: https://developer.android.com/training/permissions/requesting#java    and using the code there to help monkey patch the PythonActivity.java file(s) in the .buildozer directory within my project's directory.  I can try to walk you through what I did if you'd like, but like I said, I've only tested on one device so no guarantee that it'll work, though I don't see any reason why it wouldn't.  



Mkie

unread,
Dec 11, 2018, 1:49:47 AM12/11/18
to Kivy users support


On Sunday, November 11, 2018 at 3:26:38 PM UTC-8, T. Kuam wrote:
As of the new (not so new at this point...) API 26 requirement for android apps permissions need to be requested at runtime and unless an official solution has been implemented recently, I'm not aware of a way to do that strictly from buildozer.  Ensuring you have the permissions listed in your buildozer.spec (e.g. android.permissions = WRITE_EXTERNAL_STORAGE,READ_EXTERNAL_STORAGE, etc....) is a first step (which you've probably done?) and will get those permissions in the androidmanifest.xml, but assuming you're running into the issue I was, that's not enough anymore for android devices running 6.0 or higher.  I managed to get runtime permissions working for my app (at least on the one device I've tested it on), but it required some delving into this: https://developer.android.com/training/permissions/requesting#java    and using the code there to help monkey patch the PythonActivity.java file(s) in the .buildozer directory within my project's directory.  I can try to walk you through what I did if you'd like, but like I said, I've only tested on one device so no guarantee that it'll work, though I don't see any reason why it wouldn't.  

can you please show the walkthrough for this? thanks! 

T. Kuam

unread,
Dec 11, 2018, 6:54:02 AM12/11/18
to Kivy users support
Sure thing.  I'm still a bit new to all of this still and had to sort of 'brute force' test things to get it working but hopefully it'll work for you as well.  So just for reference, all of the java code I more or less just copy/pasted from here https://developer.android.com/training/permissions/requesting#java , with some minor edits to get it working how I needed it to.

Also, these steps assume you have been successful in getting your apk built for API 26.

So first off, you'll be primarily editing the PythonActivity.java file, which can be found wherever your p4a source directory is located.  There will be a few of the files, but I believe the one you want is the one located in ...bootstraps/sdl2/build/src/main/java/org/kivy/android/.  Prior to building the apk, after you make the edits to PythonActivity.java you'll need to clear out your dists directory (can be found in the .buildozer directory where you have your app being built from: .buildozer/android/platform/build/dists/your_app) that contains the current build of your apk.  This directory contains other PythonActivity.java files (which are created from the one in the p4a directory mentioned earlier) and buildozer will not replace them if it finds the files already there (so the edits made to the template PythonActivity.java would not be inserted).  This is why the current build of your app in the dists directory needs to be removed.

Alternatively, if you're worried that clearing the dists directory would break something else like I was :)  you can just edit the PythonActivity.java files found in the .buildozer directory where your app files are.  This just means you'll need to make the same edits to multiple PythonActivity.java files. These files should be located at:
.buildozer/android/platform/build/dists/your_app/build/src/main/java/org/kivy/android 
.buildozer/android/platform/build/build/bootstrap_builds/sdl2_gradle-python2/src/main/java/org/kivy/android
.buildozer/android/platform/build/dists/your_app/src/main/java/org/kivy/android

or similar paths, depending on how you've built your app. I'm not sure if it was entirely necessary of me to make the edits all of the ones that I did, but like I said, I just tried things out until it finally worked and that was good enough for me :)

 Now, on to the edits.  So with your PythonActivity.java file open, starting from the top you'll need to add a few imports:
import android.Manifest;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;

Just tack those on to the bottom of the imports.  Just below the imports you should see...

public class PythonActivity extends SDLActivity {
   
private static final String TAG = "PythonActivity";

Just under that you'll want to add:

    private static final int MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 0;

From my understanding, this is a constant that one of the permission requesting functions refers to. You can change the name of it to whatever makes sense for the permission you're requesting, just make sure it matches to what is edited later obviously.

Last step with the PythonActivity.java file is then is to scroll down to the onCreate() method, which will look like this:
@Override
   
protected void onCreate(Bundle savedInstanceState) {
       
Log.v(TAG, "My oncreate running");
        resourceManager
= new ResourceManager(this);

       
Log.v(TAG, "About to do super onCreate");
       
super.onCreate(savedInstanceState);
       
Log.v(TAG, "Did super onCreate");

       
this.mActivity = this;
       
this.showLoadingScreen();

       
new UnpackFilesTask().execute(getAppRoot());

and within this method is where you'll add the code that pops up the permission request when your app launches.  Again, I pretty much just copy pasted from the android link at the beginning of this so obviously, change it to what you need, but here's the code that needs to be added to the onCreate method:

    // Here, thisActivity is the current activity
       
if (ContextCompat.checkSelfPermission(mActivity,
               
Manifest.permission.WRITE_EXTERNAL_STORAGE)
               
!= PackageManager.PERMISSION_GRANTED) {
               
Log.v(TAG, "CHECKED PERMISSION");
           
// Permission is not granted
           
// Should we show an explanation?
           
if (ActivityCompat.shouldShowRequestPermissionRationale(mActivity,
                   
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                   
Log.v(TAG, "SHOW EXPLANATION");
               
// Show an explanation to the user *asynchronously* -- don't block
               
// this thread waiting for the user's response! After the user
               
// sees the explanation, try again to request the permission.
           
} else {
               
// No explanation needed; request the permission
               
ActivityCompat.requestPermissions(mActivity,
                       
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                        MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE
);
                       
Log.v(TAG, "REQUESTED PERMISSION");
               
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
               
// app-defined int constant. The callback method gets the
               
// result of the request.
           
}
       
} else {
           
Log.v(TAG, "PERMISSION ALREADY GRANTED");
           
// Permission has already been granted
           
}
   
}

   
@Override
   
public void onRequestPermissionsResult(int requestCode,
           
String permissions[], int[] grantResults) {
       
switch (requestCode) {
           
case MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE: {
               
// If request is cancelled, the result arrays are empty.
               
if (grantResults.length > 0
                   
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                   
// permission was granted, yay! Do the
                   
// contacts-related task you need to do.
                   
Log.v(TAG, "PERMISSION GRANTED!");
               
} else {
                   
Log.v(TAG, "PERMISSION DENIED");
                   
// permission denied, boo! Disable the
                   
// functionality that depends on this permission.
               
}
               
return;
           
}

           
// other 'case' lines to check for other
           
// permissions this app might request.
       
}
   
}

A couple final things to do: 
In your buildozer.spec add 'com.android.support:appcompat-v7:26.1.0' to your android.gradle_dependencies.
And finally, open up your_p4a_source_directory/bootstraps/sdl2/build/templates/build.tmpl.gradle and edit the top 22 lines to look like this:

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript
{
  repositories
{
    jcenter
()
 
}
  dependencies
{
    classpath
'com.android.tools.build:gradle:2.3.1'
 
}
}

allprojects
{
  repositories
{
    jcenter
()
    mavenCentral
()
    maven
{
      url
"https://maven.google.com"
   
}
    flatDir
{
      dirs
'libs'
   
}
 
}
}

Make sure the file(s) are saved and try building your apk again.  If I haven't forgotten any steps then hopefully it will work!  If you run into any errors feel free to show me and I'll see if I can help.  Also, the procedure for this is essentially the same as what's found here http://quadropoly.com.au/kivy-and-admob-for-android-api-27/
just adapted for the runtime permissions code.  On that page, mind_writer helped me a bunch to get things working for me and you might run into some of the same errors that are mentioned in his tutorial there, or in the comments below if you read through them. 

Hopefully these instructions are clear enough and will help, or at least get you pointed in the right direction, but again if you run into any issues feel free to post them and I'll see if I can help.

 

Roger Morrell

unread,
Dec 12, 2018, 10:25:18 PM12/12/18
to Kivy users support
two issues

I have ported over a Kivy App that works under windows and linux to Android

I'm testing it on a Lenovo Tab 4 just upgraded to android 8

I followed Robert's instructions to just use p4a  (i may go back and have another shot at buildozer using zen_code's latest virtual system)

I added the WRITE_EXTERNAL_STORAGE as a p4a parameter and my writing to files half worked

Then upon further research I could also set individual APP permissions from the config setting screen on the Tablet - I did this and a whole lot more file reading and writing started working.  I have not gone back and properly analysed exactly the connection.  this may help Mkie ?

But I did encounter some unexplained file mapping that I have not been able to unravel yet

there is a config.ini file - that both the windows and linux version understand an take notice of

Also I have an app.ini file too that also works.

But because the Android file structure is different and partly organized around the APP - my Kivy app does no find these files or if it does it ignores them.

Also I'm successful in creating directories and files in what is called an external file  but is really on the internal storage in my App's space and I can read or write the into one of the user's directories - e.g the download directory , in this way data files can be put i this directory by email and imported ot exported by may application.  

But what I have not been able to do is read or write the external SD card and see if there is a permission specific to that.  I was not successful in researching the Android doc in finding a list of possible permissions.

So what I would like to see documented in the Kivy Python to Android implementation

where is the config.ini put - and the Permissions needed to read/write  it
where is the APP.ini put and the permissions to read/write it 

both of these are well defined in Windows and Linux

Roger
Reply all
Reply to author
Forward
0 new messages