PySide for Android guide: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
 
(9 intermediate revisions by 4 users not shown)
Line 1: Line 1:
[[Category:LanguageBindings::PySide]]
[[Category:PySide]]
 
{| class="wikitable"
|-
| style="background: #ff6961;text-align: center;"| Attention
|-
| This is a page dedicated to PySide (Qt4). For recent development on PySide2 (Qt5) and PySide6 (Qt6) refer to [[Qt for Python]]
|}


= PySide for Android =
= PySide for Android =


[toc align_right="yes" depth="3"]


This guide describes:
This guide describes:


* how to build Shiboken & PySide for Android using the Necessitas SDK
* how to build Shiboken & PySide for Android using the Necessitas SDK
* how to use the resulting libraries
* how to use the resulting libraries
* and how to bundle them with your Python program in a standalone APK
* and how to bundle them with your Python program in a standalone APK


'''NOTE:''' If you just want to run you Python & PySide programs on Android, you can skip the ''Building PySide'' section and go directly to "PySide for Android example application":http://wiki.qt.io/PySide_for_Android_guide#0f9f7f288b4f606f352d2dfede683e15 & "Example project for the Necessitas Qt Creator":http://wiki.qt.io/PySide_for_Android_guide#9de8e69b9d5975439d9560475508d28b .
'''NOTE:''' If you just want to run you Python & PySide programs on Android, you can skip the ''Building PySide'' section and go directly to [http://wiki.qt.io/PySide_for_Android_guide#0f9f7f288b4f606f352d2dfede683e15 PySide for Android example application] & [http://wiki.qt.io/PySide_for_Android_guide#9de8e69b9d5975439d9560475508d28b Example project for the Necessitas Qt Creator] .


See "Links":http://wiki.qt.io/PySide_for_Android_guide/#bd908db5ccb07777ced8023dffc802f4 for "source code":http://wiki.qt.io/PySide_for_Android_guide/#b8e1f77d0be4f2c3175a2050caae5132 & "pre-built binaries":http://wiki.qt.io/PySide_for_Android_guide/#9b5d07e7366cd5412ce3607b5d4b2785.
See [http://wiki.qt.io/PySide_for_Android_guide/#bd908db5ccb07777ced8023dffc802f4 Links] for [http://wiki.qt.io/PySide_for_Android_guide/#b8e1f77d0be4f2c3175a2050caae5132 source code] & [http://wiki.qt.io/PySide_for_Android_guide/#9b5d07e7366cd5412ce3607b5d4b2785 pre-built binaries].


== Building PySide ==
== Building PySide ==
Line 19: Line 25:
=== Prerequisites ===
=== Prerequisites ===


==== Necessitas SDK<br />Make sure to get the latest Necessitas alpha 4 SDK - older version might not work correctly with the build script (incompatible libraries, different paths, etc.). ====
==== Necessitas SDK ====
Make sure to get the latest Necessitas alpha 4 SDK - older version might not work correctly with the build script (incompatible libraries, different paths, etc.).  
 
Download & run the Necessitas SDK installer
 
<code>
wget http://files.kde.org/necessitas/installer/release/linux-online-necessitas-alpha4-sdk-installer
chmod ''x linux-online-necessitas-alpha4-sdk-installer
./linux-online-necessitas-alpha4-sdk-installer
</code>
 
'''Once the installer starts -> don't forget to install Android API 14 [[Image:|Image:]]*
* on the ''Select components'' page go to * Miscellaneous->Android SDK''' and select '''API 14''' for installation


Download &amp; run the Necessitas SDK installer
* to make sure you have the Android SDK platform/API 14 installed in the Necessitas SDK (can be done after SDK installation):
- run SDKMaintenanceTool select ''Package manager'' and in '''Miscantelous->Android SDK''' check if you have '''API 14''' installed
- PySide should probably compile even against a lower API, but that has not been tested yet


<code><br />wget http://files.kde.org/necessitas/installer/release/linux-online-necessitas-alpha4-sdk-installer<br />chmod ''x linux-online-necessitas-alpha4-sdk-installer<br />./linux-online-necessitas-alpha4-sdk-installer<br /></code>
==== Other prerequisites ====
<br />'''Once the installer starts <s>&gt; don't forget to install Android API 14 [[Image:|Image:]]*<br />* on the ''Select components'' page go to * Miscellaneous</s>&gt;Android SDK''' and select '''API 14''' for installation
* system-wide installed Shiboken
<br />* to make sure you have the Android SDK platform/API 14 installed in the Necessitas SDK (can be done after SDK installation):<br />- run &lt;code&amp;gt;SDKMaintenanceTool&amp;lt;/code&amp;gt; select ''Package manager'' and in '''Miscantelous-&gt;Android SDK''' check if you have '''API 14''' installed<br />- PySide should probably compile even against a lower API, but that has not been tested yet
* system-wide installed Python 2.7
<br />h4. Other prerequisites
* Python 2.7 compiled for Android
<br />* system-wide installed Shiboken<br />* system-wide installed Python 2.7<br />* Python 2.7 compiled for Android<br />* cmake<br />* git
* cmake
<br />This command should probably fetch most of the prerequisites on Ubuntu:<br /><code><br />sudo apt-get install build-essential cmake git python2.7-minimal shiboken<br /></code>
* git
<br />If you find some are is missing or if you wan't to provide similar command for other distributions, add them ! :)
<br />Then clone the ''Android-pyside-build-scripts'' project and ''cd'' to it's directory:<br /><code><br />git clone https://github.com/M4rtinK/android-pyside-build-scripts.git<br />cd android-pyside-build-scripts<br /></code>
<br />Now run the ''prepare.sh'' script:<br /><code><br />./prepare.sh<br /></code><br />It clones Android-modified Shiboken &amp; PySide and creates some folders needed for the build.
<br />And that's it, you are ready to start the build. :)
<br />h3. Build
<br />To start the build, just run the main build script, called ''build.sh'':<br /><code><br />./build.sh<br /></code><br />It first builds Shiboken, followed by PySide. The script is fully automatic, but waits for the user to ''press any key'':<br />* after Shiboken is configured for build<br />* after PySide is configured for build<br />Like this you can easily check for any errors during configuration.
<br />Also note, that when running the script, it clears any previous build results before building.
<br />You can also run the ''build_shiboken.sh'' and ''build_pyside.sh'' scripts manually, just always make sure to run the Shiboken one before running the PySide one.
<br />h3. Build issues
<br />If you have any issues during the PySide build, the first thing you should do is to check the PySide for Android build scripts repository if it was not updated since you cloned it, as it might already contain a fix for you issue.
<br />h4. arm-linux-androideabi-g: Internal error: Killed (program cc1plus)
<br />This error seems to be caused by low system resources during build and/or running the compilation in multiple threads on some machines. If you are experiencing this error, try to set &lt;code&amp;gt;BUILD_THREAD_COUNT&amp;lt;/code&amp;gt; in &lt;code&amp;gt;env.sh&amp;lt;/code&amp;gt; to 1.
<br />h3. Results
<br />The resulting PySide libraries compiled for Android are located in the ''stage/lib'' folder.
<br />See the ''Example project for the Necessitas Qt Creator'', &quot;Modifying the project&amp;quot;:http://wiki.qt.io/PySide_for_Android_guide#9de8e69b9d5975439d9560475508d28b, section ''Replacing PySide libraries'' for how the PySide libraries can be used as a part of a self-contained Android application.


<br />h2. PySide for Android example application
This command should probably fetch most of the prerequisites on Ubuntu:
<br />This is an example, that demonstrates a fully functional standalone Android application that uses Python, PySide and Qt Components.
<code>
<br />[[Image:&#123;width: 25%; height: 25%;&#125;http://modrana.org/images/android/example/example_landscape.png|example application in ladscape]] [[Image:&#123;width: 14%; height: 14%;&#125;http://modrana.org/images/android/example/example_portrait_kbtest.png|example application in portrait]] [[Image:&#123;width: 14%; height: 14%;&#125;http://modrana.org/images/android/example/example_portrait_tools.png|example application showing the tools menu]]
sudo apt-get install build-essential cmake git python2.7-minimal shiboken
<br />&quot;more screenshots&amp;quot;:http://modrana.org/trac/wiki/ScreenshotsEN#PySideQtComponentsexample
</code>
<br />h3. Ready-to-install APK
<br />A ready-to-install standalone APK is available here:
<br />http://modrana.org/platforms/android/pyside_example/PySideExample_1.2.apk
<br />Just install it and press the ''PySideExample'' icon.
<br />h4. First start
<br />If you haven't yet installed any Ministro using Qt application on your Android device, you will be redirected to the Play store to install the Ministro application. Ministro is a manager &amp; updater for the Qt libraries for Android. The example application requires to be installed to run.<br />So just install Ministro and everything else will be handled automatically. You might need to press the ''PySideExample'' icon again once Ministro is installed.
<br />Once Ministro is installed and does it's work, the example might still take some time to start, as it is unpacking Python, Qt Components, theme for Qt Components and the example program to it's working directory. Once the unpacking is finished, the example application will be started.
<br />The unpacking is done only once on the first application start, following starts are very fast, at least when tested on my device (HP Touchpad with CM9).
<br />h4. What the example application demonstrates
<br />* sending data to Python and back<br /> * the content of the entry field is sent to Python, where it is painted on the PySide image and returned to QML using ImageProvider<br /> * the date is retrieved in Python and shown in QML<br />* working text entry with the Android virtual keyboard<br />* working screen rotation<br />* correct Portrait/Landscape orientation switching<br /> * in both normal &amp; inverted orientations<br />* working notifications (InfoBanner)<br />* working ToolBar<br />* working Menu<br />* &quot;tools&amp;quot; menu with rotation &amp; opacity sliders for the PySide image
<br />h4. Source code
<br />Available from Github under BSD licence:<br />https://github.com/M4rtinK/expyside/tree/android
<br />h4. Size of the APK
<br />The example APK has about 16 MB. This is because it needs to bundle quite a lot of<br />libraries and related files. Big part of it is actually not used by the example in any way.
<br />For normal applications it should be possible to make the resulting APK much smaller by:<br />* including only the PySide libraries that are actually used<br />* removing unused Python modules<br />* cutting down the Qt Components theme from all graphics &amp; icons that are not used
<br />h2. Example project for the Necessitas Qt Creator
<br />This project has been used to generate the above mentioned application example APK.
<br />h3. Using the project
<br />Using the project to build your own project is very easy. Just install the [http://necessitas.kde.org/necessitas/necessitas_sdk_installer.php Necessitas SDK] and clone the example project from git:<br /><code><br />git clone https://github.com/M4rtinK/android-pyside-example-project.git<br /></code><br />Then just open the ''PySideExample.pro'' with the Necessitas Qt Creator.
<br />To generate a new APK, just click the green '''run''' arrow in the lower left - Qt Creator should rebuild the the APK and deploy it either to the simulator or to any connected Android device that has debugging enabled.
<br />h4. Build &amp; deployment issues
<br />h5. '''The example fails to start when deployed to device'''
<br />First check you have the latest clone of the project.
<br />Then check for which ARM architecture are you building by clicking on '''Projects'''. The available architecture targets are:<br />* Necessitas Qt 4.8.2 for Android armv5<br />* Necessitas Qt 4.8.2 for Android armv7a
<br />The currently used architecture dark, the unused is white-grey. The build architecture needs to correspond to what the CPU of your device is using. If not sure, just try both and stick with the one that works. :)
<br />h5. '''Cannot find ELF information'''
<br />This error is harmless and can be safely ignored.
<br />h3. How does it work ?
<br />The project contains various components, that together enable the creation of fully standalone Python &amp; PySide application APK, while also allowing to bundle any arbitrary libraries and files needed by the application.
<br />The example project is called &lt;code&amp;gt;PySideExample&amp;lt;/code&amp;gt; and uses the &lt;code&amp;gt;org.modrana.PySideExample&amp;lt;/code&amp;gt; unique name. This means, that when it's APK is installed on and Android device, it gets installed to this directory:<br /><code><br />/data/data/org.modrana.PySide.Example/<br /></code><br />This path is important, as the application needs to set a couple of environmental variables during startup, pointing to libraries and themes that reside in this directory.
<br />h4. C''+ wrapper


The &lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; and &lt;code&amp;gt;main.h&amp;lt;/code&amp;gt; files are used to build a C++ Python wrapper. This wrapper is build against the the Android-compiled python libraries in &lt;code&amp;gt;build_dependencies/python&amp;lt;/code&amp;gt; by Necessitas.
If you find some are is missing or if you wan't to provide similar command for other distributions, add them ! :)


Once the APK is deployd to the device and started, this wrapper is run. It initializes it's build-in Python interpreter, which tries to start the &lt;code&amp;gt;/data/data/org.modrana.PySide.Example/files/main.py&amp;lt;/code&amp;gt; Python file. This Python code then imports PySide, instantiates a QApplication and starts the main loop.
Then clone the ''Android-pyside-build-scripts'' project and ''cd'' to it's directory:
<code>
git clone https://github.com/M4rtinK/android-pyside-build-scripts.git
cd android-pyside-build-scripts
</code>


Behind the scenes, Necessitas handles wrapping the QApplication to an Android activity and showing it on the screen. It also handles other stuff like keyboard input &amp; Qt Mobility.
Now run the ''prepare.sh'' script:
<code>
./prepare.sh
</code>
It clones Android-modified Shiboken & PySide and creates some folders needed for the build.
 
And that's it, you are ready to start the build. :)
 
=== Build ===
To start the build, just run the main build script, called ''build.sh'':
<code>
./build.sh
</code>
It first builds Shiboken, followed by PySide. The script is fully automatic, but waits for the user to ''press any key'':
* after Shiboken is configured for build
* after PySide is configured for build
Like this you can easily check for any errors during configuration.
 
Also note, that when running the script, it clears any previous build results before building.
 
You can also run the ''build_shiboken.sh'' and ''build_pyside.sh'' scripts manually, just always make sure to run the Shiboken one before running the PySide one.
 
=== Build issues ===
If you have any issues during the PySide build, the first thing you should do is to check the PySide for Android build scripts repository if it was not updated since you cloned it, as it might already contain a fix for you issue.
 
==== arm-linux-androideabi-g: Internal error: Killed (program cc1plus) ====
This error seems to be caused by low system resources during build and/or running the compilation in multiple threads on some machines. If you are experiencing this error, try to set BUILD_THREAD_COUNT in env.sh to 1.
 
=== Results ===
The resulting PySide libraries compiled for Android are located in the ''stage/lib'' folder.
 
See the ''Example project for the Necessitas Qt Creator'', [http://wiki.qt.io/PySide_for_Android_guide#9de8e69b9d5975439d9560475508d28b Modifying the project], section ''Replacing PySide libraries'' for how the PySide libraries can be used as a part of a self-contained Android application.
 
 
== PySide for Android example application ==
This is an example, that demonstrates a fully functional standalone Android application that uses Python, PySide and Qt Components.
 
<gallery>
File:Expyside1.png|example application in ladscape
File:Expyside2.png|example application in portrait
File:Expyside3.png|example application showing the tools menu
</gallery>
[http://modrana.org/trac/wiki/ScreenshotsEN#PySideQtComponentsexample more screenshots]
 
=== Ready-to-install APK ===
A ready-to-install standalone APK is available here:
 
http://modrana.org/platforms/android/pyside_example/PySideExample_1.2.apk
 
Just install it and press the ''PySideExample'' icon.
 
==== First start ====
If you haven't yet installed any Ministro using Qt application on your Android device, you will be redirected to the Play store to install the Ministro application. Ministro is a manager & updater for the Qt libraries for Android. The example application requires to be installed to run.
So just install Ministro and everything else will be handled automatically. You might need to press the ''PySideExample'' icon again once Ministro is installed.
 
Once Ministro is installed and does it's work, the example might still take some time to start, as it is unpacking Python, Qt Components, theme for Qt Components and the example program to it's working directory. Once the unpacking is finished, the example application will be started.
 
The unpacking is done only once on the first application start, following starts are very fast, at least when tested on my device (HP Touchpad with CM9).
 
==== What the example application demonstrates ====
* sending data to Python and back * the content of the entry field is sent to Python, where it is painted on the PySide image and returned to QML using ImageProvider * the date is retrieved in Python and shown in QML
* working text entry with the Android virtual keyboard
* working screen rotation
* correct Portrait/Landscape orientation switching * in both normal & inverted orientations
* working notifications (InfoBanner)
* working ToolBar
* working Menu
* "tools" menu with rotation & opacity sliders for the PySide image
 
==== Source code ====
Available from Github under BSD licence:
https://github.com/M4rtinK/expyside/tree/android
 
==== Size of the APK ====
The example APK has about 16 MB. This is because it needs to bundle quite a lot of
libraries and related files. Big part of it is actually not used by the example in any way.
 
For normal applications it should be possible to make the resulting APK much smaller by:
* including only the PySide libraries that are actually used
* removing unused Python modules
* cutting down the Qt Components theme from all graphics & icons that are not used
 
== Example project for the Necessitas Qt Creator ==
This project has been used to generate the above mentioned application example APK.
 
=== Using the project ===
Using the project to build your own project is very easy. Just install the [http://necessitas.kde.org/necessitas/necessitas_sdk_installer.php Necessitas SDK] and clone the example project from git:
<code>
git clone https://github.com/M4rtinK/android-pyside-example-project.git
</code>
Then just open the ''PySideExample.pro'' with the Necessitas Qt Creator.
 
To generate a new APK, just click the green '''run''' arrow in the lower left - Qt Creator should rebuild the the APK and deploy it either to the simulator or to any connected Android device that has debugging enabled.
 
==== Build & deployment issues ====
===== '''The example fails to start when deployed to device''' =====
First check you have the latest clone of the project.
 
Then check for which ARM architecture are you building by clicking on '''Projects'''. The available architecture targets are:
* Necessitas Qt 4.8.2 for Android armv5
* Necessitas Qt 4.8.2 for Android armv7a
 
The currently used architecture dark, the unused is white-grey. The build architecture needs to correspond to what the CPU of your device is using. If not sure, just try both and stick with the one that works. :)
 
===== '''Cannot find ELF information''' =====
This error is harmless and can be safely ignored.
 
=== How does it work ? ===
The project contains various components, that together enable the creation of fully standalone Python & PySide application APK, while also allowing to bundle any arbitrary libraries and files needed by the application.
 
The example project is called PySideExample and uses the org.modrana.PySideExample unique name. This means, that when it's APK is installed on and Android device, it gets installed to this directory:
<code>
/data/data/org.modrana.PySide.Example/
</code>
This path is important, as the application needs to set a couple of environmental variables during startup, pointing to libraries and themes that reside in this directory.
 
==== C''+ wrapper ====
The main.cpp and main.h files are used to build a C++ Python wrapper. This wrapper is build against the the Android-compiled python libraries in build_dependencies/python by Necessitas.
 
Once the APK is deployd to the device and started, this wrapper is run. It initializes it's build-in Python interpreter, which tries to start the /data/data/org.modrana.PySide.Example/files/main.py Python file. This Python code then imports PySide, instantiates a QApplication and starts the main loop.
 
Behind the scenes, Necessitas handles wrapping the QApplication to an Android activity and showing it on the screen. It also handles other stuff like keyboard input & Qt Mobility.


===== main.h =====
===== main.h =====
Line 91: Line 190:
This file contains important paths for the C++ wrapper.
This file contains important paths for the C++ wrapper.


<code><br />#ifndef MAIN_H<br />#define MAIN_H
<code>
#ifndef MAIN_H
#define MAIN_H


#define MAIN_PYTHON_FILE &quot;/data/data/org.modrana.PySideExample/files/main.py&amp;quot;
#define MAIN_PYTHON_FILE "/data/data/org.modrana.PySideExample/files/main.py"


#define PYTHON_HOME &quot;/data/data/org.modrana.PySideExample/files/python/&amp;quot;
#define PYTHON_HOME "/data/data/org.modrana.PySideExample/files/python/"


#define PYTHON_PATH &quot;/data/data/org.modrana.PySideExample/files/python/lib/python2.7/lib-dynload:/data/data/org.modrana.PySideExample/files/python/lib/python2.7/:/data/data/org.modrana.PySideExample/files/python/lib/python2.7/site-packages:/data/data/org.modrana.PySideExample/files/python/lib&amp;quot;
#define PYTHON_PATH "/data/data/org.modrana.PySideExample/files/python/lib/python2.7/lib-
dynload:/data/data/org.modrana.PySideExample/files/python/lib/python2.7/:/data/data/org.modrana.
PySideExample/files/python/lib/python2.7/site-
packages:/data/data/org.modrana.PySideExample/files/python/lib"


#define LD_LIBRARY_PATH &quot;/data/data/org.modrana.PySideExample/files/python/lib:/data/data/org.modrana.PySideExample/files/python/lib/python2.7/lib-dynload:/data/data/org.kde.necessitas.ministro/files/qt/lib/&amp;quot;
#define LD_LIBRARY_PATH "/data/data/org.modrana.PySideExample/files/python/lib:/data
/data/org.modrana.PySideExample/files/python/lib/python2.7/lib-
dynload:/data/data/org.kde.necessitas.ministro/files/qt/lib/"


#define PATH &quot;/data/data/org.modrana.PySideExample/files/python/bin:$PATH&amp;quot;
#define PATH "/data/data/org.modrana.PySideExample/files/python/bin:$PATH"


#define THEME_PATH &quot;/data/data/org.modrana.PySideExample/files/python/themes/&amp;quot;
#define THEME_PATH "/data/data/org.modrana.PySideExample/files/python/themes/"


#define QML_IMPORT_PATH &quot;/data/data/org.modrana.PySideExample/files/python/imports/&amp;quot;
#define QML_IMPORT_PATH "/data/data/org.modrana.PySideExample/files/python/imports/"


#define PYSIDE_APPLICATION_FOLDER &quot;/data/data/org.modrana.PySideExample/&amp;quot;
#define PYSIDE_APPLICATION_FOLDER "/data/data/org.modrana.PySideExample/"


#endif // MAIN_H<br /></code>
#endif // MAIN_H
</code>


* &lt;code&amp;gt;MAIN_PYTHON_FILE&amp;lt;/code&amp;gt; - path to the main Python file to run once the application is started
* MAIN_PYTHON_FILE - path to the main Python file to run once the application is started
* &lt;code&amp;gt;PYTHON_HOME&amp;lt;/code&amp;gt;
* PYTHON_HOME
* &lt;code&amp;gt;LD_LIBRARY_PATH&amp;lt;/code&amp;gt; - '':'' separated list of paths used to look for libraries when loading them
* LD_LIBRARY_PATH - '':'' separated list of paths used to look for libraries when loading them
* &lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; - search path for executables
* PATH - search path for executables
* &lt;code&amp;gt;THEME_PATH&amp;lt;/code&amp;gt; - path to the main themes folder for Qt Components
* THEME_PATH - path to the main themes folder for Qt Components
* &lt;code&amp;gt;QML_IMPORT_PATH&amp;lt;/code&amp;gt; - path to the Qt Components &lt;code&amp;gt;imports&amp;lt;/code&amp;gt; folder
* QML_IMPORT_PATH - path to the Qt Components imports folder


===== main.cpp =====
===== main.cpp =====


This is the C++ wrapper, it contains the embedded Python interpreter that is used to start the application and also sets some important environmental variables specified through &lt;code&amp;gt;main.h&amp;lt;/code&amp;gt; .
This is the C++ wrapper, it contains the embedded Python interpreter that is used to start the application and also sets some important environmental variables specified through main.h .


==== The example Python application ====
==== The example Python application ====


The example in &lt;code&amp;gt;main.py&amp;lt;/code&amp;gt; inside &lt;code&amp;gt;my_python_project.zip&amp;lt;/code&amp;gt; is basically a normal PySide application, it imports PySide, instantiates QApplication and starts the main loop. There is only one main difference in this piece of code:
The example in main.py inside my_python_project.zip is basically a normal PySide application, it imports PySide, instantiates QApplication and starts the main loop. There is only one main difference in this piece of code:


<code><br />from ctypes import *<br />PROJECT_FOLDER = os.environ['PYSIDE_APPLICATION_FOLDER']<br /># 'PYSIDE_APPLICATION_FOLDER' can be configured in main.h<br />LIB_DIR = os.path.join(PROJECT_FOLDER, 'files/python/lib')<br />SHIBOKEN_SO = os.path.join(LIB_DIR, 'libshiboken.so')<br />PYSIDE_SO = os.path.join(LIB_DIR, 'libpyside.so')<br /></code>
<code>
from ctypes import *
PROJECT_FOLDER = os.environ['PYSIDE_APPLICATION_FOLDER']
# 'PYSIDE_APPLICATION_FOLDER' can be configured in main.h
LIB_DIR = os.path.join(PROJECT_FOLDER, 'files/python/lib')
SHIBOKEN_SO = os.path.join(LIB_DIR, 'libshiboken.so')
PYSIDE_SO = os.path.join(LIB_DIR, 'libpyside.so')
</code>


Due to some not yet identified bug, unless &lt;code&amp;gt;libshiboken.so&amp;lt;/code&amp;gt; &amp; &lt;code&amp;gt;libpyside.so&amp;lt;/code&amp;gt; are manually loaded to memory like this, importing any PySide module fails.
Due to some not yet identified bug, unless libshiboken.so & libpyside.so are manually loaded to memory like this, importing any PySide module fails.


'''So make sure this piece of code is somewhere in your application and is executed before import of any PySide module takes place.'''
'''So make sure this piece of code is somewhere in your application and is executed before import of any PySide module takes place.'''


Regarding the &lt;code&amp;gt;PYSIDE_APPLICATION_FOLDER&amp;lt;/code&amp;gt; environmental variable, it is set by the &lt;code&amp;gt;main.cpp&amp;lt;/code&amp;gt; wrapper and can be configured in &lt;code&amp;gt;main.h&amp;lt;/code&amp;gt; .
Regarding the PYSIDE_APPLICATION_FOLDER environmental variable, it is set by the main.cpp wrapper and can be configured in main.h .


==== Bundling ====
==== Bundling ====
Line 140: Line 254:
===== Modified QtActivity.java =====
===== Modified QtActivity.java =====


Another mportant file is the main Android ''activity'' located in &lt;code&amp;gt;android/src/org/kde/necessitas/origo/QtActivity.java&amp;lt;/code&amp;gt; This is actually the first thing that is started once you press the application icon on android. It basically works as a glue between Android, Qt and in our case, Python &amp; PySide.
Another mportant file is the main Android ''activity'' located in <code>android/src/org/kde/necessitas/origo/QtActivity.java</code> This is actually the first thing that is started once you press the application icon on android. It basically works as a glue between Android, Qt and in our case, Python & PySide.


The basic activity file that is part of every Necessitas Qt Creator project has been modified by the ''android_python27'' project, to look for two specific zip archives in the installation folder at startup ant to decompress them &amp; then remover the archives.
The basic activity file that is part of every Necessitas Qt Creator project has been modified by the ''android_python27'' project, to look for two specific zip archives in the installation folder at startup ant to decompress them & then remover the archives.


This way bundling of arbitrary files (libraries, executables, code, themes, etc.) inside the application APK has been achieved.
This way bundling of arbitrary files (libraries, executables, code, themes, etc.) inside the application APK has been achieved.


'''NOTE:''' Necessitas Qt Creator might sometimes want to update the pre-generated '''.java files with a new version. If this happens, check if the update didn't break or remove the bundling code in &lt;code&amp;gt;QtActivity.java&amp;lt;/code&amp;gt; .
'''NOTE:''' Necessitas Qt Creator might sometimes want to update the pre-generated '''.java files with a new version. If this happens, check if the update didn't break or remove the bundling code in QtActivity.java .
<br />h5. GlobalConstants.java
 
<br />The file &lt;code&amp;gt;android/src/org/kde/necessitas/origo/GlobalConstants.java&amp;lt;/code&amp;gt; contains variables for the main &lt;code&amp;gt;QtActivity&amp;lt;/code&amp;gt; file.
===== GlobalConstants.java =====
<br />It looks like this:
The file android/src/org/kde/necessitas/origo/GlobalConstants.java contains variables for the main QtActivity file.
<br /><code><br />package org.kde.necessitas.origo;
 
<br />public class GlobalConstants {
It looks like this:
<br /> public static final String PYTHON_MAIN_SCRIPT_NAME = &quot;main.py&amp;quot;;<br /> public static final String PYTHON_PROJECT_ZIP_NAME = &quot;my_python_project.zip&amp;quot;;<br /> public static final String PYTHON_ZIP_NAME = &quot;python_27.zip&amp;quot;;<br /> public static final String PYTHON_EXTRAS_ZIP_NAME = &quot;python_extras_27.zip&amp;quot;;
 
<br /> public static final boolean IS_FOREGROUND_SERVICE = true;
<code>
<br /> public static final String PYTHON_BIN_RELATIVE_PATH = &quot;/python/bin/python&amp;quot;;<br /> public static final String PYTHON_NAME = &quot;python&amp;quot;;<br /> public static final String PYTHON_NICE_NAME = &quot;Python 2.7.2&amp;quot;;
package org.kde.necessitas.origo;
<br /> public static String[] SCRIPT_ARGS = { &quot;—foreground&amp;quot; };
 
<br /> public static final String LOG_TAG = &quot;PythonAPK&amp;quot;;<br />}<br /></code><br />As you can see, you can use it to set various variables, such as name of the bundling archives or logging prefix (does this actually work ?).
public class GlobalConstants {
<br />h5. my_python_project.zip
 
<br />The first archive, located in &lt;code&amp;gt;android/res/raw/my_python_project.zip&amp;lt;/code&amp;gt; in the project contains the Python application code. On first application start, it's contents are unpacked into:
public static final String PYTHON_MAIN_SCRIPT_NAME = "main.py";
<br />&lt;code&amp;gt;/data/data/org.modrana.PySide.Example/files/&amp;lt;/code&amp;gt;
public static final String PYTHON_PROJECT_ZIP_NAME = "my_python_project.zip";
<br />h5. python27.zip
public static final String PYTHON_ZIP_NAME = "python_27.zip";
<br />This file is located &lt;code&amp;gt;android/res/raw/python_27.zip&amp;lt;/code&amp;gt; in the project and it's content is unpacked to:
public static final String PYTHON_EXTRAS_ZIP_NAME = "python_extras_27.zip";
<br />&lt;code&amp;gt;/data/data/org.modrana.PySide.Example/files/python&amp;lt;/code&amp;gt;
 
<br />The paths set in &lt;code&amp;gt;main.h&amp;lt;/code&amp;gt; expect this and point the corresponding environmental variables to the &lt;code&amp;gt;bin&amp;lt;/code&amp;gt;, &lt;code&amp;gt;lib&amp;lt;/code&amp;gt;, &lt;code&amp;gt;imports&amp;lt;/code&amp;gt; and &lt;code&amp;gt;themes&amp;lt;/code&amp;gt; folders in this directory.
public static final boolean IS_FOREGROUND_SERVICE = true;
<br />h3. Modifying the project
 
<br />When you want to use the example project as basis for your Python application for Android, you just need to rename it and replace the example application.  
public static final String PYTHON_BIN_RELATIVE_PATH = "/python/bin/python";
<br />But just in case I've also documented replacing all the other components.
public static final String PYTHON_NAME = "python";
<br />h4. Renaming
public static final String PYTHON_NICE_NAME = "Python 2.7.2";
<br />h5. Names
 
<br />There are actually two names - the project/application name and the unique application name.
public static String[] SCRIPT_ARGS = { "—foreground" };
<br />For the example project, they project name is &lt;code&amp;gt;PySideExample&amp;lt;/code&amp;gt; and the unique name is &lt;code&amp;gt;org.modrana.PySideExample&amp;lt;/code&amp;gt;. As you can see, the project name is also a suffix for the unique name. (You probably can use a project name that differs from the suffix, but I rather make them the same to avoid needless confusion).
 
<br />The unique name is very important:<br />''' it has to be unique so it dosn't clash with other applications<br /> * for this reason, it is mostly based on a domain name you control or some other string with low possibility of being used by another developer<br />* the unique name is used for path to the installation folder<br /> * the example project uses the &lt;code&amp;gt;org.modrana.PySideExample&amp;lt;/code&amp;gt; and it is installed into &lt;code&amp;gt;/data/data/org.modrana.PySideExample&amp;lt;/code&amp;gt; as a result<br /> * the path to the installation folder is used when setting important environmental variables, so make sure to change all the corresponding paths when changing the unique name
public static final String LOG_TAG = "PythonAPK";
}
</code>
As you can see, you can use it to set various variables, such as name of the bundling archives or logging prefix (does this actually work ?).
 
===== my_python_project.zip =====
The first archive, located in android/res/raw/my_python_project.zip in the project contains the Python application code. On first application start, it's contents are unpacked into:
 
/data/data/org.modrana.PySide.Example/files/
 
===== python27.zip =====
 
This file is located android/res/raw/python_27.zip in the project and it's content is unpacked to:
 
/data/data/org.modrana.PySide.Example/files/python
 
The paths set in main.h expect this and point the corresponding environmental variables to the bin, lib, imports and themes folders in this directory.
 
=== Modifying the project ===
When you want to use the example project as basis for your Python application for Android, you just need to rename it and replace the example application.  
 
But just in case I've also documented replacing all the other components.
 
==== Renaming ====
===== Names =====
There are actually two names - the project/application name and the unique application name.
 
For the example project, they project name is PySideExample and the unique name is org.modrana.PySideExample. As you can see, the project name is also a suffix for the unique name. (You probably can use a project name that differs from the suffix, but I rather make them the same to avoid needless confusion).
 
The unique name is very important:
* it has to be unique so it dosn't clash with other applications * for this reason, it is mostly based on a domain name you control or some other string with low possibility of being used by another developer
* the unique name is used for path to the installation folder * the example project uses the org.modrana.PySideExample and it is installed into /data/data/org.modrana.PySideExample as a result * the path to the installation folder is used when setting important environmental variables, so make sure to change all the corresponding paths when changing the unique name


===== Project rename script =====
===== Project rename script =====


You can also run this combined script from the project directory, which should do all the needed renaming:<br /><code><br />NEW_NAME=&quot;BarApp&amp;quot;<br />NEW_UNIQUE_NAME=&quot;foo.foomatic.${NEW_NAME}&quot;
You can also run this combined script from the project directory, which should do all the needed renaming:
<code>
NEW_NAME="BarApp"
NEW_UNIQUE_NAME="foo.foomatic.${NEW_NAME}"


mv PySideExample.pro &quot;${NEW_NAME}.pro&amp;quot;<br />sed -i &quot;s/PySideExample/${NEW_NAME}/g&amp;quot; &quot;${NEW_NAME}.pro&amp;quot;<br />sed -i &quot;s/org.modrana.PySideExample/${NEW_UNIQUE_NAME}/g&amp;quot; main.h<br />sed -i &quot;s/org.modrana.PySideExample/${NEW_UNIQUE_NAME}/g&amp;quot; android/src/org/kde/necessitas/origo/QtActivity.java<br />sed -i &quot;s/org.modrana.PySideExample/${NEW_UNIQUE_NAME}/g&amp;quot; android/AndroidManifest.xml<br />sed -i &quot;s/PySideExample/${NEW_NAME}/g&amp;quot; android/AndroidManifest.xml<br />sed -i &quot;s/PySideExample/${NEW_NAME}/g&amp;quot; android/res/values/strings.xml<br />sed -i &quot;s/PySideExample/${NEW_NAME}/g&amp;quot; android/build.xml<br /></code><br />Just change &lt;code&amp;gt;NEW_NAME&amp;lt;/code&amp;gt; and &lt;code&amp;gt;NEW_UNIQUE_NAME&amp;lt;/code&amp;gt; to values matching you application and you are set. :)
mv PySideExample.pro "${NEW_NAME}.pro"
sed -i "s/PySideExample/${NEW_NAME}/g" "${NEW_NAME}.pro"
sed -i "s/org.modrana.PySideExample/${NEW_UNIQUE_NAME}/g" main.h
sed -i "s/org.modrana.PySideExample/${NEW_UNIQUE_NAME}/g" android/src/org/kde/necessitas/origo/QtActivity.java
sed -i "s/org.modrana.PySideExample/${NEW_UNIQUE_NAME}/g" android/AndroidManifest.xml
sed -i "s/PySideExample/${NEW_NAME}/g" android/AndroidManifest.xml
sed -i "s/PySideExample/${NEW_NAME}/g" android/res/values/strings.xml
sed -i "s/PySideExample/${NEW_NAME}/g" android/build.xml
</code>
Just change NEW_NAME and NEW_UNIQUE_NAME to values matching you application and you are set. :)


===== What the rename script does =====
===== What the rename script does =====


Lets say we want to rename the example project from &lt;code&amp;gt;PySideExample&amp;lt;/code&amp;gt; to &lt;code&amp;gt;BarApp&amp;lt;/code&amp;gt; and from &lt;code&amp;gt;org.modrana.PySideExample&amp;lt;/code&amp;gt; to &lt;code&amp;gt;foo.foomatic.BarApp&amp;lt;/code&amp;gt;
Lets say we want to rename the example project from PySideExample to BarApp and from org.modrana.PySideExample to foo.foomatic.BarApp


* rename the project file:<br /><code><br />mv PySideExample.pro BarApp.pro<br /></code>
* rename the project file:
<code>
mv PySideExample.pro BarApp.pro
</code>


* replace the name inside the project file:<br /><code><br />sed -i &quot;s/PySideExample/BarApp/g&amp;quot; BarApp.pro<br /></code>
* replace the name inside the project file:
<code>
sed -i "s/PySideExample/BarApp/g" BarApp.pro
</code>


* replace all unique names in &lt;code&amp;gt;main.h&amp;lt;/code&amp;gt;:<br /><code><br />sed -i &quot;s/org.modrana.PySideExample/foo.foomatic.BarApp/g&amp;quot; main.h<br /></code>
* replace all unique names in main.h:
<code>
sed -i "s/org.modrana.PySideExample/foo.foomatic.BarApp/g" main.h
</code>


* replace all unique names in the &lt;code&amp;gt;QtActivity&amp;lt;/code&amp;gt;:<br /><code><br />sed -i &quot;s/org.modrana.PySideExample/foo.foomatic.BarApp/g&amp;quot; android/src/org/kde/necessitas/origo/QtActivity.java<br /></code>
* replace all unique names in the QtActivity:
<code>
sed -i "s/org.modrana.PySideExample/foo.foomatic.BarApp/g" android/src/org/kde/necessitas/origo/QtActivity.java
</code>


* replace all names in the Android manifest file:<br /><code><br />sed -i &quot;s/org.modrana.PySideExample/foo.foomatic.BarApp/g&amp;quot; android/AndroidManifest.xml<br />sed -i &quot;s/PySideExample/BarApp/g&amp;quot; android/AndroidManifest.xml<br /></code>
* replace all names in the Android manifest file:
<code>
sed -i "s/org.modrana.PySideExample/foo.foomatic.BarApp/g" android/AndroidManifest.xml
sed -i "s/PySideExample/BarApp/g" android/AndroidManifest.xml
</code>


* and the last is in the &lt;code&amp;gt;android/res/strings.xml&amp;lt;/code&amp;gt; and &lt;code&amp;gt;android/build.xml&amp;lt;/code&amp;gt; file:<br /><code><br />sed -i &quot;s/PySideExample/BarApp/g&amp;quot; android/res/values/strings.xml<br />sed -i &quot;s/PySideExample/BarApp/g&amp;quot; android/build.xml<br /></code>
* and the last is in the android/res/strings.xml and android/build.xml file:
<code>
sed -i "s/PySideExample/BarApp/g" android/res/values/strings.xml
sed -i "s/PySideExample/BarApp/g" android/build.xml
</code>


'''NOTE:''' Some of these names can be changed from the Necessitas Qt Creator GUI or of course also by using an editor.
'''NOTE:''' Some of these names can be changed from the Necessitas Qt Creator GUI or of course also by using an editor.
Line 199: Line 376:
To verify that you have really changed all of the original names or if there are still some left, you can use this command:
To verify that you have really changed all of the original names or if there are still some left, you can use this command:


<code><br />find . -type f -print0 | xargs –0 file | grep -P text | cut -d: <s>f1 | xargs grep &quot;PySideExample&amp;quot;<br /></code>
<code>
<br />h4. Replacing the application
find . -type f -print0 | xargs –0 file | grep -P text | cut -d: -f1 | xargs grep "PySideExample"
<br />The application is located in: &lt;code&amp;gt;android/res/raw/my_python_project.zip&amp;lt;/code&amp;gt;
</code>
<br />This file is decompressed into the &lt;code&amp;gt;/data/data/org.modrana.PySide.Example/files/&amp;lt;/code&amp;gt; folder on first start after installation. Then &lt;code&amp;gt;/data/data/org.modrana.PySide.Example/files/main.py&amp;lt;/code&amp;gt; is run by Python.
 
<br />To replace the example application, just replace the contents of &lt;code&amp;gt;my_python_project.zip&amp;lt;/code&amp;gt;, if you want to start other file than &lt;code&amp;gt;main.py&amp;lt;/code&amp;gt;, just change the ''MAIN_PYTHON_FILE'' path in &lt;code&amp;gt;main.h&amp;lt;/code&amp;gt; .
==== Replacing the application ====
<br />h4. Replacing Python
The application is located in: android/res/raw/my_python_project.zip
<br />The project contains two Python &quot;bundles&amp;quot;, one is used to compile the application wrapper and is located in &lt;code&amp;gt;build_dependencies/python&amp;lt;/code&amp;gt;, the other one is in &lt;code&amp;gt;android/res/raw/python_27.zip&amp;lt;/code&amp;gt; and is deployed on first start after installation into &lt;code&amp;gt;/data/data/org.modrana.PySide.Example/files/python&amp;lt;/code&amp;gt; with all other bundled libraries and files in this archive.
 
<br />When replacing Python, you should probably replace both bundles with the same Android-compiled Python version, or at least use the same series (2.7 &amp; 2.7 not 2.7 &amp; 2.6).
This file is decompressed into the /data/data/org.modrana.PySide.Example/files/ folder on first start after installation. Then /data/data/org.modrana.PySide.Example/files/main.py is run by Python.
<br />h4. Replacing PySide libraries
 
<br />The PySide libraries are located in &lt;code&amp;gt;android/res/raw/python_27.zip&amp;lt;/code&amp;gt; archive inside the ''lib'' folder. This folder is deployed to &lt;code&amp;gt;/data/data/org.modrana.PySide.Example/files/python/lib&amp;lt;/code&amp;gt; on the Android device.
To replace the example application, just replace the contents of my_python_project.zip, if you want to start other file than main.py, just change the ''MAIN_PYTHON_FILE'' path in main.h .
<br />When replacing PySide, you need to replace the libshiboken and libpyside:<br /><code><br />Replace lib/libshiboken.so by stage/lib/libshiboken.so<br />Replace lib/libpyside.so by stage/lib/libpyside.so<br />Replace lib/python2.7/site-packages/PySide by stage/lib/python2.7/site-packages/PySide<br /></code>
 
<br />h4. Replacing Qt Components
==== Replacing Python ====
<br />The Qt Components are packed in the &lt;code&amp;gt;android/res/raw/python_27.zip&amp;lt;/code&amp;gt; in the &lt;code&amp;gt;imports&amp;lt;/code&amp;gt; directory, the theme is in &lt;code&amp;gt;themes&amp;lt;/code&amp;gt;. These to folders are deployed like this after installation:<br /><code><br />/data/org.modrana.PySide.Example/python/imports<br />/data/org.modrana.PySide.Example/python/themes<br /></code>
The project contains two Python "bundles", one is used to compile the application wrapper and is located in build_dependencies/python, the other one is in android/res/raw/python_27.zip and is deployed on first start after installation into /data/data/org.modrana.PySide.Example/files/python with all other bundled libraries and files in this archive.
<br />So to replace Qt Components and/or their theme, just replace the content of the ''imports'' and/or ''themes'' folders in the &lt;code&amp;gt;python_27.zip&amp;lt;/code&amp;gt; archives.
 
<br />h4. Adding files, libraries &amp; executables
When replacing Python, you should probably replace both bundles with the same Android-compiled Python version, or at least use the same series (2.7 & 2.7 not 2.7 & 2.6).
<br />h5. Files
 
<br />Arbitrary files needed by you application should probably go to the &lt;code&amp;gt;my_python_project.zip&amp;lt;/code&amp;gt;, to be deployed together with your application to the main instalation folder.
==== Replacing PySide libraries ====
<br />h5. Libraries &amp; executables
The PySide libraries are located in android/res/raw/python_27.zip archive inside the ''lib'' folder. This folder is deployed to /data/data/org.modrana.PySide.Example/files/python/lib on the Android device.
<br />Libraries should be added to &lt;code&amp;gt;python_27.zip&amp;lt;/code&amp;gt; to the &lt;code&amp;gt;lib&amp;lt;/code&amp;gt; folder, exectuables to the &lt;code&amp;gt;bin&amp;lt;/code&amp;gt; folder. Like this they will be deployed to a folder that is listed in &lt;code&amp;gt;$LD_LIBRARY_PATH&amp;lt;/code&amp;gt; and &lt;code&amp;gt;$PATH&amp;lt;/code&amp;gt; respectively.
 
<br />'''NOTE:''' I haven't yet tested if running executables through ''subprocess'' actually works.
When replacing PySide, you need to replace the libshiboken and libpyside:
<br />h2. Ideas for improvement
<code>
<br />There is definitely still room for improvement, such as:<br />* customizes Necessitas Qt Creator PySide projects<br />* building APKs from command line only without Qt Creator<br />* show a progress bar when the bundled libs are unpacked on first start<br />* modified bundling that doesn't unpack the files during startup bud during installation<br /> * this could speed up the first start quite a bit<br />* compiling the many Qt Components files &amp; images to a single resource file ?<br />* documenting how to use Android specific APIs from Python<br />* videos
Replace lib/libshiboken.so by stage/lib/libshiboken.so
<br />h2. Links
Replace lib/libpyside.so by stage/lib/libpyside.so
<br />h3. Source code listing
Replace lib/python2.7/site-packages/PySide by stage/lib/python2.7/site-packages/PySide
<br />A convenient listing of sources for all the components used for the PySide &amp; co port to Android. :)
</code>
<br />Shiboken for Android<br />https://github.com/M4rtinK/shiboken-android/tree/android
 
<br />PySide for Android<br />https://github.com/M4rtinK/pyside-android/tree/android
==== Replacing Qt Components ====
<br />PySide for Android build scripts<br />https://github.com/M4rtinK/android-pyside-build-scripts
The Qt Components are packed in the android/res/raw/python_27.zip in the imports directory, the theme is in themes. These to folders are deployed like this after installation:
<br />Qt Components<br />https://qt.gitorious.org/~martink/qt-components/martinks-ineans-qt-components/commits/android
<code>
<br />Example program<br />https://github.com/M4rtinK/expyside/tree/android
/data/org.modrana.PySide.Example/python/imports
<br />Example project for Necessitas QtCreator<br />https://github.com/M4rtinK/android-pyside-example-project
/data/org.modrana.PySide.Example/python/themes
<br />h3. Binary listing
</code>
<br />List of relevant pre-built binaries
 
<br />PySide libraries<br />http://modrana.org/platforms/android/pyside/
So to replace Qt Components and/or their theme, just replace the content of the ''imports'' and/or ''themes'' folders in the python_27.zip archives.
<br />PyQt libraries<br />http://modrana.org/platforms/android/pyqt4/
 
<br />Python 2.7 compiled for android</s> libs, executables &amp; headers<br />http://www.modrana.org/platforms/android/python2.7/python2.7_for_android_v1.zip
==== Adding files, libraries & executables ====
===== Files =====
Arbitrary files needed by you application should probably go to the my_python_project.zip, to be deployed together with your application to the main instalation folder.
 
===== Libraries & executables =====
Libraries should be added to python_27.zip to the lib> folder, exectuables to the bin folder. Like this they will be deployed to a folder that is listed in $LD_LIBRARY_PATH and $PATH respectively.
 
'''NOTE:''' I haven't yet tested if running executables through ''subprocess'' actually works.
 
== Ideas for improvement ==
There is definitely still room for improvement, such as:
* customizes Necessitas Qt Creator PySide projects
* building APKs from command line only without Qt Creator
* show a progress bar when the bundled libs are unpacked on first start
* modified bundling that doesn't unpack the files during startup bud during installation * this could speed up the first start quite a bit
* compiling the many Qt Components files & images to a single resource file ?
* documenting how to use Android specific APIs from Python
* videos
 
== Links ==
=== Source code listing ===
A convenient listing of sources for all the components used for the PySide & co port to Android. :)
 
Shiboken for Android
https://github.com/M4rtinK/shiboken-android/tree/android
 
PySide for Android
https://github.com/M4rtinK/pyside-android/tree/android
 
PySide for Android build scripts
https://github.com/M4rtinK/android-pyside-build-scripts
 
Qt Components
https://qt.gitorious.org/~martink/qt-components/martinks-ineans-qt-components/commits/android
 
Example program
https://github.com/M4rtinK/expyside/tree/android
 
Example project for Necessitas QtCreator
https://github.com/M4rtinK/android-pyside-example-project
 
=== Binary listing ===
List of relevant pre-built binaries
 
PySide libraries
http://modrana.org/platforms/android/pyside/
 
PyQt libraries
http://modrana.org/platforms/android/pyqt4/
 
Python 2.7 compiled for android- libs, executables & headers
http://www.modrana.org/platforms/android/python2.7/python2.7_for_android_v1.zip


Qt Components for Android<br />http://modrana.org/platforms/android/qt_components/qt_components_v1.zip
Qt Components for Android
http://modrana.org/platforms/android/qt_components/qt_components_v1.zip


Cut-down Qt Components theme<br />http://modrana.org/platforms/android/qt_components/qt_components_theme_mini_v1.zip
Cut-down Qt Components theme
http://modrana.org/platforms/android/qt_components/qt_components_theme_mini_v1.zip


Example application APK<br />http://modrana.org/platforms/android/pyside_example/PySideExample_1.2.apk
Example application APK
http://modrana.org/platforms/android/pyside_example/PySideExample_1.2.apk


== Acknowledgement ==
== Acknowledgement ==


As usual with open source development, I haven't done all of this single handedly, but built on work done by others before me. So I'd like to both acknowledge on which work this is build upon and also provided links to the sources I've used:<br />* THPs &quot;PySide for Android&amp;quot;:http://thp.io/2011/pyside-android/ - showing that this is possible<br />* Adrià Cereto-Massagué - integrated &amp; improved THPs patches for &quot;Shiboken&amp;quot;:https://github.com/ssorgatem/PySide/tree/android and &quot;PySide&amp;quot;:https://github.com/ssorgatem/PySide/tree/android<br />* &quot;The Android-Python2.7 project&amp;quot;:http://code.google.com/p/android-python27/ - solved the APK bundling issue, provides Android-buildable Python 2.7<br />* &quot;the BlackBerry-Py Building PySide guide&amp;quot;:http://hg.microcode.ca/blackberry-py/wiki/Building PySide - I've used this as a base when making the Android build scripts<br />* &quot;the Necessitas project&amp;quot;:http://necessitas.kde.org/ - made Qt on Android possible<br /> * also provides the Necessitas Qt Creator used for by the example project for building standalone APKs<br />* &quot;Qt-Project&amp;quot;:http://qt.io/ - provides the GUI toolkit :)<br />* &quot;PySide&amp;quot;:http://wiki.qt.io/PySide - provides the Python-Qt bindings<br />* &quot;Ineans Qt Components&amp;quot;:https://gitorious.org/~inean/qt-components/ineans-qt-components - with small modifications used in the example application &amp; project
As usual with open source development, I haven't done all of this single handedly, but built on work done by others before me. So I'd like to both acknowledge on which work this is build upon and also provided links to the sources I've used:
* THPs [http://thp.io/2011/pyside-android/ PySide for Android] - showing that this is possible
* Adrià Cereto-Massagué - integrated & improved THPs patches for [https://github.com/ssorgatem/PySide/tree/android Shiboken] and [https://github.com/ssorgatem/PySide/tree/android PySide]
* [http://code.google.com/p/android-python27/ The Android-Python2.7 project] - solved the APK bundling issue, provides Android-buildable Python 2.7
* [http://hg.microcode.ca/blackberry-py/wiki/Building the BlackBerry-Py Building PySide guide] PySide - I've used this as a base when making the Android build scripts
* [http://necessitas.kde.org/ the Necessitas project] - made Qt on Android possible * also provides the Necessitas Qt Creator used for by the example project for building standalone APKs
* [http://qt.io/ Qt-Project] - provides the GUI toolkit :)
* [http://wiki.qt.io/PySide PySide] - provides the Python-Qt bindings
* [https://gitorious.org/~inean/qt-components/ineans-qt-components Ineans Qt Components] - with small modifications used in the example application & project

Latest revision as of 10:33, 24 February 2022


Attention
This is a page dedicated to PySide (Qt4). For recent development on PySide2 (Qt5) and PySide6 (Qt6) refer to Qt for Python

PySide for Android

This guide describes:

  • how to build Shiboken & PySide for Android using the Necessitas SDK
  • how to use the resulting libraries
  • and how to bundle them with your Python program in a standalone APK

NOTE: If you just want to run you Python & PySide programs on Android, you can skip the Building PySide section and go directly to PySide for Android example application & Example project for the Necessitas Qt Creator .

See Links for source code & pre-built binaries.

Building PySide

Prerequisites

Necessitas SDK

Make sure to get the latest Necessitas alpha 4 SDK - older version might not work correctly with the build script (incompatible libraries, different paths, etc.).

Download & run the Necessitas SDK installer

wget http://files.kde.org/necessitas/installer/release/linux-online-necessitas-alpha4-sdk-installer
chmod ''x linux-online-necessitas-alpha4-sdk-installer
./linux-online-necessitas-alpha4-sdk-installer

Once the installer starts -> don't forget to install Android API 14 [[Image:|Image:]]*

  • on the Select components page go to * Miscellaneous->Android SDK and select API 14 for installation
  • to make sure you have the Android SDK platform/API 14 installed in the Necessitas SDK (can be done after SDK installation):

- run SDKMaintenanceTool select Package manager and in Miscantelous->Android SDK check if you have API 14 installed - PySide should probably compile even against a lower API, but that has not been tested yet

Other prerequisites

  • system-wide installed Shiboken
  • system-wide installed Python 2.7
  • Python 2.7 compiled for Android
  • cmake
  • git

This command should probably fetch most of the prerequisites on Ubuntu:

sudo apt-get install build-essential cmake git python2.7-minimal shiboken

If you find some are is missing or if you wan't to provide similar command for other distributions, add them ! :)

Then clone the Android-pyside-build-scripts project and cd to it's directory:

git clone https://github.com/M4rtinK/android-pyside-build-scripts.git
cd android-pyside-build-scripts

Now run the prepare.sh script:

./prepare.sh

It clones Android-modified Shiboken & PySide and creates some folders needed for the build.

And that's it, you are ready to start the build. :)

Build

To start the build, just run the main build script, called build.sh:

./build.sh

It first builds Shiboken, followed by PySide. The script is fully automatic, but waits for the user to press any key:

  • after Shiboken is configured for build
  • after PySide is configured for build

Like this you can easily check for any errors during configuration.

Also note, that when running the script, it clears any previous build results before building.

You can also run the build_shiboken.sh and build_pyside.sh scripts manually, just always make sure to run the Shiboken one before running the PySide one.

Build issues

If you have any issues during the PySide build, the first thing you should do is to check the PySide for Android build scripts repository if it was not updated since you cloned it, as it might already contain a fix for you issue.

arm-linux-androideabi-g: Internal error: Killed (program cc1plus)

This error seems to be caused by low system resources during build and/or running the compilation in multiple threads on some machines. If you are experiencing this error, try to set BUILD_THREAD_COUNT in env.sh to 1.

Results

The resulting PySide libraries compiled for Android are located in the stage/lib folder.

See the Example project for the Necessitas Qt Creator, Modifying the project, section Replacing PySide libraries for how the PySide libraries can be used as a part of a self-contained Android application.


PySide for Android example application

This is an example, that demonstrates a fully functional standalone Android application that uses Python, PySide and Qt Components.

more screenshots

Ready-to-install APK

A ready-to-install standalone APK is available here:

http://modrana.org/platforms/android/pyside_example/PySideExample_1.2.apk

Just install it and press the PySideExample icon.

First start

If you haven't yet installed any Ministro using Qt application on your Android device, you will be redirected to the Play store to install the Ministro application. Ministro is a manager & updater for the Qt libraries for Android. The example application requires to be installed to run. So just install Ministro and everything else will be handled automatically. You might need to press the PySideExample icon again once Ministro is installed.

Once Ministro is installed and does it's work, the example might still take some time to start, as it is unpacking Python, Qt Components, theme for Qt Components and the example program to it's working directory. Once the unpacking is finished, the example application will be started.

The unpacking is done only once on the first application start, following starts are very fast, at least when tested on my device (HP Touchpad with CM9).

What the example application demonstrates

  • sending data to Python and back * the content of the entry field is sent to Python, where it is painted on the PySide image and returned to QML using ImageProvider * the date is retrieved in Python and shown in QML
  • working text entry with the Android virtual keyboard
  • working screen rotation
  • correct Portrait/Landscape orientation switching * in both normal & inverted orientations
  • working notifications (InfoBanner)
  • working ToolBar
  • working Menu
  • "tools" menu with rotation & opacity sliders for the PySide image

Source code

Available from Github under BSD licence: https://github.com/M4rtinK/expyside/tree/android

Size of the APK

The example APK has about 16 MB. This is because it needs to bundle quite a lot of libraries and related files. Big part of it is actually not used by the example in any way.

For normal applications it should be possible to make the resulting APK much smaller by:

  • including only the PySide libraries that are actually used
  • removing unused Python modules
  • cutting down the Qt Components theme from all graphics & icons that are not used

Example project for the Necessitas Qt Creator

This project has been used to generate the above mentioned application example APK.

Using the project

Using the project to build your own project is very easy. Just install the Necessitas SDK and clone the example project from git:

git clone https://github.com/M4rtinK/android-pyside-example-project.git

Then just open the PySideExample.pro with the Necessitas Qt Creator.

To generate a new APK, just click the green run arrow in the lower left - Qt Creator should rebuild the the APK and deploy it either to the simulator or to any connected Android device that has debugging enabled.

Build & deployment issues

The example fails to start when deployed to device

First check you have the latest clone of the project.

Then check for which ARM architecture are you building by clicking on Projects. The available architecture targets are:

  • Necessitas Qt 4.8.2 for Android armv5
  • Necessitas Qt 4.8.2 for Android armv7a

The currently used architecture dark, the unused is white-grey. The build architecture needs to correspond to what the CPU of your device is using. If not sure, just try both and stick with the one that works. :)

Cannot find ELF information

This error is harmless and can be safely ignored.

How does it work ?

The project contains various components, that together enable the creation of fully standalone Python & PySide application APK, while also allowing to bundle any arbitrary libraries and files needed by the application.

The example project is called PySideExample and uses the org.modrana.PySideExample unique name. This means, that when it's APK is installed on and Android device, it gets installed to this directory:

/data/data/org.modrana.PySide.Example/

This path is important, as the application needs to set a couple of environmental variables during startup, pointing to libraries and themes that reside in this directory.

C+ wrapper

The main.cpp and main.h files are used to build a C++ Python wrapper. This wrapper is build against the the Android-compiled python libraries in build_dependencies/python by Necessitas.

Once the APK is deployd to the device and started, this wrapper is run. It initializes it's build-in Python interpreter, which tries to start the /data/data/org.modrana.PySide.Example/files/main.py Python file. This Python code then imports PySide, instantiates a QApplication and starts the main loop.

Behind the scenes, Necessitas handles wrapping the QApplication to an Android activity and showing it on the screen. It also handles other stuff like keyboard input & Qt Mobility.

main.h

This file contains important paths for the C++ wrapper.

#ifndef MAIN_H
#define MAIN_H

#define MAIN_PYTHON_FILE "/data/data/org.modrana.PySideExample/files/main.py"

#define PYTHON_HOME "/data/data/org.modrana.PySideExample/files/python/"

#define PYTHON_PATH "/data/data/org.modrana.PySideExample/files/python/lib/python2.7/lib-
dynload:/data/data/org.modrana.PySideExample/files/python/lib/python2.7/:/data/data/org.modrana.
PySideExample/files/python/lib/python2.7/site-
packages:/data/data/org.modrana.PySideExample/files/python/lib"

#define LD_LIBRARY_PATH "/data/data/org.modrana.PySideExample/files/python/lib:/data
/data/org.modrana.PySideExample/files/python/lib/python2.7/lib-
dynload:/data/data/org.kde.necessitas.ministro/files/qt/lib/"

#define PATH "/data/data/org.modrana.PySideExample/files/python/bin:$PATH"

#define THEME_PATH "/data/data/org.modrana.PySideExample/files/python/themes/"

#define QML_IMPORT_PATH "/data/data/org.modrana.PySideExample/files/python/imports/"

#define PYSIDE_APPLICATION_FOLDER "/data/data/org.modrana.PySideExample/"

#endif // MAIN_H
  • MAIN_PYTHON_FILE - path to the main Python file to run once the application is started
  • PYTHON_HOME
  • LD_LIBRARY_PATH - : separated list of paths used to look for libraries when loading them
  • PATH - search path for executables
  • THEME_PATH - path to the main themes folder for Qt Components
  • QML_IMPORT_PATH - path to the Qt Components imports folder
main.cpp

This is the C++ wrapper, it contains the embedded Python interpreter that is used to start the application and also sets some important environmental variables specified through main.h .

The example Python application

The example in main.py inside my_python_project.zip is basically a normal PySide application, it imports PySide, instantiates QApplication and starts the main loop. There is only one main difference in this piece of code:

from ctypes import *
PROJECT_FOLDER = os.environ['PYSIDE_APPLICATION_FOLDER']
# 'PYSIDE_APPLICATION_FOLDER' can be configured in main.h
LIB_DIR = os.path.join(PROJECT_FOLDER, 'files/python/lib')
SHIBOKEN_SO = os.path.join(LIB_DIR, 'libshiboken.so')
PYSIDE_SO = os.path.join(LIB_DIR, 'libpyside.so')

Due to some not yet identified bug, unless libshiboken.so & libpyside.so are manually loaded to memory like this, importing any PySide module fails.

So make sure this piece of code is somewhere in your application and is executed before import of any PySide module takes place.

Regarding the PYSIDE_APPLICATION_FOLDER environmental variable, it is set by the main.cpp wrapper and can be configured in main.h .

Bundling

The example project bundles all files needed by the application inside the standalone APK. This section describes how the bundling works.

Modified QtActivity.java

Another mportant file is the main Android activity located in

android/src/org/kde/necessitas/origo/QtActivity.java

This is actually the first thing that is started once you press the application icon on android. It basically works as a glue between Android, Qt and in our case, Python & PySide.

The basic activity file that is part of every Necessitas Qt Creator project has been modified by the android_python27 project, to look for two specific zip archives in the installation folder at startup ant to decompress them & then remover the archives.

This way bundling of arbitrary files (libraries, executables, code, themes, etc.) inside the application APK has been achieved.

NOTE: Necessitas Qt Creator might sometimes want to update the pre-generated .java files with a new version. If this happens, check if the update didn't break or remove the bundling code in QtActivity.java .

GlobalConstants.java

The file android/src/org/kde/necessitas/origo/GlobalConstants.java contains variables for the main QtActivity file.

It looks like this:

package org.kde.necessitas.origo;

public class GlobalConstants {

 public static final String PYTHON_MAIN_SCRIPT_NAME = "main.py";
 public static final String PYTHON_PROJECT_ZIP_NAME = "my_python_project.zip";
 public static final String PYTHON_ZIP_NAME = "python_27.zip";
 public static final String PYTHON_EXTRAS_ZIP_NAME = "python_extras_27.zip";

 public static final boolean IS_FOREGROUND_SERVICE = true;

 public static final String PYTHON_BIN_RELATIVE_PATH = "/python/bin/python";
 public static final String PYTHON_NAME = "python";
 public static final String PYTHON_NICE_NAME = "Python 2.7.2";

 public static String[] SCRIPT_ARGS = { "—foreground" };

 public static final String LOG_TAG = "PythonAPK";
}

As you can see, you can use it to set various variables, such as name of the bundling archives or logging prefix (does this actually work ?).

my_python_project.zip

The first archive, located in android/res/raw/my_python_project.zip in the project contains the Python application code. On first application start, it's contents are unpacked into:

/data/data/org.modrana.PySide.Example/files/

python27.zip

This file is located android/res/raw/python_27.zip in the project and it's content is unpacked to:

/data/data/org.modrana.PySide.Example/files/python

The paths set in main.h expect this and point the corresponding environmental variables to the bin, lib, imports and themes folders in this directory.

Modifying the project

When you want to use the example project as basis for your Python application for Android, you just need to rename it and replace the example application.

But just in case I've also documented replacing all the other components.

Renaming

Names

There are actually two names - the project/application name and the unique application name.

For the example project, they project name is PySideExample and the unique name is org.modrana.PySideExample. As you can see, the project name is also a suffix for the unique name. (You probably can use a project name that differs from the suffix, but I rather make them the same to avoid needless confusion).

The unique name is very important:

  • it has to be unique so it dosn't clash with other applications * for this reason, it is mostly based on a domain name you control or some other string with low possibility of being used by another developer
  • the unique name is used for path to the installation folder * the example project uses the org.modrana.PySideExample and it is installed into /data/data/org.modrana.PySideExample as a result * the path to the installation folder is used when setting important environmental variables, so make sure to change all the corresponding paths when changing the unique name
Project rename script

You can also run this combined script from the project directory, which should do all the needed renaming:

NEW_NAME="BarApp"
NEW_UNIQUE_NAME="foo.foomatic.${NEW_NAME}"

mv PySideExample.pro "${NEW_NAME}.pro"
sed -i "s/PySideExample/${NEW_NAME}/g" "${NEW_NAME}.pro"
sed -i "s/org.modrana.PySideExample/${NEW_UNIQUE_NAME}/g" main.h
sed -i "s/org.modrana.PySideExample/${NEW_UNIQUE_NAME}/g" android/src/org/kde/necessitas/origo/QtActivity.java
sed -i "s/org.modrana.PySideExample/${NEW_UNIQUE_NAME}/g" android/AndroidManifest.xml
sed -i "s/PySideExample/${NEW_NAME}/g" android/AndroidManifest.xml
sed -i "s/PySideExample/${NEW_NAME}/g" android/res/values/strings.xml
sed -i "s/PySideExample/${NEW_NAME}/g" android/build.xml

Just change NEW_NAME and NEW_UNIQUE_NAME to values matching you application and you are set. :)

What the rename script does

Lets say we want to rename the example project from PySideExample to BarApp and from org.modrana.PySideExample to foo.foomatic.BarApp

  • rename the project file:
mv PySideExample.pro BarApp.pro
  • replace the name inside the project file:
sed -i "s/PySideExample/BarApp/g" BarApp.pro
  • replace all unique names in main.h:
sed -i "s/org.modrana.PySideExample/foo.foomatic.BarApp/g" main.h
  • replace all unique names in the QtActivity:
sed -i "s/org.modrana.PySideExample/foo.foomatic.BarApp/g" android/src/org/kde/necessitas/origo/QtActivity.java
  • replace all names in the Android manifest file:
sed -i "s/org.modrana.PySideExample/foo.foomatic.BarApp/g" android/AndroidManifest.xml
sed -i "s/PySideExample/BarApp/g" android/AndroidManifest.xml
  • and the last is in the android/res/strings.xml and android/build.xml file:
sed -i "s/PySideExample/BarApp/g" android/res/values/strings.xml
sed -i "s/PySideExample/BarApp/g" android/build.xml

NOTE: Some of these names can be changed from the Necessitas Qt Creator GUI or of course also by using an editor.

To verify that you have really changed all of the original names or if there are still some left, you can use this command:

find . -type f -print0 | xargs 0 file | grep -P text | cut -d: -f1 | xargs grep "PySideExample"

Replacing the application

The application is located in: android/res/raw/my_python_project.zip

This file is decompressed into the /data/data/org.modrana.PySide.Example/files/ folder on first start after installation. Then /data/data/org.modrana.PySide.Example/files/main.py is run by Python.

To replace the example application, just replace the contents of my_python_project.zip, if you want to start other file than main.py, just change the MAIN_PYTHON_FILE path in main.h .

Replacing Python

The project contains two Python "bundles", one is used to compile the application wrapper and is located in build_dependencies/python, the other one is in android/res/raw/python_27.zip and is deployed on first start after installation into /data/data/org.modrana.PySide.Example/files/python with all other bundled libraries and files in this archive.

When replacing Python, you should probably replace both bundles with the same Android-compiled Python version, or at least use the same series (2.7 & 2.7 not 2.7 & 2.6).

Replacing PySide libraries

The PySide libraries are located in android/res/raw/python_27.zip archive inside the lib folder. This folder is deployed to /data/data/org.modrana.PySide.Example/files/python/lib on the Android device.

When replacing PySide, you need to replace the libshiboken and libpyside:

Replace lib/libshiboken.so by stage/lib/libshiboken.so
Replace lib/libpyside.so by stage/lib/libpyside.so
Replace lib/python2.7/site-packages/PySide by stage/lib/python2.7/site-packages/PySide

Replacing Qt Components

The Qt Components are packed in the android/res/raw/python_27.zip in the imports directory, the theme is in themes. These to folders are deployed like this after installation:

/data/org.modrana.PySide.Example/python/imports
/data/org.modrana.PySide.Example/python/themes

So to replace Qt Components and/or their theme, just replace the content of the imports and/or themes folders in the python_27.zip archives.

Adding files, libraries & executables

Files

Arbitrary files needed by you application should probably go to the my_python_project.zip, to be deployed together with your application to the main instalation folder.

Libraries & executables

Libraries should be added to python_27.zip to the lib> folder, exectuables to the bin folder. Like this they will be deployed to a folder that is listed in $LD_LIBRARY_PATH and $PATH respectively.

NOTE: I haven't yet tested if running executables through subprocess actually works.

Ideas for improvement

There is definitely still room for improvement, such as:

  • customizes Necessitas Qt Creator PySide projects
  • building APKs from command line only without Qt Creator
  • show a progress bar when the bundled libs are unpacked on first start
  • modified bundling that doesn't unpack the files during startup bud during installation * this could speed up the first start quite a bit
  • compiling the many Qt Components files & images to a single resource file ?
  • documenting how to use Android specific APIs from Python
  • videos

Links

Source code listing

A convenient listing of sources for all the components used for the PySide & co port to Android. :)

Shiboken for Android https://github.com/M4rtinK/shiboken-android/tree/android

PySide for Android https://github.com/M4rtinK/pyside-android/tree/android

PySide for Android build scripts https://github.com/M4rtinK/android-pyside-build-scripts

Qt Components https://qt.gitorious.org/~martink/qt-components/martinks-ineans-qt-components/commits/android

Example program https://github.com/M4rtinK/expyside/tree/android

Example project for Necessitas QtCreator https://github.com/M4rtinK/android-pyside-example-project

Binary listing

List of relevant pre-built binaries

PySide libraries http://modrana.org/platforms/android/pyside/

PyQt libraries http://modrana.org/platforms/android/pyqt4/

Python 2.7 compiled for android- libs, executables & headers http://www.modrana.org/platforms/android/python2.7/python2.7_for_android_v1.zip

Qt Components for Android http://modrana.org/platforms/android/qt_components/qt_components_v1.zip

Cut-down Qt Components theme http://modrana.org/platforms/android/qt_components/qt_components_theme_mini_v1.zip

Example application APK http://modrana.org/platforms/android/pyside_example/PySideExample_1.2.apk

Acknowledgement

As usual with open source development, I haven't done all of this single handedly, but built on work done by others before me. So I'd like to both acknowledge on which work this is build upon and also provided links to the sources I've used: