Compare commits

..
5 Commits
Author SHA1 Message Date
soft_windy 295558836b 调整文件目录 2026-07-07 14:37:04 +08:00
soft_windy 98a1e9d371 提交新代码 2026-06-11 03:57:37 +08:00
soft_windy 09d2244dbe 提交新代码 2026-06-11 03:45:09 +08:00
soft_windy 7340ecd283 Sync extraction fixes across installers 2026-05-20 18:01:34 +08:00
soft_windy d0a96ad578 Ignore packaged executables 2026-05-20 14:01:10 +08:00
79 changed files with 55368 additions and 5046 deletions
+48 -6
View File
@@ -1,24 +1,66 @@
*.pyc
# Python 缓存/编译产物
__pycache__/
**/__pycache__/
*.py[cod]
*.pyd
*.pyo
# 打包产物
# PyInstaller / Cython / 打包产物
build/
dist/
dist_cy/
dist_obf/
**/build/
**/dist/
**/dist_cy/
**/dist_obf/
*.spec
_core.*
launcher.py
setup_cython.py
# APK文件夹
apks/
# 打包好的安装器,不提交 exe 成品
*.exe
*.dll
*Installer*.exe
*安装*.exe
*刷入工具*.exe
*推送工具*.exe
*Pusher*.exe
UNIZ-*.exe
# 资源包
# 资源包/车机文件/临时拉取文件
package.bin
*package*.bin
*.apk
*.img
*.dat
*.zip
*.7z
*.rar
apks/
**/apks/
diag_apk/
pull_list.txt
unit.bat
# 本地工具链副本;只提交需要维护的脚本/说明,不提交二进制
tools/*.exe
tools/*.dll
tools/__pycache__/
Q05-Lidar/app.ico
Q05-Lidar/tools/*
!Q05-Lidar/tools/
!Q05-Lidar/tools/encrypt_q05_lidar_resource.py
# IDE
.vscode/
.idea/
# 临时文件
# 本地日志/临时文件
*.log
*.tmp
*.bak
*.old
*.swp
~$*
+2 -2
View File
@@ -3,13 +3,13 @@ from PyInstaller.utils.hooks import collect_all
datas = [('adb.exe', '.'), ('AdbWinApi.dll', '.'), ('AdbWinUsbApi.dll', '.'), ('7za.exe', '.')]
binaries = []
hiddenimports = ['queue', 'threading', 'tkinter', 'tkinter.simpledialog', 'zipfile', 'json', 'urllib', 'urllib.parse']
hiddenimports = ['queue', 'threading', 'tkinter', 'zipfile', 'json', 'urllib']
tmp_ret = collect_all('tkinter')
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
a = Analysis(
['S05_fixed.py'],
['app.py'],
pathex=[],
binaries=binaries,
datas=datas,
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

+18 -10
View File
@@ -1,7 +1,11 @@
@echo off
chcp 65001 >nul
set NAME=深蓝S05刷入工具_fixed
set SRC=S05_fixed.py
cd /d "%~dp0"
set "ROOT=%~dp0.."
set "TOOLS=%ROOT%\tools"
set "NAME=Qiyuan_07_Multi-lan-installer"
set "SRC=Qiyuan_A07_Multi-lan-installer.py"
set "ICON=%~dp0app.ico"
title %NAME% - Build
echo ============================================================
@@ -15,6 +19,11 @@ if errorlevel 1 (
pause
exit /b
)
if not exist "%ICON%" (
echo [ERROR] app.ico not found in A07 folder: %ICON%
pause
exit /b
)
for /f "delims=" %%i in ('where python') do set PY=%%i
echo Python: %PY%
@@ -55,14 +64,14 @@ copy "%PYD%" _core.pyd >nul
%PY% -c "open('launcher.py','w').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
echo [4/6] Copy resources...
copy ..\adb.exe . >nul
copy ..\AdbWinApi.dll . >nul
copy ..\AdbWinUsbApi.dll . >nul
copy ..\7za.exe . >nul
if exist "..\app.ico" copy "..\app.ico" . >nul
copy "%TOOLS%\adb.exe" . >nul
copy "%TOOLS%\AdbWinApi.dll" . >nul
copy "%TOOLS%\AdbWinUsbApi.dll" . >nul
copy "%TOOLS%\7za.exe" . >nul
copy "%ICON%" . >nul
echo [5/6] PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon=app.ico --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=tkinter.simpledialog --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --collect-all tkinter --uac-admin launcher.py
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon="%ICON%" --add-data "%ICON%;." --add-data "%TOOLS%\adb.exe;." --add-data "%TOOLS%\AdbWinApi.dll;." --add-data "%TOOLS%\AdbWinUsbApi.dll;." --add-data "%TOOLS%\7za.exe;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=tkinter.simpledialog --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
@@ -77,9 +86,8 @@ cd ..
goto :DONE
:NORMAL
cd /d "%~dp0"
echo [INFO] Normal PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon=app.ico --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=tkinter.simpledialog --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --collect-all tkinter --uac-admin %SRC%
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon="%ICON%" --add-data "%ICON%;." --add-data "%TOOLS%\adb.exe;." --add-data "%TOOLS%\AdbWinApi.dll;." --add-data "%TOOLS%\AdbWinUsbApi.dll;." --add-data "%TOOLS%\7za.exe;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=tkinter.simpledialog --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --collect-all tkinter --uac-admin %SRC%
:DONE
echo.
+243 -127
View File
@@ -2,167 +2,283 @@
## Overview
A Windows GUI tool suite (Python 3.6+ / tkinter) for flashing multi-language APKs onto Android-based vehicle infotainment systems. Built by 宜宾科宜科技有限公司.
Windows GUI tool suite (Python 3.6+ / tkinter) for flashing or pushing multi-language APKs to Android-based vehicle infotainment systems. Built by 宜宾科宜科技有限公司.
The suite contains **5 tool variants**, each targeting a different vehicle model. All share the same `ADKAPKGUI` class architecture with model-specific customizations. Authorization is VIN-based via a cloud API.
Most tools are single-file tkinter apps with the same rough architecture: GUI, VIN authorization, package extraction, ADB commands, logging, and worker threads live in one class. Preserve that style unless the user explicitly asks for a larger refactor.
| Tool file | Vehicle | Window title | Pack script |
|-----------|---------|-------------|-------------|
| `app.py` | 启源Q07 | 长安语言安装工具 | `pack_q07.bat` |
| `S05.py` | 深蓝S05 | 深蓝S05多语言安装 | `pack_s05.bat` |
| `X5plusTool.py` | X5plus | 适用于X5plus多语言安装 | `pack_x5plus.bat` |
| `app-install.py` | 长安逸动 (通用) | 长安语言刷入工具 | `pack_common.bat` |
| `app-yidong.py` | 长安逸动 | 长安逸动语言刷入工具 | `pack_yidong.bat` |
## Tool Variants
## Project structure
| Tool file | Vehicle / purpose | Window title | Pack script |
|-----------|-------------------|--------------|-------------|
| `Q07/Qiyuan_Q07-multi-lan-installer.py` | 启源Q07 | 适用于启源Q07多语言安装 | `Q07/pack_q07.bat` |
| `S05/S05.py` | 深蓝S05 original | 深蓝S05多语言安装 | `S05/pack_s05.bat` |
| `S05/S05_fixed.py` | 深蓝S05 fixed/experimental copy | 长安语言安装工具 | `S05/pack_s05_fixed.bat` |
| `X5plus/X5plusTool.py` | X5plus | 适用于X5plus多语言安装 | `X5plus/pack_x5plus.bat` |
| `CS55-Q05/CS55-Q05_Installer.py` | CS55Plus/Q05 通用 | CS55Plus/Q05 语言刷入工具 | `CS55-Q05/pack_cs55_q05.bat` |
| `CS75Pro/CS75Pro_Installer.py` | CS75Pro | CS75Pro 语言刷入工具 | `CS75Pro/pack_cs75pro.bat` |
| `Yidong/app-yidong.py` | 长安逸动 | 长安逸动语言刷入工具 | `Yidong/pack_yidong.bat` |
| `UNIZ/UNIZ.py` | UNI-Z file pusher | UNI-Z语言文件推送工具 | `UNIZ/pack_uniz.bat` |
| `UNI-T/UNI-T-multi-lan-installer.py` | UNI-T | 适用于UNI-T多语言安装 | `UNI-T/pack_unit.bat` |
| `Mazda-EZ60/Mazda-EZ60_1.2.py` | Mazda-EZ60 OS 1.2 | Mazda-EZ60_OS-1.2适用 | `Mazda-EZ60/pack_mazda_ez60_1.2.bat` |
| `Mazda-EZ60/Mazda_EZ60-Language-Install_v1.0.py` | Mazda-EZ60 OS 1.0 | 马自达EZ60刷机工具_OS-1.0 | `Mazda-EZ60/pack_mazda_ez60_1.0.bat` |
| `Q05-Lidar/Q05-Lidar_Installer.py` | Q05_Lidar permission/bootstrap + language installer | Q05_Lidar | `Q05-Lidar/pack_q05_lidar.bat` |
## Project Structure
```
├── app.py # 启源Q07 tool
├── S05.py # 深蓝S05 tool
├── X5plusTool.py # X5plus tool
├── app-install.py # 逸动通用 tool
├── app-yidong.py # 逸动 tool
├── pack_q07.bat # Q07 pack script
├── pack_s05.bat # S05 pack script
├── pack_x5plus.bat # X5plus pack script
├── pack_common.bat # 逸动通用 pack script
├── pack_yidong.bat # 逸动 pack script
├── test_extract.py # Standalone test for package.bin extraction
├── app.ico # Application icon
├── package.bin # Encrypted ZIP (not in repo)
── adb.exe # Bundled ADB
├── AdbWinApi.dll # ADB dependency
├── AdbWinUsbApi.dll # ADB dependency
└── .vscode/
── settings.json
├── Q07/ # Q07 script, pack scripts, ignored build outputs
├── S05/ # S05 original and fixed copy
├── X5plus/ # X5plus tool
├── CS55-Q05/ # CS55Plus/Q05 common installer and icon
├── CS75Pro/ # CS75Pro installer copied from CS55-Q05 flow
├── Yidong/ # Yidong-specific tool
├── UNIZ/ # UNI-Z file pusher
├── UNI-T/ # UNI-T installer cloned from Q07 flow
├── Mazda-EZ60/ # Mazda-EZ60 tool
├── A07/ # Qiyuan A07 tool
├── Q05-Lidar/ # Q05_Lidar tool plus resource.dat/tools
├── app.ico
├── package.bin # encrypted package, not committed; shared from root
── tools/ # shared adb/fastboot/7za dependencies for pack scripts
├── adb.exe
├── AdbWinApi.dll
├── AdbWinUsbApi.dll
── fastboot.exe
└── 7za.exe # 7-Zip Extra 26.01, bundled by pack scripts
```
## Architecture
## Architecture Notes
### Single-file design
- Most tools use class `ADKAPKGUI`; `UNIZ/UNIZ.py` uses `UNIZLanguageGUI`.
- Worker actions run in `threading.Thread(..., daemon=True)`.
- Tkinter calls from workers must go through `run_on_ui_thread(...)`.
- Prefer `self.root.after(0, lambda: func(*args, **kwargs))` in `run_on_ui_thread`; direct `after(0, func, *args, **kwargs)` breaks when kwargs such as `text=` or `fg=` are passed.
- Background `messagebox.*` calls should be scheduled with `run_on_ui_thread`.
- Keep files UTF-8 with `# -*- coding: utf-8 -*-`.
Each tool is a single Python file under the `ADKAPKGUI` class. No MVC separation — the class handles GUI, business logic, ADB operations, network calls, and file extraction.
## ADB And Auth
### Threading model
- `run_adb_command(command)` handles normal ADB commands such as `adb devices`, `adb push`, and non-shell install calls.
- `run_adb_shell(shell_command)` exists in the 逸动-family tools and Mazda copy; it shells into the device and automatically sends password `adb36987`.
- All `adb shell` operations in `CS55-Q05/CS55-Q05_Installer.py`, `CS75Pro/CS75Pro_Installer.py`, `Yidong/app-yidong.py`, and `Mazda-EZ60/Mazda-EZ60_1.2.py` should go through `run_adb_shell()`.
- `UNIZ/UNIZ.py` must not use `adb shell`; it only checks devices and pushes APKs to `/storage/emulated/0/Download/`.
- Standard auth flow uses:
- `auth-check?vin=...` for authorization.
- `package-key?vin=...` for `package.bin` extraction password.
- VIN keys:
- Q07/S05/X5plus: `ca_vin_info` or `VIN`.
- UNI-T: try `persist.vendor.car.VIN`, then `settings get global VIN`, then legacy system VIN keys.
- 逸动/Mazda: `settings get system ca.car.vin` via auto-password shell.
- UNI-Z: user manually enters VIN.
- **Main thread**: tkinter event loop (`root.mainloop()`)
- **Background threads**: All user-triggered operations spawn `threading.Thread(target=..., daemon=True)`
- **Thread-safety**: UI mutations via `self.run_on_ui_thread(func, ...)``self.root.after(0, func, ...)`. Internal `_impl` methods are the actual tkinter-touching implementations.
## Package Extraction
### ADB operations
- `package.bin`-style encrypted resources are extracted under `%LOCALAPPDATA%\.cache\system\.android\...`.
- Current cache directories:
- `Q07/Qiyuan_Q07-multi-lan-installer.py` -> `apps_cache_Q07`
- `S05/S05.py` / `S05/S05_fixed.py` -> `apps_cache_S05`
- `X5plus/X5plusTool.py` -> `apps_cache_X5plus`
- `CS55-Q05/CS55-Q05_Installer.py` -> `apps_cache_common`
- `CS75Pro/CS75Pro_Installer.py` -> `apps_cache_CS75Pro`
- `Yidong/app-yidong.py` -> `apps_cache_yidong`
- `UNIZ/UNIZ.py` -> `apps_cache_UNIZ`
- `UNI-T/UNI-T-multi-lan-installer.py` -> `apps_cache_UNI_T`
- `Mazda-EZ60/Mazda-EZ60_1.2.py` -> `apps_cache_Mazda_EZ60`
- Shared binaries are managed under root `tools/`: `adb.exe`, `AdbWinApi.dll`, `AdbWinUsbApi.dll`, `fastboot.exe`, and `7za.exe`. Vehicle pack scripts in subfolders should copy from `%ROOT%\tools`, not from each vehicle folder.
- For progress display, detect support for `-bsp1` by checking for `-bs{o|e|p}` in 7za help output.
- If `Incorrect command line` appears, retry with the basic compatible command: `x PACKAGE -pPASSWORD -oDIR -y`.
- Decode 7za output with GBK first, then UTF-8 fallback.
- 7za progress must parse streamed output cumulatively. Do not read one byte and regex that single byte; percentages such as `42%` span multiple bytes and will otherwise jump from 0 to 100.
- User-facing resource extraction text should say `资源准备中` / `Preparing resources`, not `资源解压` / `Extracting package`, unless the UI is an explicit debug test.
- Cache cleanup should be best effort in three places when feasible: before a new extraction, during normal window close, and via `atexit` for ordinary process exit. A forced process kill cannot be guaranteed, so also clear stale caches at next extraction/startup.
- `run_adb_command(command)` — standard ADB commands; auto-substitutes `adb` with bundled `adb.exe` path when frozen
- `run_adb_shell(shell_command)` — only in app-install.py / app-yidong.py; shells into device with auto-password `adb36987`
## Shared UX And Safety Rules
ADB path is portable: `self.adb` resolves to `sys._MEIPASS/adb.exe` when frozen (PyInstaller bundle), or `'adb'` in development.
- Hosts update logic should replace conflicting entries for the managed domain. If the hosts file already contains the target domain with a different IP, delete that line and write the expected `IP domain` entry instead of appending duplicates.
- VIN authorization logs should be explicit for operator-facing flows: print the current VIN, print `data.vehicleName` when `auth-check` returns it, print authorization success, and print a clear unauthorized/failure log when denied.
- `package-key` requests should use the vehicle name returned by `auth-check` (`data.vehicleName`) whenever available. Do not hardcode a model name if the authorization API already returned the exact vehicle name for the VIN.
- Normal users should not see low-level sensitive process details such as `fastboot`, `init_boot`, boot keys, or image names during permission/bootstrap flows. Use black-box text such as `正在获取权限中`, `获取成功`, and `获取失败`; leave command details for debug mode only.
- Process logs should stay minimal in normal mode. Detailed ADB/7za/API command logs belong behind debug mode.
- All Tkinter UI updates and `messagebox.*` calls from workers must go through `run_on_ui_thread(...)`.
### Authentication flow
## Model-Specific Behavior
1. ADB detects device → reads VIN (`ca_vin_info` or `VIN`; 逸动 uses `ca.car.vin`)
2. VIN sent to `https://api.changan.softwindy.cn/api/authorizations/auth-check?vin=...`
3. Package password from `https://api.changan.softwindy.cn/api/authorizations/package-key?vin=...`
4. Password used to decrypt `package.bin`
### Q07
### Package extraction
- Main script is `Q07/Qiyuan_Q07-multi-lan-installer.py`; keep `Q07/app.py` retired unless explicitly asked to restore the old name.
- Q07 release resource package is `Q07_package.bin`, not shared root `package.bin`. The tool may keep a compatibility fallback for old local `package.bin`, but user-facing errors/logs should name `Q07_package.bin`.
- Q07 cache directory is `%LOCALAPPDATA%\.cache\system\.android\apps_cache_Q07`. Clean it before extraction, on normal window close, and through `atexit`.
- Q07 `package-key` requests must include both `vin` and `vehicleName`; `vehicleName` comes from `auth-check` (`data.vehicleName`) and should be cached when available.
- Q07 `安装App` must also verify the current VIN is authorized before installing selected APK files. Debug mode may skip this check; normal mode must not.
- Q07 debug mode uses `Ctrl+Shift+D` and verifies the password through `POST /api/authorizations/verify-debug-mode-password`; do not restore hardcoded local debug passwords.
- Q07 debug mode exposes `解压测试` / `Ctrl+Shift+E`; it fetches `package-key` and extracts `Q07_package.bin`. The success log should only say `资源准备完成` / `Resources ready`, not app or priv-app counts.
- Q07 normal logs should keep the resource structure black-box: do not show app/priv-app counts or the current APK name during `刷入语言包`. `安装App` may show the selected APK filename currently being installed.
- Q07 UI has only language switching. Do not reintroduce dark/light theme switching or company/about subtitle text.
- Q07 window/taskbar icon should use `Q07/app.ico` at runtime: call `iconbitmap`, set a Windows AppUserModelID before creating `Tk()`, and set big/small Win32 window icons when possible. The pack scripts must include `--icon="%ICON%"` and `--add-data "%ICON%;."`.
- Q07 pack scripts (`Q07/pack_q07.bat` and `Q07/pack.bat`) are Cython-only. If Cython fails or no `_core*.pyd` is generated, stop with an error; do not fallback to normal PyInstaller.
- Q07 pack scripts use ASCII output name `Qiyuan_Q07-multi-lan-installer`, compile `Qiyuan_Q07-multi-lan-installer.py` into `_core.pyd`, use a tiny launcher, and bundle `adb.exe`, `AdbWinApi.dll`, `AdbWinUsbApi.dll`, `7za.exe`, and `Q07/app.ico`.
- `package.bin` is a password-protected ZIP (AES via pyzipper, fallback to zipfile)
- Extracted to `%LOCALAPPDATA%\.cache\system\.android\apps_cache_{variant}` (hidden via `attrib +h`)
- Each tool has its own cache folder to avoid conflicts:
- app.py → `apps_cache_Q07`
- S05.py → `apps_cache_S05`
- X5plusTool.py → `apps_cache_X5plus`
- app-install.py → `apps_cache_common`
- app-yidong.py → `apps_cache_common` (default)
- Extracted APKs in `app/` pushed to `/system/app/`, `priv-app/` to `/system/priv-app/`
### S05
### Device status monitoring
- Keep `S05/S05.py` as original unless explicitly asked.
- Use `S05/S05_fixed.py` for experimental/fixed S05 changes.
- Do not add `chmod`, `chown`, or `restorecon` to the S05 system-app push path unless explicitly requested; the target system inherits permissions.
- `S05/S05_fixed.py` includes debug extract test `Ctrl+Shift+E` and 7za progress support.
Background daemon thread runs `adb devices` every 5 seconds to detect connect/disconnect events.
### UNI-Z
## GUI layout (650x640 dark theme for most; 650x550 for 逸动)
- Endpoint for visible passwords: `/api/authorizations/get-uni-z-pwd`.
- Display `factoryPwd` as factory mode password and `password` as debug password.
- If `authorized == false` or `password` is empty, show unauthorized state and do not proceed.
- `password` from `get-uni-z-pwd` is not the package extraction password.
- Before push, call `/api/authorizations/package-key?vin=...` to get the real `package.bin` password.
- Push only to `/storage/emulated/0/Download/`; no `adb shell`.
- Language selection: RU/FR/ES/EN. Only the selected language Settings APK is pushed; other language Settings APKs are skipped silently.
- Hidden debug mode: `Ctrl+Shift+D`, password `zxch5200`, logs full ADB/7za/API details.
| Section | Contents |
|---------|----------|
| Title bar | Vehicle model + company subtitle |
| Password query | Hidden VIN→password lookup (S05, app-install only) |
| Button row 1 | 获取权限 (Q07/S05), 刷入语言包, 安装App, 语言设置 |
| Button row 2 | 时区设置, 安卓设置, 重启设备, 禁用升级 |
| Status bar | Connection dot, VIN, Auth status, Refresh button |
| Tips | Usage warnings |
| Progress | Extraction + push progress (hidden by default) |
| Log area | ScrolledText with tags (INFO/SUCCESS/ERROR/WARNING/CMD), 清空日志 button in title bar |
### UNI-T
## Key features
- Main script is `UNI-T/UNI-T-multi-lan-installer.py`; it is cloned from the Q07 installer flow and preserves Q07-style VIN authorization, package extraction, system app push/install logic, language settings, debug password verification, and Cython-only packaging.
- UNI-T VIN should be read with fallbacks: `adb shell getprop persist.vendor.car.VIN`, then `settings get global VIN`, then legacy `settings get system VIN` / `settings get system ca_vin_info`. On the connected S202_MCA device, the live VIN is currently in `settings global VIN`.
- UNI-T `获取权限` must run `adb shell setenforce 0` before `adb root` and `adb remount`; without this pre-step, `adb root` may not open on this vehicle.
- UNI-T release resource package is `UNI-T_package.bin`, with legacy `package.bin` fallback only for local compatibility. User-facing errors/logs should name `UNI-T_package.bin`.
- UNI-T cache directory is `%LOCALAPPDATA%\.cache\system\.android\apps_cache_UNI_T`. Clean it before extraction, on normal window close, and through `atexit`.
- Before UNI-T `刷入语言包` pushes files, run `pm disable-user --user 10` for: `com.wt.roadbook`, `com.thunder.carplay`, `com.tencent.wecarmas`, `com.tencent.qqlive.audiobox`, `com.incall.apps.softmanager`, `com.changan.appmarket`, and `com.bytedance.byteautoservice`.
- UNI-T package root may contain `CarSystemUI.apk`; during `刷入语言包`, push it separately and copy it with `cp -f` to `/system/system_ext/priv-app/CarSystemUI/CarSystemUI.apk`.
- UNI-T `package-key` requests must include both `vin` and `vehicleName`; `vehicleName` comes from `auth-check` (`data.vehicleName`) and should be cached when available.
- `UNI-T/pack_unit.bat` is Cython-only. If Cython fails or no `_core*.pyd` is generated, stop the build; do not fallback to normal PyInstaller.
### Install App (unified single/batch)
"安装App" button uses `filedialog.askopenfilenames` for multi-file selection, replacing old separate "单个安装" and "批量安装" buttons. Select 1 or more APKs and installs all in one pass (`adb install -r`).
### CS55-Q05
### Debug mode (hidden)
Press `Ctrl+Shift+D` → password `zxch5200` to enter debug mode:
- Bypasses device connection and authorization checks (UI shows "已连接" / "已授权")
- Logs all raw ADB commands and output to the log panel
- Exiting debug mode auto-refreshes real device state
- CS55Plus/Q05 common installer lives in `CS55-Q05/CS55-Q05_Installer.py`, with icon `CS55-Q05/cs55-q05.ico` and pack script `CS55-Q05/pack_cs55_q05.bat`.
- `pack_cs55_q05.bat` is Cython-only. If Cython fails or no `_core*.pyd` is generated, stop the build; do not fall back to normal PyInstaller.
- `刷入语言包` must verify VIN authorization before resource flashing. After authorization passes and before APK flashing, run both `pm disable-user <package>` and `pm uninstall -k --user 0 <package>` through `run_adb_shell()` for `com.wtcl.electronicdirections`, `com.tinnove.netease.music`, and `com.changan.appmarket`.
- All CS55/Q05 language package and manual APK installs should use `pm install -d -f -r <apk>` through `run_adb_shell()` so older/different app versions can install reliably.
- After CS55/Q05 language flashing or APK installation, do not reset `setprop vecentek.model` back to `0`; keep it at `1` so users can continue installing APKs manually.
- Normal `刷入语言包` logs should not reveal APK names; show generic current/total progress only. `安装App` may show each APK result and current APK name.
### Language quick-set
Popup with 8 one-click locale switches (zh-CN, en-US, ru-RU, fr-FR, es-ES, pt-BR, it-IT, ar-SA). Also links to native Android language settings. Changes take effect after reboot.
### CS75Pro
### Model-specific behaviors
- CS75Pro installer lives in `CS75Pro/CS75Pro_Installer.py`, copied from the CS55-Q05 flow, with icon `CS75Pro/cs75pro.ico` and pack script `CS75Pro/pack_cs75pro.bat`.
- Keep the CS75Pro flashing flow aligned with CS55-Q05 unless explicitly requested.
- CS75Pro cache directory is `%LOCALAPPDATA%\.cache\system\.android\apps_cache_CS75Pro`.
- CS75Pro `package-key` requests must include both `vin` and `vehicleName`, but `vehicleName` is intentionally hardcoded to `CS75Pro`. This is an explicit exception to the general auth-returned `vehicleName` rule; do not replace it with `auth-check` `data.vehicleName` in future edits.
- Before CS75Pro `刷入语言包`, run `pm disable-user <package>` first and then `pm uninstall -k --user 0 <package>` through `run_adb_shell()` for `com.wtcl.electronicdirections`, `com.tinnove.netease.music`, `com.incall.apps.softmanager`, and `com.tencent.qqlive.audiobox`.
- CS75Pro language package installs should use `pm install -d -f -r <apk>` through `run_adb_shell()`.
| Feature | Q07 (app.py) | S05 (S05.py) | X5plus (X5plusTool.py) | 逸动 (app-install/yidong) |
|---------|-------------|-------------|------------------------|---------------------------|
| Root perm | Y | Y | N (no btn_root) | N |
| priv-app | Y | Y | Y | N (app only) |
| ADB shell | Standard | Standard | Standard | Auto-password `adb36987` |
| VIN key | ca_vin_info/VIN | ca_vin_info/VIN | ca_vin_info/VIN | ca.car.vin |
| Old app cleanup | N | N | Y (5 packages) | N |
| Font push | N | N | Y (FZLTHPro) | N |
| Overlay enable | N | N | N | N (removed) |
| Password query | N | Y | N | Y |
| Factory hints | N | Y | Y (dynamic pwd) | Y |
### Mazda-EZ60
## Build process
- Based on `CS55-Q05/CS55-Q05_Installer.py` / 逸动 flow.
- Uses auto-password shell (`adb36987`) for VIN reads, `pm install`, overlay enable, disable commands, settings, and reboot.
- Installs APKs from extracted `apps` via push to `/data/local/tmp` then `pm install -r -d`.
- `Mazda-EZ60/Mazda-EZ60_1.2.py` should show 7za extraction progress with stream parsing.
- Mazda 1.2 resource package is `package_voice-assistant.bin`, not the old `package.bin`; `package-key` still supplies the extraction password.
- Mazda 1.2 package cache is `%LOCALAPPDATA%\.cache\system\.android\apps_cache_Mazda_EZ60`; clean it on startup, before extraction, on normal window close, and through `atexit`.
- Mazda `package-key` requests must include both `vin` and `vehicleName`; cache `data.vehicleName` from `auth-check`, and query `auth-check` before `package-key` if it is missing.
- Mazda 1.2 has a first-row `语音助理补丁` button that installs Magisk modules from the same extracted package. The package should contain `enable_install.zip` and `MazdaEZ60VoiceEnglish-1.2-Aemeth.zip` beside `apps/` (the tool also tolerates them inside `apps/`), and each zip must contain a valid `module.prop`.
- Mazda 1.2 `获取权限` uses a separate `boot-challenge` -> `boot-key` flow and must only use `data.sessionKey` / BOOT_KEY to decrypt `EZ60_resource.dat`; do not reuse `package-key` as the init_boot resource key.
- Mazda 1.2 `EZ60_resource.dat` is an AES-256-GCM init_boot resource with `EZ60R2` header / `ez60-resource-v2` format and default AAD `Mazda-EZ60 init_boot resource v1`. Generate it with `tools/encrypt_q05_lidar_resource.py --vehicle ez60 -o EZ60_resource.dat ...` using the EZ60 patched `init_boot.img`.
- Mazda 1.2 `EZ60_resource.dat` is optional at build time: `pack_mazda_ez60_1.2.bat` should embed it into the exe only when the file exists, and should not fail the build when it is absent. The permission feature still needs it at runtime to complete init_boot flashing.
- Mazda 1.2 `获取权限` follows the Q05_Lidar bootstrap shape: extract `runtime.dat` to `base.apk` using the package-key password when needed, run `setprop vecentek.model 1` through `run_adb_shell()` so the `adb36987` auto-password is sent, push/install `base.apk`, then fetch the boot key, reboot to fastboot through `run_adb_shell('reboot fastboot')`, wait for a real `<serial> fastboot` row, flash `init_boot`, immediately reboot, clear the temporary img, and keep normal logs black-box (`正在获取权限中` / `获取成功` / `获取失败`).
- Mazda 1.2 `runtime.dat` is copied next to the release exe by `pack_mazda_ez60_1.2.bat`, and its temporary cache is `%LOCALAPPDATA%\.cache\system\.android\apps_cache_Mazda_EZ60_runtime`.
- Mazda 1.2 detects the bootloader driver environment like Q05_Lidar. If missing, prompt once and install automatically; keep a manual `安装驱动` button in the status bar. Bundle `tools/usb_driver/` into the onefile exe via PyInstaller `--add-data`, resolving it from `_MEIPASS` at runtime.
- After Mazda 1.2 voice patch root authorization succeeds, clean the Magisk manager/stub launcher entry with the tested `pm uninstall -k com.topjohnwu.magisk` path first, then optional per-user uninstall/disable and manager/stub apk cache cleanup. Because the icon can reappear after reboot, also install a tiny Magisk module under `/data/adb/modules/ez60_magisk_manager_cleanup` whose `service.sh` repeats the same manager/stub cleanup after boot. Do not remove `/data/adb/modules` or the voice modules.
- `Mazda-EZ60/Mazda_EZ60-Language-Install_v1.0.py` is the exception: its `package-key` `vehicleName` is fixed to `EZ60_1.0`. Do not replace it with the authorization-returned vehicle name.
- Mazda hosts setup should keep exactly one target mapping for `spm.auto-pai.com`: replace mismatched IPs with `103.236.55.140 spm.auto-pai.com` instead of appending a conflicting duplicate. If hosts setup fails, tell the user `环境配置失败`.
- Mazda UI should not show the company/about subtitle.
- Mazda language switching should cover all operator-facing buttons, labels, dialogs, logs, progress text, hotspot status, password query UI, and quick-language popup text. The right-side usage tips should render from translated `hint_lines` with wrapping so English text does not overlap or overflow.
- Mazda normal logs/prompts should keep only key operator-facing outcomes and fuzzy resource/environment errors. Do not show package names, language package APK names, raw commands, paths, or command output during `刷入语言包`; manual `安装App` may show selected APK filenames. VIN and `vehicleName` are not sensitive and may remain visible.
- Mazda debug mode uses `Ctrl+Shift+D` and verifies the password through `POST /api/authorizations/verify-debug-mode-password`; detailed ADB/7za/API output belongs in debug mode only.
- Mazda pack scripts `pack_mazda_ez60_1.0.bat` and `pack_mazda_ez60_1.2.bat` are Cython-only. If dependencies, Cython compilation, PYD generation, resource copy, PyInstaller, or final exe output fail, stop immediately with an `[ERROR]` reason; do not fall back to normal PyInstaller.
- Regardless of APK install failures, run post-install configuration after the install loop.
- Post-install overlays to enable:
- `com.tinnove.launcher.overlay`
- `com.tinnove.scenemode.overlay`
- `com.incall.dvr.overlay`
- Post-install packages to disable:
- `com.carinno.p1`
- `com.wtcl.electronicdirections`
- `com.ximalaya.ting.android.car`
- `com.tinnove.netease.music`
- `com.migu.miguplay.car`
- `cn.cmvideo.car.play`
- `com.tinnove.carshow`
- `com.tinnove.changba`
- `com.qiyi.video.iv`
- User cancelled the `Ctrl+Shift+E` direct extract test request for Mazda; do not add it unless asked again.
Each `pack_*.bat` follows the same pipeline:
1. Install deps: `pyinstaller`, `cython`, `pyzipper`
2. Clean old build dirs
3. Cython compile: `{source}.py``_core.pyd`
4. Copy resources: `adb.exe`, DLLs, `app.ico`
5. PyInstaller: single `.exe` with `--uac-admin`, bundling `_core.pyd` + ADB + DLLs
6. Fallback to normal PyInstaller if Cython fails
### Q05_Lidar
Output exe is self-contained — bundles `adb.exe` and DLLs via `sys._MEIPASS`, no external ADB needed.
- This is the Q05_Lidar-specific tool and must not be confused with any ordinary Q05 variant or package.
- Based on the shared installer visual style, but its resource structure and flashing flow are Q05_Lidar-specific.
- The first-row `获取权限` button installs `runtime.dat` -> `base.apk`, reboots to fastboot, waits for a real `fastboot devices` row like `<serial> fastboot` with a non-aggressive interval, then fetches a boot key through `POST /api/authorizations/boot-challenge` then `POST /api/authorizations/boot-key`, decrypts embedded `resource.dat`, flashes `init_boot`, immediately reboots, and deletes the temporary img. Keep the decrypted img lifetime as short as possible.
- `resource.dat` is AES-GCM encrypted and must match the server `BOOT_KEY`; the tool only accepts `data.sessionKey` from `boot-key`.
- Device fingerprint data sent to the server includes ADB serial, `ro.serialno`, `ro.boot.serialno`, manufacturer, model, device, build fingerprint, and VIN.
- `刷入语言包` installs Magisk modules, not APKs. It opens `com.topjohnwu.magisk`, warns the user to grant Shell/root permission, verifies `/debug_ramdisk/su -c "id"` returns `uid=0`, silently uninstalls `com.topjohnwu.magisk` for user 0, extracts `Q05_Lidar-package.bin`, reads each module zip's root `module.prop` on the PC to get `id=`, pushes each zip to `/data/local/tmp/q05_lidar_modules/<MODID>.zip`, then root-unzips it into `/data/adb/modules/<MODID>`.
- If Magisk shows its first-run environment repair/additional setup prompt, do not automate UI clicking in the tool; the operator should confirm it manually and reboot once before retrying.
- Before installing Q05_Lidar language resources, disable OTA with `pm disable-user com.incall.apps.softmanager`, then for `com.carcontrolhome.app`, `com.tinnove.netease.music`, and `com.wtcl.electronicdirections` run both `pm disable-user <package>` and `pm uninstall --user 0 <package>`. These commands must go through `run_adb_shell()`.
- `Q05_Lidar-package.bin` should unpack to module zip files, preferably under `modules/`, for example `modules/Qiyuan_Q05-multi_lan.zip` and `modules/disable_wireless_adb_vecentek.zip`. Each module zip must contain `module.prop` at zip root, plus scripts and `system/` as needed. Do not wrap `module.prop` inside an extra outer folder.
- Q05_Lidar package cache is `%LOCALAPPDATA%\.cache\system\.android\apps_cache_Q05_Lidar`; the tool cleans it on startup/extraction and on normal/atexit shutdown.
- Q05_Lidar `runtime.dat` cache is `%LOCALAPPDATA%\.cache\system\.android\apps_cache_q05_lidar_runtime`; treat it as temporary and clean stale contents before extraction.
- `Q05_Lidar-package.bin` is an external release file next to the exe because it is large. `resource.dat` is embedded in the exe; `runtime.dat` should be copied next to the exe by the pack script.
- Q05_Lidar checks driver environment on startup. If the driver environment already exists, stay silent and do not log a success/info message for the operator.
- If the startup check finds the driver environment missing, show a single simple prompt such as `驱动缺失,即将自动安装驱动。`; after the user clicks confirm, start installation immediately. Do not show a second `是否继续` confirmation in that startup flow.
- User-facing driver logs/prompts should say only `驱动环境` / `Driver environment`; do not mention `USB/Fastboot` or `Android/Fastboot`.
- Manual `安装驱动` remains available in the status bar, but `检查` should appear before it visually because it is more directly related to device status/refresh actions.
- `usb_driver/` is bundled inside the Q05_Lidar onefile exe via PyInstaller `--add-data`, and runtime driver installation should resolve files from the extracted temporary resource directory (for frozen builds, `_MEIPASS`) instead of requiring a sidecar `usb_driver` folder next to the exe.
- `package-key` must include the `vehicleName` returned by `auth-check` for the VIN. The tool caches `data.vehicleName` from password query / authorization check and uses it for package-key; if missing, query `auth-check` first rather than falling back to a hardcoded Q05_Lidar value.
- All `adb shell` commands in Q05_Lidar, including Magisk launch and `/debug_ramdisk/su -c ...`, must go through `run_adb_shell()` so the tool silently sends `adb36987`.
- The `安装App` button remains the APK install path: file picker -> `adb push` -> `setprop vecentek.model 1` -> `pm install -r -d -f` -> cleanup. Do not replace it with the Magisk module flow.
- Temporary debug mode exists only for development and should be removed before release when requested. Press `Ctrl+Shift+D`; the password is verified through `POST /api/authorizations/verify-debug-mode-password`.
- In Q05_Lidar debug mode, hidden buttons appear for:
- `指纹测试`: collect and log device fingerprint fields plus local SHA256 summary.
- `解密测试`: if VIN/device is available, fetch boot key; otherwise prompt for a pasted `BOOT_KEY`/`sessionKey`, decrypt `resource.dat` locally to a temporary img, log size/SHA256, then delete it.
- `解压测试`: fetch `package-key`, extract `Q05_Lidar-package.bin`, and verify the main Magisk module plus `disable_wireless_adb_vecentek` module can be identified.
- Do not log the actual boot key/session key in debug mode.
## Key behaviors to preserve
### Yidong/app-yidong.py
1. **Thread safety**: Never call tkinter from background threads — always use `run_on_ui_thread`
2. **VIN-based auth**: Authorization required before push; flow must remain intact
3. **Silent extraction**: Auto-extract `package.bin` without user step
4. **ADB portability**: `self.adb` resolves to bundled exe path; all commands go through `run_adb_command`
5. **vecentek.model**: Set to 1 before install, 0 after
6. **Chinese encoding**: `# -*- coding: utf-8 -*-` throughout
7. **Debug mode**: `self.debug_mode` flag gates auth/connection bypass and verbose logging
8. **Separate cache dirs**: Each tool extracts to its own cache folder
- Uses `apps_cache_yidong`.
- Has 7za compatibility handling for progress switches and `Incorrect command line` fallback.
- `Yidong/pack_yidong.bat` output name is ASCII: `Changan-Yidong-Language-Installer.exe`, to avoid CMD codepage issues with Chinese `NAME`.
## Known issues
## Build Notes
- `test_extract.py` hardcodes password — should fetch from API
- `on_disable_upgrade` uses `findstr` (Windows-specific)
- Exception handling is minimal in many places (bare `except: pass`)
- 逸动 tools (app-install/yidong) use `subprocess.Popen` with stdin password injection — fragile
- Pack scripts install/use `pyinstaller`, `cython`, and usually `pyzipper`.
- Cython success requires Microsoft C++ Build Tools.
- Cython success signs in logs:
- `building '_core' extension`
- `_core.cpXXX-win_amd64.pyd`
- `PYD: _core...pyd`
- output under `dist_cy\dist\...exe`
- If logs show `[WARN] Cython failed, fallback` and `[INFO] Normal PyInstaller`, the exe still builds but is normal PyInstaller and easier to reverse.
- For security-sensitive tools like Q05_Lidar and Q07, do not keep a normal PyInstaller fallback. If Cython fails or no `_core*.pyd` is generated, stop the build and show an error.
- A Cython onefile PyInstaller build should use a tiny `launcher.py` that imports `main` from compiled `_core.pyd`, and the exe archive should contain `_core*.pyd`. Confirm with PyInstaller archive viewer when in doubt.
- `UNIZ/pack_uniz.bat` and Mazda-EZ60 pack scripts use ASCII output names to avoid CMD encoding problems.
- Generated `.exe`, `.spec`, `build/`, `dist/`, and `dist_cy/` are build artifacts and should not be committed unless explicitly requested.
## Current local state (2026-05-20)
## Key Behaviors To Preserve
- `S05.py` is kept as the original S05 tool entry. Do not fold the fixed-version changes back into it unless explicitly requested.
- `S05_fixed.py` is the active experimental/fixed S05 copy. It includes:
- `simpledialog` import fix for debug mode.
- Thread-safe message boxes from background threads via `run_on_ui_thread`.
- Quoted/portable ADB command path helper.
- `try/finally` recovery for `setprop vecentek.model 0` in install flows.
- `_refreshing` reset in `refresh_device_status()` via `finally`.
- URL-encoded VIN query parameters.
- `Ctrl+Shift+E` debug-only package extraction test that skips device/auth checks and asks for the package password.
- 7za progress support: detects `-bsp1` support and enables `-bsp1 -bso0 -bse1` only when supported, otherwise falls back to normal extraction.
- Root `7za.exe` has been replaced with 7-Zip Extra `26.01 (x64)` and is the file pack scripts will bundle.
- The unpacked 7-Zip Extra files/folders (`x64/`, `arm64/`, `Far/`, `7za.dll`, `7zxa.dll`, docs) are present locally, but existing pack scripts only bundle root `7za.exe`.
- `pack_s05_fixed.bat` was added to build `S05_fixed.py` separately as `深蓝S05刷入工具_fixed.exe`; it leaves `pack_s05.bat` unchanged.
- Do not add `chmod`, `chown`, or `restorecon` commands to the S05 system-app push path unless explicitly requested; the user confirmed the target system inherits permissions automatically.
1. Keep original tools untouched when a fixed or model-specific copy exists.
2. Preserve VIN-based authorization for normal flashing tools.
3. Fetch `package-key` from the server instead of hardcoding package passwords.
4. Keep all shell commands in 逸动/Mazda tools behind `run_adb_shell()`.
5. Keep UNI-Z shell-free.
6. Use `run_on_ui_thread()` for all tkinter UI updates from worker threads.
7. Keep shared Android/7za binaries under root `tools/` and have pack scripts copy from there.
## Current Local State (2026-05-28)
- `UNIZ/UNIZ.py` and `UNIZ/pack_uniz.bat` exist locally. Cython build has succeeded after installing Microsoft C++ Build Tools, producing `dist_cy\dist\UNIZ-Language-Pusher.exe`.
- `Mazda-EZ60/Mazda-EZ60_1.2.py` with `pack_mazda_ez60_1.2.bat`, and `Mazda-EZ60/Mazda_EZ60-Language-Install_v1.0.py` with `pack_mazda_ez60_1.0.bat`, exist locally. Mazda has 7za progress extraction, Cython-only packaging, and version-specific output names.
- `Yidong/app-yidong.py` has been updated for 7za progress compatibility and `Incorrect command line` fallback.
- `Yidong/pack_yidong.bat` has been updated with quoted paths, `cd /d "%~dp0"`, and ASCII output name.
- `.gitignore` has been expanded to ignore generated exe/spec artifacts.
- There may be untracked local build outputs and generated specs; inspect `git status --ignored` before committing.
## Known Issues
- Some older tools still have minimal exception handling and bare `except: pass`.
- `test_extract.py` hardcodes a password and should not be treated as production flow.
- `on_disable_upgrade` behavior is Windows/vehicle specific.
- Pure PyInstaller fallback is easy to reverse; prefer successful Cython builds for release.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+183 -113
View File
@@ -1,151 +1,221 @@
# 长安语言刷入工具 (Changan Language Flashing Tool)
# 长安语言刷入工具 (Changan Language Flashing Tool)
## Overview
A Windows GUI tool suite (Python 3.6+ / tkinter) for flashing multi-language APKs onto Android-based vehicle infotainment systems. Built by 宜宾科宜科技有限公司.
Windows GUI tool suite (Python 3.6+ / tkinter) for flashing or pushing multi-language APKs to Android-based vehicle infotainment systems. Built by 宜宾科宜科技有限公司.
The suite contains **5 tool variants**, each targeting a different vehicle model. All share the same `ADKAPKGUI` class architecture with model-specific customizations. Authorization is VIN-based via a cloud API.
Most tools are single-file tkinter apps with the same rough architecture: GUI, VIN authorization, package extraction, ADB commands, logging, and worker threads live in one class. Preserve that style unless the user explicitly asks for a larger refactor.
| Tool file | Vehicle | Window title | Pack script |
|-----------|---------|-------------|-------------|
| `app.py` | 启源Q07 | 长安语言安装工具 | `pack_q07.bat` |
| `S05.py` | 深蓝S05 | 深蓝S05多语言安装 | `pack_s05.bat` |
| `X5plusTool.py` | X5plus | 适用于X5plus多语言安装 | `pack_x5plus.bat` |
| `app-install.py` | 长安逸动 (通用) | 长安语言刷入工具 | `pack_common.bat` |
| `app-yidong.py` | 长安逸动 | 长安逸动语言刷入工具 | `pack_yidong.bat` |
## Tool Variants
## Project structure
| Tool file | Vehicle / purpose | Window title | Pack script |
|-----------|-------------------|--------------|-------------|
| `Q07/app.py` | 启源Q07 | 长安语言安装工具 | `Q07/pack_q07.bat` |
| `S05/S05.py` | 深蓝S05 original | 深蓝S05多语言安装 | `S05/pack_s05.bat` |
| `S05/S05_fixed.py` | 深蓝S05 fixed/experimental copy | 长安语言安装工具 | `S05/pack_s05_fixed.bat` |
| `X5plus/X5plusTool.py` | X5plus | 适用于X5plus多语言安装 | `X5plus/pack_x5plus.bat` |
| `CS55-Q05/CS55-Q05_Installer.py` | CS55Plus/Q05 通用 | CS55Plus/Q05 语言刷入工具 | `CS55-Q05/pack_cs55_q05.bat` |
| `Yidong/app-yidong.py` | 长安逸动 | 长安逸动语言刷入工具 | `Yidong/pack_yidong.bat` |
| `UNIZ/UNIZ.py` | UNI-Z file pusher | UNI-Z语言文件推送工具 | `UNIZ/pack_uniz.bat` |
| `Mazda-EZ60/Mazda-EZ60_1.2.py` | Mazda-EZ60 OS 1.2 | Mazda-EZ60_OS-1.2适用 | `Mazda-EZ60/pack_mazda_ez60_1.2.bat` |
| `Mazda-EZ60/Mazda_EZ60-Language-Install_v1.0.py` | Mazda-EZ60 OS 1.0 | 马自达EZ60刷机工具_OS-1.0 | `Mazda-EZ60/pack_mazda_ez60_1.0.bat` |
| `Q05-Lidar/Q05-Lidar_Installer.py` | Q05_Lidar permission/bootstrap + language installer | Q05_Lidar | `Q05-Lidar/pack_q05_lidar.bat` |
## Project Structure
```
├── app.py # 启源Q07 tool
├── S05.py # 深蓝S05 tool
├── X5plusTool.py # X5plus tool
├── app-install.py # 逸动通用 tool
├── app-yidong.py # 逸动 tool
├── pack_q07.bat # Q07 pack script
├── pack_s05.bat # S05 pack script
├── pack_x5plus.bat # X5plus pack script
├── pack_common.bat # 逸动通用 pack script
├── pack_yidong.bat # 逸动 pack script
├── test_extract.py # Standalone test for package.bin extraction
── app.ico # Application icon
├── package.bin # Encrypted ZIP (not in repo)
├── adb.exe # Bundled ADB
├── AdbWinApi.dll # ADB dependency
├── AdbWinUsbApi.dll # ADB dependency
└── .vscode/
└── settings.json
├── Q07/ # Q07 script, pack scripts, ignored build outputs
├── S05/ # S05 original and fixed copy
├── X5plus/ # X5plus tool
├── CS55-Q05/ # CS55Plus/Q05 common installer and icon
├── Yidong/ # Yidong-specific tool
├── UNIZ/ # UNI-Z file pusher
├── Mazda-EZ60/ # Mazda-EZ60 tool
├── A07/ # Qiyuan A07 tool
├── Q05-Lidar/ # Q05_Lidar tool plus resource.dat/tools
├── app.ico
├── package.bin # encrypted package, not committed; shared from root
── tools/ # shared adb/fastboot/7za dependencies for pack scripts
├── adb.exe
├── AdbWinApi.dll
├── AdbWinUsbApi.dll
├── fastboot.exe
└── 7za.exe # 7-Zip Extra 26.01, bundled by pack scripts
```
## Architecture
## Architecture Notes
### Single-file design
- Most tools use class `ADKAPKGUI`; `UNIZ/UNIZ.py` uses `UNIZLanguageGUI`.
- Worker actions run in `threading.Thread(..., daemon=True)`.
- Tkinter calls from workers must go through `run_on_ui_thread(...)`.
- Prefer `self.root.after(0, lambda: func(*args, **kwargs))` in `run_on_ui_thread`; direct `after(0, func, *args, **kwargs)` breaks when kwargs such as `text=` or `fg=` are passed.
- Background `messagebox.*` calls should be scheduled with `run_on_ui_thread`.
- Keep files UTF-8 with `# -*- coding: utf-8 -*-`.
Each tool is a single Python file under the `ADKAPKGUI` class. No MVC separation — the class handles GUI, business logic, ADB operations, network calls, and file extraction.
## ADB And Auth
### Threading model
- `run_adb_command(command)` handles normal ADB commands such as `adb devices`, `adb push`, and non-shell install calls.
- `run_adb_shell(shell_command)` exists in the 逸动-family tools and Mazda copy; it shells into the device and automatically sends password `adb36987`.
- All `adb shell` operations in `CS55-Q05/CS55-Q05_Installer.py`, `Yidong/app-yidong.py`, and `Mazda-EZ60/Mazda-EZ60_1.2.py` should go through `run_adb_shell()`.
- `UNIZ/UNIZ.py` must not use `adb shell`; it only checks devices and pushes APKs to `/storage/emulated/0/Download/`.
- Standard auth flow uses:
- `auth-check?vin=...` for authorization.
- `package-key?vin=...` for `package.bin` extraction password.
- VIN keys:
- Q07/S05/X5plus: `ca_vin_info` or `VIN`.
- 逸动/Mazda: `settings get system ca.car.vin` via auto-password shell.
- UNI-Z: user manually enters VIN.
- **Main thread**: tkinter event loop (`root.mainloop()`)
- **Background threads**: All user-triggered operations spawn `threading.Thread(target=..., daemon=True)`
- **Thread-safety**: UI mutations via `self.run_on_ui_thread(func, ...)``self.root.after(0, func, ...)`. Internal `_impl` methods are the actual tkinter-touching implementations.
## Package Extraction
### ADB operations
- `package.bin` is extracted under `%LOCALAPPDATA%\.cache\system\.android\...`.
- Current cache directories:
- `Q07/app.py` -> `apps_cache_Q07`
- `S05/S05.py` / `S05/S05_fixed.py` -> `apps_cache_S05`
- `X5plus/X5plusTool.py` -> `apps_cache_X5plus`
- `CS55-Q05/CS55-Q05_Installer.py` -> `apps_cache_common`
- `Yidong/app-yidong.py` -> `apps_cache_yidong`
- `UNIZ/UNIZ.py` -> `apps_cache_UNIZ`
- `Mazda-EZ60/Mazda-EZ60_1.2.py` -> `apps_cache_Mazda_EZ60`
- Shared binaries are managed under root `tools/`: `adb.exe`, `AdbWinApi.dll`, `AdbWinUsbApi.dll`, `fastboot.exe`, and `7za.exe`. Vehicle pack scripts in subfolders should copy from `%ROOT%\tools`, not from each vehicle folder.
- For progress display, detect support for `-bsp1` by checking for `-bs{o|e|p}` in 7za help output.
- If `Incorrect command line` appears, retry with the basic compatible command: `x package.bin -pPASSWORD -oDIR -y`.
- Decode 7za output with GBK first, then UTF-8 fallback.
- 7za progress must parse streamed output cumulatively. Do not read one byte and regex that single byte; percentages such as `42%` span multiple bytes and will otherwise jump from 0 to 100.
- User-facing resource extraction text should say `资源准备中` / `Preparing resources`, not `资源解压` / `Extracting package`, unless the UI is an explicit debug test.
- Cache cleanup should be best effort in three places when feasible: before a new extraction, during normal window close, and via `atexit` for ordinary process exit. A forced process kill cannot be guaranteed, so also clear stale caches at next extraction/startup.
- `run_adb_command(command)` — standard ADB commands; auto-substitutes `adb` with bundled `adb.exe` path when frozen
- `run_adb_shell(shell_command)` — only in app-install.py / app-yidong.py; shells into device with auto-password `adb36987`
## Shared UX And Safety Rules
ADB path is portable: `self.adb` resolves to `sys._MEIPASS/adb.exe` when frozen (PyInstaller bundle), or `'adb'` in development.
- Hosts update logic should replace conflicting entries for the managed domain. If the hosts file already contains the target domain with a different IP, delete that line and write the expected `IP domain` entry instead of appending duplicates.
- VIN authorization logs should be explicit for operator-facing flows: print the current VIN, print `data.vehicleName` when `auth-check` returns it, print authorization success, and print a clear unauthorized/failure log when denied.
- `package-key` requests should use the vehicle name returned by `auth-check` (`data.vehicleName`) whenever available. Do not hardcode a model name if the authorization API already returned the exact vehicle name for the VIN.
- Normal users should not see low-level sensitive process details such as `fastboot`, `init_boot`, boot keys, or image names during permission/bootstrap flows. Use black-box text such as `正在获取权限中`, `获取成功`, and `获取失败`; leave command details for debug mode only.
- Process logs should stay minimal in normal mode. Detailed ADB/7za/API command logs belong behind debug mode.
- All Tkinter UI updates and `messagebox.*` calls from workers must go through `run_on_ui_thread(...)`.
### Authentication flow
## Model-Specific Behavior
1. ADB detects device → reads VIN (`ca_vin_info` or `VIN`; 逸动 uses `ca.car.vin`)
2. VIN sent to `https://api.changan.softwindy.cn/api/authorizations/auth-check?vin=...`
3. Package password from `https://api.changan.softwindy.cn/api/authorizations/package-key?vin=...`
4. Password used to decrypt `package.bin`
### S05
### Package extraction
- Keep `S05/S05.py` as original unless explicitly asked.
- Use `S05/S05_fixed.py` for experimental/fixed S05 changes.
- Do not add `chmod`, `chown`, or `restorecon` to the S05 system-app push path unless explicitly requested; the target system inherits permissions.
- `S05/S05_fixed.py` includes debug extract test `Ctrl+Shift+E` and 7za progress support.
- `package.bin` is a password-protected ZIP (AES via pyzipper, fallback to zipfile)
- Extracted to `%LOCALAPPDATA%\.cache\system\.android\apps_cache_{variant}` (hidden via `attrib +h`)
- Each tool has its own cache folder to avoid conflicts:
- app.py → `apps_cache_Q07`
- S05.py → `apps_cache_S05`
- X5plusTool.py → `apps_cache_X5plus`
- app-install.py → `apps_cache_common`
- app-yidong.py → `apps_cache_common` (default)
- Extracted APKs in `app/` pushed to `/system/app/`, `priv-app/` to `/system/priv-app/`
### UNI-Z
### Device status monitoring
- Endpoint for visible passwords: `/api/authorizations/get-uni-z-pwd`.
- Display `factoryPwd` as factory mode password and `password` as debug password.
- If `authorized == false` or `password` is empty, show unauthorized state and do not proceed.
- `password` from `get-uni-z-pwd` is not the package extraction password.
- Before push, call `/api/authorizations/package-key?vin=...` to get the real `package.bin` password.
- Push only to `/storage/emulated/0/Download/`; no `adb shell`.
- Language selection: RU/FR/ES/EN. Only the selected language Settings APK is pushed; other language Settings APKs are skipped silently.
- Hidden debug mode: `Ctrl+Shift+D`, password `zxch5200`, logs full ADB/7za/API details.
Background daemon thread runs `adb devices` every 5 seconds to detect connect/disconnect events.
### CS55-Q05
## GUI layout (650x640 dark theme for most; 650x550 for 逸动)
- CS55Plus/Q05 common installer lives in `CS55-Q05/CS55-Q05_Installer.py`, with icon `CS55-Q05/cs55-q05.ico` and pack script `CS55-Q05/pack_cs55_q05.bat`.
- `pack_cs55_q05.bat` is Cython-only. If Cython fails or no `_core*.pyd` is generated, stop the build; do not fall back to normal PyInstaller.
- Normal `刷入语言包` logs should not reveal APK names; show generic current/total progress only. `安装App` may show each APK result and current APK name.
| Section | Contents |
|---------|----------|
| Title bar | Vehicle model + company subtitle |
| Password query | Hidden VIN→password lookup (S05, app-install only) |
| Button row 1 | 获取权限 (Q07/S05), 刷入语言包, 安装App, 语言设置 |
| Button row 2 | 时区设置, 安卓设置, 重启设备, 禁用升级 |
| Status bar | Connection dot, VIN, Auth status, Refresh button |
| Tips | Usage warnings |
| Progress | Extraction + push progress (hidden by default) |
| Log area | ScrolledText with tags (INFO/SUCCESS/ERROR/WARNING/CMD), 清空日志 button in title bar |
### Mazda-EZ60
## Key features
- Based on `CS55-Q05/CS55-Q05_Installer.py` / 逸动 flow.
- Uses auto-password shell (`adb36987`) for VIN reads, `pm install`, overlay enable, disable commands, settings, and reboot.
- Installs APKs from extracted `apps` via push to `/data/local/tmp` then `pm install -r -d`.
- `Mazda-EZ60/Mazda-EZ60_1.2.py` should show 7za extraction progress with stream parsing.
- Mazda 1.2 package cache is `%LOCALAPPDATA%\.cache\system\.android\apps_cache_Mazda_EZ60`; clean it on startup, before extraction, on normal window close, and through `atexit`.
- Mazda `package-key` requests must include both `vin` and `vehicleName`; cache `data.vehicleName` from `auth-check`, and query `auth-check` before `package-key` if it is missing.
- Mazda hosts setup should keep exactly one target mapping for `spm.auto-pai.com`: replace mismatched IPs with `103.236.55.140 spm.auto-pai.com` instead of appending a conflicting duplicate. If hosts setup fails, tell the user `环境配置失败`.
- Mazda UI should not show the company/about subtitle.
- Mazda language switching should cover all operator-facing buttons, labels, dialogs, logs, progress text, hotspot status, password query UI, and quick-language popup text. The right-side usage tips should render from translated `hint_lines` with wrapping so English text does not overlap or overflow.
- Mazda normal logs/prompts should keep only key operator-facing outcomes and fuzzy resource/environment errors. Do not show package names, language package APK names, raw commands, paths, or command output during `刷入语言包`; manual `安装App` may show selected APK filenames. VIN and `vehicleName` are not sensitive and may remain visible.
- Mazda debug mode uses `Ctrl+Shift+D` and verifies the password through `POST /api/authorizations/verify-debug-mode-password`; detailed ADB/7za/API output belongs in debug mode only.
- Mazda pack scripts `pack_mazda_ez60_1.0.bat` and `pack_mazda_ez60_1.2.bat` are Cython-only. If dependencies, Cython compilation, PYD generation, resource copy, PyInstaller, or final exe output fail, stop immediately with an `[ERROR]` reason; do not fall back to normal PyInstaller.
- Regardless of APK install failures, run post-install configuration after the install loop.
- Post-install overlays to enable:
- `com.tinnove.launcher.overlay`
- `com.tinnove.scenemode.overlay`
- `com.incall.dvr.overlay`
- Post-install packages to disable:
- `com.carinno.p1`
- `com.wtcl.electronicdirections`
- `com.ximalaya.ting.android.car`
- `com.tinnove.netease.music`
- `com.migu.miguplay.car`
- `cn.cmvideo.car.play`
- `com.tinnove.carshow`
- `com.tinnove.changba`
- `com.qiyi.video.iv`
- User cancelled the `Ctrl+Shift+E` direct extract test request for Mazda; do not add it unless asked again.
### Install App (unified single/batch)
"安装App" button uses `filedialog.askopenfilenames` for multi-file selection, replacing old separate "单个安装" and "批量安装" buttons. Select 1 or more APKs and installs all in one pass (`adb install -r`).
### Q05_Lidar
### Debug mode (hidden)
Press `Ctrl+Shift+D` → password `zxch5200` to enter debug mode:
- Bypasses device connection and authorization checks (UI shows "已连接" / "已授权")
- Logs all raw ADB commands and output to the log panel
- Exiting debug mode auto-refreshes real device state
- This is the Q05_Lidar-specific tool and must not be confused with any ordinary Q05 variant or package.
- Based on the shared installer visual style, but its resource structure and flashing flow are Q05_Lidar-specific.
- The first-row `获取权限` button installs `runtime.dat` -> `base.apk`, reboots to fastboot, waits for a real `fastboot devices` row like `<serial> fastboot` with a non-aggressive interval, then fetches a boot key through `POST /api/authorizations/boot-challenge` then `POST /api/authorizations/boot-key`, decrypts embedded `resource.dat`, flashes `init_boot`, immediately reboots, and deletes the temporary img. Keep the decrypted img lifetime as short as possible.
- `resource.dat` is AES-GCM encrypted and must match the server `BOOT_KEY`; the tool only accepts `data.sessionKey` from `boot-key`.
- Device fingerprint data sent to the server includes ADB serial, `ro.serialno`, `ro.boot.serialno`, manufacturer, model, device, build fingerprint, and VIN.
- `刷入语言包` installs Magisk modules, not APKs. It opens `com.topjohnwu.magisk`, warns the user to grant Shell/root permission, verifies `/debug_ramdisk/su -c "id"` returns `uid=0`, extracts `Q05_Lidar-package.bin`, then pushes module files to `/data/local/tmp/q05_lidar_modules/<MODID>/` and root-copies them into `/data/adb/modules/<MODID>`.
- `Q05_Lidar-package.bin` should unpack with module files at archive root: `module.prop`, scripts, `system/`, and `disable-wireless-adb-vecentek-magisk.zip`; do not wrap them in an outer `Q05_LIDAR_DATA/` directory.
- Q05_Lidar package cache is `%LOCALAPPDATA%\.cache\system\.android\apps_cache_Q05_Lidar`; the tool cleans it on startup/extraction and on normal/atexit shutdown.
- Q05_Lidar `runtime.dat` cache is `%LOCALAPPDATA%\.cache\system\.android\apps_cache_q05_lidar_runtime`; treat it as temporary and clean stale contents before extraction.
- `Q05_Lidar-package.bin` is an external release file next to the exe because it is large. `resource.dat` is embedded in the exe; `runtime.dat` should be copied next to the exe by the pack script.
- `package-key` must include the `vehicleName` returned by `auth-check` for the VIN. The tool caches `data.vehicleName` from password query / authorization check and uses it for package-key; if missing, query `auth-check` first rather than falling back to a hardcoded Q05_Lidar value.
- All `adb shell` commands in Q05_Lidar, including Magisk launch and `/debug_ramdisk/su -c ...`, must go through `run_adb_shell()` so the tool silently sends `adb36987`.
- The `安装App` button remains the APK install path: file picker -> `adb push` -> `setprop vecentek.model 1` -> `pm install -r -d -f` -> cleanup. Do not replace it with the Magisk module flow.
- Temporary debug mode exists only for development and should be removed before release when requested. Press `Ctrl+Shift+D`; the password is verified through `POST /api/authorizations/verify-debug-mode-password`.
- In Q05_Lidar debug mode, hidden buttons appear for:
- `指纹测试`: collect and log device fingerprint fields plus local SHA256 summary.
- `解密测试`: if VIN/device is available, fetch boot key; otherwise prompt for a pasted `BOOT_KEY`/`sessionKey`, decrypt `resource.dat` locally to a temporary img, log size/SHA256, then delete it.
- `解压测试`: fetch `package-key`, extract `Q05_Lidar-package.bin`, and verify the main Magisk module plus `disable_wireless_adb_vecentek` module can be identified.
- Do not log the actual boot key/session key in debug mode.
### Language quick-set
Popup with 8 one-click locale switches (zh-CN, en-US, ru-RU, fr-FR, es-ES, pt-BR, it-IT, ar-SA). Also links to native Android language settings. Changes take effect after reboot.
### Yidong/app-yidong.py
### Model-specific behaviors
- Uses `apps_cache_yidong`.
- Has 7za compatibility handling for progress switches and `Incorrect command line` fallback.
- `Yidong/pack_yidong.bat` output name is ASCII: `Changan-Yidong-Language-Installer.exe`, to avoid CMD codepage issues with Chinese `NAME`.
| Feature | Q07 (app.py) | S05 (S05.py) | X5plus (X5plusTool.py) | 逸动 (app-install/yidong) |
|---------|-------------|-------------|------------------------|---------------------------|
| Root perm | Y | Y | N (no btn_root) | N |
| priv-app | Y | Y | Y | N (app only) |
| ADB shell | Standard | Standard | Standard | Auto-password `adb36987` |
| VIN key | ca_vin_info/VIN | ca_vin_info/VIN | ca_vin_info/VIN | ca.car.vin |
| Old app cleanup | N | N | Y (5 packages) | N |
| Font push | N | N | Y (FZLTHPro) | N |
| Overlay enable | N | N | N | N (removed) |
| Password query | N | Y | N | Y |
| Factory hints | N | Y | Y (dynamic pwd) | Y |
## Build Notes
## Build process
- Pack scripts install/use `pyinstaller`, `cython`, and usually `pyzipper`.
- Cython success requires Microsoft C++ Build Tools.
- Cython success signs in logs:
- `building '_core' extension`
- `_core.cpXXX-win_amd64.pyd`
- `PYD: _core...pyd`
- output under `dist_cy\dist\...exe`
- If logs show `[WARN] Cython failed, fallback` and `[INFO] Normal PyInstaller`, the exe still builds but is normal PyInstaller and easier to reverse.
- For security-sensitive tools like Q05_Lidar, do not keep a normal PyInstaller fallback. If Cython fails or no `_core*.pyd` is generated, stop the build and show an error.
- A Cython onefile PyInstaller build should use a tiny `launcher.py` that imports `main` from compiled `_core.pyd`, and the exe archive should contain `_core*.pyd`. Confirm with PyInstaller archive viewer when in doubt.
- `UNIZ/pack_uniz.bat` and Mazda-EZ60 pack scripts use ASCII output names to avoid CMD encoding problems.
- Generated `.exe`, `.spec`, `build/`, `dist/`, and `dist_cy/` are build artifacts and should not be committed unless explicitly requested.
Each `pack_*.bat` follows the same pipeline:
1. Install deps: `pyinstaller`, `cython`, `pyzipper`
2. Clean old build dirs
3. Cython compile: `{source}.py``_core.pyd`
4. Copy resources: `adb.exe`, DLLs, `app.ico`
5. PyInstaller: single `.exe` with `--uac-admin`, bundling `_core.pyd` + ADB + DLLs
6. Fallback to normal PyInstaller if Cython fails
## Key Behaviors To Preserve
Output exe is self-contained — bundles `adb.exe` and DLLs via `sys._MEIPASS`, no external ADB needed.
1. Keep original tools untouched when a fixed or model-specific copy exists.
2. Preserve VIN-based authorization for normal flashing tools.
3. Fetch `package-key` from the server instead of hardcoding package passwords.
4. Keep all shell commands in 逸动/Mazda tools behind `run_adb_shell()`.
5. Keep UNI-Z shell-free.
6. Use `run_on_ui_thread()` for all tkinter UI updates from worker threads.
7. Keep shared Android/7za binaries under root `tools/` and have pack scripts copy from there.
## Key behaviors to preserve
## Current Local State (2026-05-28)
1. **Thread safety**: Never call tkinter from background threads — always use `run_on_ui_thread`
2. **VIN-based auth**: Authorization required before push; flow must remain intact
3. **Silent extraction**: Auto-extract `package.bin` without user step
4. **ADB portability**: `self.adb` resolves to bundled exe path; all commands go through `run_adb_command`
5. **vecentek.model**: Set to 1 before install, 0 after
6. **Chinese encoding**: `# -*- coding: utf-8 -*-` throughout
7. **Debug mode**: `self.debug_mode` flag gates auth/connection bypass and verbose logging
8. **Separate cache dirs**: Each tool extracts to its own cache folder
- `UNIZ/UNIZ.py` and `UNIZ/pack_uniz.bat` exist locally. Cython build has succeeded after installing Microsoft C++ Build Tools, producing `dist_cy\dist\UNIZ-Language-Pusher.exe`.
- `Mazda-EZ60/Mazda-EZ60_1.2.py` with `pack_mazda_ez60_1.2.bat`, and `Mazda-EZ60/Mazda_EZ60-Language-Install_v1.0.py` with `pack_mazda_ez60_1.0.bat`, exist locally. Mazda has 7za progress extraction, Cython-only packaging, and version-specific output names.
- `Yidong/app-yidong.py` has been updated for 7za progress compatibility and `Incorrect command line` fallback.
- `Yidong/pack_yidong.bat` has been updated with quoted paths, `cd /d "%~dp0"`, and ASCII output name.
- `.gitignore` has been expanded to ignore generated exe/spec artifacts.
- There may be untracked local build outputs and generated specs; inspect `git status --ignored` before committing.
## Known issues
## Known Issues
- `test_extract.py` hardcodes password — should fetch from API
- `on_disable_upgrade` uses `findstr` (Windows-specific)
- Exception handling is minimal in many places (bare `except: pass`)
- 逸动 tools (app-install/yidong) use `subprocess.Popen` with stdin password injection — fragile
- Some older tools still have minimal exception handling and bare `except: pass`.
- `test_extract.py` hardcodes a password and should not be treated as production flow.
- `on_disable_upgrade` behavior is Windows/vehicle specific.
- Pure PyInstaller fallback is easy to reverse; prefer successful Cython builds for release.
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

+1
View File
@@ -0,0 +1 @@
Q1DLEsRw96XfzeCXtWG5PlTP10PpL8HbHQvr4YUqDzhUCzSboW924hT5xhjKu78S5ZZGGhxqjyPDh3GHf9L4cqCwpeg2tfKlsl/b7bmUWVVY5KfpwhRQuJlhQn7VJkycYe+TNb89n56mLYIV7DhNLhgGENXdMjHWPdUXQhNanpata8n920J2GGe71dONPRh/Ljeab2sv8SJprCaUYaSwxtkXXz5OS/9L5CRGJ13YDuu+aEIQp5R4i25mqqL4KD+zSkjkyHfQzzemIolfueVya27xZYULSBnQCYL/39GjdTM5btZ7OL9FCjzXROfQyyZ21HZIZgKo/p1wuRH7j4Ne0g==
+133
View File
@@ -0,0 +1,133 @@
@echo off
chcp 65001 >nul
cd /d "%~dp0"
set "ROOT=%~dp0.."
set "TOOLS=%ROOT%\tools"
set "NAME=CS55-Q05-Installer"
set "SRC=CS55-Q05_Installer.py"
set "ICON=cs55-q05.ico"
title %NAME% - Cython Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b 1
)
for /f "delims=" %%i in ('where python') do set "PY=%%i"
echo Python: %PY%
if not exist "%SRC%" (
echo [ERROR] Source not found: %SRC%
pause
exit /b 1
)
if not exist "%ICON%" (
echo [ERROR] Icon not found: %ICON%
pause
exit /b 1
)
if not exist "%TOOLS%\adb.exe" (
echo [ERROR] adb.exe not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\7za.exe" (
echo [ERROR] 7za.exe not found in %TOOLS%
pause
exit /b 1
)
echo [1/6] Installing deps...
%PY% -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
%PY% -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
if errorlevel 1 (
echo [ERROR] Dependency install failed
pause
exit /b 1
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
if exist "%NAME%.spec" del /q "%NAME%.spec" 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy "%SRC%" dist_cy\_core.py >nul
%PY% -c "open('dist_cy/setup_cython.py','w',encoding='utf-8').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
cd dist_cy
%PY% setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [ERROR] Cython failed. Build stopped.
pause
exit /b 1
)
set "PYD="
for %%f in (_core*.pyd) do set "PYD=%%f"
if "%PYD%"=="" (
cd ..
echo [ERROR] No Cython PYD generated. Build stopped.
pause
exit /b 1
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
if errorlevel 1 (
cd ..
echo [ERROR] Failed to copy Cython PYD
pause
exit /b 1
)
%PY% -c "open('launcher.py','w',encoding='utf-8').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
echo [4/6] Copy resources...
copy "%TOOLS%\adb.exe" . >nul
copy "%TOOLS%\AdbWinApi.dll" . >nul
copy "%TOOLS%\AdbWinUsbApi.dll" . >nul
copy "%TOOLS%\7za.exe" . >nul
copy "..\%ICON%" . >nul
if errorlevel 1 (
cd ..
echo [ERROR] Copy resources failed
pause
exit /b 1
)
echo [5/6] PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon="%ICON%" --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --add-data "%ICON%;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=tkinter.simpledialog --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b 1
)
echo [6/6] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py "%ICON%" 2>nul
rmdir /s /q build 2>nul
cd ..
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else (
echo [ERROR] Output exe was not generated
pause
exit /b 1
)
pause
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

+133
View File
@@ -0,0 +1,133 @@
@echo off
chcp 65001 >nul
cd /d "%~dp0"
set "ROOT=%~dp0.."
set "TOOLS=%ROOT%\tools"
set "NAME=CS75Pro-Installer"
set "SRC=CS75Pro_Installer.py"
set "ICON=cs75pro.ico"
title %NAME% - Cython Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b 1
)
for /f "delims=" %%i in ('where python') do set "PY=%%i"
echo Python: %PY%
if not exist "%SRC%" (
echo [ERROR] Source not found: %SRC%
pause
exit /b 1
)
if not exist "%ICON%" (
echo [ERROR] Icon not found: %ICON%
pause
exit /b 1
)
if not exist "%TOOLS%\adb.exe" (
echo [ERROR] adb.exe not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\7za.exe" (
echo [ERROR] 7za.exe not found in %TOOLS%
pause
exit /b 1
)
echo [1/6] Installing deps...
%PY% -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
%PY% -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
if errorlevel 1 (
echo [ERROR] Dependency install failed
pause
exit /b 1
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
if exist "%NAME%.spec" del /q "%NAME%.spec" 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy "%SRC%" dist_cy\_core.py >nul
%PY% -c "open('dist_cy/setup_cython.py','w',encoding='utf-8').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
cd dist_cy
%PY% setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [ERROR] Cython failed. Build stopped.
pause
exit /b 1
)
set "PYD="
for %%f in (_core*.pyd) do set "PYD=%%f"
if "%PYD%"=="" (
cd ..
echo [ERROR] No Cython PYD generated. Build stopped.
pause
exit /b 1
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
if errorlevel 1 (
cd ..
echo [ERROR] Failed to copy Cython PYD
pause
exit /b 1
)
%PY% -c "open('launcher.py','w',encoding='utf-8').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
echo [4/6] Copy resources...
copy "%TOOLS%\adb.exe" . >nul
copy "%TOOLS%\AdbWinApi.dll" . >nul
copy "%TOOLS%\AdbWinUsbApi.dll" . >nul
copy "%TOOLS%\7za.exe" . >nul
copy "..\%ICON%" . >nul
if errorlevel 1 (
cd ..
echo [ERROR] Copy resources failed
pause
exit /b 1
)
echo [5/6] PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon="%ICON%" --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --add-data "%ICON%;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=tkinter.simpledialog --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b 1
)
echo [6/6] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py "%ICON%" 2>nul
rmdir /s /q build 2>nul
cd ..
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else (
echo [ERROR] Output exe was not generated
pause
exit /b 1
)
pause
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

+153
View File
@@ -0,0 +1,153 @@
@echo off
chcp 65001 >nul
cd /d "%~dp0"
set "ROOT=%~dp0.."
set "TOOLS=%ROOT%\tools"
set "NAME=Mazda-EZ6-Installer"
set "SRC=Mazda-EZ6_Installer.py"
set "ICON=%~dp0app.ico"
title %NAME% - Cython Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b 1
)
for /f "delims=" %%i in ('where python') do set "PY=%%i"
echo Python: %PY%
if not exist "%SRC%" (
echo [ERROR] Source not found: %SRC%
pause
exit /b 1
)
if not exist "%ICON%" (
echo [ERROR] Icon not found: %ICON%
pause
exit /b 1
)
if not exist "%TOOLS%\adb.exe" (
echo [ERROR] adb.exe not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinApi.dll" (
echo [ERROR] AdbWinApi.dll not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinUsbApi.dll" (
echo [ERROR] AdbWinUsbApi.dll not found in %TOOLS%
pause
exit /b 1
)
echo [1/6] Installing deps...
"%PY%" -m pip install pyinstaller cython -q
if errorlevel 1 (
"%PY%" -m pip install pyinstaller cython -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
if errorlevel 1 (
echo [ERROR] Dependency install failed
pause
exit /b 1
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
if exist "%NAME%.spec" del /q "%NAME%.spec" 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy "%SRC%" "dist_cy\_core.py" >nul
if errorlevel 1 (
echo [ERROR] Copy source failed
pause
exit /b 1
)
"%PY%" -c "open('dist_cy/setup_cython.py','w',encoding='utf-8').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
if errorlevel 1 (
echo [ERROR] Failed to create Cython setup script
pause
exit /b 1
)
cd dist_cy
"%PY%" setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [ERROR] Cython failed. Build stopped.
pause
exit /b 1
)
set "PYD="
for %%f in (_core*.pyd) do set "PYD=%%f"
if "%PYD%"=="" (
cd ..
echo [ERROR] No Cython PYD generated. Build stopped.
pause
exit /b 1
)
echo PYD: %PYD%
copy "%PYD%" "_core.pyd" >nul
if errorlevel 1 (
cd ..
echo [ERROR] Failed to copy Cython PYD
pause
exit /b 1
)
"%PY%" -c "open('launcher.py','w',encoding='utf-8').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
if errorlevel 1 (
cd ..
echo [ERROR] Failed to create launcher.py
pause
exit /b 1
)
echo [4/6] Copy resources...
copy "%TOOLS%\adb.exe" . >nul
copy "%TOOLS%\AdbWinApi.dll" . >nul
copy "%TOOLS%\AdbWinUsbApi.dll" . >nul
copy "%ICON%" . >nul
if errorlevel 1 (
cd ..
echo [ERROR] Copy resources failed
pause
exit /b 1
)
echo [5/6] PyInstaller...
"%PY%" -m PyInstaller --onefile --windowed --name="%NAME%" --icon="app.ico" --add-data "app.ico;." --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=tkinter.filedialog --hidden-import=tkinter.messagebox --hidden-import=tkinter.scrolledtext --hidden-import=tkinter.ttk --hidden-import=json --hidden-import=urllib --hidden-import=urllib.error --hidden-import=urllib.parse --hidden-import=urllib.request --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b 1
)
echo [6/6] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py adb.exe AdbWinApi.dll AdbWinUsbApi.dll app.ico 2>nul
rmdir /s /q build 2>nul
cd ..
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else (
echo [ERROR] Output exe was not generated
pause
exit /b 1
)
pause
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

@@ -0,0 +1,209 @@
param(
[string]$AppsDir = "",
[string]$AdbPath = "",
[string]$ShellPassword = "adb36987"
)
$ErrorActionPreference = "Stop"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
if (-not $AppsDir) {
$AppsDir = Join-Path $ScriptDir "apps"
}
function Find-AdbPath {
param(
[string]$BaseDir
)
$candidates = @(
(Join-Path $BaseDir "adb.exe"),
(Join-Path $BaseDir "tools\adb.exe"),
(Join-Path $BaseDir "..\adb.exe"),
(Join-Path $BaseDir "..\tools\adb.exe"),
(Join-Path $BaseDir "..\..\tools\adb.exe"),
"D:\Code\language-installer\tools\adb.exe",
"D:\apk_tools\platform-tools\adb.exe"
)
foreach ($candidate in $candidates) {
try {
$resolved = Resolve-Path -LiteralPath $candidate -ErrorAction Stop
if ($resolved) {
return $resolved.Path
}
} catch {}
}
$pathAdb = Get-Command adb.exe -ErrorAction SilentlyContinue
if ($pathAdb) {
return $pathAdb.Source
}
return ""
}
if (-not $AdbPath) {
$AdbPath = Find-AdbPath -BaseDir $ScriptDir
}
if (-not (Test-Path -LiteralPath $AdbPath)) {
throw "adb.exe not found. Put adb.exe next to this script or run with -AdbPath `"D:\path\adb.exe`""
}
if (-not (Test-Path -LiteralPath $AppsDir)) {
throw "apps directory not found: $AppsDir"
}
function Quote-ProcessArgument {
param(
[Parameter(Mandatory = $true)]
[string]$Value
)
if ($Value -notmatch '[\s"]') {
return $Value
}
return '"' + $Value.Replace('"', '\"') + '"'
}
function Invoke-Adb {
param(
[Parameter(Mandatory = $true)]
[string[]]$Arguments
)
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $AdbPath
$psi.Arguments = (($Arguments | ForEach-Object { Quote-ProcessArgument $_ }) -join " ")
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.UseShellExecute = $false
$psi.CreateNoWindow = $true
$proc = [System.Diagnostics.Process]::Start($psi)
$stdout = $proc.StandardOutput.ReadToEnd()
$stderr = $proc.StandardError.ReadToEnd()
$proc.WaitForExit()
return [pscustomobject]@{
Code = $proc.ExitCode
Out = ($stdout + $stderr).Trim()
}
}
function Invoke-AdbShellWithPassword {
param(
[Parameter(Mandatory = $true)]
[string]$Command,
[int]$TimeoutMs = 60000
)
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $AdbPath
$psi.Arguments = "-d shell"
$psi.RedirectStandardInput = $true
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.UseShellExecute = $false
$psi.CreateNoWindow = $true
$proc = New-Object System.Diagnostics.Process
$proc.StartInfo = $psi
[void]$proc.Start()
Start-Sleep -Milliseconds 500
$proc.StandardInput.WriteLine($ShellPassword)
Start-Sleep -Milliseconds 300
$proc.StandardInput.WriteLine($Command)
$proc.StandardInput.WriteLine("exit")
$proc.StandardInput.Close()
if (-not $proc.WaitForExit($TimeoutMs)) {
try { $proc.Kill() } catch {}
return [pscustomobject]@{
Code = -1
Out = "shell command timeout: $Command"
}
}
$stdout = $proc.StandardOutput.ReadToEnd()
$stderr = $proc.StandardError.ReadToEnd()
return [pscustomobject]@{
Code = $proc.ExitCode
Out = ($stdout + $stderr).Trim()
}
}
Write-Host "ADB: $AdbPath"
Write-Host "Apps: $AppsDir"
$devices = Invoke-Adb -Arguments @("-d", "devices")
if ($devices.Code -ne 0 -or $devices.Out -notmatch "`tdevice") {
Write-Host "[ERROR] No adb device connected." -ForegroundColor Red
if ($devices.Out) { Write-Host $devices.Out }
exit 1
}
$root = Invoke-Adb -Arguments @("-d", "root")
if ($root.Out) {
Write-Host $root.Out
}
Start-Sleep -Seconds 2
$apks = Get-ChildItem -LiteralPath $AppsDir -Filter "*.apk" -File | Sort-Object Name
if (-not $apks) {
Write-Host "[ERROR] No APK files found in apps directory." -ForegroundColor Red
exit 1
}
$total = $apks.Count
$index = 0
$success = 0
foreach ($apk in $apks) {
$index++
$apkName = [System.IO.Path]::GetFileNameWithoutExtension($apk.Name)
$targetDir = "/system/app/$apkName"
$targetApk = "$targetDir/$($apk.Name)"
Write-Host ""
Write-Host "[$index/$total] $($apk.Name)" -ForegroundColor Cyan
$mkdir = Invoke-AdbShellWithPassword -Command "mkdir -p '$targetDir'"
if ($mkdir.Code -ne 0) {
Write-Host "[ERROR] mkdir failed: $targetDir" -ForegroundColor Red
if ($mkdir.Out) { Write-Host $mkdir.Out }
exit 1
}
$push = Invoke-Adb -Arguments @("-d", "push", $apk.FullName, $targetApk)
if ($push.Code -ne 0) {
Write-Host "[ERROR] push failed: $($apk.Name)" -ForegroundColor Red
if ($push.Out) { Write-Host $push.Out }
exit 1
}
if ($push.Out) {
Write-Host $push.Out
}
$chmodDir = Invoke-AdbShellWithPassword -Command "chmod 755 '$targetDir'"
if ($chmodDir.Code -ne 0) {
Write-Host "[ERROR] chmod 755 failed: $targetDir" -ForegroundColor Red
if ($chmodDir.Out) { Write-Host $chmodDir.Out }
exit 1
}
$chmodApk = Invoke-AdbShellWithPassword -Command "chmod 644 '$targetApk'"
if ($chmodApk.Code -ne 0) {
Write-Host "[ERROR] chmod 644 failed: $targetApk" -ForegroundColor Red
if ($chmodApk.Out) { Write-Host $chmodApk.Out }
exit 1
}
$success++
Write-Host "[OK] $($apk.Name)" -ForegroundColor Green
}
Write-Host ""
Write-Host "[DONE] Pushed $success/$total APK files." -ForegroundColor Green
+159
View File
@@ -0,0 +1,159 @@
@echo off
chcp 65001 >nul
cd /d "%~dp0"
set "ROOT=%~dp0.."
set "TOOLS=%ROOT%\tools"
set "NAME=Mazda_EZ60-Language-Install_v1.0"
set "SRC=Mazda_EZ60-Language-Install_v1.0.py"
set "ICON=%~dp0app.ico"
title %NAME% - Cython Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b 1
)
for /f "delims=" %%i in ('where python') do set "PY=%%i"
echo Python: %PY%
if not exist "%SRC%" (
echo [ERROR] Source not found: %SRC%
pause
exit /b 1
)
if not exist "%ICON%" (
echo [ERROR] Icon not found: %ICON%
pause
exit /b 1
)
if not exist "%TOOLS%\adb.exe" (
echo [ERROR] adb.exe not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinApi.dll" (
echo [ERROR] AdbWinApi.dll not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinUsbApi.dll" (
echo [ERROR] AdbWinUsbApi.dll not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\7za.exe" (
echo [ERROR] 7za.exe not found in %TOOLS%
pause
exit /b 1
)
echo [1/6] Installing deps...
"%PY%" -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
"%PY%" -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
if errorlevel 1 (
echo [ERROR] Dependency install failed
pause
exit /b 1
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
if exist "%NAME%.spec" del /q "%NAME%.spec" 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy "%SRC%" dist_cy\_core.py >nul
if errorlevel 1 (
echo [ERROR] Copy source failed
pause
exit /b 1
)
"%PY%" -c "open('dist_cy/setup_cython.py','w',encoding='utf-8').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
if errorlevel 1 (
echo [ERROR] Failed to create Cython setup script
pause
exit /b 1
)
cd dist_cy
"%PY%" setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [ERROR] Cython failed. Build stopped.
pause
exit /b 1
)
set "PYD="
for %%f in (_core*.pyd) do set "PYD=%%f"
if "%PYD%"=="" (
cd ..
echo [ERROR] No Cython PYD generated. Build stopped.
pause
exit /b 1
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
if errorlevel 1 (
cd ..
echo [ERROR] Failed to copy Cython PYD
pause
exit /b 1
)
"%PY%" -c "open('launcher.py','w',encoding='utf-8').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
if errorlevel 1 (
cd ..
echo [ERROR] Failed to create launcher.py
pause
exit /b 1
)
echo [4/6] Copy resources...
copy "%TOOLS%\adb.exe" . >nul
copy "%TOOLS%\AdbWinApi.dll" . >nul
copy "%TOOLS%\AdbWinUsbApi.dll" . >nul
copy "%TOOLS%\7za.exe" . >nul
copy "%ICON%" . >nul
if errorlevel 1 (
cd ..
echo [ERROR] Copy resources failed
pause
exit /b 1
)
echo [5/6] PyInstaller...
"%PY%" -m PyInstaller --onefile --windowed --name="%NAME%" --icon="app.ico" --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --add-data "app.ico;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=tkinter.simpledialog --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b 1
)
echo [6/6] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py app.ico 2>nul
rmdir /s /q build 2>nul
cd ..
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else (
echo [ERROR] Output exe was not generated
pause
exit /b 1
)
pause
@@ -0,0 +1,159 @@
@echo off
chcp 65001 >nul
cd /d "%~dp0"
set "ROOT=%~dp0.."
set "TOOLS=%ROOT%\tools"
set "NAME=Mazda_EZ60-Language-Install_v1.0-direct-push"
set "SRC=Mazda_EZ60-Language-Install_v1.0_direct_push.py"
set "ICON=%~dp0app.ico"
title %NAME% - Cython Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b 1
)
for /f "delims=" %%i in ('where python') do set "PY=%%i"
echo Python: %PY%
if not exist "%SRC%" (
echo [ERROR] Source not found: %SRC%
pause
exit /b 1
)
if not exist "%ICON%" (
echo [ERROR] Icon not found: %ICON%
pause
exit /b 1
)
if not exist "%TOOLS%\adb.exe" (
echo [ERROR] adb.exe not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinApi.dll" (
echo [ERROR] AdbWinApi.dll not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinUsbApi.dll" (
echo [ERROR] AdbWinUsbApi.dll not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\7za.exe" (
echo [ERROR] 7za.exe not found in %TOOLS%
pause
exit /b 1
)
echo [1/6] Installing deps...
"%PY%" -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
"%PY%" -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
if errorlevel 1 (
echo [ERROR] Dependency install failed
pause
exit /b 1
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
if exist "%NAME%.spec" del /q "%NAME%.spec" 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy "%SRC%" dist_cy\_core.py >nul
if errorlevel 1 (
echo [ERROR] Copy source failed
pause
exit /b 1
)
"%PY%" -c "open('dist_cy/setup_cython.py','w',encoding='utf-8').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
if errorlevel 1 (
echo [ERROR] Failed to create Cython setup script
pause
exit /b 1
)
cd dist_cy
"%PY%" setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [ERROR] Cython failed. Build stopped.
pause
exit /b 1
)
set "PYD="
for %%f in (_core*.pyd) do set "PYD=%%f"
if "%PYD%"=="" (
cd ..
echo [ERROR] No Cython PYD generated. Build stopped.
pause
exit /b 1
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
if errorlevel 1 (
cd ..
echo [ERROR] Failed to copy Cython PYD
pause
exit /b 1
)
"%PY%" -c "open('launcher.py','w',encoding='utf-8').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
if errorlevel 1 (
cd ..
echo [ERROR] Failed to create launcher.py
pause
exit /b 1
)
echo [4/6] Copy resources...
copy "%TOOLS%\adb.exe" . >nul
copy "%TOOLS%\AdbWinApi.dll" . >nul
copy "%TOOLS%\AdbWinUsbApi.dll" . >nul
copy "%TOOLS%\7za.exe" . >nul
copy "%ICON%" . >nul
if errorlevel 1 (
cd ..
echo [ERROR] Copy resources failed
pause
exit /b 1
)
echo [5/6] PyInstaller...
"%PY%" -m PyInstaller --onefile --windowed --name="%NAME%" --icon="app.ico" --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --add-data "app.ico;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=tkinter.simpledialog --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b 1
)
echo [6/6] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py app.ico 2>nul
rmdir /s /q build 2>nul
cd ..
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else (
echo [ERROR] Output exe was not generated
pause
exit /b 1
)
pause
+194
View File
@@ -0,0 +1,194 @@
@echo off
chcp 65001 >nul
cd /d "%~dp0"
set "ROOT=%~dp0.."
set "TOOLS=%ROOT%\tools"
set "NAME=Mazda-EZ60-Language-Installer_v1.2"
set "SRC=Mazda-EZ60_1.2.py"
set "ICON=%~dp0app.ico"
title %NAME% - Cython Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b 1
)
for /f "delims=" %%i in ('where python') do set "PY=%%i"
echo Python: %PY%
if not exist "%SRC%" (
echo [ERROR] Source not found: %SRC%
pause
exit /b 1
)
if not exist "%ICON%" (
echo [ERROR] Icon not found: %ICON%
pause
exit /b 1
)
if not exist "%TOOLS%\adb.exe" (
echo [ERROR] adb.exe not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinApi.dll" (
echo [ERROR] AdbWinApi.dll not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinUsbApi.dll" (
echo [ERROR] AdbWinUsbApi.dll not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\7za.exe" (
echo [ERROR] 7za.exe not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\fastboot.exe" (
echo [ERROR] fastboot.exe not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\usb_driver\android_winusb.inf" (
echo [ERROR] usb_driver not found at %TOOLS%\usb_driver
pause
exit /b 1
)
if not exist "%~dp0runtime.dat" (
echo [ERROR] runtime.dat not found at %~dp0runtime.dat
pause
exit /b 1
)
echo [1/6] Installing deps...
"%PY%" -m pip install pyinstaller cython pyzipper cryptography -q
if errorlevel 1 (
"%PY%" -m pip install pyinstaller cython pyzipper cryptography -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
if errorlevel 1 (
echo [ERROR] Dependency install failed
pause
exit /b 1
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
if exist "%NAME%.spec" del /q "%NAME%.spec" 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy "%SRC%" dist_cy\_core.py >nul
if errorlevel 1 (
echo [ERROR] Copy source failed
pause
exit /b 1
)
"%PY%" -c "open('dist_cy/setup_cython.py','w',encoding='utf-8').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
if errorlevel 1 (
echo [ERROR] Failed to create Cython setup script
pause
exit /b 1
)
cd dist_cy
"%PY%" setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [ERROR] Cython failed. Build stopped.
pause
exit /b 1
)
set "PYD="
for %%f in (_core*.pyd) do set "PYD=%%f"
if "%PYD%"=="" (
cd ..
echo [ERROR] No Cython PYD generated. Build stopped.
pause
exit /b 1
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
if errorlevel 1 (
cd ..
echo [ERROR] Failed to copy Cython PYD
pause
exit /b 1
)
"%PY%" -c "open('launcher.py','w',encoding='utf-8').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
if errorlevel 1 (
cd ..
echo [ERROR] Failed to create launcher.py
pause
exit /b 1
)
echo [4/6] Copy resources...
copy "%TOOLS%\adb.exe" . >nul
copy "%TOOLS%\AdbWinApi.dll" . >nul
copy "%TOOLS%\AdbWinUsbApi.dll" . >nul
copy "%TOOLS%\7za.exe" . >nul
copy "%TOOLS%\fastboot.exe" . >nul
copy "%ICON%" . >nul
if errorlevel 1 (
cd ..
echo [ERROR] Copy resources failed
pause
exit /b 1
)
if exist "%~dp0EZ60_resource.dat" copy "%~dp0EZ60_resource.dat" . >nul
echo [5/6] PyInstaller...
set ADD_PERMISSION_RESOURCE=
if exist "EZ60_resource.dat" set ADD_PERMISSION_RESOURCE=--add-data "EZ60_resource.dat;."
"%PY%" -m PyInstaller --onefile --windowed --name="%NAME%" --icon="app.ico" --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --add-data "fastboot.exe;." --add-data "app.ico;." --add-data "%TOOLS%\usb_driver;usb_driver" %ADD_PERMISSION_RESOURCE% --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=tkinter.simpledialog --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --hidden-import=cryptography --collect-all tkinter --collect-all cryptography --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b 1
)
echo [6/6] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py app.ico fastboot.exe EZ60_resource.dat 2>nul
rmdir /s /q build 2>nul
cd ..
if not exist "dist_cy\dist\%NAME%.exe" (
echo [ERROR] Output exe was not generated
pause
exit /b 1
)
copy "runtime.dat" "dist_cy\dist\runtime.dat" >nul
if errorlevel 1 (
echo [ERROR] Copy runtime.dat failed
pause
exit /b 1
)
if exist "package_voice-assistant.bin" (
copy "package_voice-assistant.bin" "dist_cy\dist\package_voice-assistant.bin" >nul
if errorlevel 1 (
echo [ERROR] Copy package_voice-assistant.bin failed
pause
exit /b 1
)
)
echo.
echo Done.
echo Output: dist_cy\dist\%NAME%.exe
pause
File diff suppressed because it is too large Load Diff
+183
View File
@@ -0,0 +1,183 @@
@echo off
chcp 65001 >nul
cd /d "%~dp0"
set "NAME=Q05-Lidar_Installer"
set "SRC=Q05-Lidar_Installer.py"
set "APPDIR=%~dp0"
set "ROOT=%~dp0.."
set "TOOLS=%ROOT%\tools"
title %NAME% - Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
set "PY=C:\Users\31770\AppData\Local\Programs\Python\Python313\python.exe"
if not exist "%PY%" (
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b
)
for /f "delims=" %%i in ('where python') do set "PY=%%i"
)
echo Python: %PY%
echo [1/6] Installing deps...
"%PY%" -m pip install pyinstaller cython pyzipper cryptography -q
if errorlevel 1 (
"%PY%" -m pip install pyinstaller cython pyzipper cryptography -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy "%SRC%" "dist_cy\_core.py" >nul
if errorlevel 1 (
echo [ERROR] Copy source failed. Cython build stopped.
pause
exit /b 1
)
"%PY%" -c "open('dist_cy/setup_cython.py','w').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
cd dist_cy
"%PY%" setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [ERROR] Cython build failed. Normal PyInstaller fallback is disabled.
pause
exit /b 1
)
for %%f in (_core*.pyd) do set PYD=%%f
if "%PYD%"=="" (
cd ..
echo [ERROR] No Cython pyd generated. Normal PyInstaller fallback is disabled.
pause
exit /b 1
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
"%PY%" -c "open('launcher.py','w').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
echo [4/6] Copy resources...
if not exist "%TOOLS%\adb.exe" (
echo [ERROR] tools\adb.exe not found
cd ..
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinApi.dll" (
echo [ERROR] tools\AdbWinApi.dll not found
cd ..
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinUsbApi.dll" (
echo [ERROR] tools\AdbWinUsbApi.dll not found
cd ..
pause
exit /b 1
)
if not exist "%TOOLS%\fastboot.exe" (
echo [ERROR] tools\fastboot.exe not found
cd ..
pause
exit /b 1
)
if not exist "%TOOLS%\7za.exe" (
echo [ERROR] tools\7za.exe not found at %TOOLS%\7za.exe
cd ..
pause
exit /b 1
)
if not exist "%APPDIR%app.ico" (
echo [ERROR] app.ico not found at %APPDIR%app.ico
cd ..
pause
exit /b 1
)
copy "%TOOLS%\adb.exe" . >nul
copy "%TOOLS%\AdbWinApi.dll" . >nul
copy "%TOOLS%\AdbWinUsbApi.dll" . >nul
copy "%TOOLS%\7za.exe" . >nul
copy "%TOOLS%\fastboot.exe" . >nul
copy "%APPDIR%app.ico" . >nul
if exist "%APPDIR%resource.dat" copy "%APPDIR%resource.dat" . >nul
echo [5/6] PyInstaller...
set ADD_RESOURCE=
if exist "resource.dat" set ADD_RESOURCE=--add-data "resource.dat;."
"%PY%" -m PyInstaller --onefile --windowed --name="%NAME%" --icon="app.ico" --add-data "app.ico;." --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --add-data "fastboot.exe;." --add-data "%APPDIR%usb_driver;usb_driver" %ADD_RESOURCE% --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=cryptography --collect-all tkinter --collect-all cryptography --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b
)
echo [6/7] Copy release data...
if not exist "dist\%NAME%.exe" (
cd ..
echo [ERROR] Build output exe not found
pause
exit /b 1
)
if not exist "%APPDIR%runtime.dat" (
cd ..
echo [ERROR] runtime.dat not found at %APPDIR%runtime.dat
pause
exit /b 1
)
if not exist "%APPDIR%Q05_Lidar-package.bin" (
cd ..
echo [ERROR] Q05_Lidar-package.bin not found at %APPDIR%Q05_Lidar-package.bin
pause
exit /b 1
)
copy "%APPDIR%runtime.dat" "dist\runtime.dat" >nul
if errorlevel 1 (
cd ..
echo [ERROR] Copy runtime.dat failed
pause
exit /b 1
)
copy "%APPDIR%Q05_Lidar-package.bin" "dist\Q05_Lidar-package.bin" >nul
if errorlevel 1 (
cd ..
echo [ERROR] Copy Q05_Lidar-package.bin failed
pause
exit /b 1
)
if not exist "%APPDIR%usb_driver\android_winusb.inf" (
cd ..
echo [ERROR] usb_driver\android_winusb.inf not found at %APPDIR%usb_driver
pause
exit /b 1
)
echo [7/7] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py adb.exe AdbWinApi.dll AdbWinUsbApi.dll 7za.exe fastboot.exe resource.dat 2>nul
rmdir /s /q build 2>nul
cd ..
goto :DONE
:DONE
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else if exist "dist\%NAME%.exe" (
echo Output: dist\%NAME%.exe
) else (
echo Check dist folder
)
pause
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

+121
View File
@@ -0,0 +1,121 @@
@echo off
chcp 65001 >nul
cd /d "%~dp0"
set "ROOT=%~dp0.."
set "TOOLS=%ROOT%\tools"
set "ICON=%~dp0app.ico"
set NAME=Qiyuan_Q07-multi-lan-installer
set SRC=Qiyuan_Q07-multi-lan-installer.py
title %NAME% - Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b
)
for /f "delims=" %%i in ('where python') do set PY=%%i
echo Python: %PY%
echo [1/6] Installing deps...
%PY% -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
%PY% -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
echo [2/7] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
echo [3/7] Checking resources...
if not exist "%ICON%" (
echo [ERROR] app.ico not found in Q07 folder: %ICON%
pause
exit /b 1
)
if not exist "%TOOLS%\adb.exe" (
echo [ERROR] Missing ADB file: %TOOLS%\adb.exe
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinApi.dll" (
echo [ERROR] Missing ADB file: %TOOLS%\AdbWinApi.dll
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinUsbApi.dll" (
echo [ERROR] Missing ADB file: %TOOLS%\AdbWinUsbApi.dll
pause
exit /b 1
)
if not exist "%TOOLS%\7za.exe" (
echo [ERROR] Missing 7za file: %TOOLS%\7za.exe
pause
exit /b 1
)
echo [4/7] Cython compile...
mkdir dist_cy 2>nul
copy %SRC% dist_cy\_core.py >nul
set "PYD="
%PY% -c "open('dist_cy/setup_cython.py','w').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
cd dist_cy
%PY% setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [ERROR] Cython build failed. Install Microsoft C++ Build Tools and retry.
pause
exit /b 1
)
for %%f in (_core*.pyd) do set PYD=%%f
if "%PYD%"=="" (
cd ..
echo [ERROR] Cython build did not generate _core*.pyd. Stop.
pause
exit /b 1
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
%PY% -c "open('launcher.py','w').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
echo [5/7] Copy resources...
copy "%TOOLS%\adb.exe" . >nul
copy "%TOOLS%\AdbWinApi.dll" . >nul
copy "%TOOLS%\AdbWinUsbApi.dll" . >nul
copy "%TOOLS%\7za.exe" . >nul
copy "%ICON%" . >nul
echo [6/7] PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon="%ICON%" --add-data "%ICON%;." --add-data "%TOOLS%\adb.exe;." --add-data "%TOOLS%\AdbWinApi.dll;." --add-data "%TOOLS%\AdbWinUsbApi.dll;." --add-data "%TOOLS%\7za.exe;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=tkinter.simpledialog --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b 1
)
echo [7/7] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py 2>nul
rmdir /s /q build 2>nul
cd ..
goto :DONE
:DONE
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else (
echo Check dist folder
)
pause
+23 -2
View File
@@ -1,3 +1,24 @@
# language_installer
# language_installer
长安语言刷入工具适用于启源Q07、深蓝S05、X5plus、长安逸动等多车型的Android车机多语言APK刷入工具套件
长安语言刷入工具套件,适用于启源Q07、深蓝S05、X5plus、长安逸动、UNI-Z、Mazda-EZ60 等 Android 车机多语言 APK 刷入/推送场景
## 常用入口
| 文件 | 用途 | 打包脚本 |
|------|------|----------|
| `Q07/app.py` | 启源Q07 | `Q07/pack_q07.bat` |
| `S05/S05.py` | 深蓝S05原版 | `S05/pack_s05.bat` |
| `S05/S05_fixed.py` | 深蓝S05修复版 | `S05/pack_s05_fixed.bat` |
| `X5plus/X5plusTool.py` | X5plus | `X5plus/pack_x5plus.bat` |
| `CS55-Q05/CS55-Q05_Installer.py` | CS55Plus/Q05 通用 | `CS55-Q05/pack_cs55_q05.bat` |
| `CS75Pro/CS75Pro_Installer.py` | CS75Pro | `CS75Pro/pack_cs75pro.bat` |
| `Yidong/app-yidong.py` | 长安逸动 | `Yidong/pack_yidong.bat` |
| `UNIZ/UNIZ.py` | UNI-Z 文件推送 | `UNIZ/pack_uniz.bat` |
| `Mazda-EZ60/Mazda-EZ60_1.2.py` | Mazda-EZ60 OS 1.2 | `Mazda-EZ60/pack_mazda_ez60_1.2.bat` |
| `Mazda-EZ60/Mazda_EZ60-Language-Install_v1.0.py` | Mazda-EZ60 OS 1.0 | `Mazda-EZ60/pack_mazda_ez60_1.0.bat` |
| `A07/Qiyuan_A07_Multi-lan-installer.py` | 启源A07 | `A07/pack_a07.bat` |
| `Q05-Lidar/Q05-Lidar_Installer.py` | Q05_Lidar | `Q05-Lidar/pack_q05_lidar.bat` |
公共工具如 `adb.exe``fastboot.exe``7za.exe` 及相关 DLL 统一放在根目录 `tools/` 管理;`app.ico``package.bin` 保留在仓库根目录。各车型脚本会自动回退查找这些资源。
详细维护说明见 `AGENTS.md` / `CLAUDE.md`
-1559
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

+160
View File
@@ -0,0 +1,160 @@
@echo off
setlocal EnableExtensions
cd /d "%~dp0"
set "ROOT=%~dp0.."
set "TOOLS=%ROOT%\tools"
set "NAME=Deepal_S05_Installer"
set "SRC=Deepal_S05.py"
set "ICON=%~dp0app.ico"
title %NAME% - Cython Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>nul
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b 1
)
for /f "delims=" %%i in ('where python') do set "PY=%%i"
echo Python: %PY%
if not exist "%SRC%" (
echo [ERROR] Source not found: %SRC%
pause
exit /b 1
)
if not exist "%ICON%" (
echo [ERROR] Icon not found: %ICON%
pause
exit /b 1
)
if not exist "%TOOLS%\adb.exe" (
echo [ERROR] adb.exe not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinApi.dll" (
echo [ERROR] AdbWinApi.dll not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinUsbApi.dll" (
echo [ERROR] AdbWinUsbApi.dll not found in %TOOLS%
pause
exit /b 1
)
if not exist "%TOOLS%\7za.exe" (
echo [ERROR] 7za.exe not found in %TOOLS%
pause
exit /b 1
)
echo [1/6] Installing deps...
"%PY%" -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
"%PY%" -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
if errorlevel 1 (
echo [ERROR] Dependency install failed
pause
exit /b 1
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q "dist_cy" 2>nul
if exist "build" rmdir /s /q "build" 2>nul
if exist "dist" rmdir /s /q "dist" 2>nul
if exist "%NAME%.spec" del /q "%NAME%.spec" 2>nul
echo [3/6] Cython compile...
mkdir "dist_cy" 2>nul
copy "%SRC%" "dist_cy\_core.py" >nul
if errorlevel 1 (
echo [ERROR] Copy source failed
pause
exit /b 1
)
"%PY%" -c "open('dist_cy/setup_cython.py','w',encoding='utf-8').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
if errorlevel 1 (
echo [ERROR] Failed to create Cython setup script
pause
exit /b 1
)
cd /d "dist_cy"
"%PY%" "setup_cython.py" build_ext --inplace
if errorlevel 1 (
cd /d "%~dp0"
echo [ERROR] Cython failed. Build stopped.
pause
exit /b 1
)
set "PYD="
for %%f in (_core*.pyd) do set "PYD=%%f"
if "%PYD%"=="" (
cd /d "%~dp0"
echo [ERROR] No Cython PYD generated. Build stopped.
pause
exit /b 1
)
echo PYD: %PYD%
copy "%PYD%" "_core.pyd" >nul
if errorlevel 1 (
cd /d "%~dp0"
echo [ERROR] Failed to copy Cython PYD
pause
exit /b 1
)
"%PY%" -c "open('launcher.py','w',encoding='utf-8').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
if errorlevel 1 (
cd /d "%~dp0"
echo [ERROR] Failed to create launcher.py
pause
exit /b 1
)
echo [4/6] Copy resources...
copy "%TOOLS%\adb.exe" . >nul
copy "%TOOLS%\AdbWinApi.dll" . >nul
copy "%TOOLS%\AdbWinUsbApi.dll" . >nul
copy "%TOOLS%\7za.exe" . >nul
copy "%ICON%" . >nul
if errorlevel 1 (
cd /d "%~dp0"
echo [ERROR] Copy resources failed
pause
exit /b 1
)
echo [5/6] PyInstaller...
"%PY%" -m PyInstaller --onefile --windowed --name="%NAME%" --icon="app.ico" --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --add-data "app.ico;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=tkinter.simpledialog --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --collect-all tkinter --uac-admin "launcher.py"
if errorlevel 1 (
cd /d "%~dp0"
echo [ERROR] PyInstaller failed
pause
exit /b 1
)
echo [6/6] Cleanup...
del /q "_core.py" "_core.c" "_core.pyd" "%PYD%" "launcher.py" "setup_cython.py" "app.ico" 2>nul
rmdir /s /q "build" 2>nul
cd /d "%~dp0"
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else (
echo [ERROR] Output exe was not generated
pause
exit /b 1
)
pause
File diff suppressed because it is too large Load Diff
+121
View File
@@ -0,0 +1,121 @@
@echo off
chcp 65001 >nul
cd /d "%~dp0"
set "ROOT=%~dp0.."
set "TOOLS=%ROOT%\tools"
set "ICON=%~dp0app.ico"
set NAME=UNI-T-multi-lan-installer
set SRC=UNI-T-multi-lan-installer.py
title %NAME% - Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b
)
for /f "delims=" %%i in ('where python') do set PY=%%i
echo Python: %PY%
echo [1/6] Installing deps...
%PY% -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
%PY% -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
echo [2/7] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
echo [3/7] Checking resources...
if not exist "%ICON%" (
echo [ERROR] app.ico not found in UNI-T folder: %ICON%
pause
exit /b 1
)
if not exist "%TOOLS%\adb.exe" (
echo [ERROR] Missing ADB file: %TOOLS%\adb.exe
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinApi.dll" (
echo [ERROR] Missing ADB file: %TOOLS%\AdbWinApi.dll
pause
exit /b 1
)
if not exist "%TOOLS%\AdbWinUsbApi.dll" (
echo [ERROR] Missing ADB file: %TOOLS%\AdbWinUsbApi.dll
pause
exit /b 1
)
if not exist "%TOOLS%\7za.exe" (
echo [ERROR] Missing 7za file: %TOOLS%\7za.exe
pause
exit /b 1
)
echo [4/7] Cython compile...
mkdir dist_cy 2>nul
copy %SRC% dist_cy\_core.py >nul
set "PYD="
%PY% -c "open('dist_cy/setup_cython.py','w').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
cd dist_cy
%PY% setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [ERROR] Cython build failed. Install Microsoft C++ Build Tools and retry.
pause
exit /b 1
)
for %%f in (_core*.pyd) do set PYD=%%f
if "%PYD%"=="" (
cd ..
echo [ERROR] Cython build did not generate _core*.pyd. Stop.
pause
exit /b 1
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
%PY% -c "open('launcher.py','w').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
echo [5/7] Copy resources...
copy "%TOOLS%\adb.exe" . >nul
copy "%TOOLS%\AdbWinApi.dll" . >nul
copy "%TOOLS%\AdbWinUsbApi.dll" . >nul
copy "%TOOLS%\7za.exe" . >nul
copy "%ICON%" . >nul
echo [6/7] PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon="%ICON%" --add-data "%ICON%;." --add-data "%TOOLS%\adb.exe;." --add-data "%TOOLS%\AdbWinApi.dll;." --add-data "%TOOLS%\AdbWinUsbApi.dll;." --add-data "%TOOLS%\7za.exe;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=tkinter.simpledialog --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b 1
)
echo [7/7] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py 2>nul
rmdir /s /q build 2>nul
cd ..
goto :DONE
:DONE
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else (
echo Check dist folder
)
pause
+1212
View File
File diff suppressed because it is too large Load Diff
+100
View File
@@ -0,0 +1,100 @@
@echo off
chcp 65001 >nul
cd /d "%~dp0"
set "ROOT=%~dp0.."
set "TOOLS=%ROOT%\tools"
set "NAME=UNIZ-Language-Pusher"
set "SRC=UNIZ.py"
title %NAME% - Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b
)
for /f "delims=" %%i in ('where python') do set PY=%%i
echo Python: %PY%
echo [1/6] Installing deps...
"%PY%" -m pip install pyinstaller cython -q
if errorlevel 1 (
"%PY%" -m pip install pyinstaller cython -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy "%SRC%" "dist_cy\_core.py" >nul
if errorlevel 1 (
echo [WARN] Copy source failed, fallback
goto :NORMAL
)
"%PY%" -c "open('dist_cy/setup_cython.py','w').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
cd dist_cy
"%PY%" setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [WARN] Cython failed, fallback
goto :NORMAL
)
for %%f in (_core*.pyd) do set PYD=%%f
if "%PYD%"=="" (
cd ..
echo [WARN] No pyd, fallback
goto :NORMAL
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
"%PY%" -c "open('launcher.py','w').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
echo [4/6] Copy resources...
copy "%TOOLS%\adb.exe" . >nul
copy "%TOOLS%\AdbWinApi.dll" . >nul
copy "%TOOLS%\AdbWinUsbApi.dll" . >nul
copy "%TOOLS%\7za.exe" . >nul
if exist "%ROOT%\app.ico" copy "%ROOT%\app.ico" . >nul
echo [5/6] PyInstaller...
"%PY%" -m PyInstaller --onefile --windowed --name="%NAME%" --icon="%ROOT%\app.ico" --add-data "%TOOLS%\adb.exe;." --add-data "%TOOLS%\AdbWinApi.dll;." --add-data "%TOOLS%\AdbWinUsbApi.dll;." --add-data "%TOOLS%\7za.exe;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --collect-all tkinter launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b
)
echo [6/6] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py 2>nul
rmdir /s /q build 2>nul
cd ..
goto :DONE
:NORMAL
echo [INFO] Normal PyInstaller...
"%PY%" -m PyInstaller --onefile --windowed --name="%NAME%" --icon="%ROOT%\app.ico" --add-data "%TOOLS%\adb.exe;." --add-data "%TOOLS%\AdbWinApi.dll;." --add-data "%TOOLS%\AdbWinUsbApi.dll;." --add-data "%TOOLS%\7za.exe;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --collect-all tkinter "%SRC%"
:DONE
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else if exist "dist\%NAME%.exe" (
echo Output: dist\%NAME%.exe
) else (
echo Check dist folder
)
pause
Binary file not shown.
Binary file not shown.
+2241
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.
+157
View File
@@ -0,0 +1,157 @@
@echo off
chcp 65001 >nul
setlocal
cd /d "%~dp0"
set "ROOT=%~dp0.."
set "TOOLS=%ROOT%\tools"
set "ICON=%~dp0app.ico"
set "NAME=Changan_X5Plus-Installer"
set "SRC=X5plusTool.py"
title %NAME% - Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
set "PY="
where python >nul 2>&1
if not errorlevel 1 (
for /f "delims=" %%i in ('where python') do (
if not defined PY set "PY=%%i"
)
)
if not defined PY (
where py >nul 2>&1
if not errorlevel 1 set "PY=py"
)
if not defined PY (
if exist "%LOCALAPPDATA%\Microsoft\WindowsApps\python.exe" set "PY=%LOCALAPPDATA%\Microsoft\WindowsApps\python.exe"
)
if not defined PY (
echo [ERROR] Python not found
pause
exit /b 1
)
echo Python: %PY%
if not exist "%SRC%" (
echo [ERROR] Source not found: %SRC%
pause
exit /b 1
)
if not exist "%ICON%" (
echo [ERROR] app.ico not found: %ICON%
pause
exit /b 1
)
echo [1/6] Installing deps...
"%PY%" -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
"%PY%" -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
if errorlevel 1 (
echo [ERROR] Dependency installation failed
pause
exit /b 1
)
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy "%SRC%" "dist_cy\_core.py" >nul
if errorlevel 1 (
echo [ERROR] Copy source failed
pause
exit /b 1
)
"%PY%" -c "open('dist_cy/setup_cython.py','w',encoding='utf-8').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
if errorlevel 1 (
echo [ERROR] Generate Cython setup failed
pause
exit /b 1
)
cd dist_cy
"%PY%" setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [ERROR] Cython compile failed
pause
exit /b 1
)
set "PYD="
for %%f in (_core*.pyd) do set "PYD=%%f"
if "%PYD%"=="" (
cd ..
echo [ERROR] No Cython pyd generated
pause
exit /b 1
)
echo PYD: %PYD%
copy "%PYD%" "_core.pyd" >nul
if errorlevel 1 (
cd ..
echo [ERROR] Copy Cython pyd failed
pause
exit /b 1
)
"%PY%" -c "open('launcher.py','w',encoding='utf-8').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
if errorlevel 1 (
cd ..
echo [ERROR] Generate launcher failed
pause
exit /b 1
)
echo [4/6] Copy resources...
copy "%TOOLS%\adb.exe" . >nul
if errorlevel 1 (
cd ..
echo [ERROR] adb.exe not found in %TOOLS%
pause
exit /b 1
)
copy "%TOOLS%\AdbWinApi.dll" . >nul
copy "%TOOLS%\AdbWinUsbApi.dll" . >nul
copy "%TOOLS%\7za.exe" . >nul
copy "%ICON%" . >nul
if errorlevel 1 (
cd ..
echo [ERROR] Copy resources failed
pause
exit /b 1
)
echo [5/6] PyInstaller...
"%PY%" -m PyInstaller --onefile --windowed --name="%NAME%" --icon="%ICON%" --add-data "%ICON%;." --add-data "%TOOLS%\adb.exe;." --add-data "%TOOLS%\AdbWinApi.dll;." --add-data "%TOOLS%\AdbWinUsbApi.dll;." --add-data "%TOOLS%\7za.exe;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=tkinter.simpledialog --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --hidden-import=urllib.parse --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b 1
)
echo [6/6] Cleanup...
del /q "_core.py" "_core.c" "_core.pyd" "%PYD%" "launcher.py" "setup_cython.py" 2>nul
rmdir /s /q build 2>nul
cd ..
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else (
echo [ERROR] Build output not found
)
pause
-1447
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+390 -151
View File
@@ -5,12 +5,14 @@ import os
import sys
import subprocess
import json
import re
import threading
import tkinter as tk
from tkinter import ttk, scrolledtext, filedialog, messagebox
from tkinter import ttk, scrolledtext, filedialog, messagebox, simpledialog
from pathlib import Path
from urllib.request import urlopen, Request
from urllib.error import URLError, HTTPError
from urllib.parse import urlencode
from datetime import datetime
import zipfile
try:
@@ -20,6 +22,44 @@ except ImportError:
import shutil
import time
def get_app_dir():
return Path(sys.executable).resolve().parent if getattr(sys, 'frozen', False) else Path(__file__).resolve().parent
def resource_candidates(file_name):
base_dir = get_app_dir()
candidates = []
if getattr(sys, 'frozen', False):
candidates.append(Path(getattr(sys, '_MEIPASS', base_dir)) / file_name)
candidates.extend([
base_dir / file_name,
base_dir / 'tools' / file_name,
base_dir / 'shared' / file_name,
base_dir.parent / 'tools' / file_name,
base_dir.parent / 'shared' / file_name,
base_dir.parent / file_name,
])
unique = []
for candidate in candidates:
if candidate not in unique:
unique.append(candidate)
return unique
def find_resource(file_name):
candidates = resource_candidates(file_name)
for candidate in candidates:
if candidate.exists():
return candidate
return candidates[0]
def find_tool(file_name, fallback=None):
path = find_resource(file_name)
if path.exists():
return str(path)
return fallback or str(path)
class ADKAPKGUI:
def __init__(self):
self.root = tk.Tk()
@@ -128,20 +168,17 @@ class ADKAPKGUI:
}
}
self.base_dir = Path(sys.executable).parent if getattr(sys, 'frozen', False) else Path(__file__).parent
if getattr(sys, 'frozen', False):
self.adb = str(Path(sys._MEIPASS) / 'adb.exe')
self.sz = str(Path(sys._MEIPASS) / '7za.exe')
else:
self.adb = 'adb'
self.sz = str(self.base_dir / '7za.exe')
self.package_file = self.base_dir / "package.bin"
self.base_dir = get_app_dir()
self.adb = find_tool('adb.exe', 'adb')
self.sz = find_tool('7za.exe')
self.package_file = find_resource("package.bin")
self.extract_password = None
self.apps_dir = None
self.temp_dir = None
self.api_url = "https://api.changan.softwindy.cn/api/authorizations/auth-check"
self.vin = None
self.device_connected = False
self.debug_mode = False # debug mode
self._refreshing = False # 防止并发刷新
# 设置样式
@@ -438,6 +475,10 @@ class ADKAPKGUI:
relief=tk.FLAT, cursor='hand2')
self.btn_lang_switch.pack(side=tk.RIGHT, padx=5)
# Debug shortcuts
self.root.bind('<Control-Shift-D>', self._toggle_debug)
self.root.bind('<Control-Shift-E>', self._debug_test_extract)
# ========== 右侧提示面板 ==========
# 热点信息卡片
hotspot_card = tk.Frame(right_frame, bg=self.colors['bg_dark'], relief=tk.RAISED, bd=1)
@@ -549,7 +590,10 @@ class ADKAPKGUI:
def run_on_ui_thread(self, func, *args, **kwargs):
"""将函数调度到主线程执行,确保线程安全"""
self.root.after(0, func, *args, **kwargs)
self.root.after(0, lambda: func(*args, **kwargs))
def _adb_cmd(self):
return subprocess.list2cmdline([self.adb])
def t(self, key):
return self.T.get(self.lang, self.T['zh']).get(key, key)
@@ -705,6 +749,8 @@ class ADKAPKGUI:
def check_device_connection(self):
"""检查设备是否连接"""
if self.debug_mode:
return True
if not self.device_connected:
messagebox.showwarning("设备未连接", "请先连接设备并点击「检查」按钮刷新状态!")
return False
@@ -715,7 +761,7 @@ class ADKAPKGUI:
def monitor():
while True:
try:
result = subprocess.run('adb -d devices', shell=True, capture_output=True, text=True)
result = subprocess.run(f'{self._adb_cmd()} -d devices', shell=True, capture_output=True, text=True)
lines = result.stdout.strip().split('\n')
devices = [line for line in lines[1:] if line.strip() and 'device' in line and 'offline' not in line]
@@ -740,9 +786,11 @@ class ADKAPKGUI:
def run_adb_shell(self, shell_command):
"""执行 adb shell 命令,自动静默输入设备密码 adb36987。
静默执行不显示 adb 原始输出仅返回结果"""
if self.debug_mode:
self.log(f"CMD: adb shell {shell_command}", "CMD")
try:
proc = subprocess.Popen(
f'adb -d shell {shell_command}',
f'{self._adb_cmd()} -d shell {shell_command}',
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
@@ -763,15 +811,23 @@ class ADKAPKGUI:
output = '\n'.join(output_lines).strip()
if proc.returncode == 0:
if self.debug_mode:
self.log(f"CMD OK: {output[:200]}", "CMD")
return True, output
else:
if self.debug_mode:
self.log(f"CMD FAIL: {stderr.strip()[:200]}", "CMD")
return False, stderr.strip()
except subprocess.TimeoutExpired:
proc.kill()
proc.communicate()
if self.debug_mode:
self.log("CMD TIMEOUT", "CMD")
return False, "命令超时"
except Exception as e:
if self.debug_mode:
self.log(f"CMD ERROR: {str(e)}", "CMD")
return False, str(e)
# ============================================================
@@ -782,104 +838,227 @@ class ADKAPKGUI:
"""执行原始 adb 命令(adb push / adb install 等,无需 shell 密码)。
静默执行不显示 adb 原始输出仅返回结果"""
try:
command = command.replace('adb', self._adb_cmd(), 1)
if self.debug_mode:
self.log(f"CMD: {command}", "CMD")
result = subprocess.run(command, shell=True, capture_output=True, text=True, encoding='utf-8')
if result.returncode == 0:
if self.debug_mode:
self.log(f"CMD OK: {result.stdout.strip()[:200]}", "CMD")
return True, result.stdout.strip()
else:
if self.debug_mode:
self.log(f"CMD FAIL: {result.stderr.strip()[:200]}", "CMD")
return False, result.stderr.strip()
except Exception as e:
if self.debug_mode:
self.log(f"CMD ERROR: {str(e)}", "CMD")
return False, str(e)
def check_package_extracted(self):
"""检查语言包是否已解压"""
has_app = self.apps_dir and self.apps_dir.exists() and len(list(self.apps_dir.glob("*.apk"))) > 0
if has_app:
ok, reason = self._validate_extracted_apks()
if not ok:
self.log(f"已解压缓存无效: {reason}", "ERROR")
self._clear_extracted_cache()
return False
return has_app
def _validate_extracted_apks(self):
if not self.apps_dir or not self.apps_dir.exists():
return False, "缺少 apps 目录"
apks = list(self.apps_dir.glob("*.apk"))
if not apks:
return False, "apps 目录没有 APK"
zero_apks = [apk.name for apk in apks if apk.stat().st_size <= 0]
if zero_apks:
preview = ", ".join(zero_apks[:5])
suffix = "..." if len(zero_apks) > 5 else ""
return False, f"发现 0KB APK: {preview}{suffix}"
return True, ""
def _clear_extracted_cache(self):
if self.temp_dir and self.temp_dir.exists():
shutil.rmtree(self.temp_dir, ignore_errors=True)
time.sleep(0.5)
self.apps_dir = None
def _format_extract_error(self, err_msg, return_code):
text = (err_msg or "").lower()
if any(marker in text for marker in (
"wrong password",
"incorrect password",
"password is incorrect",
"data error in encrypted file",
"can not open encrypted archive",
)):
return "解压密码错误,请重新确认 package.bin 密码"
if "data error" in text:
return "资源包数据错误,可能是密码错误或 package.bin 损坏"
if "headers error" in text or "unexpected end" in text:
return "资源包损坏或不完整,请检查 package.bin"
if err_msg.strip():
return f"解压失败: {err_msg.strip()[:300]}"
return f"解压失败 (返回码 {return_code}),请检查密码是否正确"
def _decode_7z_output(self, *outputs):
"""解码 7za 输出,兼容中文 Windows 控制台编码。"""
parts = []
for output in outputs:
if not output:
continue
for enc in ['gbk', 'utf-8']:
try:
parts.append(output.decode(enc, errors='replace'))
break
except Exception:
continue
return ''.join(parts).strip()
def _seven_zip_supports_progress_stream(self):
"""检测 7za 是否支持 -bsp1 进度流参数。"""
try:
result = subprocess.run(
[self.sz],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
creationflags=subprocess.CREATE_NO_WINDOW if sys.platform == 'win32' else 0
)
output = self._decode_7z_output(result.stdout, result.stderr)
return '-bs{o|e|p}' in output
except Exception:
return False
def _extract_with_7za_progress(self, use_progress_switches=False):
"""执行 7za 解压并尽量解析百分比进度。"""
self.update_progress(0, 100, "Loading resources...")
cmd = [
self.sz, 'x', str(self.package_file),
f'-p{self.extract_password}',
f'-o{self.temp_dir}', '-y'
]
if use_progress_switches:
cmd.extend(['-bsp1', '-bso0', '-bse1'])
if getattr(self, 'debug_mode', False):
self.log(f"7ZA CMD: {subprocess.list2cmdline(cmd)}", "CMD")
proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
stdin=subprocess.DEVNULL,
creationflags=subprocess.CREATE_NO_WINDOW if sys.platform == 'win32' else 0,
bufsize=0
)
output = bytearray()
last_percent = -1
while True:
chunk = proc.stdout.read(1) if proc.stdout else b''
if not chunk:
if proc.poll() is not None:
break
time.sleep(0.05)
continue
output.extend(chunk)
if len(output) > 60000:
del output[:-60000]
matches = re.findall(rb'(\d{1,3})%', bytes(output[-512:]))
if matches:
percent = min(100, int(matches[-1]))
if percent != last_percent:
last_percent = percent
self.update_progress(percent, 100, "Loading resources...")
return_code = proc.wait()
decoded_output = self._decode_7z_output(bytes(output))
if return_code == 0:
self.update_progress(100, 100, "Resources loaded")
if getattr(self, 'debug_mode', False):
self.log(f"7ZA RET: {return_code}", "CMD" if return_code == 0 else "ERROR")
if decoded_output:
self.log(f"7ZA OUTPUT:\n{decoded_output}", "CMD" if return_code == 0 else "ERROR")
return return_code, decoded_output
def extract_package_silent(self):
"""静默解压语言包(带进度)—— 逸动版仅处理 app 目录"""
"""Extract package.bin silently with progress; app directory only."""
if not self.package_file.exists():
self.log(f"错误:未找到资源包 ({self.package_file})", "ERROR")
self.log(f"Error: package not found ({self.package_file})", "ERROR")
return False
if not self.extract_password:
self.log("错误:解压密码未设置", "ERROR")
self.log("Error: extract password is not set", "ERROR")
return False
if not os.path.exists(self.sz):
self.log(f"错误:未找到 7za.exe ({self.sz})", "ERROR")
self.log(f"Error: 7za.exe not found ({self.sz})", "ERROR")
return False
try:
# 使用用户目录,无需管理员权限
local_appdata = os.environ.get('LOCALAPPDATA', os.path.expanduser('~\\AppData\\Local'))
hidden_path = Path(local_appdata) / ".cache" / "system" / ".android"
hidden_path.mkdir(parents=True, exist_ok=True)
self.temp_dir = hidden_path / "apps_cache_yidong"
# 如果已存在,先清理
if self.temp_dir.exists():
shutil.rmtree(self.temp_dir, ignore_errors=True)
time.sleep(0.5)
self.temp_dir.mkdir(parents=True, exist_ok=True)
# 设置隐藏属性(Windows
if sys.platform == 'win32':
subprocess.run(f'attrib +h "{self.temp_dir.parent}"', shell=True, capture_output=True)
subprocess.run(f'attrib +h "{self.temp_dir}"', shell=True, capture_output=True)
self.log(f"正在解压资源包...", "INFO")
self.log("正在准备资源包", "INFO")
# 使用 7za 解压(不用 text=True 避免编码问题)
self.update_progress(0, 1, "资源加载中...")
result = subprocess.run(
[self.sz, 'x', str(self.package_file),
f'-p{self.extract_password}',
f'-o{self.temp_dir}', '-y'],
capture_output=True,
creationflags=subprocess.CREATE_NO_WINDOW if sys.platform == 'win32' else 0
)
use_progress_switches = self._seven_zip_supports_progress_stream()
return_code, err_msg = self._extract_with_7za_progress(use_progress_switches)
if result.returncode != 0:
err_msg = ""
for output in [result.stderr, result.stdout]:
if output:
for enc in ['gbk', 'utf-8']:
try:
err_msg += output.decode(enc, errors='replace')
break
except:
continue
if err_msg.strip():
self.log(f"解压失败: {err_msg.strip()[:300]}", "ERROR")
else:
self.log(f"解压失败 (返回码: {result.returncode}),请检查密码是否正确", "ERROR")
if return_code != 0 and use_progress_switches and "Incorrect command line" in err_msg:
self.log("当前 7za 不支持进度参数,正在使用兼容模式重试解压...", "WARNING")
return_code, err_msg = self._extract_with_7za_progress(False)
if return_code != 0:
self.log(self._format_extract_error(err_msg, return_code), "ERROR")
self._clear_extracted_cache()
return False
self.update_progress(1, 1, "资源加载完成")
# 查找 app 目录(逸动无 priv-app
self.apps_dir = None
app_candidates = list(self.temp_dir.rglob("apps"))
app_candidates = list(self.temp_dir.rglob("apps")) or list(self.temp_dir.rglob("app"))
if app_candidates:
self.apps_dir = app_candidates[0]
if not self.apps_dir:
self.log("警告:未找到 apps 目录", "WARNING")
self._clear_extracted_cache()
return False
apk_count = len(list(self.apps_dir.glob("*.apk")))
ok, reason = self._validate_extracted_apks()
if not ok:
self.log(f"解压后的资源无效: {reason}。已停止刷入,请检查解压密码或资源包。", "ERROR")
self._clear_extracted_cache()
return False
self.log(f"资源准备完成 (app: {apk_count})", "SUCCESS")
return True
except Exception as e:
if getattr(self, 'debug_mode', False):
self.log(f"资源准备失败: {str(e)}", "ERROR")
self.log(f"Package preparation failed: {str(e)}", "ERROR")
import traceback
self.log(traceback.format_exc(), "ERROR")
else:
self.log("资源准备失败,请检查网络连接后重试", "ERROR")
self._clear_extracted_cache()
return False
def check_environment(self):
@@ -889,7 +1068,7 @@ class ADKAPKGUI:
# 刷新热点显示
self.refresh_hotspot_display()
try:
result = subprocess.run('adb version', shell=True, capture_output=True, text=True)
result = subprocess.run(f'{self._adb_cmd()} version', shell=True, capture_output=True, text=True)
if result.returncode == 0:
self.refresh_device_status()
if not self.package_file.exists():
@@ -900,78 +1079,81 @@ class ADKAPKGUI:
self.log("未找到adb命令,请将ADB文件放入本目录", "ERROR")
def refresh_device_status(self, force=False):
"""刷新设备状态 —— 逸动版使用 ca.car.vin 获取 VIN"""
# 防止并发刷新(手动点击「检查」时强制忽略锁)
"""Refresh device status; Yidong uses ca.car.vin."""
if self._refreshing and not force:
return
self._refreshing = True
def refresh():
was_connected = self.device_connected
try:
was_connected = self.device_connected
# 检查设备连接
result = subprocess.run('adb -d devices', shell=True, capture_output=True, text=True)
lines = result.stdout.strip().split('\n')
devices = [line for line in lines[1:] if line.strip() and 'device' in line and 'offline' not in line]
result = subprocess.run(f'{self._adb_cmd()} -d devices', shell=True, capture_output=True, text=True)
lines = result.stdout.strip().splitlines()
devices = [line for line in lines[1:] if line.strip() and 'device' in line and 'offline' not in line]
if devices:
if not was_connected:
self.log("设备已连接", "SUCCESS")
if devices:
if not was_connected:
self.log("Device connected", "SUCCESS")
# 获取VIN —— 逸动车型使用 ca.car.vin
success, vin_output = self.run_adb_shell(
'settings get system ca.car.vin')
vin = vin_output.strip() if success else ''
success, vin_output = self.run_adb_shell('settings get system ca.car.vin')
vin = vin_output.strip() if success else ''
if vin == 'null':
vin = ''
if vin:
self.log(f"VIN: {vin}", "INFO")
authorized = self.check_authorization(vin)
self.update_device_status(True, vin, authorized)
if vin:
self.log(f"VIN: {vin}", "INFO")
authorized = self.check_authorization(vin)
self.update_device_status(True, vin, authorized)
else:
self.log("Unable to read VIN, please confirm factory mode", "WARNING")
self.update_device_status(True, None, False)
else:
self.log("无法获取VIN,请确认设备已进入工厂模式", "WARNING")
self.update_device_status(True, None, False)
else:
if was_connected:
self.log("设备未连接", "WARNING")
self.update_device_status(False)
self._refreshing = False
if was_connected:
self.log("Device disconnected", "WARNING")
self.update_device_status(False)
except Exception as e:
self.log(f"Refresh device status failed: {str(e)}", "ERROR")
finally:
self._refreshing = False
threading.Thread(target=refresh, daemon=True).start()
def check_authorization(self, vin):
"""检查授权"""
self.log("正在验证授权状态...", "INFO")
"""Check authorization."""
if getattr(self, 'debug_mode', False):
self.log("Debug mode: skip authorization", "WARNING")
return True
self.log("Checking authorization...", "INFO")
try:
url = f"{self.api_url}?vin={vin}"
url = f"{self.api_url}?{urlencode({'vin': vin})}"
req = Request(url, method='GET', headers={'User-Agent': 'Mozilla/5.0'})
with urlopen(req, timeout=10) as response:
data = json.loads(response.read().decode('utf-8'))
if data.get('authorized') == True:
self.log("✅ 授权验证通过!", "SUCCESS")
self.log("Authorization passed", "SUCCESS")
if 'data' in data and 'vehicleName' in data['data']:
self.log(f"车辆名称: {data['data']['vehicleName']}", "INFO")
self.log(f"Vehicle name: {data['data']['vehicleName']}", "INFO")
return True
else:
self.log(f"❌ 授权验证失败", "ERROR")
self.log("Authorization failed", "ERROR")
return False
except Exception as e:
self.log(f"❌ 授权验证失败", "ERROR")
except Exception:
self.log("Authorization failed", "ERROR")
return False
def fetch_package_password(self):
"""从服务端获取资源包解压密码"""
"""Fetch package password from server."""
if not self.vin:
self.log("请先连接adb", "ERROR")
self.log("Please connect adb first", "ERROR")
return False
try:
pwd_api_url = "https://api.changan.softwindy.cn/api/authorizations/package-key"
url = f"{pwd_api_url}?vin={self.vin}"
url = f"{pwd_api_url}?{urlencode({'vin': self.vin})}"
req = Request(url, method='GET', headers={'User-Agent': 'Mozilla/5.0'})
with urlopen(req, timeout=10) as response:
@@ -981,11 +1163,11 @@ class ADKAPKGUI:
self.extract_password = data['data']['password']
return True
else:
self.log(f"数据准备失败: {data.get('message', '未知错误')}", "ERROR")
self.log(f"Data preparation failed: {data.get('message', 'unknown error')}", "ERROR")
return False
except Exception as e:
self.log(f"数据准备失败: {str(e)}", "ERROR")
self.log(f"Data preparation failed: {str(e)}", "ERROR")
return False
def push_single_apk(self, apk_path, apk_name):
@@ -1050,33 +1232,33 @@ class ADKAPKGUI:
self.run_adb_shell('mkdir -p /data/local/tmp')
self.run_adb_shell('setprop vecentek.model 1')
all_apks = list(self.apps_dir.glob("*.apk"))
if not all_apks:
self.log("未找到语言包文件", "WARNING")
self.show_progress(False, is_push=True)
return
total = len(all_apks)
success_count = 0
for i, apk_path in enumerate(all_apks, 1):
apk_name = apk_path.stem
ok, _ = self.push_single_apk(apk_path, apk_name)
if ok:
self.log(f"安装成功: {apk_name}.apk", "SUCCESS")
success_count += 1
try:
all_apks = list(self.apps_dir.glob("*.apk"))
if not all_apks:
self.log("未找到语言包文件", "WARNING")
return
total = len(all_apks)
for i, apk_path in enumerate(all_apks, 1):
apk_name = apk_path.stem
ok, _ = self.push_single_apk(apk_path, apk_name)
if ok:
self.log(f"安装成功: {apk_name}.apk", "SUCCESS")
success_count += 1
else:
self.log(f"安装失败: {apk_name}.apk", "ERROR")
self.update_progress(i, total, "正在刷入...", is_push=True)
self.update_progress(total, total, "刷入完成", is_push=True)
if success_count > 0:
self._enable_overlays()
else:
self.log(f"安装失败: {apk_name}.apk", "ERROR")
self.update_progress(i, total, "正在刷入...", is_push=True)
self.update_progress(total, total, "刷入完成", is_push=True)
self.run_adb_shell('setprop vecentek.model 0')
if success_count > 0:
self._enable_overlays()
else:
self.log("语言包刷入失败", "ERROR")
self.show_progress(False, is_push=True)
self.log("语言包刷入失败", "ERROR")
finally:
self.run_adb_shell('setprop vecentek.model 0')
self.show_progress(False, is_push=True)
threading.Thread(target=do_push_all, daemon=True).start()
@@ -1106,6 +1288,8 @@ class ADKAPKGUI:
# 使用当前目录下的apks文件夹
apk_dir = self.base_dir / "apks"
if not apk_dir.exists():
apk_dir = find_resource("apks")
# 检查apk文件夹是否存在
if not apk_dir.exists():
@@ -1131,30 +1315,34 @@ class ADKAPKGUI:
total = len(apk_files)
self.log(f"开始批量安装 {total} 个APK...", "INFO")
self.run_adb_shell('setprop vecentek.model 1')
success_count = 0
for i, apk_path in enumerate(apk_files, 1):
apk_name = apk_path.stem
self.update_progress(i, total, "安装中...", is_push=True)
if self._push_and_install(apk_path, apk_name):
self.log(f"安装成功: {apk_name}.apk", "SUCCESS")
success_count += 1
try:
self.run_adb_shell('setprop vecentek.model 1')
for i, apk_path in enumerate(apk_files, 1):
apk_name = apk_path.stem
self.update_progress(i, total, "安装中...", is_push=True)
if self._push_and_install(apk_path, apk_name):
self.log(f"安装成功: {apk_name}.apk", "SUCCESS")
success_count += 1
else:
self.log(f"安装失败: {apk_name}.apk", "ERROR")
self.update_progress(total, total, "安装完成", is_push=True)
if success_count == total:
self.run_on_ui_thread(messagebox.showinfo, "安装完成", f"成功安装 {total} 个APK")
elif success_count > 0:
self.run_on_ui_thread(messagebox.showwarning, "部分成功", f"成功: {success_count}\n失败: {total - success_count}")
else:
self.log(f"安装失败: {apk_name}.apk", "ERROR")
self.run_adb_shell('setprop vecentek.model 0')
self.update_progress(total, total, "安装完成", is_push=True)
self.show_progress(False, is_push=True)
if success_count == total:
messagebox.showinfo("安装完成", f"成功安装 {total} 个APK")
elif success_count > 0:
messagebox.showwarning("部分成功", f"成功: {success_count}\n失败: {total - success_count}")
messagebox.showwarning("部分成功", f"成功: {success_count}\n失败: {total - success_count}")
else:
self.log("安装失败", "ERROR")
messagebox.showerror("安装失败", "所有APK安装失败!")
self.log("安装失败", "ERROR")
self.run_on_ui_thread(messagebox.showerror, "安装失败", "所有APK安装失败!")
except Exception as e:
self.log(f"安装过程异常: {str(e)}", "ERROR")
self.run_on_ui_thread(messagebox.showerror, "安装失败", f"安装过程异常:{str(e)}")
finally:
self.run_adb_shell('setprop vecentek.model 0')
self.show_progress(False, is_push=True)
threading.Thread(target=install, daemon=True).start()
@@ -1182,16 +1370,19 @@ class ADKAPKGUI:
self.show_progress(True, is_push=True)
self.update_progress(30, 100, "安装中", is_push=True)
self.run_adb_shell('setprop vecentek.model 1')
success = self._push_and_install(file_path, apk_name)
self.run_adb_shell('setprop vecentek.model 0')
self.update_progress(100, 100, "完成", is_push=True)
if success:
self.log("安装成功", "SUCCESS")
else:
self.log("安装失败", "ERROR")
self.show_progress(False, is_push=True)
try:
self.run_adb_shell('setprop vecentek.model 1')
success = self._push_and_install(file_path, apk_name)
self.update_progress(100, 100, "完成", is_push=True)
if success:
self.log("安装成功", "SUCCESS")
else:
self.log("安装失败", "ERROR")
except Exception as e:
self.log(f"安装过程异常: {str(e)}", "ERROR")
finally:
self.run_adb_shell('setprop vecentek.model 0')
self.show_progress(False, is_push=True)
threading.Thread(target=install, daemon=True).start()
@@ -1300,13 +1491,14 @@ class ADKAPKGUI:
if success:
self.log(f"✓ 语言已设置为 {language_name}", "SUCCESS")
messagebox.showinfo(
self.run_on_ui_thread(
messagebox.showinfo,
"设置成功",
f"系统语言已设置为 {language_name}\n\n⚠️ 请重启设备使其生效。"
)
else:
self.log(f"✗ 语言设置失败: {output}", "ERROR")
messagebox.showerror("设置失败", f"语言设置失败!\n\n{output}")
self.run_on_ui_thread(messagebox.showerror, "设置失败", f"语言设置失败!\n\n{output}")
threading.Thread(target=do_set, daemon=True).start()
@@ -1332,7 +1524,7 @@ class ADKAPKGUI:
if not self.check_device_connection():
return
if messagebox.askyesno("确认重启", "确定要重启设备吗?"):
proc = subprocess.Popen(f'{self.adb} -d shell reboot', shell=True,
proc = subprocess.Popen(f'{self._adb_cmd()} -d shell reboot', shell=True,
stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
try:
proc.stdin.write(b'adb36987\n')
@@ -1369,10 +1561,10 @@ class ADKAPKGUI:
if success:
self.log("系统升级已禁用", "SUCCESS")
messagebox.showinfo("成功", "系统升级已成功禁用!")
self.run_on_ui_thread(messagebox.showinfo, "成功", "系统升级已成功禁用!")
else:
self.log("禁用系统升级失败", "ERROR")
messagebox.showerror("错误", f"禁用失败:{output}")
self.run_on_ui_thread(messagebox.showerror, "错误", f"禁用失败:{output}")
self.show_progress(False, is_push=False)
@@ -1562,6 +1754,53 @@ class ADKAPKGUI:
threading.Thread(target=poll, daemon=True).start()
def _toggle_debug(self, event=None):
"""Toggle debug mode."""
if self.debug_mode:
self.debug_mode = False
self.log("Debug mode disabled", "WARNING")
self.refresh_device_status(force=True)
return
pwd = simpledialog.askstring("Debug mode", "Enter debug password:", show='*', parent=self.root)
if pwd == "zxch5200":
self.debug_mode = True
self.log("Debug mode enabled", "WARNING")
self.update_device_status(True, self.vin or "DEBUG-VIN", True)
elif pwd:
messagebox.showwarning("Error", "Wrong password")
def _debug_test_extract(self, event=None):
"""Debug-only package extraction test."""
if not getattr(self, 'debug_mode', False):
messagebox.showwarning("Debug mode", "Press Ctrl+Shift+D to enable debug mode first")
return
pwd = simpledialog.askstring("Test extraction", "Enter package.bin password:", show='*', parent=self.root)
if not pwd:
return
def do_extract():
old_password = self.extract_password
self.extract_password = pwd
try:
self.show_progress(True, is_push=False)
if self.extract_package_silent():
self.log("Test extraction succeeded", "SUCCESS")
self.run_on_ui_thread(
messagebox.showinfo,
"Test extraction succeeded",
f"Resources extracted to:\n{self.temp_dir}"
)
else:
self.log("Test extraction failed", "ERROR")
self.run_on_ui_thread(messagebox.showerror, "Test extraction failed", "Check the 7za output in logs")
finally:
self.extract_password = old_password
self.show_progress(False, is_push=False)
threading.Thread(target=do_extract, daemon=True).start()
def run(self):
"""运行程序"""
self.root.mainloop()
+100
View File
@@ -0,0 +1,100 @@
@echo off
chcp 65001 >nul
cd /d "%~dp0"
set "ROOT=%~dp0.."
set "TOOLS=%ROOT%\tools"
set "NAME=Changan-Yidong-Language-Installer"
set "SRC=app-yidong.py"
title %NAME% - Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b
)
for /f "delims=" %%i in ('where python') do set "PY=%%i"
echo Python: %PY%
echo [1/6] Installing deps...
"%PY%" -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
"%PY%" -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy "%SRC%" dist_cy\_core.py >nul
if errorlevel 1 (
echo [WARN] Copy source failed, fallback
goto :NORMAL
)
"%PY%" -c "open('dist_cy/setup_cython.py','w').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
cd dist_cy
"%PY%" setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [WARN] Cython failed, fallback
goto :NORMAL
)
for %%f in (_core*.pyd) do set PYD=%%f
if "%PYD%"=="" (
cd ..
echo [WARN] No pyd, fallback
goto :NORMAL
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
"%PY%" -c "open('launcher.py','w').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
echo [4/6] Copy resources...
copy "%TOOLS%\adb.exe" . >nul
copy "%TOOLS%\AdbWinApi.dll" . >nul
copy "%TOOLS%\AdbWinUsbApi.dll" . >nul
copy "%TOOLS%\7za.exe" . >nul
if exist "%ROOT%\app.ico" copy "%ROOT%\app.ico" . >nul
echo [5/6] PyInstaller...
"%PY%" -m PyInstaller --onefile --windowed --name="%NAME%" --icon="%ROOT%\app.ico" --add-data "%TOOLS%\adb.exe;." --add-data "%TOOLS%\AdbWinApi.dll;." --add-data "%TOOLS%\AdbWinUsbApi.dll;." --add-data "%TOOLS%\7za.exe;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b
)
echo [6/6] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py 2>nul
rmdir /s /q build 2>nul
cd ..
goto :DONE
:NORMAL
echo [INFO] Normal PyInstaller...
"%PY%" -m PyInstaller --onefile --windowed --name="%NAME%" --icon="%ROOT%\app.ico" --add-data "%TOOLS%\adb.exe;." --add-data "%TOOLS%\AdbWinApi.dll;." --add-data "%TOOLS%\AdbWinUsbApi.dll;." --add-data "%TOOLS%\7za.exe;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --collect-all tkinter --uac-admin "%SRC%"
:DONE
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else if exist "dist\%NAME%.exe" (
echo Output: dist\%NAME%.exe
) else (
echo Check dist folder
)
pause
BIN
View File
Binary file not shown.
-92
View File
@@ -1,92 +0,0 @@
@echo off
chcp 65001 >nul
set NAME=启源Q07刷入工具
title %NAME% - Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b
)
for /f "delims=" %%i in ('where python') do set PY=%%i
echo Python: %PY%
echo [1/6] Installing deps...
%PY% -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
%PY% -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy app.py dist_cy\_core.py >nul
%PY% -c "open('dist_cy/setup_cython.py','w').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
cd dist_cy
%PY% setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [WARN] Cython failed, fallback
goto :NORMAL
)
for %%f in (_core*.pyd) do set PYD=%%f
if "%PYD%"=="" (
cd ..
echo [WARN] No pyd, fallback
goto :NORMAL
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
%PY% -c "open('launcher.py','w').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
echo [4/6] Copy resources...
copy ..\adb.exe . >nul
copy ..\AdbWinApi.dll . >nul
copy ..\AdbWinUsbApi.dll . >nul
if exist "..\app.ico" copy "..\app.ico" . >nul
echo [5/6] PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon=app.ico --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b
)
echo [6/6] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py 2>nul
rmdir /s /q build 2>nul
cd ..
goto :DONE
:NORMAL
cd /d "%~dp0"
echo [INFO] Normal PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon=app.ico --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --collect-all tkinter --uac-admin app.py
:DONE
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else if exist "dist\%NAME%.exe" (
echo Output: dist\%NAME%.exe
) else (
echo Check dist folder
)
pause
-94
View File
@@ -1,94 +0,0 @@
@echo off
chcp 65001 >nul
set NAME=长安逸动刷入工具
set SRC=app-install.py
title %NAME% - Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b
)
for /f "delims=" %%i in ('where python') do set PY=%%i
echo Python: %PY%
echo [1/6] Installing deps...
%PY% -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
%PY% -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy %SRC% dist_cy\_core.py >nul
%PY% -c "open('dist_cy/setup_cython.py','w').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
cd dist_cy
%PY% setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [WARN] Cython failed, fallback
goto :NORMAL
)
for %%f in (_core*.pyd) do set PYD=%%f
if "%PYD%"=="" (
cd ..
echo [WARN] No pyd, fallback
goto :NORMAL
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
%PY% -c "open('launcher.py','w').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
echo [4/6] Copy resources...
copy ..\adb.exe . >nul
copy ..\AdbWinApi.dll . >nul
copy ..\AdbWinUsbApi.dll . >nul
copy ..\7za.exe . >nul
if exist "..\app.ico" copy "..\app.ico" . >nul
echo [5/6] PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon=app.ico --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b
)
echo [6/6] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py 2>nul
rmdir /s /q build 2>nul
cd ..
goto :DONE
:NORMAL
cd /d "%~dp0"
echo [INFO] Normal PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon=app.ico --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --collect-all tkinter --uac-admin %SRC%
:DONE
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else if exist "dist\%NAME%.exe" (
echo Output: dist\%NAME%.exe
) else (
echo Check dist folder
)
pause
-94
View File
@@ -1,94 +0,0 @@
@echo off
chcp 65001 >nul
set NAME=启源Q07刷入工具
set SRC=app.py
title %NAME% - Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b
)
for /f "delims=" %%i in ('where python') do set PY=%%i
echo Python: %PY%
echo [1/6] Installing deps...
%PY% -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
%PY% -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy %SRC% dist_cy\_core.py >nul
%PY% -c "open('dist_cy/setup_cython.py','w').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
cd dist_cy
%PY% setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [WARN] Cython failed, fallback
goto :NORMAL
)
for %%f in (_core*.pyd) do set PYD=%%f
if "%PYD%"=="" (
cd ..
echo [WARN] No pyd, fallback
goto :NORMAL
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
%PY% -c "open('launcher.py','w').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
echo [4/6] Copy resources...
copy ..\adb.exe . >nul
copy ..\AdbWinApi.dll . >nul
copy ..\AdbWinUsbApi.dll . >nul
copy ..\7za.exe . >nul
if exist "..\app.ico" copy "..\app.ico" . >nul
echo [5/6] PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon=app.ico --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b
)
echo [6/6] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py 2>nul
rmdir /s /q build 2>nul
cd ..
goto :DONE
:NORMAL
cd /d "%~dp0"
echo [INFO] Normal PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon=app.ico --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --collect-all tkinter --uac-admin %SRC%
:DONE
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else if exist "dist\%NAME%.exe" (
echo Output: dist\%NAME%.exe
) else (
echo Check dist folder
)
pause
-94
View File
@@ -1,94 +0,0 @@
@echo off
chcp 65001 >nul
set NAME=深蓝S05刷入工具
set SRC=S05.py
title %NAME% - Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b
)
for /f "delims=" %%i in ('where python') do set PY=%%i
echo Python: %PY%
echo [1/6] Installing deps...
%PY% -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
%PY% -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy %SRC% dist_cy\_core.py >nul
%PY% -c "open('dist_cy/setup_cython.py','w').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
cd dist_cy
%PY% setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [WARN] Cython failed, fallback
goto :NORMAL
)
for %%f in (_core*.pyd) do set PYD=%%f
if "%PYD%"=="" (
cd ..
echo [WARN] No pyd, fallback
goto :NORMAL
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
%PY% -c "open('launcher.py','w').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
echo [4/6] Copy resources...
copy ..\adb.exe . >nul
copy ..\AdbWinApi.dll . >nul
copy ..\AdbWinUsbApi.dll . >nul
copy ..\7za.exe . >nul
if exist "..\app.ico" copy "..\app.ico" . >nul
echo [5/6] PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon=app.ico --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b
)
echo [6/6] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py 2>nul
rmdir /s /q build 2>nul
cd ..
goto :DONE
:NORMAL
cd /d "%~dp0"
echo [INFO] Normal PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon=app.ico --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --collect-all tkinter --uac-admin %SRC%
:DONE
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else if exist "dist\%NAME%.exe" (
echo Output: dist\%NAME%.exe
) else (
echo Check dist folder
)
pause
-94
View File
@@ -1,94 +0,0 @@
@echo off
chcp 65001 >nul
set NAME=X5plus刷入工具
set SRC=X5plusTool.py
title %NAME% - Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b
)
for /f "delims=" %%i in ('where python') do set PY=%%i
echo Python: %PY%
echo [1/6] Installing deps...
%PY% -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
%PY% -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy %SRC% dist_cy\_core.py >nul
%PY% -c "open('dist_cy/setup_cython.py','w').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
cd dist_cy
%PY% setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [WARN] Cython failed, fallback
goto :NORMAL
)
for %%f in (_core*.pyd) do set PYD=%%f
if "%PYD%"=="" (
cd ..
echo [WARN] No pyd, fallback
goto :NORMAL
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
%PY% -c "open('launcher.py','w').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
echo [4/6] Copy resources...
copy ..\adb.exe . >nul
copy ..\AdbWinApi.dll . >nul
copy ..\AdbWinUsbApi.dll . >nul
copy ..\7za.exe . >nul
if exist "..\app.ico" copy "..\app.ico" . >nul
echo [5/6] PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon=app.ico --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b
)
echo [6/6] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py 2>nul
rmdir /s /q build 2>nul
cd ..
goto :DONE
:NORMAL
cd /d "%~dp0"
echo [INFO] Normal PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon=app.ico --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --collect-all tkinter --uac-admin %SRC%
:DONE
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else if exist "dist\%NAME%.exe" (
echo Output: dist\%NAME%.exe
) else (
echo Check dist folder
)
pause
-94
View File
@@ -1,94 +0,0 @@
@echo off
chcp 65001 >nul
set NAME=长安逸动刷入工具
set SRC=app-yidong.py
title %NAME% - Build
echo ============================================================
echo %NAME% - Cython Build
echo ============================================================
echo.
where python >nul 2>&1
if errorlevel 1 (
echo [ERROR] Python not found
pause
exit /b
)
for /f "delims=" %%i in ('where python') do set PY=%%i
echo Python: %PY%
echo [1/6] Installing deps...
%PY% -m pip install pyinstaller cython pyzipper -q
if errorlevel 1 (
%PY% -m pip install pyinstaller cython pyzipper -q -i https://pypi.tuna.tsinghua.edu.cn/simple
)
echo [2/6] Clean...
if exist "dist_cy" rmdir /s /q dist_cy 2>nul
if exist "build" rmdir /s /q build 2>nul
if exist "dist" rmdir /s /q dist 2>nul
echo [3/6] Cython compile...
mkdir dist_cy 2>nul
copy %SRC% dist_cy\_core.py >nul
%PY% -c "open('dist_cy/setup_cython.py','w').write('from setuptools import setup\nfrom Cython.Build import cythonize\nsetup(ext_modules=cythonize(\"_core.py\", compiler_directives={\"language_level\":\"3\"}))\n')"
cd dist_cy
%PY% setup_cython.py build_ext --inplace
if errorlevel 1 (
cd ..
echo [WARN] Cython failed, fallback
goto :NORMAL
)
for %%f in (_core*.pyd) do set PYD=%%f
if "%PYD%"=="" (
cd ..
echo [WARN] No pyd, fallback
goto :NORMAL
)
echo PYD: %PYD%
copy "%PYD%" _core.pyd >nul
%PY% -c "open('launcher.py','w').write('# -*- coding: utf-8 -*-\nfrom _core import main\nmain()\n')"
echo [4/6] Copy resources...
copy ..\adb.exe . >nul
copy ..\AdbWinApi.dll . >nul
copy ..\AdbWinUsbApi.dll . >nul
copy ..\7za.exe . >nul
if exist "..\app.ico" copy "..\app.ico" . >nul
echo [5/6] PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon=app.ico --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --add-binary "_core.pyd;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --collect-all tkinter --uac-admin launcher.py
if errorlevel 1 (
cd ..
echo [ERROR] PyInstaller failed
pause
exit /b
)
echo [6/6] Cleanup...
del /q _core.py _core.c _core.pyd %PYD% launcher.py setup_cython.py 2>nul
rmdir /s /q build 2>nul
cd ..
goto :DONE
:NORMAL
cd /d "%~dp0"
echo [INFO] Normal PyInstaller...
%PY% -m PyInstaller --onefile --windowed --name="%NAME%" --icon=app.ico --add-data "adb.exe;." --add-data "AdbWinApi.dll;." --add-data "AdbWinUsbApi.dll;." --add-data "7za.exe;." --hidden-import=queue --hidden-import=threading --hidden-import=tkinter --hidden-import=zipfile --hidden-import=json --hidden-import=urllib --collect-all tkinter --uac-admin %SRC%
:DONE
echo.
echo Done.
if exist "dist_cy\dist\%NAME%.exe" (
echo Output: dist_cy\dist\%NAME%.exe
) else if exist "dist\%NAME%.exe" (
echo Output: dist\%NAME%.exe
) else (
echo Check dist folder
)
pause
View File
View File
+21905
View File
File diff suppressed because it is too large Load Diff
+123
View File
@@ -0,0 +1,123 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
import base64
import hashlib
import json
import os
import struct
import zlib
from pathlib import Path
DEFAULT_AAD = "Q05-Lidar init_boot resource v1"
FORMAT_MAGIC = {
"q05": (b"Q05R2\x00", "q05-lidar-resource-v2", DEFAULT_AAD),
"ez60": (b"EZ60R2\x00", "ez60-resource-v2", "Mazda-EZ60 init_boot resource v1"),
}
def b64u(data):
return base64.urlsafe_b64encode(data).decode("ascii").rstrip("=")
def decode_key_material(key_text):
text = str(key_text).strip()
if text.startswith("raw:"):
key = text.split(":", 1)[1].encode("utf-8")
elif len(text) == 64 and all(c in "0123456789abcdefABCDEF" for c in text):
key = bytes.fromhex(text)
elif len(text.encode("utf-8")) == 32:
key = text.encode("utf-8")
else:
key = base64.urlsafe_b64decode(text + "=" * (-len(text) % 4))
if len(key) != 32:
raise ValueError(f"key must decode to 32 bytes, got {len(key)} bytes")
return key
def main():
parser = argparse.ArgumentParser(
description="Encrypt a vehicle init_boot image into a resource dat file"
)
parser.add_argument("input_img", help="Magisk-patched init_boot image")
parser.add_argument(
"-o", "--output",
default="resource.dat",
help="Output encrypted resource file, default: resource.dat",
)
parser.add_argument(
"--vehicle",
choices=sorted(FORMAT_MAGIC.keys()),
default="q05",
help="Resource header/profile to write. Default: q05.",
)
parser.add_argument(
"--aad",
help="Optional AES-GCM AAD text. Defaults to the selected vehicle profile.",
)
parser.add_argument(
"--key",
help="Optional AES-256 key as base64url, 64-char hex, raw:TEXT, or 32-byte UTF-8 text. Omit to generate a random key.",
)
parser.add_argument(
"--no-compress",
action="store_true",
help="Disable zlib compression before encryption.",
)
args = parser.parse_args()
try:
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
except ImportError:
raise SystemExit(
"Missing dependency: cryptography. Install it with: "
"python -m pip install cryptography"
)
input_path = Path(args.input_img)
plain = input_path.read_bytes()
sha256 = hashlib.sha256(plain).hexdigest()
magic, resource_format, default_aad = FORMAT_MAGIC[args.vehicle]
aad = (args.aad or default_aad).encode("utf-8")
if args.key:
try:
key = decode_key_material(args.key)
except Exception as e:
raise SystemExit(str(e))
else:
key = os.urandom(32)
compression = "none" if args.no_compress else "zlib"
body = plain if args.no_compress else zlib.compress(plain, level=9)
nonce = os.urandom(12)
ciphertext = AESGCM(key).encrypt(nonce, body, aad)
header = {
"format": resource_format,
"cipher": "AES-256-GCM",
"kdf": "none",
"compression": compression,
"aad": aad.decode("utf-8"),
"nonce": b64u(nonce),
"sha256": sha256,
"plainSize": len(plain),
"packedSize": len(body),
}
output_path = Path(args.output)
header_bytes = json.dumps(header, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
output_path.write_bytes(magic + struct.pack(">I", len(header_bytes)) + header_bytes + ciphertext)
print("resource.dat created")
print(f"input: {input_path}")
print(f"output: {output_path}")
print(f"plainSize: {len(plain)}")
print(f"packedSize: {len(body)}")
print(f"sha256: {sha256}")
print(f"cloudKey: {b64u(key)}")
if __name__ == "__main__":
main()
+53
View File
@@ -0,0 +1,53 @@
[defaults]
base_features = sparse_super,large_file,filetype,dir_index,ext_attr
default_mntopts = acl,user_xattr
enable_periodic_fsck = 0
blocksize = 4096
inode_size = 256
inode_ratio = 16384
reserved_ratio = 1.0
[fs_types]
ext3 = {
features = has_journal
}
ext4 = {
features = has_journal,extent,huge_file,dir_nlink,extra_isize,uninit_bg
inode_size = 256
}
ext4dev = {
features = has_journal,extent,huge_file,flex_bg,inline_data,64bit,dir_nlink,extra_isize
inode_size = 256
options = test_fs=1
}
small = {
blocksize = 1024
inode_size = 128
inode_ratio = 4096
}
floppy = {
blocksize = 1024
inode_size = 128
inode_ratio = 8192
}
big = {
inode_ratio = 32768
}
huge = {
inode_ratio = 65536
}
news = {
inode_ratio = 4096
}
largefile = {
inode_ratio = 1048576
blocksize = -1
}
largefile4 = {
inode_ratio = 4194304
blocksize = -1
}
hurd = {
blocksize = 4096
inode_size = 128
}
+2
View File
@@ -0,0 +1,2 @@
Pkg.UserSrc=false
Pkg.Revision=37.0.0
+195
View File
@@ -0,0 +1,195 @@
;
; Android WinUsb driver installation.
;
[Version]
Signature = "$Windows NT$"
Class = AndroidUsbDeviceClass
ClassGuid = {3F966BD9-FA04-4ec5-991C-D326973B5128}
Provider = %ProviderName%
DriverVer = 08/28/2014,11.0.0000.00000
CatalogFile.NTx86 = androidwinusb86.cat
CatalogFile.NTamd64 = androidwinusba64.cat
[ClassInstall32]
Addreg = AndroidWinUsbClassReg
[AndroidWinUsbClassReg]
HKR,,,0,%ClassName%
HKR,,Icon,,-1
[Manufacturer]
%ProviderName% = Google, NTx86, NTamd64
[Google.NTx86]
;Google Nexus One
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_0D02
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_0D02&MI_01
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_4E11
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4E12&MI_01
;Google Nexus S
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_4E21
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4E22&MI_01
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_4E23
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4E24&MI_01
;Google Nexus 7
%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_4E40
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4E42&MI_01
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4E44&MI_01
;Google Nexus Q
%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_2C10
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_2C11
;Google Nexus (generic)
%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_4EE0
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4EE2&MI_01
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4EE4&MI_02
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4EE6&MI_01
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4EE7
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_D001
;Google Glass
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_9001
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_9001&MI_01
;Google Glass EE1
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_9003
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_9003&MI_01
%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_9004
;Google Glass EE2
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_9005
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_9005&MI_00
%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_9006
;Project Tango (generic)
%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_4D00
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4D02&MI_01
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4D04&MI_02
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4D06&MI_01
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4D07
[Google.NTamd64]
;Google Nexus One
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_0D02
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_0D02&MI_01
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_4E11
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4E12&MI_01
;Google Nexus S
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_4E21
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4E22&MI_01
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_4E23
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4E24&MI_01
;Google Nexus 7
%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_4E40
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4E42&MI_01
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4E44&MI_01
;Google Nexus Q
%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_2C10
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_2C11
;Google Nexus (generic)
%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_4EE0
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4EE2&MI_01
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4EE4&MI_02
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4EE6&MI_01
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4EE7
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_D001
;Google Glass
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_9001
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_9001&MI_01
;Google Glass EE1
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_9003
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_9003&MI_01
%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_9004
;Google Glass EE2
%SingleAdbInterface% = USB_Install, USB\VID_18D1&PID_9005
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_9005&MI_00
%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_9006
;Project Tango (generic)
%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_4D00
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4D02&MI_01
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4D04&MI_02
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4D06&MI_01
%CompositeAdbInterface% = USB_Install, USB\VID_18D1&PID_4D07
[USB_Install]
Include = winusb.inf
Needs = WINUSB.NT
[USB_Install.Services]
Include = winusb.inf
AddService = WinUSB,0x00000002,WinUSB_ServiceInstall
[WinUSB_ServiceInstall]
DisplayName = %WinUSB_SvcDesc%
ServiceType = 1
StartType = 3
ErrorControl = 1
ServiceBinary = %12%\WinUSB.sys
[USB_Install.Wdf]
KmdfService = WINUSB, WinUSB_Install
[WinUSB_Install]
KmdfLibraryVersion = 1.9
[USB_Install.HW]
AddReg = Dev_AddReg
[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,"{F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}"
[USB_Install.CoInstallers]
AddReg = CoInstallers_AddReg
CopyFiles = CoInstallers_CopyFiles
[CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01009.dll,WdfCoInstaller","WinUSBCoInstaller2.dll"
[CoInstallers_CopyFiles]
WinUSBCoInstaller2.dll
WdfCoInstaller01009.dll
[DestinationDirs]
CoInstallers_CopyFiles=11
[SourceDisksNames]
1 = %DISK_NAME%,,,\i386
2 = %DISK_NAME%,,,\amd64
[SourceDisksFiles.x86]
WinUSBCoInstaller2.dll = 1
WdfCoInstaller01009.dll = 1
[SourceDisksFiles.amd64]
WinUSBCoInstaller2.dll = 2
WdfCoInstaller01009.dll = 2
[Strings]
ProviderName = "Google, Inc."
SingleAdbInterface = "Android ADB Interface"
CompositeAdbInterface = "Android Composite ADB Interface"
SingleBootLoaderInterface = "Android Bootloader Interface"
WinUSB_SvcDesc = "Android USB Driver"
DISK_NAME = "Android WinUsb installation disk"
ClassName = "Android Device"
Binary file not shown.
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
Pkg.Revision=13
Archive.HostOs=WINDOWS
Extra.Path=usb_driver