193 lines
5.6 KiB
Bash
Executable File
193 lines
5.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# ============================================================
|
|
# 星元智灵 APK 手动编译脚本 (无 Gradle)
|
|
# 使用 Android SDK 命令行工具: aapt / javac / d8 / zipalign / apksigner
|
|
# ============================================================
|
|
set -e
|
|
|
|
# ---- 路径配置 ----
|
|
PROJECT="$(cd "$(dirname "$0")" && pwd)"
|
|
SDK="$HOME/Library/Android/sdk"
|
|
BT="$SDK/build-tools/34.0.0"
|
|
PLATFORM="$SDK/platforms/android-28/android.jar"
|
|
SRC="$PROJECT/app/src/main"
|
|
BUILD="$PROJECT/build"
|
|
KEYSTORE="$PROJECT/keystore/zhitou-debug.keystore"
|
|
APK_BASENAME="xingyuan-zhiling"
|
|
STORE_PASS="android"
|
|
KEY_PASS="android"
|
|
KEY_ALIAS="androiddebugkey"
|
|
|
|
# ---- 工具路径 ----
|
|
AAPT="$BT/aapt"
|
|
D8="$BT/d8"
|
|
ZIPALIGN="$BT/zipalign"
|
|
APKSIGNER="$BT/apksigner"
|
|
NDK_VERSION="27.3.13750724"
|
|
NDK="$SDK/ndk/$NDK_VERSION"
|
|
ARM_CLANGXX="$NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin/armv7a-linux-androideabi21-clang++"
|
|
|
|
# ---- 输出目录 ----
|
|
OUT="$BUILD/out"
|
|
GEN="$BUILD/gen"
|
|
CLASSES="$BUILD/classes"
|
|
DEX="$BUILD/dex"
|
|
|
|
echo "=========================================="
|
|
echo " 星元智灵 APK 编译"
|
|
echo "=========================================="
|
|
echo "SDK: $SDK"
|
|
echo "BuildTools: 34.0.0"
|
|
echo "Platform: android-28"
|
|
echo "Project: $PROJECT"
|
|
echo ""
|
|
|
|
# ---- 恢复超过 Git 单文件限制的人脸模型 ----
|
|
"$PROJECT/scripts/restore-face-models.sh"
|
|
|
|
# ---- Debug 签名证书 ----
|
|
if [ ! -f "$KEYSTORE" ]; then
|
|
echo "未找到 debug keystore,正在生成: $KEYSTORE"
|
|
mkdir -p "$(dirname "$KEYSTORE")"
|
|
keytool -genkeypair \
|
|
-keystore "$KEYSTORE" \
|
|
-storepass "$STORE_PASS" \
|
|
-keypass "$KEY_PASS" \
|
|
-alias "$KEY_ALIAS" \
|
|
-keyalg RSA \
|
|
-keysize 2048 \
|
|
-validity 10000 \
|
|
-dname "CN=Android Debug,O=Xingyuan Zhiling,C=CN" >/dev/null
|
|
fi
|
|
|
|
# ---- Step 1: 清理 ----
|
|
echo "[1/8] 清理旧的编译产物..."
|
|
rm -rf "$GEN" "$CLASSES" "$DEX"
|
|
mkdir -p "$GEN" "$CLASSES" "$DEX" "$OUT"
|
|
|
|
# ---- Step 2: 生成 R.java ----
|
|
echo "[2/8] 生成 R.java..."
|
|
"$AAPT" package -f -m \
|
|
-J "$GEN" \
|
|
-M "$SRC/AndroidManifest.xml" \
|
|
-S "$SRC/res" \
|
|
-A "$SRC/assets" \
|
|
-I "$PLATFORM"
|
|
|
|
# ---- Step 3: 收集 Java 源文件 ----
|
|
echo "[3/8] 收集 Java 源文件..."
|
|
SRC_FILES=$(find "$SRC/java" "$GEN" -name "*.java" | tr '\n' ' ')
|
|
echo " 源文件数量: $(echo $SRC_FILES | wc -w | tr -d ' ')"
|
|
|
|
# ---- Step 4: 编译 Java ----
|
|
echo "[4/8] 编译 Java 源码..."
|
|
javac --release 8 -parameters \
|
|
-classpath "$PLATFORM" \
|
|
-sourcepath "$GEN" \
|
|
-d "$CLASSES" \
|
|
$SRC_FILES 2>&1
|
|
echo " 编译完成"
|
|
|
|
# ---- Step 5: 转换为 DEX ----
|
|
echo "[5/8] 转换为 DEX..."
|
|
CLASS_FILES=$(find "$CLASSES" -name "*.class" | tr '\n' ' ')
|
|
"$D8" \
|
|
--output "$DEX" \
|
|
--lib "$PLATFORM" \
|
|
$CLASS_FILES 2>&1
|
|
echo " DEX 生成完成: $DEX/classes.dex"
|
|
|
|
# ---- Step 6: 打包资源 + Manifest + Assets ----
|
|
echo "[6/8] 打包 APK (资源 + Manifest + Assets)..."
|
|
rm -f "$OUT/$APK_BASENAME-unsigned.apk" "$OUT/$APK_BASENAME-aligned.apk" "$OUT/$APK_BASENAME-signed.apk"
|
|
"$AAPT" package -f \
|
|
-M "$SRC/AndroidManifest.xml" \
|
|
-S "$SRC/res" \
|
|
-A "$SRC/assets" \
|
|
-I "$PLATFORM" \
|
|
-F "$OUT/$APK_BASENAME-unsigned.apk"
|
|
|
|
# ---- Step 7: 添加 DEX 和 Native 库 ----
|
|
echo "[7/8] 添加 DEX 和 Native 库到 APK..."
|
|
# 添加 classes.dex
|
|
cd "$DEX"
|
|
zip -j "$OUT/$APK_BASENAME-unsigned.apk" classes.dex
|
|
cd "$PROJECT"
|
|
|
|
# 构建 SeetaFace6 JNI 桥(官方 Android 库就位后自动启用)
|
|
FACE_LIB_DIR="$SRC/jniLibs/armeabi-v7a"
|
|
FACE_JNI_SOURCE="$SRC/cpp/face_engine_jni.cpp"
|
|
FACE_JNI_OUTPUT="$FACE_LIB_DIR/libxingyuan_face.so"
|
|
FACE_REQUIRED_LIBS=(
|
|
libTenniS.so
|
|
libSeetaAuthorize.so
|
|
libSeetaFaceDetector600.so
|
|
libSeetaFaceLandmarker600.so
|
|
libSeetaFaceRecognizer600.so
|
|
)
|
|
FACE_LIBS_READY=true
|
|
for library in "${FACE_REQUIRED_LIBS[@]}"; do
|
|
if [ ! -f "$FACE_LIB_DIR/$library" ]; then
|
|
FACE_LIBS_READY=false
|
|
fi
|
|
done
|
|
if [ "$FACE_LIBS_READY" = true ] && [ -x "$ARM_CLANGXX" ]; then
|
|
echo " 编译 SeetaFace6 JNI 桥..."
|
|
"$ARM_CLANGXX" \
|
|
--sysroot="$NDK/toolchains/llvm/prebuilt/darwin-x86_64/sysroot" \
|
|
-std=c++11 -O2 -fPIC -shared -static-libstdc++ \
|
|
-I"$SRC/cpp/include" \
|
|
"$FACE_JNI_SOURCE" \
|
|
-L"$FACE_LIB_DIR" \
|
|
-lSeetaFaceDetector600 \
|
|
-lSeetaFaceLandmarker600 \
|
|
-lSeetaFaceRecognizer600 \
|
|
-lSeetaAuthorize \
|
|
-lTenniS \
|
|
-llog -lz -ldl -lm \
|
|
-o "$FACE_JNI_OUTPUT"
|
|
else
|
|
rm -f "$FACE_JNI_OUTPUT"
|
|
echo " ⚠ SeetaFace6 官方 Android 动态库尚未齐备,人脸 JNI 暂不打包"
|
|
fi
|
|
|
|
# 添加 native 库 (APK 中需要 lib/<abi>/ 结构)
|
|
NATIVE_STAGING="$BUILD/native_staging"
|
|
rm -rf "$NATIVE_STAGING"
|
|
mkdir -p "$NATIVE_STAGING/lib/armeabi-v7a"
|
|
find "$SRC/jniLibs/armeabi-v7a" -maxdepth 1 -type f -name "*.so" -exec cp {} "$NATIVE_STAGING/lib/armeabi-v7a/" \;
|
|
cd "$NATIVE_STAGING"
|
|
zip -r "$OUT/$APK_BASENAME-unsigned.apk" lib/
|
|
cd "$PROJECT"
|
|
echo " APK 打包完成"
|
|
|
|
# ---- Step 8: Zipalign + 签名 ----
|
|
echo "[8/8] Zipalign 并签名..."
|
|
# Zipalign
|
|
"$ZIPALIGN" -f 4 "$OUT/$APK_BASENAME-unsigned.apk" "$OUT/$APK_BASENAME-aligned.apk"
|
|
|
|
# 签名
|
|
"$APKSIGNER" sign \
|
|
--ks "$KEYSTORE" \
|
|
--ks-pass "pass:$STORE_PASS" \
|
|
--ks-key-alias "$KEY_ALIAS" \
|
|
--key-pass "pass:$KEY_PASS" \
|
|
--out "$OUT/$APK_BASENAME-signed.apk" \
|
|
"$OUT/$APK_BASENAME-aligned.apk"
|
|
|
|
# 验证签名
|
|
"$APKSIGNER" verify --verbose "$OUT/$APK_BASENAME-signed.apk" 2>&1
|
|
|
|
# ---- 完成 ----
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " ✅ 编译成功!"
|
|
echo "=========================================="
|
|
echo ""
|
|
ls -lh "$OUT/$APK_BASENAME-signed.apk"
|
|
echo ""
|
|
echo "输出文件: $OUT/$APK_BASENAME-signed.apk"
|
|
echo ""
|
|
echo "安装命令:"
|
|
echo " adb install -r $OUT/$APK_BASENAME-signed.apk"
|