fix and update
This commit is contained in:
@@ -50,17 +50,26 @@ echo "==> Настройка Android SDK (offline, без загрузки platf
|
||||
echo "==> Настройка offline Gradle wrapper (если bundled zip доступен)"
|
||||
/workspace/tauri_app/docker/install-offline-gradle.sh /workspace/tauri_app/src-tauri/gen/android
|
||||
|
||||
echo "==> Сборка Android APK"
|
||||
echo "==> Подготовка keystore для release-подписи APK"
|
||||
/workspace/tauri_app/docker/ensure-android-keystore.sh
|
||||
/workspace/tauri_app/docker/patch-android-signing.sh /workspace/tauri_app/src-tauri/gen/android
|
||||
|
||||
echo "==> Сборка Android APK (release, signed)"
|
||||
npm run tauri -- android build --apk
|
||||
|
||||
APK_PATH="$(find /workspace/tauri_app/src-tauri/gen/android -type f -name '*.apk' | sort | tail -n 1 || true)"
|
||||
APK_PATH="$(find /workspace/tauri_app/src-tauri/gen/android -type f -name '*release*.apk' ! -name '*unsigned*' | sort | tail -n 1 || true)"
|
||||
if [[ -z "${APK_PATH}" ]]; then
|
||||
APK_PATH="$(find /workspace/tauri_app/src-tauri/gen/android -type f -name '*.apk' ! -name '*unsigned*' | sort | tail -n 1 || true)"
|
||||
fi
|
||||
|
||||
if [ -z "${APK_PATH}" ] || [ ! -f "${APK_PATH}" ]; then
|
||||
echo "APK не найден после сборки" >&2
|
||||
find /workspace/tauri_app/src-tauri/gen/android -maxdepth 8 -type f | sort >&2 || true
|
||||
find /workspace/tauri_app/src-tauri/gen/android -maxdepth 8 -type f -name '*.apk' | sort >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
/workspace/tauri_app/docker/verify-apk-signature.sh "${APK_PATH}"
|
||||
|
||||
cp "${APK_PATH}" /out/lendry-id.apk
|
||||
chmod 0644 /out/lendry-id.apk
|
||||
|
||||
|
||||
79
tauri_app/docker/ensure-android-keystore.sh
Normal file
79
tauri_app/docker/ensure-android-keystore.sh
Normal file
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env bash
|
||||
# Создаёт release keystore для подписи APK, если его ещё нет.
|
||||
set -euo pipefail
|
||||
|
||||
SECRETS_DIR="${ANDROID_SECRETS_DIR:-/workspace/tauri_app/.secrets}"
|
||||
KEYSTORE_FILE="${ANDROID_KEYSTORE_FILE:-${SECRETS_DIR}/lendry-id-release.keystore}"
|
||||
KEY_ALIAS="${ANDROID_KEY_ALIAS:-lendry-id}"
|
||||
CREDENTIALS_FILE="${SECRETS_DIR}/signing-credentials.env"
|
||||
KEYSTORE_PROPS_TEMPLATE="${SECRETS_DIR}/keystore.properties.template"
|
||||
|
||||
mkdir -p "${SECRETS_DIR}"
|
||||
chmod 700 "${SECRETS_DIR}" || true
|
||||
|
||||
if [[ -f "${KEYSTORE_FILE}" ]]; then
|
||||
echo "==> Android keystore уже существует: ${KEYSTORE_FILE}"
|
||||
if [[ ! -f "${PROPS_TEMPLATE}" && -f "${CREDENTIALS_FILE}" ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "${CREDENTIALS_FILE}"
|
||||
cat > "${PROPS_TEMPLATE}" <<EOF
|
||||
storePassword=${ANDROID_KEYSTORE_PASSWORD}
|
||||
keyPassword=${ANDROID_KEY_PASSWORD}
|
||||
keyAlias=${ANDROID_KEY_ALIAS}
|
||||
storeFile=../../../.secrets/lendry-id-release.keystore
|
||||
EOF
|
||||
chmod 600 "${PROPS_TEMPLATE}" || true
|
||||
echo "==> Восстановлен keystore.properties.template из signing-credentials.env"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! command -v keytool >/dev/null 2>&1; then
|
||||
echo "keytool не найден — нужен JDK для генерации keystore" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
gen_secret() {
|
||||
if command -v openssl >/dev/null 2>&1; then
|
||||
openssl rand -base64 32 | tr -dc 'A-Za-z0-9' | head -c 24
|
||||
else
|
||||
date +%s%N | sha256sum | head -c 24
|
||||
fi
|
||||
}
|
||||
|
||||
STORE_PASSWORD="$(gen_secret)"
|
||||
KEY_PASSWORD="$(gen_secret)"
|
||||
|
||||
echo "==> Генерация release keystore для подписи APK..."
|
||||
keytool -genkeypair -v \
|
||||
-storetype PKCS12 \
|
||||
-keystore "${KEYSTORE_FILE}" \
|
||||
-alias "${KEY_ALIAS}" \
|
||||
-keyalg RSA \
|
||||
-keysize 2048 \
|
||||
-validity 10000 \
|
||||
-storepass "${STORE_PASSWORD}" \
|
||||
-keypass "${KEY_PASSWORD}" \
|
||||
-dname "CN=Lendry ID, OU=Mobile, O=Lendry, C=RU"
|
||||
|
||||
chmod 600 "${KEYSTORE_FILE}" || true
|
||||
|
||||
cat > "${CREDENTIALS_FILE}" <<EOF
|
||||
# Сгенерировано $(date -u +"%Y-%m-%dT%H:%M:%SZ") — храните в безопасном месте.
|
||||
ANDROID_KEYSTORE_FILE=${KEYSTORE_FILE}
|
||||
ANDROID_KEY_ALIAS=${KEY_ALIAS}
|
||||
ANDROID_KEYSTORE_PASSWORD=${STORE_PASSWORD}
|
||||
ANDROID_KEY_PASSWORD=${KEY_PASSWORD}
|
||||
EOF
|
||||
chmod 600 "${CREDENTIALS_FILE}" || true
|
||||
|
||||
cat > "${KEYSTORE_PROPS_TEMPLATE}" <<EOF
|
||||
storePassword=${STORE_PASSWORD}
|
||||
keyPassword=${KEY_PASSWORD}
|
||||
keyAlias=${KEY_ALIAS}
|
||||
storeFile=../../../.secrets/lendry-id-release.keystore
|
||||
EOF
|
||||
chmod 600 "${KEYSTORE_PROPS_TEMPLATE}" || true
|
||||
|
||||
echo "==> Keystore создан: ${KEYSTORE_FILE}"
|
||||
echo "==> Пароли сохранены: ${CREDENTIALS_FILE}"
|
||||
61
tauri_app/docker/patch-android-signing.sh
Normal file
61
tauri_app/docker/patch-android-signing.sh
Normal file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
# Подключает release-подпись APK через keystore.properties + Gradle script.
|
||||
set -euo pipefail
|
||||
|
||||
ANDROID_GEN="${1:-/workspace/tauri_app/src-tauri/gen/android}"
|
||||
SECRETS_DIR="${ANDROID_SECRETS_DIR:-/workspace/tauri_app/.secrets}"
|
||||
KEYSTORE_FILE="${ANDROID_KEYSTORE_FILE:-${SECRETS_DIR}/lendry-id-release.keystore}"
|
||||
APP_GRADLE="${ANDROID_GEN}/app/build.gradle.kts"
|
||||
KEYSTORE_PROPS="${ANDROID_GEN}/keystore.properties"
|
||||
SIGNING_SCRIPT="${ANDROID_GEN}/app/release-signing.gradle.kts"
|
||||
PROPS_TEMPLATE="${SECRETS_DIR}/keystore.properties.template"
|
||||
|
||||
if [[ ! -d "${ANDROID_GEN}" ]]; then
|
||||
echo "Android project not found: ${ANDROID_GEN}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "${KEYSTORE_FILE}" ]]; then
|
||||
echo "Keystore не найден: ${KEYSTORE_FILE}. Запустите ensure-android-keystore.sh" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -f "${PROPS_TEMPLATE}" ]]; then
|
||||
cp "${PROPS_TEMPLATE}" "${KEYSTORE_PROPS}"
|
||||
else
|
||||
echo "keystore.properties.template не найден в ${SECRETS_DIR}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
chmod 600 "${KEYSTORE_PROPS}" || true
|
||||
|
||||
cat > "${SIGNING_SCRIPT}" <<'EOF'
|
||||
import com.android.build.api.dsl.ApplicationExtension
|
||||
import java.util.Properties
|
||||
|
||||
val keystoreProperties = Properties().apply {
|
||||
rootProject.file("keystore.properties").inputStream().use { load(it) }
|
||||
}
|
||||
|
||||
extensions.configure<ApplicationExtension>("android") {
|
||||
signingConfigs {
|
||||
create("release") {
|
||||
keyAlias = keystoreProperties.getProperty("keyAlias")
|
||||
keyPassword = keystoreProperties.getProperty("keyPassword")
|
||||
storeFile = rootProject.file(keystoreProperties.getProperty("storeFile"))
|
||||
storePassword = keystoreProperties.getProperty("storePassword")
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
getByName("release") {
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
if ! grep -q 'release-signing.gradle.kts' "${APP_GRADLE}"; then
|
||||
printf '\napply(from = "release-signing.gradle.kts")\n' >> "${APP_GRADLE}"
|
||||
fi
|
||||
|
||||
echo "==> Android release signing patched (${KEYSTORE_PROPS})"
|
||||
21
tauri_app/docker/verify-apk-signature.sh
Normal file
21
tauri_app/docker/verify-apk-signature.sh
Normal file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
APK_PATH="${1:-}"
|
||||
ANDROID_HOME="${ANDROID_HOME:-/opt/android-sdk}"
|
||||
|
||||
if [[ -z "${APK_PATH}" || ! -f "${APK_PATH}" ]]; then
|
||||
echo "APK не найден для проверки подписи: ${APK_PATH}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
APKSIGNER="$(find "${ANDROID_HOME}/build-tools" -name apksigner -type f 2>/dev/null | sort -V | tail -n 1 || true)"
|
||||
|
||||
if [[ -z "${APKSIGNER}" ]]; then
|
||||
echo "apksigner не найден в ${ANDROID_HOME}/build-tools" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> Проверка подписи APK: ${APK_PATH}"
|
||||
"${APKSIGNER}" verify --verbose "${APK_PATH}"
|
||||
echo "==> Подпись APK подтверждена (apksigner verify)"
|
||||
Reference in New Issue
Block a user