Using pyqtdeploy0.5 on Linux to cross compile a PyQt app for Android: Part 3

Rehash

You have:

  1.  set up your dev machine and built static libraries
  2. pyqtdeployed your app so it is ready to deploy

This part discusses:

  • deploying your app to a test target machine
  • debugging your app

More about pyqtdeploy work flow

The pyqtdeploy GUI lets you choose your work flow.  That is, in the ‘Build’ step, you can choose optional steps: qmake, make, ‘run app’.  For example, you can choose none of those, and Build will only create a .pro file.

Then you can switch to:

  • the command line
  • or Qt Creator (a GUI app)

and resume the work flow (qmake, make, deploying, and running.)

(I’m haven’t tried  ‘run’ in pyqtdeploy for target Android, I always switch to another tool.)

pyqtdeploy developer notes

The pyqtdeploy directory contains a file DeveloperNotes.txt.  These notes are by the developer of pyqtdeploy  but are useful hints about Android development.  The author of the notes has said the notes are NOT definitive and should be used with care.  I have found  typos there.

Deploying using the command line

Follow the instructions in the developer notes.   I.e. :

# Assert you ran qmake and make in pyqtdeploy, but not run

# cd to dir that pyqtdeploy created
cd ~/hellobuild/build
export ANDROID_NDK_ROOT=$HOME/android-ndk-r10
export ANDROID_SDK_ROOT=$HOME/android-sdk-linux
# configure install
make install INSTALL_ROOT=deploy
# make deployable
/home/bootch/Qt/5.3/android_armv7/bin/androiddeployqt \
 --input android-lib*.so-deployment-settings.json \
 --output deploy
# deploy
adb install -r deploy/bin/QtApp-debug.apk
echo Now go to AVD and run app

This only installs your app to a target device.  You subsequently must use the target device’s GUI to run your app.

If you get:

Failure [INSTALL_FAILED_ALREADY_EXISTS]

this means you omitted the -r flag, which means reinstall.  An alternative is to manually uninstall the app first (on the device, choose Settings>Apps, then select your app, then choose the Uninstall button.)

Deploying using Qt Creator

When you choose the ‘Run’ icon in Qt Creator, it builds, deploys, and runs your app.  So it is more automated, but harder to understand what Qt Creator is actually doing on your behalf.

Debugging pyqtdeployed apps on android

First, refresh the tools

The tools (especially pqytdeploy, SIP, and PyQt but also Qt and Python) are updated frequently.  You should use the latest versions, which may have fixed some Android crashes.

Remember that pyqtdeploy is the tool that helps build static Python, etc. libraries.   So if you update pyqtdeploy, you should probably rebuild static Python starting with invoking pyqtdeploy (so that any new patches known by pyqtdeploy are applied.)

Stderr and Android logcat

Unfortunately, Python prints exceptions to stdout/stderr.  These by default are dedirected to /dev/null on Android (which means they disappear.)

On android, the system log is called ‘logcat’.  To see it remotely:

>adb logcat > logcat.tmp
>Ctl-C
>vi logcat.tmp

Its a circular file.  Fileness means it persists (even across your debugging sessions.)  Circular means it wraps around, overwriting older data. Pragmatically, one debug session never seems to wrap around on itself.  The end of the file is always the latest log entries?  You can clear it by rebooting the device (powering it off.)

Redirecting stderr to logcat

You should be able to configure your target device to redirect stdout and stderr to logcat.  To do this requires:

  • a rooted real device
  • an AVD (virtual device)

An AVD is always rooted (you have superuser privileges to bypass all security and do what you want).

Rooting a real device is an adventure unto itself, so I chose not to do it yet.  But the advantage is that a real device eliminates the simulator layer, and is quicker to boot and so forth than an AVD.  You can still do certain debugging on an un-rooted real device, you just won’t be able to see Python exceptions directed to stderr.

!!! If a device is not rooted, the adb commands to redirect stdio fail quietly.  So you still won’t see stderr in the logcat.

To do it you can:

  • issue adb commands
  • create a persistent configuration file

adb commands to redirect stdout/stderr

>adb shell stop
>adb shell setprop log.redirect-stdio true
>adb shell start

Remember this doesn’t persist if you reboot the device (whether and AVD or a real device.)

If the device is rooted real device, you must precede that with >adb root.  (AVD’s are always rooted, so >adb root is not necessary.)

Debugging methods

Traditional choices:

  • use a debugger such as gdb (which is built into Qt Creator)
  • harness code with print statements
  • simple code analysis using crash dumps and Python exception tracebacks

It depends on where the bugs are:

  • in the Python interpreter
  • in your pyqtdeploy build process
  • in your app’s Python code

It is not uncommon to find bugs in the Python interpreter, since the Android platform is not supported by Python.org.  (the pyqtdeploy process patches the Python interpreter, and you might find that another patch is required.)

The pyqtdeploy build process is intricate.  It is not uncommmon to find that you have not frozen a needed Python module (and then you might get an ImportError exception.)

Once you get as far as running your own app’s Python code, you probably have installed an exception hook, and can display the exception and traceback on the GUI of the device. (But probably, you are only porting to Android, and have worked out most of your app’s bugs on another platform, except for any Android specific code.)

Harnessing pyqtdeploy apps on android

I experienced the need to harness (since my app seemed to crash before Qt Creator’s debugger could even get started properly and without any Python exceptions.)

This means writing C code.  You can use:

  • qWarning() C function.  It is properly redirected to Android logcat.
  • __android_log foo C function.

If you need to harness the Python interpreter, you might need to study how to write Python extensions, for example to convert a PyObject * to a representation that is a C string suitable for qWarning().

I harnessed pyqtdeploy_start.cpp and Python/import.c.

Here is the code I used:

TODO

Building a debug version of Python

reading an Android crash dump

packaging using Qt Creator

Advertisements

2 thoughts on “Using pyqtdeploy0.5 on Linux to cross compile a PyQt app for Android: Part 3

  1. Pingback: Deploying PyQt Python Qt apps cross platform using pyqtdeploy | plashless

  2. Did you manage to make it works ?
    I successfully compile python, pyqt, sip, create an apk with qtcreator following your tutorial but when the app starts on android (emulator or real) it crash with SIGSEGV signal.
    I’m using the last Python 3.4.3, Qt 5.4.1, Sip 4.16.7 and pyqtdeploy 1.0
    Android ndk r10d, and android sdk 22

    Could you help me ?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s