Kivy and Admob for Android API 27: guide for Kivy devs

I have been using kivmob solution before Google’s requirement for Android packages to target API 26+ that came into effect in August 2018. Unfortunately, making it to work with newer API required some changes. In this guide I will try to sum up the steps required to make it work again. Hope it will be of use to Kivy developers.
I am still using kivmob code developed by Michael Stott, so all credit for making it available to kivy developers goes to him.
This guide assumes you are able to build your app for API 27 without Admob. There are some hoops one have to jump through to get it working.
I am using Admob with API 27 for Quadropoly

Here are the changes in buildozer.spec required:

# (int) Android API to use
android.api = 27
# (int) Minimum API required
android.minapi = 19
android.gradle_dependencies = 'com.google.android.gms:play-services-ads:15.0.0', 'com.android.support:appcompat-v7:26.1.0'

Clone python-for-android repo. Reference its location in buildozer.spec: p4a.source_dir = your/path/here

Modify pythonforandroid/bootstraps/sdl2/build/src/main/java/org/kivy/android/PythonActivity.java mixing in all the kivmob bits. Here is the code all the way to “public String getAppRoot()”, the rest is unchanged:

package org.kivy.android;

import java.io.InputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;

import android.view.View;
import android.view.Gravity;
import android.os.Handler;
import android.os.Message;
import android.widget.FrameLayout;

import android.view.ViewGroup;
import android.view.SurfaceView;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.PowerManager;
import android.graphics.PixelFormat;
import android.view.SurfaceHolder;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ApplicationInfo;
import android.content.Intent;
import android.widget.ImageView;
import java.io.InputStream;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;

import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.InterstitialAd;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.AdView;
import com.google.ads.mediation.admob.AdMobAdapter;

import org.libsdl.app.SDLActivity;

import org.kivy.android.PythonUtil;
import org.kivy.android.launcher.Project;

import org.renpy.android.ResourceManager;
import org.renpy.android.AssetExtract;

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

  public static PythonActivity mActivity = null;

  private ResourceManager resourceManager = null;
  private Bundle mMetaData = null;
  private PowerManager.WakeLock mWakeLock = null;

  /* KivMob backend starts here. */
  private static AdView adView = null;
  private static InterstitialAd interstitialAd = null;
  private static ArrayList testDevices = new ArrayList();
  public static enum AdCmd {INIT_ADS,
  ADD_TEST_DEVICE,
  NEW_BANNER,
  NEW_INTERSTITIAL,
  REQ_BANNER,
  REQ_INTERSTITIAL,
  SHOW_BANNER,
  SHOW_INTERSTITIAL,
  HIDE_BANNER
  };

  // Handles all communications to ad threads
  public static Handler adHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      AdRequest.Builder builder = new AdRequest.Builder();
      switch (AdCmd.values()[msg.what]) {
        case INIT_ADS: MobileAds.initialize(mActivity, msg.getData().getString("appID"));
        break;
        case ADD_TEST_DEVICE: testDevices.add(msg.getData().getString("deviceID"));
        break;
        case NEW_BANNER: FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
        FrameLayout.LayoutParams.WRAP_CONTENT,
        FrameLayout.LayoutParams.WRAP_CONTENT,
        Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL);
        adView = new AdView(mActivity);
        adView.setAdSize(AdSize.SMART_BANNER);
        adView.setAdUnitId(msg.getData().getString("unitID"));
        adView.setLayoutParams(lp);
        adView.setVisibility(View.GONE);
        adView.setAdListener(new AdListener() {});
        ViewGroup layout = getLayout();
        layout.addView(adView);
        break;
        case NEW_INTERSTITIAL:
        interstitialAd = new InterstitialAd(mActivity);
        interstitialAd.setAdUnitId(msg.getData().getString("unitID"));
        interstitialAd.setAdListener(new AdListener() {
          @Override
          public void onAdClosed() {}
        });
        break;
        case REQ_BANNER:
        for (String device: testDevices) {
          builder.addTestDevice(device);
        }
        builder.addTestDevice(AdRequest.DEVICE_ID_EMULATOR);
        AdRequest bannRequest = builder.build();
        adView.loadAd(bannRequest);
        break;
        case REQ_INTERSTITIAL: if (msg.getData().containsKey("child")) {
          builder.tagForChildDirectedTreatment(msg.getData().getBoolean("child"));
        }
        if (msg.getData().containsKey("family")) {
          Bundle extras = new Bundle();
          extras.putBoolean("is_designed_for_families",
          msg.getData().getBoolean("family"));
          builder.addNetworkExtrasBundle(AdMobAdapter.class, extras);
        }
        builder.addTestDevice(AdRequest.DEVICE_ID_EMULATOR);
        for (String device: testDevices) {
          builder.addTestDevice(device);
        }
        AdRequest interRequest = builder.build();
        interstitialAd.loadAd(interRequest);
        break;
        case SHOW_BANNER: adView.setVisibility(View.VISIBLE);
        break;
        case SHOW_INTERSTITIAL: if (interstitialAd.isLoaded()) {
          interstitialAd
        }.show();
      }
      break;
      case HIDE_BANNER:
      adView.setVisibility(View.GONE);
      break;
      default: break;
    }
  }
};

public static boolean isLoaded() {
  return interstitialAd.isLoaded();
}
/* End of KivMob code. */
public String getAppRoot() { /* The rest is unchanged */

Next, modify pythonforandroid/bootstraps/sdl2/build/templates/build.tmpl.gradle file so top 22 lines 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'
    }
  }
}

Here are the links to full versions of the files:
PythonActivity.java:
https://pastebin.com/raw/kkTDGZLB
build.tmpl.gradle:
https://pastebin.com/raw/bFbBQUPD

Try building your APK (do not forget requirements = kivmob in your buildozer.spec), but you are very likely to get “Error: No resource found that matches the given name” errors during the process. That means your build tools version is not compatible with com.android.support:appcompat-v7 version. It can be fixed by installing build tools manually:

Open SDK Manager: ~/.buildozer/android/platform/android-sdk-20/tools/android
Your SDK version might be different.

Scroll down to Extras and install Android Support Repository and Google Repository.

I have the following versions of Android SDK Build-tools installed, not 100% sure if all of them are required: 19.1, 23.0.1, 26.0.1, 28.0.2. If you keep getting the same error, try uninstalling  28.0.2 version. Older versions do not really matter as buildozer picks up the highest version available during the build. If that does not help, try installing SDK Platform 26.

buildozer android clean -> buildozer android release -> enjoy!
Oh, and don’t forget to follow the readme in kivmob repo. Do not clone the repo though, it is no longer required (and won’t work) for API 27. android.bootstrap = sdl2-admob should not be used either.

Please let me know if it works for you in the comments below.
Good luck!

71 thoughts on “Kivy and Admob for Android API 27: guide for Kivy devs”

  1. Ok, so I had the chance to try this but got an error (see below)

    Is there anyway you could format the code above or even better link to your edited files?

    I copy and pasted and then auto indented but as I’m not familiar with java it looks like Japanese to me lol.

    Any help would be great

    error output
    https://pastebin.com/raw/HKBXzuzE

    1. Here is the whole file: https://pastebin.com/raw/kkTDGZLB
      However your error is not related to java code, this is the main message:
      Using the first of these: ['hostpython2', u'kivmob', 'sdl2_image', 'sdl2_mixer', 'sdl2_ttf', 'python2', 'sdl2', 'six', u'android', 'pyjnius', u'kivy']
      [ERROR]: virtualenv is needed to install pure-Python modules, but
      [ERROR]: virtualenv does not support nesting, and you are running
      [ERROR]: python-for-android in one. Please run p4a outside of a
      [ERROR]: virtualenv instead.

      You might have missed some dependencies for kivmob in requirements. Could you post your buildozer.spec file?

      1. Ok so I made some progress by making kivmob.py a local module to my project to avoid adding as a requirement.

        I managed to build successfully but unfortunately the app crashes on launch with the following logical error

        jnius.jnius.JavaException: Class not found ‘org/kivy/android/PythonActivity$AdCmd’

        Any ideas?

        1. You do not have to make kivmob local, having it in requirements works fine (unless you want to modify it).
          I was also getting Class not found β€˜org/kivy/android/PythonActivity$AdCmd’ error from time to time. It looks like PythonActivity is not properly instantiated yet by the time you are creating instance of KivMob. To fix it, remove your code to create KivMob() object from on_start method and put it somewhere else, so that it runs after your App starts up successfully. Or put it in try/catch block, and if it fails – try again later.

          1. Hi,

            If I add kivmob as a requirement I get the error in my initial post.

            I refactored to make sure none of my kivmob stuff instantiated or ran until I clicked a test button so app is up and running before attempting to get an ad. Still get the same PythonActivity$AdCmd not found error.

          2. Hey mate, try looking for PythonActivity.java file in your .buildozer folder where your App builds. There will be multiple instances. Make sure all of them have kivmob changes. Normally, buildozer takes the files from default bootstrap (sdl2) so setting your p4a directory with this bootstrap modified is enough. But you need to make sure you are not specifying any other bootstraps in your buildozer.spec file.
            If you are adding kivmob locally, copying kivmob.py to the location of main.py is enough. The file does not require any changes.

          3. Hi,

            Tried that and unfortunate have a new error.
            I’ve also left a paste of my spec. Pretty sure Everything is right.

            Have you ever thought about maybe forking kivmob and making the changes available or even pull request the changes?

            thanks again for your time and help. its appreciated.

            new error after changing all PythonActivity.java instances in .buildozer dir.
            https://pastebin.com/raw/zU3JLnRs

            spec
            https://pastebin.com/raw/KM3CCGR4

          4. Hey mate, your main error is this: /Users/john/Development/Git/ogleavetracker/optileave/.buildozer/android/platform/build/dists/optileave/src/main/java/org/renpy/android/PythonActivity.java:52: error: duplicate class: org.kivy.android.PythonActivity
            [DEBUG]: public class PythonActivity extends SDLActivity {

            So in line 52 of your PythonActivity.java you are declaring PythonActivity class for the second time. Copy/paste error? Try modifying this file directly without cleaning buildozer until this error goes away. The error points out the exact location of the file it takes for the build.
            In your buildozer.spec file you are taking wrong versions of play-services-ads and com.android.support:appcompat, the correct ones being commented out. It might be fine if you manage your build-tools to work with it, but I still believe going for higher versions is generally better.
            android.sdk = 23 – I am not using this, letting buildozer take whatever its default is.

            Yes I am thinking about forking and making it available on github. I made many more changes than listed in this guide for the purpose of adding RewardVideo ads. It seems to be working, but I will need more time to test on production. It is live in Play Store rolled out to 20% of users right now. Once I have tested it and fixed all the bugs I will try to arrange it as a separate bootstrap (similar to kivmob).

  2. Thanks for working on this, but unfortunately still no luck for me. When you start this process are you building for API 19 first as others have done or are all of the edits to buildozer.spec, pythonactivity.java and build.tmpl.gradle done before building for the first time? I’ve tried both ways but have been unsuccessful with each so far. Building with all of the admob edits and API set to 27 actually builds but when I run the app I get the sdl2 ftello error that others were getting when not building for 19 first.

    I’m currently working on trying to build for API 19 first with all of the admob edits but am running into the “Error: No resource found that matches the given name” errors. Uninstalling build-tools 28.0.2 has not helped and I already had SDK platform 26 installed. I’m trying a few other things and will post if anything works.

    1. It is best to get your build to work without admob first, then modify everything to add it back. I have never seen “sdl2 ftello error” myself as I used to build for API 19 before, with ‘classic’ kivmob implementation. Try startng from scratch on master python-for-android, latest version of buildozer, no admob/kivmob, target API 19 and make sure it builds and starts up. Then try the same for API 27. Once you are able to get rid of “sdl2 ftello error” start adding kivmob bits from this guide. Please let me know if it works for you.

      1. No luck still, here was my process: Built for API 19, no kivmob changes, app builds and runs successfully. Cleared out the ‘dists’ directory, built for API 27, still no kivmob additions, app builds and runs successfully. Cleared out ‘dists’ , built for API 27, with the kivmob additions to build.tmpl.gradle, pythonactivity.java, and buildozer.spec changes (gradle_dependencies), app builds successfully, but does not run, error being that it can’t find the appcompat/play-services-ads. I noticed in my app projects directory there were 4 build.tmpl.gradle files in different locations, 2 of which did not have the maven repository lines added in. I added them in to those files, built the app which during that build found appcompat/play-services-ads and downloaded them. Launched the app and this time the jnius.jnius.JavaException: Class not found ‘org/kivy/android/PythonActivity$AdCmd’ error showed up as if the kivmob additions to pythonactivity.java were not made. So I did the same thing as with the build.tmpl.gradle files in my project’s directory to the pythonactivity.java files ( just the ones that the directory path ended in the org/kivy/android) and added the kivmob code to each of those hoping it would do the trick, but now it does not build successfully and gives this error:

        public static Handler adHandler = new Handler() {
        ^
        symbol: class Handler
        location: class PythonActivity
        /home/kuam/Desktop/admobtest/.buildozer/android/platform/build/dists/workoutcreator/src/main/java/org/kivy/android/PythonActivity.java:71: error: cannot find symbol
        public static Handler adHandler = new Handler() {
        ^
        symbol: class Handler
        location: class PythonActivity
        Note: Some input files use or override a deprecated API.
        Note: Recompile with -Xlint:deprecation for details.
        4 errors
        Incremental compilation of 5 classes completed in 0.154 secs.
        :compileDebugJavaWithJavac FAILED

        Any ideas?

        1. You are on a good track mate, just make sure you have copied all the imports correctly. In my PythonActivity.java file line “public static Handler adHandler = new Handler() {” is line 85, not 71. Not sure why your buildozer did not copy the files from your p4a directory, did you specify it correctly in your buildozer.spec file? Anyway, copying it manually does the trick too. Please check if your buildozer is the latest version. Here are all the imports. You are obviously missing “import android.os.Handler;”, but I doubt it is the only one.
          package org.kivy.android;

          import java.io.InputStream;
          import java.io.FileInputStream;
          import java.io.FileOutputStream;
          import java.io.FileWriter;
          import java.io.File;
          import java.io.IOException;
          import java.util.Collections;
          import java.util.Iterator;
          import java.util.List;
          import java.util.ArrayList;

          import android.view.View;
          import android.view.Gravity;
          import android.os.Handler;
          import android.os.Message;
          import android.widget.FrameLayout;

          import android.view.ViewGroup;
          import android.view.SurfaceView;
          import android.app.Activity;
          import android.content.Intent;
          import android.util.Log;
          import android.widget.Toast;
          import android.os.AsyncTask;
          import android.os.Bundle;
          import android.os.PowerManager;
          import android.graphics.PixelFormat;
          import android.view.SurfaceHolder;
          import android.content.Context;
          import android.content.pm.ActivityInfo;
          import android.content.pm.PackageManager;
          import android.content.pm.ApplicationInfo;
          import android.content.Intent;
          import android.widget.ImageView;
          import java.io.InputStream;
          import android.graphics.Bitmap;
          import android.graphics.BitmapFactory;
          import android.graphics.Color;

          import com.google.android.gms.ads.AdListener;
          import com.google.android.gms.ads.AdRequest;
          import com.google.android.gms.ads.InterstitialAd;
          import com.google.android.gms.ads.MobileAds;
          import com.google.android.gms.ads.AdSize;
          import com.google.android.gms.ads.AdView;
          import com.google.ads.mediation.admob.AdMobAdapter;

          import org.libsdl.app.SDLActivity;

          import org.kivy.android.PythonUtil;
          import org.kivy.android.launcher.Project;

          import org.renpy.android.ResourceManager;
          import org.renpy.android.AssetExtract;

          1. Woohoo Success! Added those imports into the proper pythonactivity.java files and it builds, runs on my device, and uploads to the play store successfully. Thanks very much for the help, now I can finally move ahead with my app. Just need to finish fixing a few things in my code that were still in python3 format and I should be good to go. Thanks again!

          2. You are welcome, and well done!
            In the meantime, I made good progress on RewardVideos ad format. I will add it to the guide as well as publish my work on github (it required expanding kivmob code 2x) after publishing on Play Store and making sure it has no issues for a few weeks.

  3. Hey mate, will be trying your tuto now, my app was working fine on phones and tablets with API 19 up until the App Store upload.
    Glad there are smarter people than I out there finding ways around those problems πŸ˜‰
    I will post my results in a bit, hopefully this will work and my app will be on the App Store before tomorrow.

    1. Hi mate, let me know how it goes πŸ™‚
      Please read through the comments too if you run into issues. I will try to add main points from them to the guide later as well.

  4. Hi again,
    No luck, I keep getting the error below:
    Would there be a way for you to make a VirtualBox with a clean install of Kivy, buildozer, etc…?

    kivy@kivy-complete:~/Desktop/MyApp2$ buildozer android debug# Check configuration tokens
    # Ensure build layout
    # Check configuration tokens
    # Preparing build
    # Check requirements for android
    # Run ‘dpkg –version’
    # Cwd None
    Debian ‘dpkg’ package management program version 1.18.4 (amd64).
    This is free software; see the GNU General Public License version 2 or
    later for copying conditions. There is NO warranty.
    # Search for Git (git)
    # -> found at /usr/bin/git
    # Search for Cython (cython)
    # -> found at /usr/local/bin/cython
    # Search for Java compiler (javac)
    # -> found at /usr/lib/jvm/java-8-openjdk-amd64/bin/javac
    # Search for Java keytool (keytool)
    # -> found at /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/keytool
    # Install platform
    # Run ‘pip install -q –user “appdirs” “colorama>=0.3.3” “sh>=1.10” “jinja2” “six”‘
    # Cwd None
    # Apache ANT found at /home/kivy/.buildozer/android/platform/apache-ant-1.9.4
    # Android SDK found at /home/kivy/.buildozer/android/platform/android-sdk-20
    # Android NDK found at /home/kivy/.buildozer/android/platform/android-ndk-r9c
    # Check application requirements
    # Check garden requirements
    # Compile platform
    # Run ‘/usr/bin/python -m pythonforandroid.toolchain create –dist_name=AlphaBetaConverter –bootstrap=sdl2 –requirements=kivy,numpy,kivmob –arch armeabi-v7a –copy-libs –color=always –storage-dir=/home/kivy/Desktop/MyApp2/.buildozer/android/platform/build’
    # Cwd /home/kivy/Desktop/MyApp2/python-for-android
    [INFO]: Will compile for the following archs: armeabi-v7a
    [INFO]: Found Android API target in $ANDROIDAPI
    [INFO]: Available Android APIs are (19, 26, 27, 28)
    [INFO]: Requested API target 27 is available, continuing.
    [INFO]: Found NDK dir in $ANDROIDNDK
    [INFO]: Got NDK version from $ANDROIDNDKVER
    [INFO]: Using Google NDK r9c
    [INFO]: Found virtualenv at /usr/local/bin/virtualenv
    [INFO]: ccache is missing, the build will not be optimized in the future.
    [WARNING]: ndk_platform doesn’t exist: /home/kivy/.buildozer/android/platform/android-ndk-r9c/platforms/android-27/arch-arm
    [INFO]: Found the following toolchain versions: [‘4.6’, ‘4.8’, ‘clang3.3’]
    [INFO]: Picking the latest gcc toolchain, here 4.8
    [ERROR]: python-for-android cannot continue; aborting
    # Command failed: /usr/bin/python -m pythonforandroid.toolchain create –dist_name=AlphaBetaConverter –bootstrap=sdl2 –requirements=kivy,numpy,kivmob –arch armeabi-v7a –copy-libs –color=always –storage-dir=/home/kivy/Desktop/MyApp2/.buildozer/android/platform/build
    #
    # Buildozer failed to execute the last command
    # The error might be hidden in the log above this error
    # Please read the full log, and search for it before
    # raising an issue with buildozer itself.
    # In case of a bug report, please add a full log with log_level = 2

    1. Hey, this error does not seem to be related to admob. Can you build your app for API 27 without admob? Make sure you can do it before adding any admob bits, otherwise debugging it would be a nightmare. Looks like you NDK is not installed properly, or wrong version is set in $ANDROIDNDK
      ndk_platform doesn’t exist: /home/kivy/.buildozer/android/platform/android-ndk-r9c/platforms/android-27/arch-arm
      It took me 2 weeks of trial and error to be able to build for API 27, and I am not sure which steps were required and which were not. I believe I could repeat this process from scratch and write it up in a “Build for API 27 guide”, but it would take considerable amount of time. I cannot do it now, and I hope core kivy guys would be able to publish working VM soon. When they do, the “Build for API 27 guide” would become irrelevant. If not, I could start looking into it after clearing my current working queue, but it is not going to be soon.
      Apparently one of the gotchas when trying to build for API 27 is that you have to build for API 19 first, then switch to 27.

      1. Thanks mind_writer, APK compilation was working good for me on API 19 before I tried API 27, I could sign my app no problem but was stuck when uploading it on the Google Play Store with the error “APK must use API26 or above”. I have little idea what admob is: some sort of plugin to generate in-app ads!? If so I do not want this, I will try to understand how to remove it (deleting all lines from your tuto that contains “admob”? e.g. import com.google.ads.mediation.admob.AdMobAdapter;) and try to understand how to change my android NDK (by modifying the buildozer.spec file?).

        I will try a few things tonight: I code after my day job (which is completely unrelated to any form of computer sciences) hence my request to have the easy solution of using a premade VM, I have very very limited knownledge of most of what is involved in using Linux, Kivy, Buildozer, etc… only know how to code in Python and a tad in Kivy but that was enough up until now to create a working API19 app. I get back to you later, I will try a fresh start on the kivy 1.9.1 VM and try a list of things I found going through the entire https://github.com/kivy/python-for-android/issues/1219 thread, including the solution by StacyMAI.
        If you (or Zen_CODE who originally offered to create a working VM for API26+) find the time to create a VM in which I can simply add my main.py and do a “buildozer android release”, that would indeed be absolutely awesome, but I totally understand how this could take time. Cheers mate, your help is very much appreciated anyway!!

  5. Hello everyone,

    Can someone please post a link to the two changed files? I’m having a hard time getting them to indent as they should. I would greatly appreciate this. Thank you in advance!

      1. Hey mind_writer, I will try those right now. Thank you!!!

        Do you also do the work-around where you first compile the APK with API 19, then delete the dist folder, then change API to 27? That’s the route that I’ve been taking, unfortunately.

        1. Hi Petar,
          I believe you need to do it just once. I did not have to since I was targeting API 19 before, all the time since publishing Quadropoly. Right now I am clearing buildozer and building again without switching to API 19.

          1. Not sure if my previous post went through, so I’ll post again:

            I’m coming closer, mind_writer! Thank you for the continued assistance! I just keep getting these two errors when I try to debug:
            * What went wrong:
            [DEBUG]: Execution failed for task ‘:processDebugResources’.
            [DEBUG]: > com.android.ide.common.process.ProcessException: Failed to execute aapt

            [WARNING]: ERROR: ./gradlew failed!

            It builds and deploys fine when I take out the android.gradle_dependencies = ‘com.google.android.gms:play-services-ads:15.0.0’, ‘com.android.support:appcompat-v7:26.1.0’ but then crashes on start up.
            Would you happen to know how to circumvent these issues?

          2. Hey mate, could you please upload and send the links to buildozer.spec and pythonforandroid/bootstraps/sdl2/build/templates/build.tmpl.gradle files? Make sure to blank out any sensitive info if any. Are you able to build your app without admob? Could you also get the adb logcat to see what it is crashing on?

          3. mind_writer, I have to build my app with admob on API 19 first, right?
            I’m able to build my app (without admob) on API 19. I then delete dist folder, and change API to 27 to make it run okay (without admob). But when I try my app with admob on API 19, I get an error using:
            p4a.source_dir = /home/pl/python-for-android-admob
            p4a.bootstrap = sdl2-admob

            This is my initial buildozer spec for API 19: https://pastebin.com/XFHMWDhh
            Here is the error that I keep getting using those specs: https://pastebin.com/cKH9MVfD

          4. Hi Petar,
            There are several issues with your sequence:
            1) Make sure your app builds and starts up fine without admob on API 27. This part is not covered in detail in this guide, but for most people it means they have to build for API 19 first. No admob on either 19 or 27 on this step. After building for API 19 prior to building for API 27 you can do buildozer android clean to remove the dists.
            2) Follow the guide to clone NEW version of p4a from master branch, do not take outdated python-for-android-admob fork. Do not specify p4a.bootstrap as it does not exist there (also noted in the guide). Apply changes to .gradle and PythonActivity.java in default sdl2 bootstrap.
            3) buildozer.spec does not need to have android.ndk and android.sdk versions specified, defaults should be fine for both 19 and 27. Your error seems to be related to incorrect ndk version selected manually.

            If any of those steps are not working correctly do not try to start with the next one, it would only complicate the debugging.
            Good luck, hope that helps!

          5. hey mind_writer,I was able to build an APK with API 27 two weeks ago. I tried again after you sent me that message, and I couldn’t compile it anymore. I’m stuck on this error:

            [DEBUG]: :compileDebugJavaWithJavac

            [DEBUG]: Note: Some input files use or override a deprecated API.
            [DEBUG]: Note: Recompile with -Xlint:deprecation for details.
            [DEBUG]: 1 error
            [DEBUG]: :compileDebugJavaWithJavac FAILED
            [DEBUG]: FAILURE: Build failed with an exception.
            [DEBUG]: * What went wrong:
            [DEBUG]: Execution failed for task ‘:compileDebugJavaWithJavac’.

            [WARNING]: ERROR: ./gradlew failed!

            In the error, it said that the API was deprecated. I did the same method of building API 19, deleting dist, and changing API to 27. Have you seen this error before?

          6. Hi Petar,

            That error means one of your Java files could not compile. Most probably – there is a mistake in PythonActivity.java. The error should show the line it failed on – scroll up to find it, or send a link to full error logs. The extract from the logs above does not contain the actual error message.

        2. I can’t do one of the steps. I think it has to do with my python-for-android folder because the depo doesn’t have the same files as you stated above. For some reason my repo folder is messed up. But when I debug my app, the python-for-android folder appears in the .buildozer file of the app, and the files are in there… Could you please email your repo folder, or please upload it to a Google drive folder then share that? I can’t seem to find python-for-android folder online.

          1. Hey mate, just git clone this: https://github.com/kivy/python-for-android
            Then add its location to buildozer.spec: p4a.source_dir = [your/path/here]/[python-for-android-repo-parent-folder]
            Then replace the content of those 2 files with files from my previous reply.
            There is little point to upload the whole folder, there are only 2 files different from master branch. Besides my own local copies have way more changes to add reward video support, which is not yet finalised.
            I am also working on a different bootstrap similar to sdl2-admob bootstrap approach, that should make using it easier and avoid monkey patching.

            The way buildozer works is (and I figured it out from the evidence, could not find any related documentaion) that it copies your p4a.source_dir to .buildozer first time it is run after being cleaned (buildozer android clean), and for every consecutive builds it uses that copied version without syncing. So if you were to modify the content of your p4a repo without cleaning the buildozer, your changes will not be picked up. If you really do not want to clean buildozer, make sure to copy your changes to relevant p4a .buildozer folder too.

  6. Hey everyone, I’m having trouble with formatting the copied parts to those java files. Can anyone email me those two files already formatted correctly, please? My email is pluketina@gmail.com . I would sincerely appreciate it!

  7. Hey mind_writer, had a couple quick questions for you. First, I downloaded your app and it looks like you got the reward ads working (at least on my device they’re displaying once they have time to load), have you had any issues with them not working? Also, I used your solution from https://github.com/kivy/python-for-android/issues/1219 to get around the permission error when trying to write to a file which worked great, but I noticed your app was also able to write a folder/files directly to internal storage rather than being in buried in storage/Android/data/……etc. How did you go about doing that?

    1. Hey mate, I am still tweaking my rewards ads solution – there are quite a few crashes from Admob that I struggle to reproduce. They all appeared after I added rewarded ads and it never crashed on devices I have (maybe because I am only allowed to test on test ad). Still looking for a root cause and fix for it. But I am planning to publish my kivmob changes on github later – I had to almost double the code required.
      Second questions is easy – I always used internal storage before targeting API 27, so now I am just checking if I can get internal storage (which is the case for older Android versions, your phone must be running Android prior to 7.0), and if fails, use the work around. Also people who got the app earlier have internal storage access enabled, and if I ignore files there these people would lose all their accounts.

      1. Ah ok, yeah my device is Android 5.1. That makes sense then as my app still worked on my device without the work around but crashed on Android 8.0. Thanks again for your help and good luck on get the rewards ads solution finished.

        1. Thanks mate. The crash I am stuck with happens outside of python code, most likely outside PythonActivity.java
          This is the backtrace I am getting from Google Play console:
          backtrace:
          #00 pc 000000000004af84 /system/lib/libc.so (tgkill+12)
          #01 pc 0000000000048723 /system/lib/libc.so (pthread_kill+34)
          #02 pc 000000000001d4c5 /system/lib/libc.so (raise+10)
          #03 pc 0000000000019001 /system/lib/libc.so (__libc_android_abort+34)
          #04 pc 0000000000017064 /system/lib/libc.so (abort+4)
          #05 pc 000000000031994d /system/lib/libart.so (_ZN3art7Runtime5AbortEv+252)
          #06 pc 00000000000b4d39 /system/lib/libart.so (_ZN3art10LogMessageD2Ev+864)
          #07 pc 00000000001bb16f /system/lib/libart.so (_ZN3art22IndirectReferenceTable3AddEjPNS_6mirror6ObjectE+194)
          #08 pc 000000000026539b /system/lib/libart.so (_ZN3art3JNI16CallObjectMethodEP7_JNIEnvP8_jobjectP10_jmethodIDz+450)
          #09 pc 000000000002fe4f /data/data/au.com.quadropoly.quadropoly/files/app/lib/python2.7/site-packages/jnius/jnius.so

          Any ideas how it could be remedied are welcome πŸ™‚

          1. That looks beyond my current knowledge and ability πŸ™‚ but I’ll do some digging tomorrow and see if I can find something. The crash is happening right when the reward ad is loaded? And what were the changes you made to PythonActivity.java, just in case that helps?

          2. The crash does not seem to be related to PythonActivity: this class does not show up in the backtrace. Have no idea if it is related to Rewarded ad at all. Those crashes started appearing after deploying Rewarded ads, but it might be a coincidence. I could not reproduce it, would have been nice to be able to get adb logs.

          3. https://stackoverflow.com/questions/44301624/plyer-example-applications-break-down-on-a-real-device
            https://github.com/kivy/plyer/issues/338
            http://blog.codelv.com/2017/06/debugging-crash-in-python-native.html

            These links show some similar errors with jnius.so, libc.so, libart.so and suggest that ensuring “android” is in the buildozer.spec requirements could solve it. I imagine you already have that and it doesn’t seem like something that simple would be causing your error, unless the android requirement is not loading properly? Also saw some posts suggesting to use an addr2line tool to determine exactly where the crash is occurring. I’m not familiar with it, or really any of this πŸ™‚ but figured I’d post the links in case they help at all.

          4. Yes, I am listing android in requirements, without it I would have had much higher crash rate (now it is about 4% of daily sessions). Seems to be related to Android 7.0 only, but various devices. Thanks a lot for the links, it might be very helpful! I will let you know if I am able to take this issue any further πŸ™‚

  8. Hey mind_writer, sorry to bug you about another issue, but I had a question regarding the permission errors that people were/are getting as posted in the original API 26: issue https://github.com/kivy/python-for-android/issues/1219. I saw your workaround to write to the app’s directory which works great, but I’ve yet to find a way to easily access any other directory on Android with the new API requirements. I saw that you posted that users could grant permissions manually, but as you said, not a good user experience. I’d like for users to be able to access the ‘Downloads’ (and others perhaps) directory from within my app so images could be added to it, but I’ve not found a way to get past the permissions errors when trying to access other directories. I attempted a similar approach to what you did:

    downloads_path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()
    print downloads_path
    downloads = os.listdir(downloads_path)
    for file in downloads:
    print file

    Which will actually print out the correct path, but still throws the permission error when trying to actually access the directory. Have you had any luck in finding a way for users to grant permissions other than by displaying a message and having them do it manually?

    1. Hey mate, sorry for the late reply. For my own app I do not really need access to internal storage, it was just a convenience for users to be able to start on Free version and continue their progress on Paid if they decide to upgrade. But I made it possible with cloud backup and restores. I do not know Java very well, but from what I was able to dig up requesting permissions at runtime should be quite straight forward. There are a number of examples which could be just copy-pasted into onCreate method for PythonActivity.java. This is an official version: https://developer.android.com/training/permissions/requesting#java
      It has to be done in java, and onCreate method is the best place for it – so the dialog would appear at your App start up if permissions are not yet granted.

      1. Cool, thanks for the info and link. I’m not familiar with java either other than looking through PythonActivity.java a bit, but yeah, looking through the official android stuff on permissions looks straight forward enough. I’ll play around with it and see if I can get it working. Thanks again!

      2. Success! Thanks again for pointing me in the right direction. So yeah pretty much just copy-pasted into the onCreate method in PythonActivity.java from the link you gave, changed the permission to what I needed, added the imports that were needed, added a variable that was needed and that was it. Tested it and the Android popup appears when the app is first launched requesting the WRITE_EXTERNAL_STORAGE permission and when granted I’m able to use App.get_running_app().user_data_dir again and access other folders that I needed. Just need to handle what happens if permission is not granted and I should be all set. Thanks again mate!

        1. Great job, congrats mate!
          I will try to wrap up my p4a fork with admob support (including Reward Videos) in the next few days. Next thing would be to add In-App purchases. There were successfull implementations before, but same as Admob, I doubt it will work with API 27.

          1. Great! Looking forward to the reward ads implementation and potential In-App purchases. Thanks for all of your work on this!

          2. Awesome, thanks mate! I will check it out soon.
            Ran into something a bit strange when I just tried building my app, thought I’d let you know. During the build attempt I was suddenly greeted with an error saying it couldn’t find play-services-basement.aar (when it was working just fine yesterday). Googling led me to this link: https://stackoverflow.com/questions/50563407/could-not-find-play-services-basement-aar and the simple solution there of moving jcenter() to the end of the repositories in build.tmpl.gradle list worked and my app is building fine again. Just thought I’d let you know in case you or anyone else using your guide runs into the same problem!

          3. Thank you for this! I have not had this issue myself, but I will add this possible issue and a fix to the guide if you do not mind. Thanks again!

  9. hey mind_writer I wanted to let you know that I got further with the problem. I actually used one of @OptimusGreen’s specs:
    android.gradle_dependencies = ‘com.google.android.gms:play-services-ads:11.0.4′,’com.android.support:appcompat-v7:25.3.1’

    I’m at the final stages of cracking this kivmob issue! In my spare time though, I’ve been playing Quadropoly. It’s really cool! I’ll have to leave a review soon. I’m also really into AI but I haven’t had to time to truly delve into it… maybe when my app is finished! I’ll keep you posted if I can’t get unstuck again.

    1. Hi Petar,
      Thanks a lot for such a nice review – really appreciate it πŸ™‚
      I am also working on a proper p4a fork to make admob integration much easier. And I have expanded it with Reward Video ads support too.
      let me know your account name in Quadropoly via email (clevermindgames@gmail.com) and I will unlock top AI for you if you are interested in the game. Right now free version is limited to first 3 AI levels.

      1. πŸŽ‰πŸŽ‰πŸŽ‰ Nice!!! I’ll take a look at it rn. I was actually crawling back for help just right now haha. I initially wanted to fix my errors myself because I didn’t want to keep bothering you.

  10. hey, I really appreciate the zooming of pictures on Quadropoly board blocks. On kivy vm 27, I’m trying to debug an app without kivmob on python-for-android-kivmob27 with Api 19. but I am getting the following error.


    patching file jnius/jnius_jvm_android.pxi
    patching file setup.py
    Hunk #1 FAILED at 53.
    1 out of 1 hunk FAILED -- saving rejects to file setup.py.rej

    In pythonforandroid-kivmob27, the file __init__.py in recipe folder of pyjnius has not bin updated to pinning the version to pyjnius 1.1.2 for stable p4a and 1.1.3 for master p4a. even manually updating this file also breaks with the error above.

    Running buildozer android update in the app directory

    Thanks

    1. Hi,
      Thank you.
      I forked pythonforandroid before pyjnius version was fixed, will try to sync it with master branch today. Not getting this error myself though.

  11. Hi, I am also stuck with Could not find com.google.android.gms:play-services-ads:16.0.0 and com.android.support:appcompat-v7:26.1.0.
    After exploring sdk23/extras, I found that the play-services-ads are only available up to 11.0.4 and appcompat-v7 up to 26.0.0. Even putting the available versions in the buildozer file results in same error. After some search I found that the build.gradle file is to be update with url “https://maven.google.com”. I have done so but the problem still persists, I’m still digging into this

    https://stackoverflow.com/questions/45696551/failed-to-resolve-com-google-firebasefirebase-core11-2-0

  12. Hey Mate,
    Just wanted to share my app that I finally got a beta version released on the Play Store https://play.google.com/store/apps/details?id=kuamapps.workoutcreator.workoutcreator

    Nothing too fancy yet, but it is a fitness app that allows you to create workouts either randomly or manually from its database of exercises and then helps you time and track your workouts as you do them.

    Thanks for all of your help getting over the last few hurdles and allowing me to get my project released on the Play Store.

    I have yet to try out your rewarded ads fix as I’ve been busy getting my app released and learning the ins and outs of that, but intend to check it out soon.

    Thanks again!

    1. @tkuam, Thank you for sharing your app. I just tried it! How am I the only one unable to figure out ad integration!? πŸ˜­πŸ˜‚ Anyway, your count down is really cool. I’ll have to test your app at the gym (it’s been a while). Did you use plyer’s vibrator for the vibration?

      Also, if you remember the process to integrate ads, can you please share that process? I’m thinking since the whole process was new to you too that you may know the troubles that another noobie might face!

      1. @Petar, Thanks for checking out my app! Yes, I did use plyer for the vibration, made it super simple to implement. As for integrating the ads, I essentially followed the process that @mind_writer posted here. Ran into a couple errors along the way but he helped me get through them. If you read through the comments here from my initial post (if you haven’t already) you’ll see what I had to do.

        What part of the process are you stuck on? What error(s) are you getting? I’m certainly willing to help you try and get it working! Maybe my noobie terminology and explanations will work for you πŸ™‚

        1. Okay, I will take a look at that again. Have you tried to build your app on that method? When I opened the files on my PyCharm, I saw a couple of [ ! ], like in the KivMob27 there is a ‘cast’ variable that is underlined red. Also, should I still have __version__ == ‘1.0’ with that other method? Thank you for your continued patience!

          1. Hi Petar, cast is underlined because it is not used, I just forgot to remove it. It is just a warning. I build my app with this every day, with exactly this version.
            Not sure where __version__ == β€˜1.0’ is coming from, and why it has ever been required, cannot recall mentioning it. Should be safe to remove πŸ™‚

    2. You are welcome mate! I will try out your app in the next couple of days, happy to share feedback if you want me to πŸ™‚

    1. Thanks a lot for letting me know. This is really sad news indeed… Not really sure what is wrong with that recipe, it works for me (python2). Cannot really contribute to developing/fixing recipes yet at this point (do not understand them well enough), but open for collaborations to make it work.

Leave a Reply

Your email address will not be published. Required fields are marked *