commit 12c6a4043b4e5054eedf819657a28e30377a6d47
parent a53dded50fad595dce34be609c59fddad61d66be
Author: ghost43 <somber.night@protonmail.com>
Date: Mon, 26 Nov 2018 22:02:52 +0100
Merge pull request #4864 from SomberNight/android_build_2018nov
android: build apk using new python3 p4a toolchain
Diffstat:
4 files changed, 112 insertions(+), 82 deletions(-)
diff --git a/electrum/gui/kivy/Readme.md b/electrum/gui/kivy/Readme.md
@@ -1,6 +1,9 @@
# Kivy GUI
-The Kivy GUI is used with Electrum on Android devices. To generate an APK file, follow these instructions.
+The Kivy GUI is used with Electrum on Android devices.
+To generate an APK file, follow these instructions.
+
+Recommended env: Ubuntu 18.04
## 1. Preliminaries
@@ -21,10 +24,7 @@ sudo apt-get install python3-kivy
## 3. Install python-for-android (p4a)
p4a is used to package Electrum, Python, SDL and a bootstrap Java app into an APK file.
-We patched p4a to add some functionality we need for Electrum. Until those changes are
-merged into p4a, you need to merge them locally (into the master branch):
-
-3.1 [kivy/python-for-android#1217](https://github.com/kivy/python-for-android/pull/1217)
+We need some functionality not in p4a master, so for the time being we have our own fork.
Something like this should work:
@@ -32,12 +32,9 @@ Something like this should work:
cd /opt
git clone https://github.com/kivy/python-for-android
cd python-for-android
-git remote add agilewalker https://github.com/agilewalker/python-for-android
git remote add sombernight https://github.com/SomberNight/python-for-android
git fetch --all
-git checkout 93759f36ba45c7bbe0456a4b3e6788622924cbac
-git cherry-pick a2fb5ecbc09c4847adbcfd03c6b1ca62b3d09b8d # openssl-fix
-git cherry-pick a0ef2007bc60ed642fbd8b61937995dbed0ddd24 # disable backups
+git checkout f74226666af69f9915afaee9ef9292db85a6c617
```
## 4. Install buildozer
@@ -51,31 +48,57 @@ sudo python3 setup.py install
```
4.2 Install additional dependencies:
+
```sh
sudo apt-get install python-pip
```
-and the ones listed
-[here](https://buildozer.readthedocs.io/en/latest/installation.html#targeting-android).
-You will also need
+(from [buildozer docs](https://buildozer.readthedocs.io/en/latest/installation.html#targeting-android))
+```sh
+sudo pip install --upgrade cython==0.21
+sudo dpkg --add-architecture i386
+sudo apt-get update
+sudo apt-get install build-essential ccache git libncurses5:i386 libstdc++6:i386 libgtk2.0-0:i386 libpangox-1.0-0:i386 libpangoxft-1.0-0:i386 libidn11:i386 python2.7 python2.7-dev openjdk-8-jdk unzip zlib1g-dev zlib1g:i386
+```
+
+4.3 Download Android NDK
```sh
-python3 -m pip install colorama appdirs sh jinja2
+cd /opt
+wget https://dl.google.com/android/repository/android-ndk-r14b-linux-x86_64.zip
+unzip android-ndk-r14b-linux-x86_64.zip
```
+## 5. Some more dependencies
-4.3 Download the [Crystax NDK](https://www.crystax.net/en/download) manually.
-Extract into `/opt/crystax-ndk-10.3.2`
+```sh
+python3 -m pip install colorama appdirs sh jinja2 cython==0.29
+sudo apt-get install autotools-dev autoconf libtool pkg-config python3.7
+```
-## 5. Create the UI Atlas
-In the `gui/kivy` directory of Electrum, run `make theming`.
+## 6. Create the UI Atlas
+In the `electrum/gui/kivy` directory of Electrum, run `make theming`.
-## 6. Download Electrum dependencies
+## 7. Download Electrum dependencies
```sh
sudo contrib/make_packages
```
-## 7. Try building the APK and fail
+## 8. Try building the APK and fail
+
+### 1. Try and fail:
+
+```sh
+contrib/make_apk
+```
+
+Symlink android tools:
+
+```sh
+ln -sf ~/.buildozer/android/platform/android-sdk-24/tools ~/.buildozer/android/platform/android-sdk-24/tools.save
+```
+
+### 2. Try and fail:
```sh
contrib/make_apk
@@ -84,47 +107,43 @@ contrib/make_apk
During this build attempt, buildozer downloaded some tools,
e.g. those needed in the next step.
-## 8. Update the Android SDK build tools
+## 9. Update the Android SDK build tools
### Method 1: Using the GUI
Start the Android SDK manager in GUI mode:
- ~/.buildozer/android/platform/android-sdk-20/tools/android
+ ~/.buildozer/android/platform/android-sdk-24/tools/android
Check the latest SDK available and install it
("Android SDK Tools" and "Android SDK Platform-tools").
Close the SDK manager. Repeat until there is no newer version.
Reopen the SDK manager, and install the latest build tools
- ("Android SDK Build-tools"), 27.0.3 at the time of writing.
+ ("Android SDK Build-tools"), 28.0.3 at the time of writing.
+ Install "Android 9">"SDK Platform".
Install "Android Support Repository" from the SDK manager (under "Extras").
### Method 2: Using the command line:
Repeat the following command until there is nothing to install:
- ~/.buildozer/android/platform/android-sdk-20/tools/android update sdk -u -t tools,platform-tools
+ ~/.buildozer/android/platform/android-sdk-24/tools/android update sdk -u -t tools,platform-tools
Install Build Tools, android API 19 and Android Support Library:
- ~/.buildozer/android/platform/android-sdk-20/tools/android update sdk -u -t build-tools-27.0.3,android-19,extra-android-m2repository
+ ~/.buildozer/android/platform/android-sdk-24/tools/android update sdk -u -t build-tools-28.0.3,android-28,extra-android-m2repository
+ (FIXME: build-tools is not getting installed?! use GUI for now.)
-## 9. Build the APK
+## 10. Build the APK
```sh
contrib/make_apk
```
# FAQ
-## Why do I get errors like `package me.dm7.barcodescanner.zxing does not exist` while compiling?
-Update your Android build tools to version 27 like described above.
-
-## Why do I get errors like `(use -source 7 or higher to enable multi-catch statement)` while compiling?
-Make sure that your p4a installation includes commit a3cc78a6d1a107cd3b6bd28db8b80f89e3ecddd2.
-Also make sure you have recent SDK tools and platform-tools
## I changed something but I don't see any differences on the phone. What did I do wrong?
You probably need to clear the cache: `rm -rf .buildozer/android/platform/build/{build,dists}`
diff --git a/electrum/gui/kivy/data/java-classes/org/electrum/qr/SimpleScannerActivity.java b/electrum/gui/kivy/data/java-classes/org/electrum/qr/SimpleScannerActivity.java
@@ -4,6 +4,9 @@ import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.content.Intent;
+import android.support.v4.app.ActivityCompat;
+import android.Manifest;
+import android.content.pm.PackageManager;
import java.util.Arrays;
@@ -13,28 +16,35 @@ import com.google.zxing.Result;
import com.google.zxing.BarcodeFormat;
public class SimpleScannerActivity extends Activity implements ZXingScannerView.ResultHandler {
- private ZXingScannerView mScannerView;
- final String TAG = "org.electrum.SimpleScannerActivity";
+ private static final int MY_PERMISSIONS_CAMERA = 1002;
- @Override
- public void onCreate(Bundle state) {
- super.onCreate(state);
- mScannerView = new ZXingScannerView(this); // Programmatically initialize the scanner view
- mScannerView.setFormats(Arrays.asList(BarcodeFormat.QR_CODE));
- setContentView(mScannerView); // Set the scanner view as the content view
- }
+ private ZXingScannerView mScannerView = null;
+ final String TAG = "org.electrum.SimpleScannerActivity";
@Override
public void onResume() {
super.onResume();
- mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
- mScannerView.startCamera(); // Start camera on resume
+ if (this.hasPermission()) {
+ this.startCamera();
+ } else {
+ this.requestPermission();
+ }
}
@Override
public void onPause() {
super.onPause();
- mScannerView.stopCamera(); // Stop camera on pause
+ if (null != mScannerView) {
+ mScannerView.stopCamera(); // Stop camera on pause
+ }
+ }
+
+ private void startCamera() {
+ mScannerView = new ZXingScannerView(this); // Programmatically initialize the scanner view
+ mScannerView.setFormats(Arrays.asList(BarcodeFormat.QR_CODE));
+ setContentView(mScannerView); // Set the scanner view as the content view
+ mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
+ mScannerView.startCamera(); // Start camera on resume
}
@Override
@@ -45,4 +55,35 @@ public class SimpleScannerActivity extends Activity implements ZXingScannerView.
setResult(Activity.RESULT_OK, resultIntent);
this.finish();
}
+
+ private boolean hasPermission() {
+ return (ActivityCompat.checkSelfPermission(this,
+ Manifest.permission.CAMERA)
+ == PackageManager.PERMISSION_GRANTED);
+ }
+
+ private void requestPermission() {
+ ActivityCompat.requestPermissions(this,
+ new String[]{Manifest.permission.CAMERA},
+ MY_PERMISSIONS_CAMERA);
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode,
+ String permissions[], int[] grantResults) {
+ switch (requestCode) {
+ case MY_PERMISSIONS_CAMERA: {
+ if (grantResults.length > 0
+ && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ // permission was granted, yay!
+ this.startCamera();
+ } else {
+ // permission denied
+ this.finish();
+ }
+ return;
+ }
+ }
+ }
+
}
diff --git a/electrum/gui/kivy/tools/buildozer.spec b/electrum/gui/kivy/tools/buildozer.spec
@@ -31,7 +31,7 @@ version.filename = %(source.dir)s/electrum/version.py
#version = 1.9.8
# (list) Application requirements
-requirements = python3crystax==3.6, android, openssl, plyer, kivy==master, libsecp256k1
+requirements = python3, android, openssl, plyer, kivy==master, libffi, libsecp256k1
# (str) Presplash of the application
#presplash.filename = %(source.dir)s/gui/kivy/theming/splash.png
@@ -52,25 +52,25 @@ fullscreen = False
#
# (list) Permissions
-android.permissions = INTERNET, WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE, CAMERA
+android.permissions = INTERNET, CAMERA
# (int) Android API to use
-#android.api = 14
+android.api = 28
# (int) Minimum API required (8 = Android 2.2 devices)
-#android.minapi = 8
+android.minapi = 21
# (int) Android SDK version to use
-#android.sdk = 21
+android.sdk = 24
# (str) Android NDK version to use
-#android.ndk = 9
+android.ndk = 14b
# (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/crystax-ndk-10.3.2
+android.ndk_path = /opt/android-ndk-r14b
# (str) Android SDK directory (if empty, it will be automatically downloaded.)
#android.sdk_path =
diff --git a/electrum/util.py b/electrum/util.py
@@ -354,41 +354,11 @@ def profiler(func):
return lambda *args, **kw_args: do_profile(args, kw_args)
-def android_ext_dir():
- import jnius
- env = jnius.autoclass('android.os.Environment')
- return env.getExternalStorageDirectory().getPath()
-
def android_data_dir():
import jnius
PythonActivity = jnius.autoclass('org.kivy.android.PythonActivity')
return PythonActivity.mActivity.getFilesDir().getPath() + '/data'
-def android_headers_dir():
- d = android_ext_dir() + '/org.electrum.electrum'
- if not os.path.exists(d):
- try:
- os.mkdir(d)
- except FileExistsError:
- pass # in case of race
- return d
-
-def android_check_data_dir():
- """ if needed, move old directory to sandbox """
- ext_dir = android_ext_dir()
- data_dir = android_data_dir()
- old_electrum_dir = ext_dir + '/electrum'
- if not os.path.exists(data_dir) and os.path.exists(old_electrum_dir):
- import shutil
- new_headers_path = android_headers_dir() + '/blockchain_headers'
- old_headers_path = old_electrum_dir + '/blockchain_headers'
- if not os.path.exists(new_headers_path) and os.path.exists(old_headers_path):
- print_error("Moving headers file to", new_headers_path)
- shutil.move(old_headers_path, new_headers_path)
- print_error("Moving data to", data_dir)
- shutil.move(old_electrum_dir, data_dir)
- return data_dir
-
def ensure_sparse_file(filename):
# On modern Linux, no need to do anything.
@@ -401,7 +371,7 @@ def ensure_sparse_file(filename):
def get_headers_dir(config):
- return android_headers_dir() if 'ANDROID_DATA' in os.environ else config.path
+ return config.path
def assert_datadir_available(config_path):
@@ -484,7 +454,7 @@ def bh2u(x: bytes) -> str:
def user_dir():
if 'ANDROID_DATA' in os.environ:
- return android_check_data_dir()
+ return android_data_dir()
elif os.name == 'posix':
return os.path.join(os.environ["HOME"], ".electrum")
elif "APPDATA" in os.environ: