11.22 脚本打包APP 排错指南

一 场景,博主摸鱼,termux打包html变成APP

APP链接termux服务器时,遇到了一点问题

二 人话,手机客户端APP连不上,手机termux服务器

因为一点白名单策略。cordova打包,这里分享一下经验。便于大家快速解决问题。

三,手机没有插入源码格式,还请见谅。

#!/usr/bin/env python3

-*- coding: utf-8 -*-

一体化 Cordova 构建工具(凉安V 定制版) - Python版

import os

import sys

import shutil

import random

import subprocess

import glob

from datetime import datetime

--- 全局配置 ---

使用 os.path.expanduser 正确处理家目录路径

OUT_DIR = "/storage/emulated/0/Download"

PROJ_DIR = os.path.join(os.path.expanduser("~"), "2026")

def run_command(command, check=True, capture_output=False):

"""运行外部命令的辅助函数"""

print(f"🔧 执行命令: {command}")

try:

使用 shell=True 是为了方便处理像 cordova, pkill 这样的复合命令

在此脚本中,命令来源是可信的,风险可控

result = subprocess.run(

command,

shell=True,

check=check,

capture_output=capture_output,

text=True

)

if capture_output:

return result.stdout.strip()

return result

except subprocess.CalledProcessError as e:

print(f"❌ 命令执行失败: {command}")

print(f" 错误信息: {e.stderr.strip() if e.stderr else '未知'}")

sys.exit(1)

except FileNotFoundError:

print(f"❌ 命令未找到: {command.split()[0]}")

sys.exit(1)

--- 任务一:打包网页为APK (已修复白名单问题) ---

def build_apk():

"""打包网页为APK"""

print("\n=== 打包模式 ===")

1. 获取用户输入 (模式、路径、版本号)

print("1) 打包单个 HTML 文件")

print("2) 打包整个目录(含 index.html)")

mode = input("请选择 (1/2): ")

if mode not in ("1", "2"):

print("❌ 无效选择")

return

src_path = input("请输入路径(文件或目录): ").strip()

if not os.path.exists(src_path):

print("❌ 路径不存在")

return

app_title = ask_app_name()

2. 检查并安装依赖

check_deps()

3. 创建并配置Cordova项目

if os.path.exists(PROJ_DIR):

print(f"🧹 清理旧项目目录: {PROJ_DIR}")

shutil.rmtree(PROJ_DIR)

Cordova 项目ID使用时间戳确保唯一性

app_id = f"com.example.auto.v{int(datetime.now().timestamp())}"

run_command(f"cordova create {PROJ_DIR} {app_id} '{app_title}'")

original_cwd = os.getcwd()

os.chdir(PROJ_DIR)

print(f"📍 切换到项目目录: {os.getcwd()}")

try:

4. 复制源文件到www目录

print("📋 复制源文件...")

www_dir = "www"

shutil.rmtree(www_dir, ignore_errors=True)

os.makedirs(www_dir)

if mode == "1":

shutil.copy2(src_path, os.path.join(www_dir, "index.html"))

else:

dirs_exist_ok=True 允许复制到已存在的目录

shutil.copytree(src_path, www_dir, dirs_exist_ok=True)

5. 添加Cordova插件和平台

print("🔌 添加 InAppBrowser 插件...")

run_command("cordova plugin add cordova-plugin-inappbrowser")

print("🤖 添加 Android 平台...")

run_command("cordova platform add android@12.0.1 --no-fetch")

【关键修复】直接修改Android项目文件,解决网络问题

print("🔒 配置网络安全策略(白名单)...")

1. 创建网络安全配置文件

config_dir = "platforms/android/app/src/main/res/xml"

os.makedirs(config_dir, exist_ok=True)

config_file_path = os.path.join(config_dir, "network_security_config.xml")

with open(config_file_path, 'w') as f:

f.write(

'<?xml version="1.0" encoding="utf-8"?>\n'

'<network-security-config>\n'

' <base-config cleartextTrafficPermitted="true" />\n'

'</network-security-config>\n'

)

print("✅ 网络安全配置文件已创建。")

2. 修改AndroidManifest.xml,添加两个关键属性

manifest_path = "platforms/android/app/src/main/AndroidManifest.xml"

with open(manifest_path, 'r') as f:

manifest_content = f.read()

if 'android:usesCleartextTraffic="true"' not in manifest_content:

manifest_content = manifest_content.replace(

'<application',

'<application android:usesCleartextTraffic="true"'

)

if 'android:networkSecurityConfig="@xml/network_security_config"' not in manifest_content:

manifest_content = manifest_content.replace(

'<application',

'<application android:networkSecurityConfig="@xml/network_security_config"'

)

with open(manifest_path, 'w') as f:

f.write(manifest_content)

print("✅ AndroidManifest.xml 已更新。")

【关键修复结束】

6. 配置Gradle以使用Termux的aapt2

print("⚙️ 配置 Gradle...")

gradle_props_path = os.path.join("platforms", "android", "gradle.properties")

aapt2_termux_path = "/data/data/com.termux/files/usr/bin/aapt2"

with open(gradle_props_path, "a") as f:

f.write(f"\nandroid.aapt2FromMavenOverride={aapt2_termux_path}\n")

f.write("android.enableAapt2Daemon=false\n")

7. 清理构建缓存和旧文件

print("🧹 清理构建缓存...")

gradle_cache = os.path.expanduser("~/.gradle/caches/transforms-3")

if os.path.exists(gradle_cache):

for item in glob.glob(os.path.join(gradle_cache, "*aapt2*")):

if os.path.isdir(item):

shutil.rmtree(item)

else:

os.remove(item)

shutil.rmtree("platforms/android/build", ignore_errors=True)

shutil.rmtree("platforms/android/app/build", ignore_errors=True)

shutil.rmtree("platforms/android/app/src/main/assets/www", ignore_errors=True)

shutil.rmtree(os.path.expanduser("~/.npm/_cacache"), ignore_errors=True)

shutil.rmtree(os.path.expanduser("~/.cordova/npm_cache"), ignore_errors=True)

确保目标assets目录存在

assets_www_dir = "platforms/android/app/src/main/assets/www"

os.makedirs(assets_www_dir, exist_ok=True)

shutil.copytree("www", assets_www_dir, dirs_exist_ok=True)

杀死可能残留的gradle进程

run_command("pkill -f gradle", check=False)

8. 执行Cordova构建

print("🏗️ 开始构建...")

run_command("cordova build android")

9. 复制最终APK到输出目录

print("📦 复制APK...")

os.makedirs(OUT_DIR, exist_ok=True)

apk_src_path = "platforms/android/app/build/outputs/apk/debug/app-debug.apk"

apk_dest_path = os.path.join(OUT_DIR, "凉安V1r.apk")

shutil.copy2(apk_src_path, apk_dest_path)

print(f"✅ 构建完成 → {apk_dest_path}")

finally:

确保无论如何都切换回原目录

os.chdir(original_cwd)

--- 任务二:复制最新APK ---

def copy_latest_apk():

"""复制最新APK"""

print("\n=== 复制最新 APK ===")

1. 检查项目目录是否存在

if not os.path.isdir(PROJ_DIR):

print("❌ 项目目录不存在")

return

original_cwd = os.getcwd()

os.chdir(PROJ_DIR)

print(f"📍 切换到项目目录: {os.getcwd()}")

try:

2. 查找项目中所有APK文件

apk_list = glob.glob("./*.apk", recursive=True)

if not apk_list:

print("❌ 未找到 APK")

return

3. 确定最新的APK文件

使用 max() 和 os.path.getmtime 找到最新修改的文件

latest_apk_path = max(apk_list, key=os.path.getmtime)

print(f"🔍 找到最新APK: {latest_apk_path}")

4. 生成新的随机文件名

new_name = rand_apk_name()

5. 复制并重命名APK到输出目录

os.makedirs(OUT_DIR, exist_ok=True)

dest_path = os.path.join(OUT_DIR, new_name)

shutil.copy2(latest_apk_path, dest_path)

print(f"✅ 已复制 → {dest_path}")

finally:

os.chdir(original_cwd)

--- 辅助函数 ---

def check_deps():

"""检查并安装必要的依赖"""

print("🔍 检查依赖...")

if not shutil.which("node"):

print("❌ 请先 pkg install nodejs")

sys.exit(1)

检查 aapt2 是否已安装

try:

run_command("pkg list-installed aapt2", capture_output=True)

except SystemExit:

print("📦 aapt2 未安装,正在安装...")

run_command("pkg install aapt2 -y")

if not shutil.which("cordova"):

print("📦 Cordova 未安装,正在全局安装...")

run_command("npm i -g cordova")

print("✅ 所有依赖检查通过。")

def ask_app_name():

"""询问版本号并生成应用名称"""

ver = input("请输入今天版本号(如 11.2a): ")

if not ver:

print("❌ 版本号不能为空")

sys.exit(1)

return f"凉安V{ver}"

def rand_apk_name():

"""生成带4位随机数的APK文件名"""

num = random.randint(0, 9999)

return f"凉安V{num:04d}.apk"

--- 主程序入口 ---

if name == "main":

1. 显示主菜单

print("=== Cordova 构建工具(凉安V 版)===")

print("1) 打包网页为 APK(已修复网络问题)")

print("2) 复制最新 APK")

2. 获取用户选择

choice = input("请输入选择 (1/2): ")

3. 根据选择调用对应函数

if choice == "1":

build_apk()

elif choice == "2":

copy_latest_apk()

else:

print("❌ 无效选择")

相关推荐
Neur0toxin1 小时前
入侵排查_2025/11/23
linux·windows·应急响应
万邦科技Lafite1 小时前
1688图片搜索商品API接口(item_search_img)使用指南
java·前端·数据库·开放api·电商开放平台
蒙小萌19931 小时前
Swift UIKit MVVM + RxSwift Development Rules
开发语言·prompt·swift·rxswift
Z***25802 小时前
Java爬虫框架
java·开发语言·爬虫
小小编程能手2 小时前
Linux文件编程
linux·运维·服务器
yinuo2 小时前
网页也懂黑夜与白天:系统主题自动切换
前端
木童6622 小时前
nginx安装步骤详解
linux·运维·服务器·网络·nginx
hateregiste2 小时前
C语言中如何优雅、准确、高效地设计和处理输入输出
c语言·开发语言·scanf·输入输出
SundayBear2 小时前
C语言复杂类型声明完全解析:从右左原则到工程实践
c语言·开发语言·数据结构·嵌入式