fix(android): build static OpenSSL for Android and initialize keyring-core (#245)
* fix(android): build static OpenSSL for Android and initialize keyring-core
Android doesn't ship a system libcrypto.so, which SQLCipher (via
libsqlite3-sys) requires. This adds a build script that cross-compiles
OpenSSL as a static library for each Android target (aarch64, armv7,
x86_64) and points the Rust build at those per-target installations.
Also adds the Keyring Kotlin class and initializes the NDK context
in MainActivity so keyring-core can access Android's secure storage.
* fix(android): verify OpenSSL tarball SHA-256 integrity after download
The SHA-256 hash was defined but never checked, and the value itself
was truncated (40 chars, not 64). Replace with the correct hash from
the official release and add verification before extracting.
* fix(android): add pipefail and remove tail pipes in OpenSSL build script
set -e alone does not catch failures in pipeline commands. Adding pipefail
ensures configure/make errors propagate instead of being masked by | tail -3.
* fix(android): detect Apple Silicon NDK path and portable SHA-256 check
The Darwin case now inspects uname -m to set HOST_TAG to darwin-arm64 on
Apple Silicon instead of always using darwin-x86_64.
SHA-256 verification falls back from shasum to sha256sum so the script
works on Linux systems that only ship sha256sum. Both tools use the same
output format (hash followed by filename) so awk '{print $1}' works for
either.
This commit is contained in:
+22
-29
@@ -89,20 +89,10 @@ export CC_armv7_linux_androideabi="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$H
|
||||
export CXX_armv7_linux_androideabi="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG/bin/armv7a-linux-androideabi33-clang++"
|
||||
export AR_armv7_linux_androideabi="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG/bin/llvm-ar"
|
||||
|
||||
# OpenSSL environment variables for Android cross-compilation
|
||||
# Point to macOS OpenSSL for the build process (sqlcipher needs headers)
|
||||
if [ -d "/opt/homebrew/opt/openssl@3" ]; then
|
||||
export OPENSSL_DIR="/opt/homebrew/opt/openssl@3"
|
||||
export OPENSSL_INCLUDE_DIR="/opt/homebrew/opt/openssl@3/include"
|
||||
export OPENSSL_LIB_DIR="/opt/homebrew/opt/openssl@3/lib"
|
||||
elif [ -d "/usr/local/opt/openssl@3" ]; then
|
||||
export OPENSSL_DIR="/usr/local/opt/openssl@3"
|
||||
export OPENSSL_INCLUDE_DIR="/usr/local/opt/openssl@3/include"
|
||||
export OPENSSL_LIB_DIR="/usr/local/opt/openssl@3/lib"
|
||||
fi
|
||||
|
||||
# Use vendored OpenSSL for cross-compilation to avoid linking issues
|
||||
export OPENSSL_STATIC=1
|
||||
# Build static OpenSSL for Android targets (SQLCipher requires libcrypto)
|
||||
print_step "Building OpenSSL for Android"
|
||||
./scripts/build_openssl_android.sh
|
||||
OPENSSL_ANDROID_DIR="$PWD/rust/target/openssl/install"
|
||||
|
||||
# Check if required tools are installed
|
||||
print_step "Checking development environment"
|
||||
@@ -132,23 +122,26 @@ mkdir -p android/app/src/main/jniLibs/x86_64
|
||||
print_step "Building for Android architectures"
|
||||
cd rust
|
||||
|
||||
# aarch64 (arm64-v8a) - 64-bit ARM
|
||||
print_step "Building for aarch64 (arm64-v8a)"
|
||||
cargo build --target aarch64-linux-android --release --quiet
|
||||
cp target/aarch64-linux-android/release/librust_lib_whitenoise.so ../android/app/src/main/jniLibs/arm64-v8a/
|
||||
print_success "Built for aarch64 (arm64-v8a)"
|
||||
# Build helper: sets per-target OpenSSL env vars and runs cargo build
|
||||
build_for_target() {
|
||||
local target="$1"
|
||||
local label="$2"
|
||||
local jni_dir="$3"
|
||||
|
||||
# armv7 (armeabi-v7a) - 32-bit ARM
|
||||
print_step "Building for armv7 (armeabi-v7a)"
|
||||
cargo build --target armv7-linux-androideabi --release --quiet
|
||||
cp target/armv7-linux-androideabi/release/librust_lib_whitenoise.so ../android/app/src/main/jniLibs/armeabi-v7a/
|
||||
print_success "Built for armv7 (armeabi-v7a)"
|
||||
print_step "Building for $label"
|
||||
OPENSSL_DIR="$OPENSSL_ANDROID_DIR/$target" \
|
||||
OPENSSL_INCLUDE_DIR="$OPENSSL_ANDROID_DIR/$target/include" \
|
||||
OPENSSL_LIB_DIR="$OPENSSL_ANDROID_DIR/$target/lib" \
|
||||
OPENSSL_STATIC=1 \
|
||||
OPENSSL_NO_VENDOR=1 \
|
||||
cargo build --target "$target" --release --quiet
|
||||
cp "target/$target/release/librust_lib_whitenoise.so" "../android/app/src/main/jniLibs/$jni_dir/"
|
||||
print_success "Built for $label"
|
||||
}
|
||||
|
||||
# x86_64 - 64-bit Intel
|
||||
print_step "Building for x86_64"
|
||||
cargo build --target x86_64-linux-android --release --quiet
|
||||
cp target/x86_64-linux-android/release/librust_lib_whitenoise.so ../android/app/src/main/jniLibs/x86_64/
|
||||
print_success "Built for x86_64"
|
||||
build_for_target "aarch64-linux-android" "aarch64 (arm64-v8a)" "arm64-v8a"
|
||||
build_for_target "armv7-linux-androideabi" "armv7 (armeabi-v7a)" "armeabi-v7a"
|
||||
build_for_target "x86_64-linux-android" "x86_64" "x86_64"
|
||||
|
||||
cd ..
|
||||
|
||||
|
||||
Executable
+160
@@ -0,0 +1,160 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Build OpenSSL static libraries for Android targets
|
||||
# This is needed because libsqlite3-sys (SQLCipher) requires libcrypto,
|
||||
# and Android doesn't ship a system libcrypto.so.
|
||||
set -eo pipefail
|
||||
|
||||
print_step() {
|
||||
echo -e "\n\033[1;34m=== $1 ===\033[0m"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "\033[1;32m$1\033[0m"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "\033[1;31m$1\033[0m"
|
||||
}
|
||||
|
||||
# Configuration
|
||||
OPENSSL_VERSION="3.4.1"
|
||||
OPENSSL_SHA256="002a2d6b30b58bf4bea46c43bdd96365aaf8daa6c428782aa4feee06da197df3"
|
||||
ANDROID_API=33
|
||||
|
||||
# Resolve paths
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
OPENSSL_BUILD_DIR="$PROJECT_ROOT/rust/target/openssl"
|
||||
OPENSSL_SRC_DIR="$OPENSSL_BUILD_DIR/openssl-$OPENSSL_VERSION"
|
||||
OPENSSL_INSTALL_DIR="$OPENSSL_BUILD_DIR/install"
|
||||
|
||||
# Auto-detect Android NDK
|
||||
if [ -z "$ANDROID_NDK_HOME" ]; then
|
||||
if [ -n "$NDK_HOME" ]; then
|
||||
ANDROID_NDK_HOME="$NDK_HOME"
|
||||
elif [ -n "$ANDROID_HOME" ]; then
|
||||
NDK_DIR="$ANDROID_HOME/ndk"
|
||||
if [ -d "$NDK_DIR" ]; then
|
||||
NDK_VERSION=$(ls "$NDK_DIR" | sort -V | tail -n 1)
|
||||
if [ -n "$NDK_VERSION" ]; then
|
||||
ANDROID_NDK_HOME="$NDK_DIR/$NDK_VERSION"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$ANDROID_NDK_HOME" ] || [ ! -d "$ANDROID_NDK_HOME" ]; then
|
||||
print_error "Android NDK not found. Set ANDROID_NDK_HOME or NDK_HOME."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Detect host OS
|
||||
case "$(uname -s)" in
|
||||
Darwin*)
|
||||
case "$(uname -m)" in
|
||||
arm64|aarch64) HOST_TAG="darwin-arm64" ;;
|
||||
*) HOST_TAG="darwin-x86_64" ;;
|
||||
esac
|
||||
;;
|
||||
Linux*) HOST_TAG="linux-x86_64" ;;
|
||||
*) print_error "Unsupported host OS: $(uname -s)"; exit 1 ;;
|
||||
esac
|
||||
|
||||
TOOLCHAIN="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG"
|
||||
|
||||
# Target configurations: (rust_target openssl_target arch)
|
||||
TARGETS=(
|
||||
"aarch64-linux-android:android-arm64:aarch64"
|
||||
"armv7-linux-androideabi:android-arm:armv7a"
|
||||
"x86_64-linux-android:android-x86_64:x86_64"
|
||||
)
|
||||
|
||||
build_openssl_for_target() {
|
||||
local rust_target="$1"
|
||||
local openssl_target="$2"
|
||||
local arch="$3"
|
||||
local install_prefix="$OPENSSL_INSTALL_DIR/$rust_target"
|
||||
|
||||
# Skip if already built
|
||||
if [ -f "$install_prefix/lib/libcrypto.a" ]; then
|
||||
print_success "OpenSSL already built for $rust_target (skipping)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
print_step "Building OpenSSL for $rust_target ($openssl_target)"
|
||||
|
||||
# Clean and re-extract source for each target (OpenSSL doesn't support out-of-tree builds well)
|
||||
local build_src="$OPENSSL_BUILD_DIR/build-$rust_target"
|
||||
rm -rf "$build_src"
|
||||
cp -r "$OPENSSL_SRC_DIR" "$build_src"
|
||||
cd "$build_src"
|
||||
|
||||
export ANDROID_NDK_ROOT="$ANDROID_NDK_HOME"
|
||||
export PATH="$TOOLCHAIN/bin:$PATH"
|
||||
|
||||
./Configure "$openssl_target" \
|
||||
-D__ANDROID_API__=$ANDROID_API \
|
||||
--prefix="$install_prefix" \
|
||||
--openssldir="$install_prefix/ssl" \
|
||||
no-shared \
|
||||
no-tests \
|
||||
no-ui-console \
|
||||
no-stdio \
|
||||
-fPIC
|
||||
|
||||
make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" build_libs
|
||||
make install_dev
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
rm -rf "$build_src"
|
||||
|
||||
if [ -f "$install_prefix/lib/libcrypto.a" ]; then
|
||||
print_success "Built OpenSSL for $rust_target"
|
||||
else
|
||||
print_error "Failed to build OpenSSL for $rust_target"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Download OpenSSL source if needed
|
||||
if [ ! -d "$OPENSSL_SRC_DIR" ]; then
|
||||
print_step "Downloading OpenSSL $OPENSSL_VERSION"
|
||||
mkdir -p "$OPENSSL_BUILD_DIR"
|
||||
cd "$OPENSSL_BUILD_DIR"
|
||||
|
||||
TARBALL="openssl-$OPENSSL_VERSION.tar.gz"
|
||||
if [ ! -f "$TARBALL" ]; then
|
||||
curl -LO "https://github.com/openssl/openssl/releases/download/openssl-$OPENSSL_VERSION/$TARBALL"
|
||||
fi
|
||||
|
||||
print_step "Verifying tarball integrity"
|
||||
if command -v shasum >/dev/null 2>&1; then
|
||||
ACTUAL_SHA256=$(shasum -a 256 "$TARBALL" | awk '{print $1}')
|
||||
elif command -v sha256sum >/dev/null 2>&1; then
|
||||
ACTUAL_SHA256=$(sha256sum "$TARBALL" | awk '{print $1}')
|
||||
else
|
||||
print_error "No SHA-256 tool found (need shasum or sha256sum)"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$ACTUAL_SHA256" != "$OPENSSL_SHA256" ]; then
|
||||
print_error "SHA-256 mismatch for $TARBALL"
|
||||
print_error " Expected: $OPENSSL_SHA256"
|
||||
print_error " Actual: $ACTUAL_SHA256"
|
||||
rm -f "$TARBALL"
|
||||
exit 1
|
||||
fi
|
||||
print_success "SHA-256 verified"
|
||||
|
||||
tar xzf "$TARBALL"
|
||||
cd "$PROJECT_ROOT"
|
||||
fi
|
||||
|
||||
# Build for each target
|
||||
for target_spec in "${TARGETS[@]}"; do
|
||||
IFS=':' read -r rust_target openssl_target arch <<< "$target_spec"
|
||||
build_openssl_for_target "$rust_target" "$openssl_target" "$arch"
|
||||
done
|
||||
|
||||
print_success "All OpenSSL Android builds complete!"
|
||||
echo "Install directory: $OPENSSL_INSTALL_DIR"
|
||||
@@ -65,9 +65,6 @@ linker = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/${HOST_TAG}/bin/x86_64-li
|
||||
CC_armv7_linux_androideabi = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/${HOST_TAG}/bin/armv7a-linux-androideabi33-clang"
|
||||
CXX_armv7_linux_androideabi = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/${HOST_TAG}/bin/armv7a-linux-androideabi33-clang++"
|
||||
AR_armv7_linux_androideabi = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/${HOST_TAG}/bin/llvm-ar"
|
||||
OPENSSL_DIR = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/${HOST_TAG}/sysroot/usr"
|
||||
OPENSSL_INCLUDE_DIR = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/${HOST_TAG}/sysroot/usr/include"
|
||||
OPENSSL_LIB_DIR = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/${HOST_TAG}/sysroot/usr/lib/aarch64-linux-android"
|
||||
EOF
|
||||
|
||||
print_success "Generated Cargo config for host: $HOST_TAG"
|
||||
|
||||
Reference in New Issue
Block a user