diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..8c9cc52 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,97 @@ +on: + pull_request: + types: [opened, synchronize] + push: + branches: ["**"] + +jobs: + test-compile: + runs-on: ubuntu-latest + name: "Test P4A Compiling" + + steps: + - name: Clone LXMF + run: git clone https://github.com/markqvist/LXMF $GITHUB_WORKSPACE/LXMF + + - name: Clone LXST + run: git clone https://github.com/markqvist/LXST $GITHUB_WORKSPACE/LXST + + - name: Clone rnsh + run: git clone https://github.com/acehoss/rnsh $GITHUB_WORKSPACE/rnsh + + - name: Clone Reticulum + run: git clone https://github.com/markqvist/Reticulum $GITHUB_WORKSPACE/Reticulum + + - name: Clone rnode-flasher + run: git clone https://github.com/liamcottle/rnode-flasher $GITHUB_WORKSPACE/rnode-flasher + + - name: Clone NomadNet + run: git clone https://github.com/markqvist/nomadnet $GITHUB_WORKSPACE/NomadNet + + - name: Clone reticulum_website + run: git clone https://github.com/markqvist/reticulum_website $GITHUB_WORKSPACE/reticulum_website + + - name: Checkout Sideband + uses: actions/checkout@v3 + with: + path: Sideband/ + + # Set up caching for general cache directory + - name: Cache pip build cache + uses: actions/cache@v3 + with: + path: ~/.cache + key: ${{ runner.os }}-build-cache-${{ hashFiles('**/buildozer.spec') }} + restore-keys: | + ${{ runner.os }}-build-cache- + + # Set up caching for buildozer directories + - name: Cache buildozer + uses: actions/cache@v3 + with: + path: | + ~/.buildozer + ${{ github.workspace }}/**/.buildozer + ${{ github.workspace }}/**/.buildozer-container + key: ${{ runner.os }}-buildozer-${{ hashFiles('**/buildozer.spec') }} + restore-keys: | + ${{ runner.os }}-buildozer- + + # Set up caching for Gradle + - name: Cache Gradle files + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + ~/.gradle/daemon + ~/.gradle/native + key: ${{ runner.os }}-gradle-${{ hashFiles('**/buildozer.spec') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Create Android SDK directory + run: mkdir -p ~/.android + + - name: Generate debug keystore + run: | + keytool -genkeypair \ + -keystore ~/.android/debug.keystore \ + -storepass android \ + -keypass android \ + -alias androiddebugkey \ + -keyalg RSA \ + -keysize 2048 \ + -validity 10000 \ + -dname "CN=Android Debug,O=Android,C=US" + + - name: Attempt to build Sideband for Android (Debug) + run: | + cd $GITHUB_WORKSPACE/Sideband + ./dmake devapk + + - name: Upload built APK + uses: actions/upload-artifact@v4 + with: + name: android-debug + path: ${{ github.workspace }}/Sideband/sbapp/bin/*.apk diff --git a/.gitignore b/.gitignore index 7750d9e..08598db 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ dist docs/build sideband*.egg-info sbapp*.egg-info +Sideband.iml diff --git a/DEVELOPING.md b/DEVELOPING.md new file mode 100644 index 0000000..fa2cdc0 --- /dev/null +++ b/DEVELOPING.md @@ -0,0 +1,145 @@ +# Establishing a Development environment + +Looking to contribute some code to Sideband? Awesome! Follow the guide below to get the repository building on your machine. + +## Creating folders + +Sideband relies on a certain folder structure to achieve a psuedo-monorepo structure with the other Reticulum projects. + +To make sure that the `getrns` target runs successfully, make sure your directory tree looks like this: + +``` +repositories/ +├─ LXMF/ +├─ LXST/ +├─ rnsh/ +├─ rnode-flasher/ +├─ Reticulum/ +├─ NomadNet/ +├─ reticulum_website/ +└─ Sideband/ +``` + +Below are the git repositories for some of the above folders: + +- `LXMF`: https://github.com/markqvist/LXMF +- `LXST`: https://github.com/markqvist/LXST +- `rnsh`: https://github.com/acehoss/rnsh +- `Reticulum`: https://github.com/markqvist/Reticulum +- `rnode-flasher`: https://github.com/liamcottle/rnode-flasher +- `NomadNet`: https://github.com/markqvist/nomadnet +- `reticulum_website`: https://github.com/markqvist/reticulum_website + +> Please note: in order for the docker script and `createshare` make target to work correctly, your directory **must** be laid out like this. + +## Required dependencies for development (Docker) + +If you have a Fedora-based Linux system (see [Addendum: Fedora](#addendum-fedora)) or simply would not like to install all of P4A's dependencies manually, you may choose to use the containerized build. + +This method requires that you have Docker installed on your system: https://docs.docker.com/engine/install/ + +Additionally, [rootless Docker](https://docs.docker.com/engine/install/) should be used to minimize any possible attack surface on your system. Never run a script you haven't vetted with sudo! The `./dmake.sh` script uses `set -ex` and is designed to be used with rootless docker. + +After configuring docker, you can replace any use of the `make` command with `dmake` (i.e. `./dmake devapk`) to run make commands in the container, building it on demand if needed. + +Example: + +``` +./dmake devapk +``` + +(or if running in sbapp, it is smart enough to run itself in Sideband regardless of where it is called from) + +``` +../dmake devapk +``` + +## Required dependencies for development (Native) + +Until this repository has a `flake.nix` added, you will need to manually download the following dependencies using your Operating System's package manager. + +- `make` +- `adb` (available as a part of the `android-tools` package on Fedora, `adb` on Debian/Ubuntu, `android-platform-tools` on Brew Casks) +- `python3`/`python3-dev(el)` (must be available as `python`, on Ubuntu try `apt install python-is-python3`) +- `patchelf` +- `patch` +- `perl` +- `portaudio19-dev` +- `libopus-dev` +- `libogg-dev` +- `buildozer` (see https://buildozer.readthedocs.io/en/latest/installation.html) + - buildozer's PyPI hosted version is very far behind, therefore you should install from source at https://github.com/kivy/buildozer.git; this is easy with pipx `pipx install git+https://github.com/kivy/buildozer.git`. + - buildozer needs `wheel` to run, but it is not currently marked as a dependency. If you are using pipx, you will need to inject it with `pipx inject buildozer wheel`. +- all of buildozer's Android dependencies + - Ubuntu 22.04 LTS packages `git zip unzip openjdk-17-jdk python3-pip autoconf libtool pkg-config zlib1g-dev libncurses5-dev libncursesw5-dev libtinfo5 cmake libffi-dev libssl-dev` + - Ubuntu 24.04 LTS packages `git zip unzip openjdk-17-jdk python3-pip autoconf libtool pkg-config zlib1g-dev libncurses-dev libtinfo6 cmake libffi-dev libssl-dev` + - Fedora 41 `git zip unzip java-17-openjdk java-17-openjdk-devel python3-pip autoconf libtool pkgconf-pkg-config ghc-zlib-devel ncurses-devel ncurses-compat-libs cmake libffi-devel openssl-devel` + +In the root directory of the repository, use `pip install .` to install the package from `setup.py`. The use of a `venv` is strongly recommended. + +Make sure you manually install `Cython<3.0` into your Python install or `venv`, as buildozer will need it for Android. + +### Addendum: Fedora + +As many users of Kivy have noted before, some of Python4Android's recipes do not compile correctly on Fedora/RHEL. For this project, one package of interest is [`freetype-py` and its native dependency](https://github.com/kivy/python-for-android/blob/develop/pythonforandroid/recipes/freetype/__init__.py), which is a direct dependency of pillow, the ubiquitous Python image editing library. + +This is due to the fact that Fedora and several other distros include default versions of toolchains, which prompts python4android to abstain from downloading its own. [This issue has been encountered by many other users.](https://groups.google.com/g/kivy-users/c/z46lSJXgbjY/m/M1UoWwtWAgAJ) + +If you can't use Docker, use of Ubuntu 24.04 LTS is therefore recommended for developing this project. Ubuntu 22.04 LTS is not supported, as its `cmake` version (even with backports) is below the minimum 3.24. + +Sideband does run fine on Fedora, however. + +## Compiling and testing Sideband on an Android device + +With a correctly configured environment, run the following command to create a development APK. + +``` +make devapk +``` + +You can then install it to a connected device with + +``` +make devinstall +``` + +If you would like your release to be signed for release, you must configure the following four environment variables: + +- `P4A_RELEASE_KEYALIAS` +- `P4A_RELEASE_KEYSTORE_PASSWD` +- `P4A_RELEASE_KEYSTORE` +- `P4A_RELEASE_KEYALIAS_PASSWD` + +With `./dmake`, omitting any of these values will cause it to default to the `debug.keystore` generated with each install of the Android SDK. + +After it is configured correctly, you may build it with + +``` +make apk +``` + +and install it to a connected device with + +``` +make install +``` + +The output will be placed in `./sbapp/bin/sideband-*.apk`. + +If you have multiple devices connected at once (for example, while developing the BLE interface between devices), you may use `devinstall-multi` or `install-multi` in place of `devinstall` and `install` respectively. + +If using an Android that provides the ability to toggle DCL via storage (like GrapheneOS), make sure to enable it for Sideband, as it must load its Cython executables. + +## Compiling and testing Sideband for other platforms + +For Windows, use the following command: (make sure you have `PyInstaller` in your venv, and you are on Windows, as PyInstaller removed cross-compilation) + +``` +make build_win_exe +``` + +Wheels for other platforms can be built with + +``` +make build_wheel +``` diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..59c91b8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +# exercise extreme caution when bumping this docker image to the newest ubuntu LTS version +FROM ubuntu:24.04 + +# for rationale behind each of these dependencies, consult the native section of DEVELOPING.md +RUN DEBIAN_FRONTEND=noninteractive \ + apt update \ + && DEBIAN_FRONTEND=noninteractive apt install -y curl git libffi-dev python-is-python3 python3-dev python3-wheel python3-setuptools python3-virtualenv libssl-dev autoconf openjdk-17-jdk cmake libtool libssl-dev libncurses5-dev libsqlite3-dev libreadline-dev libtk8.6 libgdm-dev libpcap-dev unzip zip wget apksigner build-essential libopus-dev libogg-dev portaudio19-dev patchelf pipx \ + && apt install --reinstall python3 \ + && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* + +# need to run as root for a rootless docker runtime +# the repository folders owned by 1000 on the host are mounted to 0 on the container; this is intentional and unchangable + +# add pipx +ENV PATH=$PATH:/root/.local/bin + +# install & inject wheel +RUN pipx install git+https://github.com/kivy/buildozer.git@abc2d7e66c8abe096a95ed58befe6617f7efdad0 +RUN pipx inject buildozer wheel + +# needed for some transitive deps, like rnsh +RUN pipx install poetry==2.1.1 diff --git a/Makefile b/Makefile index 6f5ed59..1914718 100644 --- a/Makefile +++ b/Makefile @@ -40,4 +40,4 @@ upload: @echo Ready to publish release, hit enter to continue @read VOID @echo Uploading to PyPi... - twine upload dist/sbapp-* \ No newline at end of file + twine upload dist/sbapp-* diff --git a/dmake b/dmake new file mode 100755 index 0000000..ae8b253 --- /dev/null +++ b/dmake @@ -0,0 +1,50 @@ +#!/bin/bash + +set -ex + +# any of the tasks that require adb should be run on the host, not the guest docker container +# ad-hoc docker usb passthrough sounds miserable... +if [ $1 == "install" ] || [ $1 == "devinstall" ] || [ $1 == "install-multi" ] || [ $1 == "devinstall-multi" ]; then + echo "Command requiring adb detected, running on host..." + # shellcheck disable=SC2068 # goal is to re-split + make -C sbapp $@ + exit 0 +fi + +if [[ -z $P4A_RELEASE_KEYSTORE ]]; then + echo "P4A_RELEASE_KEYSTORE is not set correctly! Using default debug keystore..." + P4A_RELEASE_KEYSTORE=$(realpath ~/.android/debug.keystore) + P4A_RELEASE_KEYALIAS=androiddebugkey + P4A_RELEASE_KEYSTORE_PASSWD=android + P4A_RELEASE_KEYALIAS_PASSWD=android +fi + +# will hit caches automatically, unless the dockerfile was changed +# buildozer writes to its own venv, so it can't be --read-only even though it really should be +# /root/.buildozer has some build artifacts that are reused, and since they are dependent on the libraries available at compile-time, they must be isolated from ~/.buildozer as these may have different fingerprints +# ~/.cache, on the other hand, may be reused because pip is smart enough to download/rebuild native dependencies if they wouldn't be compatible +docker build --network=host -t sideband-dmake . +docker run \ + --rm \ + --tty \ + --network=host \ + --tmpfs /tmp:rw,exec \ + -e P4A_RELEASE_KEYALIAS=$P4A_RELEASE_KEYALIAS \ + -e P4A_RELEASE_KEYSTORE_PASSWD=$P4A_RELEASE_KEYSTORE_PASSWD \ + -e P4A_RELEASE_KEYSTORE="/keystore.jks" \ + -e P4A_RELEASE_KEYALIAS_PASSWD=$P4A_RELEASE_KEYALIAS_PASSWD \ + -v "$(realpath $(dirname "$0")/..):/repositories:rw" \ + -v "$(realpath ./.buildozer-container):/root/.buildozer:rw" \ + -v "$(realpath ./sbapp/.buildozer-container):/repositories/Sideband/sbapp/.buildozer:rw" \ + -v "$(realpath ~/.cache):/root/.cache:rw" \ + -v "$P4A_RELEASE_KEYSTORE:/keystore.jks:ro" \ + -v "$(realpath ~/.android):/root/.android:rw" \ + -v "$(realpath ~/.gradle):/root/.gradle:rw" \ + sideband-dmake \ + /bin/bash \ + -c \ + "python3 -m venv --system-site-packages /tmp/venv \ + && source /tmp/venv/bin/activate \ + && cd /repositories/Sideband \ + && pip install -e . \"Cython<3.0\" \ + && make -C sbapp $@" diff --git a/recipes/codec2/__init__.py b/recipes/codec2/__init__.py index 81aa527..fd63c0a 100644 --- a/recipes/codec2/__init__.py +++ b/recipes/codec2/__init__.py @@ -1,13 +1,19 @@ from os.path import join +from tempfile import TemporaryDirectory from pythonforandroid.recipe import Recipe from pythonforandroid.toolchain import current_directory, shprint +import os import sh # For debugging, clean with # buildozer android p4a -- clean_recipe_build codec2 --local-recipes ~/Information/Source/Sideband/recipes class Codec2Recipe(Recipe): + # recipe for building codec2 from https://github.com/markqvist/codec2 + url = "https://github.com/markqvist/codec2/archive/00e01c9d72d3b1607e165c71c4c9c942d277dfac.tar.gz" + sha512sum = "2f8db660592e19b7f853c146793ccbde90f1d505663084f055172c8e5088a9fc2ddb588cc014ed8dec46a678ec73aaf654bbe77ff29f21caa7c45fb121f2281f" + built_libraries = {'libcodec2.so': 'build_android/src'} def include_flags(self, arch): @@ -41,10 +47,18 @@ class Codec2Recipe(Recipe): # cd = sh.cd("build_android") os.chdir("build_android") cmake = sh.Command('cmake') + gcc = sh.Command("gcc") shprint(cmake, *flags, _env=env) - shprint(sh.make, _env=env) - sh.cp("../src/codec2.h", "./codec2/") + + # before running the make, we need to compile `generate_codebook` from the codec2 repository for the architecture we are on + # allowing it to be compiled with the rest of the + with TemporaryDirectory() as tmp: + shprint(gcc, "../src/generate_codebook.c", "-o" f"{tmp}{os.sep}generate_codebook", "-lm") + + env_tmp = env | {"PATH": f"{env['PATH']}{os.pathsep}{tmp}"} + shprint(sh.make, _env=env_tmp) + sh.cp("../src/codec2.h", "./codec2/") recipe = Codec2Recipe() diff --git a/recipes/codec2/generate_codebook b/recipes/codec2/generate_codebook deleted file mode 100755 index b4ed668..0000000 Binary files a/recipes/codec2/generate_codebook and /dev/null differ diff --git a/recipes/opusfile/__init__.py b/recipes/opusfile/__init__.py index 27d0f29..472e12d 100644 --- a/recipes/opusfile/__init__.py +++ b/recipes/opusfile/__init__.py @@ -34,8 +34,6 @@ class OpusFileRecipe(Recipe): # env['LDFLAGS'] += openssl_recipe.link_dirs_flags(arch) # env['LIBS'] = openssl_recipe.link_libs_flags() - from rich.pretty import pprint - pprint(env) time.sleep(5) configure = sh.Command('./configure') diff --git a/sbapp/Makefile b/sbapp/Makefile index d0f9028..49114eb 100644 --- a/sbapp/Makefile +++ b/sbapp/Makefile @@ -15,7 +15,7 @@ cleanlibs: cleanall: clean cleanlibs -pacthfiles: patchsdl injectxml patchpycodec2 +patchfiles: patchsdl injectxml patchpycodec2 patchsdl: # Pach USB HID behaviour @@ -35,10 +35,7 @@ patchpycodec2: injectxml: # mkdir /home/markqvist/.local/lib/python3.11/site-packages/pythonforandroid/bootstraps/sdl2/build/src/main/xml # Inject XML on arm64-v8a - mkdir -p .buildozer/android/platform/build-arm64-v8a_armeabi-v7a/dists/sideband/src/main/res/xml mkdir -p .buildozer/android/platform/build-arm64-v8a_armeabi-v7a/dists/sideband/templates - cp patches/device_filter.xml .buildozer/android/platform/build-arm64-v8a_armeabi-v7a/dists/sideband/src/main/res/xml/ - cp patches/file_paths.xml .buildozer/android/platform/build-arm64-v8a_armeabi-v7a/dists/sideband/src/main/res/xml/ cp patches/AndroidManifest.tmpl.xml .buildozer/android/platform/build-arm64-v8a_armeabi-v7a/dists/sideband/templates/ cp patches/p4a_build.py .buildozer/android/platform/build-arm64-v8a_armeabi-v7a/dists/sideband/build.py @@ -51,26 +48,95 @@ ifneq (,$(wildcard .buildozer/android/platform/build-arm64-v8a_armeabi-v7a/dists else @(echo Prebaking build before patching files...) @(sleep 2) - -(buildozer android release) + (buildozer android release) # this mustn't be ignored, or else the release will indubitably fail @(echo Prebake finished, applying patches and rebuilding...) @(sleep 2) endif +createshare: + # NOTICE: if the git refs of each repository here are not pinned, the build will NOT be deterministic! + mkdir -p ../../dist_archive + rm -vrf ../../dist_archive/* + # mirrors + # reticulum.network + cp -fv ../../reticulum_website/docs/manual/Reticulum\ Manual.pdf ../../dist_archive + cp -fv ../../reticulum_website/docs/manual/Reticulum\ Manual.epub ../../dist_archive + -(rm -rf ../../dist_archive/reticulum.network) + cp -frv ../../reticulum_website/docs ../../dist_archive/reticulum.network + # unsigned.io (mirror from https://git.liberatedsystems.co.uk/jacob.eva/openCom-Companion/src/branch/master/Dockerfile) + $(eval cwd := $(shell pwd)) + cd ../../dist_archive && \ + rm -rf ./unsigned.io && \ + wget -q https://liberatedsystems.co.uk/unsigned_io_archive.zip && \ + unzip -q unsigned_io_archive.zip && \ + rm unsigned_io_archive.zip && \ + cd $(cwd) + # build wheels + # rns, rnspure, lxmf, lxst, nomadnet, rnsh + $(eval cwd := $(shell pwd)) + cd ../../Reticulum && \ + rm -rf ./dist && \ + python3 ./setup.py bdist_wheel && \ + cp -fv ./dist/* ../dist_archive && \ + cd $(cwd) + + $(eval cwd := $(shell pwd)) + cd ../../Reticulum && \ + rm -rf ./dist && \ + python3 ./setup.py bdist_wheel --pure && \ + cp -fv ./dist/* ../dist_archive && \ + cd $(cwd) + + $(eval cwd := $(shell pwd)) + cd ../../LXMF && \ + rm -rf ./dist && \ + python3 ./setup.py bdist_wheel && \ + cp -fv ./dist/* ../dist_archive && \ + cd $(cwd) + + $(eval cwd := $(shell pwd)) + cd ../../LXST && \ + rm -rf ./dist && \ + python3 ./setup.py bdist_wheel && \ + cp -fv ./dist/* ../dist_archive && \ + cd $(cwd) + + $(eval cwd := $(shell pwd)) + cd ../../nomadnet && \ + rm -rf ./dist && \ + python3 ./setup.py bdist_wheel && \ + cp -fv ./dist/* ../dist_archive && \ + cd $(cwd) + + $(eval cwd := $(shell pwd)) + cd ../../rnsh && \ + rm -rf ./dist && \ + poetry build && \ + cp -fv ./dist/* ../dist_archive && \ + cd $(cwd) + # rnode firmware source zip + cd ../../dist_archive && \ + curl -L https://github.com/markqvist/RNode_Firmware/archive/refs/heads/master.zip --clobber -o RNode_Firmware-master.zip && \ + cd $(cwd) + fetchshare: + mkdir -p ./share/pkg -(rm ./share/pkg/*) + mkdir -p ./share/mirrors -(rm ./share/mirrors/* -r) - cp ../../dist_archive/rns-*-py3-none-any.whl ./share/pkg/ - cp ../../dist_archive/rnspure-*-py3-none-any.whl ./share/pkg/ - cp ../../dist_archive/lxmf-*-py3-none-any.whl ./share/pkg/ - cp ../../dist_archive/nomadnet-*-py3-none-any.whl ./share/pkg/ - cp ../../dist_archive/rnsh-*-py3-none-any.whl ./share/pkg/ - cp ../../dist_archive/RNode_Firmware_*_Source.zip ./share/pkg/ + cp -fv ../../dist_archive/rns-*-py3-none-any.whl ./share/pkg/ + cp -fv ../../dist_archive/rnspure-*-py3-none-any.whl ./share/pkg/ + cp -fv ../../dist_archive/lxmf-*-py3-none-any.whl ./share/pkg/ + cp -fv ../../dist_archive/lxst-*-py3-none-any.whl ./share/pkg/ + cp -fv ../../dist_archive/nomadnet-*-py3-none-any.whl ./share/pkg/ + cp -fv ../../dist_archive/rnsh-*-py3-none-any.whl ./share/pkg/ + cp -fv ../../dist_archive/RNode_Firmware-*.zip ./share/pkg/ zip --junk-paths ./share/pkg/example_plugins.zip ../docs/example_plugins/*.py - cp -r ../../dist_archive/reticulum.network ./share/mirrors/ - cp -r ../../dist_archive/unsigned.io ./share/mirrors/ - cp ../../dist_archive/Reticulum\ Manual.pdf ./share/mirrors/Reticulum_Manual.pdf - cp ../../dist_archive/Reticulum\ Manual.epub ./share/mirrors/Reticulum_Manual.epub - cp -r ../../rnode-flasher ./share/mirrors/ + cp -rfv ../../dist_archive/reticulum.network ./share/mirrors/ + cp -rfv ../../dist_archive/unsigned.io ./share/mirrors/ + cp -fv ../../dist_archive/Reticulum\ Manual.pdf ./share/mirrors/Reticulum_Manual.pdf + cp -fv ../../dist_archive/Reticulum\ Manual.epub ./share/mirrors/Reticulum_Manual.epub + cp -rfv ../../rnode-flasher ./share/mirrors/ -(rm ./share/mirrors/rnode-flasher/.git -rf) release: @@ -79,25 +145,37 @@ release: postbuild: $(MAKE) cleanrns -apk: prepare prebake pacthfiles fetchshare release postbuild +apk: clean prepare prebake patchfiles createshare fetchshare release postbuild -devapk: prepare prebake pacthfiles fetchshare debug postbuild +devapk: clean prepare prebake patchfiles debug postbuild version: @(echo $$(python ./gv.py)) install: - adb install bin/sideband-$$(python ./gv.py)-arm64-v8a_armeabi-v7a-release.apk + adb install -r bin/sideband-$$(python ./gv.py)-arm64-v8a_armeabi-v7a_x86_x86_64-release.apk + +devinstall: + adb install -r bin/sideband-$$(python ./gv.py)-arm64-v8a_armeabi-v7a_x86_x86_64-debug.apk + +install-multi: + adb devices | tail -n +2 | cut -sf 1 | xargs -iX adb -s X install -r ./bin/sideband-$$(python ./gv.py)-arm64-v8a_armeabi-v7a_x86_x86_64-release.apk + +devinstall-multi: + adb devices | tail -n +2 | cut -sf 1 | xargs -iX adb -s X install -r ./bin/sideband-$$(python ./gv.py)-arm64-v8a_armeabi-v7a_x86_x86_64-debug.apk console: (adb logcat | grep "python\|sidebandservice") getrns: - (cp -rv ../../Reticulum/RNS ./;rm ./RNS/Utilities/RNS) + (cp -rv ../../Reticulum/RNS ./) + -(rm ./RNS/Utilities/RNS) # created by the create_symlinks target in Reticulum -(rm ./RNS/__pycache__ -r) - (cp -rv ../../LXMF/LXMF ./;rm ./LXMF/Utilities/LXMF) + (cp -rv ../../LXMF/LXMF ./) + -(rm ./LXMF/Utilities/LXMF) # ditto -(rm ./LXMF/__pycache__ -r) - (cp -rv ../../LXST/LXST ./;rm ./LXST/Utilities/LXST) + (cp -rv ../../LXST/LXST ./) + -(rm ./LXST/Utilities/LXST) -(rm ./LXST/__pycache__ -r) -(rm ./LXST/Utilities/__pycache__ -r) diff --git a/sbapp/buildozer.spec b/sbapp/buildozer.spec index b6b8594..9ab9926 100644 --- a/sbapp/buildozer.spec +++ b/sbapp/buildozer.spec @@ -12,7 +12,7 @@ version.regex = __version__ = ['"](.*)['"] version.filename = %(source.dir)s/main.py android.numeric_version = 20250220 -requirements = kivy==2.3.0,libbz2,pillow==10.2.0,qrcode==7.3.1,usb4a,usbserial4a,able_recipe,libwebp,libogg,libopus,opusfile,numpy,cryptography,ffpyplayer,codec2,pycodec2,sh,pynacl,typing-extensions,mistune>=3.0.2,beautifulsoup4 +requirements = kivy==2.3.1,libbz2,pillow==10.3.0,freetype-py==2.2.0,qrcode==7.3.1,usb4a,usbserial4a,able_recipe,libwebp,libogg,libopus,opusfile,numpy,cryptography,ffpyplayer,codec2,pycodec2,sh,pynacl,typing-extensions,mistune>=3.0.2,beautifulsoup4,filetype android.gradle_dependencies = com.android.support:support-compat:28.0.0 #android.enable_androidx = True @@ -37,11 +37,13 @@ android.ndk = 25b android.skip_update = False android.accept_sdk_license = True android.release_artifact = apk -android.archs = arm64-v8a,armeabi-v7a +android.archs = arm64-v8a,armeabi-v7a,x86,x86_64 #android.logcat_filters = *:S python:D services = sidebandservice:services/sidebandservice.py:foreground android.whitelist = lib-dynload/termios.so +android.add_src = src/main/java +android.res_xml = src/main/res/xml/device_filter.xml,src/main/res/xml/file_paths.xml android.manifest.intent_filters = patches/intent-filter.xml # android.add_libs_armeabi_v7a = ../libs/armeabi/*.so* diff --git a/sbapp/main.py b/sbapp/main.py index c157d92..1b834a3 100644 --- a/sbapp/main.py +++ b/sbapp/main.py @@ -23,11 +23,30 @@ import re import pathlib import base64 import threading +import traceback import RNS.vendor.umsgpack as msgpack WINDOW_DEFAULT_WIDTH = 494 WINDOW_DEFAULT_HEIGHT = 800 +# not all exceptions caught by sys.excepthook are sent to logcat: this is a small shim that ensures that always happens +original_excepthook = sys.excepthook + +# Custom exception handler that writes to Android log +def custom_excepthook(exc_type, exc_value, exc_traceback): + # First call the original excepthook to maintain default behavior + original_excepthook(exc_type, exc_value, exc_traceback) + + # Format the exception and traceback as a string + exception_str = ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)) + + # add extra handling to make sure any Python errors are exposed to logcat + if RNS.vendor.platformutils.is_android(): + RNS.log(f"PYTHON EXCEPTION: {exception_str}") + +# Replace the default exception handler +sys.excepthook = custom_excepthook + app_ui_scaling_path = None def apply_ui_scale(): global app_ui_scaling_path diff --git a/sbapp/src/main/java/io/unsigned/sideband/.gitkeep b/sbapp/src/main/java/io/unsigned/sideband/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sbapp/patches/device_filter.xml b/sbapp/src/main/res/xml/device_filter.xml similarity index 100% rename from sbapp/patches/device_filter.xml rename to sbapp/src/main/res/xml/device_filter.xml diff --git a/sbapp/patches/file_paths.xml b/sbapp/src/main/res/xml/file_paths.xml similarity index 100% rename from sbapp/patches/file_paths.xml rename to sbapp/src/main/res/xml/file_paths.xml