diff --git a/.gitignore b/.gitignore index 193ffea3a..37c0b1b2d 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ electrum/locale/ packages env/ .buildozer/ +.buildozer_kivy/ +.buildozer_qml/ bin/ /app.fil .idea diff --git a/contrib/android/Dockerfile b/contrib/android/Dockerfile index f24094f3b..2ae130dd8 100644 --- a/contrib/android/Dockerfile +++ b/contrib/android/Dockerfile @@ -164,9 +164,10 @@ RUN cd /opt \ && git clone https://github.com/kivy/python-for-android \ && cd python-for-android \ && git remote add sombernight https://github.com/SomberNight/python-for-android \ + && git remote add accumulator https://github.com/accumulator/python-for-android \ && git fetch --all \ - # commit: from branch sombernight/electrum_20210421b - && git checkout "cdee188f0ef28ff8452207da409912da19e917ca^{commit}" \ + # commit: from branch accumulator/qt5-wip + && git checkout "ebbe8dcc271e36468666feb98f936d0a96936cf2^{commit}" \ && python3 -m pip install --no-dependencies --user -e . # build env vars diff --git a/contrib/android/Makefile b/contrib/android/Makefile index 5f38f1b2a..93d426877 100644 --- a/contrib/android/Makefile +++ b/contrib/android/Makefile @@ -28,8 +28,8 @@ theming: $(PYTHON) -m kivy.atlas ../../electrum/gui/kivy/theming/atlas/light 1024 ../../electrum/gui/kivy/theming/light/*.png prepare: # running pre build setup - @cp buildozer.spec ../../buildozer.spec # copy electrum to main.py + @cp buildozer_$(ELEC_APK_GUI).spec ../../buildozer.spec @cp ../../run_electrum ../../main.py @-if [ ! -d "../../.buildozer" ];then \ cd ../..; buildozer android debug;\ diff --git a/contrib/android/build.sh b/contrib/android/build.sh index b102260f3..534e88058 100755 --- a/contrib/android/build.sh +++ b/contrib/android/build.sh @@ -14,6 +14,21 @@ DISTDIR="$PROJECT_ROOT/dist" . "$CONTRIB"/build_tools_util.sh +# check arguments +if [[ -n "$3" \ + && ( "$1" == "kivy" || "$1" == "qml" ) \ + && ( "$2" == "all" || "$2" == "armeabi-v7a" || "$2" == "arm64-v8a" || "$2" == "x86" ) \ + && ( "$3" == "debug" || "$3" == "release" || "$3" == "release-unsigned" ) ]] ; then + info "arguments $*" +else + fail "usage: build.sh " + exit 1 +fi + +# create symlink +rm -f .buildozer +mkdir -p ".buildozer_$1" +ln -s ".buildozer_$1" .buildozer DOCKER_BUILD_FLAGS="" if [ ! -z "$ELECBUILD_NOCACHE" ] ; then @@ -44,7 +59,8 @@ else fi DOCKER_RUN_FLAGS="" -if [[ -n "$1" && "$1" == "release" ]] ; then + +if [[ "$3" == "release" ]] ; then info "'release' mode selected. mounting ~/.keystore inside container." DOCKER_RUN_FLAGS="-v $HOME/.keystore:/home/user/.keystore" fi diff --git a/contrib/android/buildozer.spec b/contrib/android/buildozer_kivy.spec similarity index 100% rename from contrib/android/buildozer.spec rename to contrib/android/buildozer_kivy.spec diff --git a/contrib/android/buildozer_qml.spec b/contrib/android/buildozer_qml.spec new file mode 100644 index 000000000..e12b75a69 --- /dev/null +++ b/contrib/android/buildozer_qml.spec @@ -0,0 +1,253 @@ +[app] + +# (str) Title of your application +title = Electrum + +# (str) Package name +package.name = Electrum + +# (str) Package domain (needed for android/ios packaging) +package.domain = org.electrum + +# (str) Source code where the main.py live +source.dir = . + +# (list) Source files to include (let empty to include all the files) +source.include_exts = py,png,jpg,qml,qmltypes,ttf,txt,gif,pem,mo,vs,fs,json,csv,so + +# (list) Source files to exclude (let empty to not exclude anything) +source.exclude_exts = spec + +# (list) List of directory to exclude (let empty to not exclude anything) +source.exclude_dirs = bin, build, dist, contrib, + electrum/tests, + electrum/gui/qt, + electrum/gui/kivy, + packages/qdarkstyle, + packages/qtpy + +# (list) List of exclusions using pattern matching +source.exclude_patterns = Makefile,setup*, + # not reproducible: + packages/aiohttp-*.dist-info/* + +# (str) Application versioning (method 1) +version.regex = APK_VERSION = '(.*)' +version.filename = %(source.dir)s/electrum/version.py + +# (str) Application versioning (method 2) +#version = 1.9.8 + +# (list) Application requirements +# note: versions and hashes are pinned in ./p4a_recipes/* +requirements = + hostpython3, + python3, + android, + openssl, + plyer, + libffi, + libsecp256k1, + cryptography, + pyqt5sip, + pyqt5 + +# (str) Presplash of the application +#presplash.filename = %(source.dir)s/gui/kivy/theming/splash.png +presplash.filename = %(source.dir)s/electrum/gui/icons/electrum_presplash.png + +# (str) Icon of the application +icon.filename = %(source.dir)s/electrum/gui/icons/android_electrum_icon_legacy.png +icon.adaptive_foreground.filename = %(source.dir)s/electrum/gui/icons/android_electrum_icon_foreground.png +icon.adaptive_background.filename = %(source.dir)s/electrum/gui/icons/android_electrum_icon_background.png + +# (str) Supported orientation (one of landscape, portrait or all) +orientation = portrait + +# (bool) Indicate if the application should be fullscreen or not +fullscreen = False + + +# +# Android specific +# + +# (list) Permissions +android.permissions = INTERNET, CAMERA, WRITE_EXTERNAL_STORAGE + +# (int) Android API to use (targetSdkVersion AND compileSdkVersion) +# note: when changing, Dockerfile also needs to be changed to install corresponding build tools +android.api = 29 + +# (int) Minimum API required. You will need to set the android.ndk_api to be as low as this value. +android.minapi = 21 + +# (str) Android NDK version to use +android.ndk = 22b + +# (int) Android NDK API to use (optional). This is the minimum API your app will support. +android.ndk_api = 21 + +# (bool) Use --private data storage (True) or --dir public storage (False) +android.private_storage = True + +# (str) Android NDK directory (if empty, it will be automatically downloaded.) +android.ndk_path = /opt/android/android-ndk + +# (str) Android SDK directory (if empty, it will be automatically downloaded.) +android.sdk_path = /opt/android/android-sdk + +# (str) ANT directory (if empty, it will be automatically downloaded.) +android.ant_path = /opt/android/apache-ant + +# (bool) If True, then skip trying to update the Android sdk +# This can be useful to avoid excess Internet downloads or save time +# when an update is due and you just want to test/build your package +# note(ghost43): probably needed for reproducibility. versions pinned in Dockerfile. +android.skip_update = True + +# (bool) If True, then automatically accept SDK license +# agreements. This is intended for automation only. If set to False, +# the default, you will be shown the license when first running +# buildozer. +android.accept_sdk_license = True + +# (str) Android entry point, default is ok for Kivy-based app +#android.entrypoint = org.renpy.android.PythonActivity + +# (list) List of Java .jar files to add to the libs so that pyjnius can access +# their classes. Don't add jars that you do not need, since extra jars can slow +# down the build process. Allows wildcards matching, for example: +# OUYA-ODK/libs/*.jar +#android.add_jars = foo.jar,bar.jar,path/to/more/*.jar +#android.add_jars = lib/android/zbar.jar + +android.add_jars = .buildozer/android/platform/*/build/libs_collections/Electrum/jar/*.jar + + +# (list) List of Java files to add to the android project (can be java or a +# directory containing the files) +android.add_src = electrum/gui/kivy/data/java-classes/ + +android.gradle_dependencies = me.dm7.barcodescanner:zxing:1.9.8 + +android.add_activities = org.electrum.qr.SimpleScannerActivity + +# (str) python-for-android branch to use, if not master, useful to try +# not yet merged features. +#android.branch = master + +# (str) OUYA Console category. Should be one of GAME or APP +# If you leave this blank, OUYA support will not be enabled +#android.ouya.category = GAME + +# (str) Filename of OUYA Console icon. It must be a 732x412 png image. +#android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png + +# (str) XML file to include as an intent filters in tag +android.manifest.intent_filters = contrib/android/bitcoin_intent.xml + +# (str) launchMode to set for the main activity +android.manifest.launch_mode = singleTask + +# (list) Android additionnal libraries to copy into libs/armeabi +#android.add_libs_armeabi = lib/android/*.so + +# (bool) Indicate whether the screen should stay on +# Don't forget to add the WAKE_LOCK permission if you set this to True +#android.wakelock = False + +# (str) The Android arch to build for, choices: armeabi-v7a, arm64-v8a, x86, x86_64 +# note: can be overwritten by APP_ANDROID_ARCH env var +#android.arch = armeabi-v7a + +# (list) Android application meta-data to set (key=value format) +#android.meta_data = + +# (list) Android library project to add (will be added in the +# project.properties automatically.) +#android.library_references = + +android.whitelist = lib-dynload/_csv.so + +# (bool) enables Android auto backup feature (Android API >=23) +android.allow_backup = False + +# +# Python for android (p4a) specific +# + +# (str) python-for-android git clone directory (if empty, it will be automatically cloned from github) +p4a.source_dir = /opt/python-for-android + +# (str) The directory in which python-for-android should look for your own build recipes (if any) +p4a.local_recipes = %(source.dir)s/contrib/android/p4a_recipes/ + +# (str) Filename to the hook for p4a +#p4a.hook = + +# (str) Bootstrap to use for android builds +p4a.bootstrap = qt5 + +# (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask) +#p4a.port = + + +# +# iOS specific +# + +# (str) Name of the certificate to use for signing the debug version +# Get a list of available identities: buildozer ios list_identities +#ios.codesign.debug = "iPhone Developer: ()" + +# (str) Name of the certificate to use for signing the release version +#ios.codesign.release = %(ios.codesign.debug)s + + + +[buildozer] + +# (int) Log level (0 = error only, 1 = info, 2 = debug (with command output)) +log_level = 1 + +# (str) Path to build output (i.e. .apk, .ipa) storage +bin_dir = ./dist + + +# ----------------------------------------------------------------------------- +# List as sections +# +# You can define all the "list" as [section:key]. +# Each line will be considered as a option to the list. +# Let's take [app] / source.exclude_patterns. +# Instead of doing: +# +# [app] +# source.exclude_patterns = license,data/audio/*.wav,data/images/original/* +# +# This can be translated into: +# +# [app:source.exclude_patterns] +# license +# data/audio/*.wav +# data/images/original/* +# + +# ----------------------------------------------------------------------------- +# Profiles +# +# You can extend section / key with a profile +# For example, you want to deploy a demo version of your application without +# HD content. You could first change the title to add "(demo)" in the name +# and extend the excluded directories to remove the HD content. +# +# [app@demo] +# title = My Application (demo) +# +# [app:source.exclude_patterns@demo] +# images/hd/* +# +# Then, invoke the command line with the "demo" profile: +# +# buildozer --profile demo android debug diff --git a/contrib/android/make_apk b/contrib/android/make_apk index 01929de07..783fb43d3 100755 --- a/contrib/android/make_apk +++ b/contrib/android/make_apk @@ -10,6 +10,10 @@ LOCALE="$PROJECT_ROOT"/electrum/locale/ . "$CONTRIB"/build_tools_util.sh + +# arguments have been checked in build.sh +export ELEC_APK_GUI=$1 + if [ ! -d "$PACKAGES" ]; then "$CONTRIB"/make_packages || fail "make_packages failed" fi @@ -37,28 +41,22 @@ info "preparing electrum-locale." pushd "$CONTRIB_ANDROID" info "apk building phase starts." -if [[ -n "$1" && "$1" == "release" ]] ; then + +if [[ "$3" == "release" ]] ; then # do release build, and sign the APKs. + TARGET="release" echo -n Keystore Password: read -s password export P4A_RELEASE_KEYSTORE=~/.keystore export P4A_RELEASE_KEYSTORE_PASSWD=$password export P4A_RELEASE_KEYALIAS_PASSWD=$password export P4A_RELEASE_KEYALIAS=electrum - # build two apks - export APP_ANDROID_ARCH=armeabi-v7a - make release - export APP_ANDROID_ARCH=arm64-v8a - make release -elif [[ -n "$1" && "$1" == "release-unsigned" ]] ; then +elif [[ "$3" == "release-unsigned" ]] ; then # do release build, but do not sign the APKs. - # build two apks - export APP_ANDROID_ARCH=armeabi-v7a - make release - export APP_ANDROID_ARCH=arm64-v8a - make release -else + TARGET="release" +elif [[ "$3" == "debug" ]] ; then # do debug build; the default. + TARGET="apk" export P4A_DEBUG_KEYSTORE="$CONTRIB_ANDROID"/android_debug.keystore export P4A_DEBUG_KEYSTORE_PASSWD=unsafepassword export P4A_DEBUG_KEYALIAS_PASSWD=unsafepassword @@ -72,11 +70,22 @@ else -keypass "$P4A_DEBUG_KEYALIAS_PASSWD" fi export ELEC_APK_USE_CURRENT_TIME=1 - # only build one apk for debug build, for faster testing iterations +else + fail "unknown build type" +fi + + +if [[ "$2" == "all" ]] ; then + # build all apks + export APP_ANDROID_ARCH=armeabi-v7a + make $TARGET export APP_ANDROID_ARCH=arm64-v8a - make apk - # export APP_ANDROID_ARCH=armeabi-v7a - # make apk + make $TARGET + #export APP_ANDROID_ARCH=x86 + #make $TARGET +else + export APP_ANDROID_ARCH=$2 + make $TARGET fi popd diff --git a/contrib/android/p4a_recipes/pyjnius/__init__.py b/contrib/android/p4a_recipes/pyjnius/__init__.py index 2321b14b3..536cbde49 100644 --- a/contrib/android/p4a_recipes/pyjnius/__init__.py +++ b/contrib/android/p4a_recipes/pyjnius/__init__.py @@ -7,7 +7,7 @@ util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__ assert PyjniusRecipe._version == "1.3.0" -assert PyjniusRecipe.depends == [('genericndkbuild', 'sdl2'), 'six', 'python3'] +assert PyjniusRecipe.depends == [('genericndkbuild', 'sdl2', 'qt5'), 'six', 'python3'] assert PyjniusRecipe.python_depends == [] diff --git a/contrib/deterministic-build/requirements-build-android.txt b/contrib/deterministic-build/requirements-build-android.txt index dfa5dee78..de534e017 100644 --- a/contrib/deterministic-build/requirements-build-android.txt +++ b/contrib/deterministic-build/requirements-build-android.txt @@ -164,4 +164,22 @@ zipp==3.7.0 \ --hash=sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375 pathlib2==2.3.7.post1 \ --hash=sha256:5266a0fd000452f1b3467d782f079a4343c63aaa119221fbdc4e39577489ca5b \ - --hash=sha256:9fe0edad898b83c0c3e199c842b27ed216645d2e177757b2dd67384d4113c641 \ No newline at end of file + --hash=sha256:9fe0edad898b83c0c3e199c842b27ed216645d2e177757b2dd67384d4113c641 \ +typing-extensions==3.7.4.3 \ + --hash=sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918 \ + --hash=sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c \ + --hash=sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f +sip==6.4.0 \ + --hash=sha256:0a1a2db03ef71372744d00a671406b0fabf920da53192cdd4a8fa9ddb76888bd \ + --hash=sha256:2ff8632ace4f274fe37ce3e09967877b672490ada33c034addca6d63dc534310 \ + --hash=sha256:42ec368520b8da4a0987218510b1b520b4981e4405086c1be384733affc2bcb0 \ + --hash=sha256:87539b534d730aaabde7396bd2edb7c5b86093ca2500eeaa617d588150b7fda9 +pyparsing==3.0.6 \ + --hash=sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4 \ + --hash=sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81 +PyQt-builder==1.12.2 \ + --hash=sha256:48f754394d235307201ec2b5355934858741201af09433ff543ca40ae57b7865 \ + --hash=sha256:f62bb688d70e0afd88c413a8d994bda824e6cebd12b612902d1945c5a67edcd7 +packaging==21.3 \ + --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ + --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 diff --git a/contrib/release.sh b/contrib/release.sh index 2e9e73706..dd5ef800c 100755 --- a/contrib/release.sh +++ b/contrib/release.sh @@ -125,9 +125,9 @@ if test -f "dist/$apk1"; then info "file exists: $apk1" else if [ ! -z "$RELEASEMANAGER" ] ; then - ./contrib/android/build.sh release + ./contrib/android/build.sh kivy all release else - ./contrib/android/build.sh release-unsigned + ./contrib/android/build.sh kivy all release-unsigned mv "$apk1_unsigned" "$apk1" mv "$apk2_unsigned" "$apk2" fi