[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6BVHHS3H45VCW3AJE1P0613":3,"skill-same:01M6BVHHS3H45VCW3AJE1P0613":96},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":49,"commitSha":50,"skillDirectory":51,"forksCount":52,"repositoryHtmlUrl":53,"repositoryHomepageUrl":54,"ownerHtmlUrl":55,"ownerBlogUrl":54,"ownerDescription":56,"updatedAt":57,"install":58,"resources":71},"01M6BVHHS3H45VCW3AJE1P0613","android-build-test",null,"Build and test ezEngine on Android devices. Use this skill when building APKs, deploying to Android devices, running tests on Android, debugging Android test failures, or setting up the Android development environment for ezEngine.","ezEngine\u002FezEngine","ezEngine","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F7082461?v=4","01M6BVHA0EZGW8WD6GQ8G3HJV3","ezEngine Project","01M6BVHA4YBS7ZFBN8Y2GGZ5CW",2038,"MIT","https:\u002F\u002Fgithub.com\u002FezEngine\u002FezEngine\u002Fblob\u002Fdev\u002F.claude\u002Fskills\u002Fandroid-build-test\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"test","android build","android build test","build test","android","build","use","running","when","for","development environment","tests","up","environment","android development","devices","running tests","development","debugging","build and test","2026-11-10 10:12:30",false,"---\nname: android-build-test\ndescription: Build and test ezEngine on Android devices. Use this skill when building APKs, deploying to Android devices, running tests on Android, debugging Android test failures, or setting up the Android development environment for ezEngine.\n---\n\n# Building and Testing ezEngine on Android\n\nThis skill covers the full Android workflow: environment setup, CMake configuration, building APKs, deploying to devices, and running tests.\n\n## Prerequisites\n\n### Installing Android SDK\u002FNDK Dependencies\n\nRun the dependency installer once to download the Android SDK, NDK, build-tools, and JDK into `Workspace\u002Fshared\u002Fandroid\u002F`, unless the folder already exists:\n\n```bash\npwsh .\u002FUtilities\u002FAndroid\u002FInstallAndroidDependencies.ps1 -acceptLicence\n```\n\nThis downloads and configures:\n- Android SDK command-line tools\n- Android NDK 26.1.10909125\n- Android build-tools 34.0.0\n- JDK 17\n- Android platform API 29\n\n### Setting Environment Variables\n\nBefore running any Android commands in the terminal, source the environment setup script:\n\n**Bash:**\n```bash\nsource Utilities\u002FAndroid\u002FSetupAndroidEnvVars.sh\n```\n\n**PowerShell:**\n```powershell\n. .\u002FUtilities\u002FAndroid\u002FSetupAndroidEnvVars.ps1\n```\n\nThis exports `ANDROID_HOME`, `ANDROID_NDK_HOME`, `JAVA_HOME` and adds `platform-tools` (adb) to `PATH`.\n\nThe CMake presets also set these variables internally, so they are only needed for manual adb\u002Fdevice interaction.\n\n## CMake Presets\n\nAll Android presets inherit from the hidden `android-base` preset which configures the NDK toolchain, Ninja generator, and Vulkan support.\n\n| Preset | ABI | Build Type |\n|---|---|---|\n| `android-arm64-debug` | arm64-v8a | Debug |\n| `android-arm64-dev` | arm64-v8a | Dev |\n| `android-arm64-shipping` | arm64-v8a | Shipping |\n| `android-x64-debug` | x86_64 | Debug |\n| `android-x64-dev` | x86_64 | Dev |\n| `android-x64-shipping` | x86_64 | Shipping |\n\nUse `arm64` presets for physical devices and `x64` presets for x86_64 emulators.\n\n## Building\n\n### Shader Compilation\n\nBefore building on Android, make sure to compile the Vulkan shaders on the host OS. Build the ShaderCompiler first (Linux or Windows build target), then run:\n\n```bash\npwsh .\u002FUtilities\u002FAndroid\u002FCompileShaders.ps1 -BinariesDir .\u002FOutput\u002FBin\u002FLinuxNinjaGccDebug64\n```\n\nThis compiles shaders for `Data\u002FBase`, `Data\u002FUnitTests`, and `Data\u002FSamples\u002FShaderExplorer`. You need a working Linux build of `ShaderCompiler` before compiling shaders.\n\n\n### Configure and Build Everything\n\n```bash\ncmake --preset android-arm64-debug\ncmake --build Workspace\u002Fandroid-arm64-debug\n```\n\n### Build a Specific Target\n\n```bash\ncmake --build Workspace\u002Fandroid-arm64-debug --target FoundationTest\n```\n\nBuild outputs (APKs and shared libraries) go to: `Output\u002FBin\u002FAndroidNinjaClangDebugArm64\u002F`\n\nThe output directory name follows the pattern `AndroidNinjaClang\u003CBuildType>Arm64` (or `X64` for x86_64).\n\n| Preset | Output Directory |\n|---|---|\n| `android-arm64-debug` | `Output\u002FBin\u002FAndroidNinjaClangDebugArm64\u002F` |\n| `android-arm64-dev` | `Output\u002FBin\u002FAndroidNinjaClangDevArm64\u002F` |\n| `android-x64-debug` | `Output\u002FBin\u002FAndroidNinjaClangDebugX64\u002F` |\n\n### Available Test Targets\n\n- `FoundationTest` — Foundation library tests (math, strings, containers, IO, threading, etc.)\n- `CoreTest` — Core library tests (resource system, world, etc.)\n- `RendererTest` — Renderer tests (requires Vulkan on device)\n- `ToolsFoundationTest` — Tools foundation tests\n\nEach target produces an APK at `Output\u002FBin\u002F\u003COutputDir>\u002F\u003CTargetName>.apk`.\n\n## Connecting to a Device\n\n### Physical Device via ADB over TCP\u002FIP\n\nIf no device is present, you can connect a physical device over TCP\u002FIP using ADB:\n\n```bash\nsource Utilities\u002FAndroid\u002FSetupAndroidEnvVars.sh\nadb connect \u003Cdevice-ip>:5555\nadb -s \u003Cdevice-ip>:5555 wait-for-device\n```\n\n### Verify Connection\n\nGet the name and port of the connected device using:\n\n```bash\nadb devices\n```\n\n### Wake and Unlock the Device\n\nBefore launching a test, wake the device and dismiss the keyguard so the native activity can create its window and receive `APP_CMD_INIT_WINDOW`:\n\n```bash\nsource Utilities\u002FAndroid\u002FSetupAndroidEnvVars.sh\n\n# Stop a test process left behind by an earlier timeout, if necessary.\nadb -s \u003Cadb-device-name> shell am force-stop com.ezengine.RendererTest\n\nadb -s \u003Cadb-device-name> shell input keyevent KEYCODE_WAKEUP\n```\n\nVerify that the device is awake before starting the test:\n\n```bash\nadb -s \u003Cadb-device-name> shell dumpsys power | grep 'mWakefulness='\n```\n\nThe expected output contains `mWakefulness=Awake`.\n\n## Running Tests on Device\n\n### Using AndroidTest.ps1\n\nThe `Utilities\u002FAndroid\u002FAndroidTest.ps1` script handles the full test lifecycle: install APK, launch activity, capture logcat, detect pass\u002Ffail, download artifacts.\n\n```bash\npwsh .\u002FUtilities\u002FAndroid\u002FAndroidTest.ps1 \\\n  -deviceAdb \u003Cadb-device-name> \\\n  -packageName com.ezengine.FoundationTest \\\n  -activityName android.app.NativeActivity \\\n  -outputFolder .\u002FOutput \\\n  -apk .\u002FOutput\u002FBin\u002FAndroidNinjaClangDebugArm64\u002FFoundationTest.apk\n```\n\n#### Passing Command-Line Arguments\n\nUse `-arguments` to pass the same flags you would use on desktop (e.g., `-noGui`, `-filter`):\n\n```bash\npwsh .\u002FUtilities\u002FAndroid\u002FAndroidTest.ps1 \\\n  -deviceAdb \u003Cadb-device-name> \\\n  -packageName com.ezengine.FoundationTest \\\n  -activityName android.app.NativeActivity \\\n  -outputFolder .\u002FOutput \\\n  -apk .\u002FOutput\u002FBin\u002FAndroidNinjaClangDebugArm64\u002FFoundationTest.apk \\\n  -arguments \"-noGui -filter Frustum\"\n```\n\nWithout `-filter` all tests run. `-filter` is not a regex, it does a case insensitive *contains* check against both test and sub-test names, with `*` and `?` available as shell style wildcards for a full match pattern.\n\nThe arguments are delivered to the native code via an Android Intent string extra (`args`), retrieved via JNI in `AndroidTestApplication.cpp`, parsed into argc\u002Fargv, and forwarded to `InitTestFramework`.\n\n#### AndroidTest.ps1 Parameters\n\n| Parameter | Required | Description |\n|---|---|---|\n| `-deviceAdb` | Yes | Device address for adb (e.g., `192.168.178.77:5555`) |\n| `-packageName` | Yes | Android package name (e.g., `com.ezengine.FoundationTest`) |\n| `-activityName` | Yes | Activity class name (always `android.app.NativeActivity`) |\n| `-outputFolder` | Yes | Local directory for logcat output and test artifacts |\n| `-apk` | No | Path to APK to install before running |\n| `-arguments` | No | Command-line arguments to pass to the test framework |\n| `-MessageBoxOnError` | No | Show error dialog on Windows (switch) |\n\n### Test Package Names\n\n| Test | Package Name |\n|---|---|\n| FoundationTest | `com.ezengine.FoundationTest` |\n| CoreTest | `com.ezengine.CoreTest` |\n| RendererTest | `com.ezengine.RendererTest` |\n| ToolsFoundationTest | `com.ezengine.ToolsFoundationTest` |\n\n\n### Manual Testing via ADB\n\nIf you need to launch a test manually without the script:\n\n```bash\nsource Utilities\u002FAndroid\u002FSetupAndroidEnvVars.sh\n\n# Install\nadb -s \u003Cadb-device-name> install -r -t Output\u002FBin\u002FAndroidNinjaClangDebugArm64\u002FFoundationTest.apk\n\n# Launch without arguments\nadb -s \u003Cadb-device-name> shell am start -n com.ezengine.FoundationTest\u002Fandroid.app.NativeActivity\n\n# Launch with arguments (note the quoting)\nadb -s \u003Cadb-device-name> shell \"am start -n com.ezengine.FoundationTest\u002Fandroid.app.NativeActivity --es args '-noGui -filter Frustum'\"\n\n# Watch logcat\nadb -s \u003Cadb-device-name> logcat -s ezEngine\n```\n\nImportant: When passing arguments containing dashes via `adb shell am start --es`, you **must** wrap the entire `am start` command in double quotes and the argument value in single quotes. Otherwise, `am` will misinterpret the dashes as its own flags.\n\n### Put the Device Back to Sleep\n\nAfter all test runs and artifact downloads have completed, turn off the display:\n\n```bash\nadb -s \u003Cadb-device-name> shell input keyevent KEYCODE_SLEEP\n```\n\nVerify that the device returned to sleep:\n\n```bash\nadb -s \u003Cadb-device-name> shell dumpsys power | grep 'mWakefulness='\n```\n\nThe expected output contains `mWakefulness=Asleep`.\n\n## Debugging\n\n### Reading Logcat\n\nAll ezEngine log output uses the tag `ezEngine`:\n\n```bash\n# Live logcat filtered to ezEngine\nadb -s \u003Cdevice>:5555 logcat -s ezEngine\n\n# Dump existing logcat\nadb -s \u003Cdevice>:5555 logcat -d -s ezEngine\n\n# Clear logcat before a test run\nadb -s \u003Cdevice>:5555 logcat --clear\n```\n\n### LLDB Remote Debugging\n\nUse the provided debug script:\n\n```bash\npwsh .\u002FUtilities\u002FAndroid\u002FDbgAndroidLldb.ps1\n```\n\n### Common Issues\n\n**Test runs all tests despite `-filter`**: The arguments must survive multiple quoting layers (PowerShell → adb → Android shell → `am`). When using `AndroidTest.ps1`, pass arguments as a single string: `-arguments \"-filter Frustum\"`. When using `adb` directly, wrap the whole `am start` command: `adb shell \"am start ... --es args '-filter Frustum'\"`.\n\n**APK install fails**: Ensure the device is connected (`adb devices`), USB debugging is enabled, and the device allows unknown sources. The script retries up to 6 times.\n\n**Activity crashes immediately**: Check logcat for the full stack trace. Common causes include missing Vulkan drivers (for RendererTest) or missing shader cache files.\n\n**Test times out without any ezEngine log output**: Check the device power state with `adb shell dumpsys power`. If the display is asleep, the native activity can remain stopped without receiving `APP_CMD_INIT_WINDOW`, so the engine and test framework never start. Wake and unlock the device before retrying.\n\n**Build fails with NDK not found**: Ensure dependencies are installed (`InstallAndroidDependencies.ps1`) and environment variables are set. The CMake presets expect the NDK at `Workspace\u002Fshared\u002Fandroid\u002Fndk\u002F26.1.10909125`.\n\n## CI Pipeline Reference\n\nThe CI pipeline in `Code\u002FBuildSystem\u002FAzurePipelines\u002FAndroid-arm64.yml` performs the following steps:\n\n1. Configure and build `linux-clang-dev` (host tools only, specifically `ShaderCompiler`)\n2. Compile Vulkan shaders using the host ShaderCompiler\n3. Install Android dependencies\n4. Configure and build `android-arm64-dev`\n5. Connect to the physical test device\n6. Run FoundationTest, CoreTest, RendererTest, ToolsFoundationTest sequentially\n7. Disconnect from device and publish test artifacts\n\n## Key Source Files\n\n- `Utilities\u002FAndroid\u002FAndroidTest.ps1` — Test runner script (install, launch, logcat, pass\u002Ffail detection)\n- `Utilities\u002FAndroid\u002FAndroidUtils.ps1` — Shared utilities (adb wrappers, retry logic, file copy)\n- `Utilities\u002FAndroid\u002FInstallAndroidDependencies.ps1` — SDK\u002FNDK\u002FJDK dependency installer\n- `Utilities\u002FAndroid\u002FCompileShaders.ps1` — Vulkan shader compiler wrapper\n- `Utilities\u002FAndroid\u002FSetupAndroidEnvVars.sh` — Bash environment variable setup\n- `Utilities\u002FAndroid\u002FSetupAndroidEnvVars.ps1` — PowerShell environment variable setup\n- `Utilities\u002FAndroid\u002FBuildApk.ps1` — APK packaging script (called by CMake)\n- `Code\u002FUnitTests\u002FTestFramework\u002FPlatform\u002FAndroid\u002FAndroidTestApplication.cpp` — Native activity lifecycle and Intent argument retrieval\n- `Code\u002FUnitTests\u002FTestFramework\u002FPlatform\u002FAndroid\u002FTestFrameworkEntryPoint_Platform.h` — Android test entry point macro\n- `Code\u002FEngine\u002FFoundation\u002FPlatform\u002FAndroid\u002FUtils\u002FAndroidJni.h` — JNI wrapper classes (ezJniAttachment, ezJniObject, ezJniString)\n- `CMakePresets.json` — Android CMake preset definitions\n","# Building and Testing ezEngine on Android\n\nThis skill covers the full Android workflow: environment setup, CMake configuration, building APKs, deploying to devices, and running tests.\n\n## Prerequisites\n\n### Installing Android SDK\u002FNDK Dependencies\n\nRun the dependency installer once to download the Android SDK, NDK, build-tools, and JDK into `Workspace\u002Fshared\u002Fandroid\u002F`, unless the folder already exists:\n\n```bash\npwsh .\u002FUtilities\u002FAndroid\u002FInstallAndroidDependencies.ps1 -acceptLicence\n```\n\nThis downloads and configures:\n- Android SDK command-line tools\n- Android NDK 26.1.10909125\n- Android build-tools 34.0.0\n- JDK 17\n- Android platform API 29\n\n### Setting Environment Variables\n\nBefore running any Android commands in the terminal, source the environment setup script:\n\n**Bash:**\n```bash\nsource Utilities\u002FAndroid\u002FSetupAndroidEnvVars.sh\n```\n\n**PowerShell:**\n```powershell\n. .\u002FUtilities\u002FAndroid\u002FSetupAndroidEnvVars.ps1\n```\n\nThis exports `ANDROID_HOME`, `ANDROID_NDK_HOME`, `JAVA_HOME` and adds `platform-tools` (adb) to `PATH`.\n\nThe CMake presets also set these variables internally, so they are only needed for manual adb\u002Fdevice interaction.\n\n## CMake Presets\n\nAll Android presets inherit from the hidden `android-base` preset which configures the NDK toolchain, Ninja generator, and Vulkan support.\n\n| Preset | ABI | Build Type |\n|---|---|---|\n| `android-arm64-debug` | arm64-v8a | Debug |\n| `android-arm64-dev` | arm64-v8a | Dev |\n| `android-arm64-shipping` | arm64-v8a | Shipping |\n| `android-x64-debug` | x86_64 | Debug |\n| `android-x64-dev` | x86_64 | Dev |\n| `android-x64-shipping` | x86_64 | Shipping |\n\nUse `arm64` presets for physical devices and `x64` presets for x86_64 emulators.\n\n## Building\n\n### Shader Compilation\n\nBefore building on Android, make sure to compile the Vulkan shaders on the host OS. Build the ShaderCompiler first (Linux or Windows build target), then run:\n\n```bash\npwsh .\u002FUtilities\u002FAndroid\u002FCompileShaders.ps1 -BinariesDir .\u002FOutput\u002FBin\u002FLinuxNinjaGccDebug64\n```\n\nThis compiles shaders for `Data\u002FBase`, `Data\u002FUnitTests`, and `Data\u002FSamples\u002FShaderExplorer`. You need a working Linux build of `ShaderCompiler` before compiling shaders.\n\n\n### Configure and Build Everything\n\n```bash\ncmake --preset android-arm64-debug\ncmake --build Workspace\u002Fandroid-arm64-debug\n```\n\n### Build a Specific Target\n\n```bash\ncmake --build Workspace\u002Fandroid-arm64-debug --target FoundationTest\n```\n\nBuild outputs (APKs and shared libraries) go to: `Output\u002FBin\u002FAndroidNinjaClangDebugArm64\u002F`\n\nThe output directory name follows the pattern `AndroidNinjaClang\u003CBuildType>Arm64` (or `X64` for x86_64).\n\n| Preset | Output Directory |\n|---|---|\n| `android-arm64-debug` | `Output\u002FBin\u002FAndroidNinjaClangDebugArm64\u002F` |\n| `android-arm64-dev` | `Output\u002FBin\u002FAndroidNinjaClangDevArm64\u002F` |\n| `android-x64-debug` | `Output\u002FBin\u002FAndroidNinjaClangDebugX64\u002F` |\n\n### Available Test Targets\n\n- `FoundationTest` — Foundation library tests (math, strings, containers, IO, threading, etc.)\n- `CoreTest` — Core library tests (resource system, world, etc.)\n- `RendererTest` — Renderer tests (requires Vulkan on device)\n- `ToolsFoundationTest` — Tools foundation tests\n\nEach target produces an APK at `Output\u002FBin\u002F\u003COutputDir>\u002F\u003CTargetName>.apk`.\n\n## Connecting to a Device\n\n### Physical Device via ADB over TCP\u002FIP\n\nIf no device is present, you can connect a physical device over TCP\u002FIP using ADB:\n\n```bash\nsource Utilities\u002FAndroid\u002FSetupAndroidEnvVars.sh\nadb connect \u003Cdevice-ip>:5555\nadb -s \u003Cdevice-ip>:5555 wait-for-device\n```\n\n### Verify Connection\n\nGet the name and port of the connected device using:\n\n```bash\nadb devices\n```\n\n### Wake and Unlock the Device\n\nBefore launching a test, wake the device and dismiss the keyguard so the native activity can create its window and receive `APP_CMD_INIT_WINDOW`:\n\n```bash\nsource Utilities\u002FAndroid\u002FSetupAndroidEnvVars.sh\n\n# Stop a test process left behind by an earlier timeout, if necessary.\nadb -s \u003Cadb-device-name> shell am force-stop com.ezengine.RendererTest\n\nadb -s \u003Cadb-device-name> shell input keyevent KEYCODE_WAKEUP\n```\n\nVerify that the device is awake before starting the test:\n\n```bash\nadb -s \u003Cadb-device-name> shell dumpsys power | grep 'mWakefulness='\n```\n\nThe expected output contains `mWakefulness=Awake`.\n\n## Running Tests on Device\n\n### Using AndroidTest.ps1\n\nThe `Utilities\u002FAndroid\u002FAndroidTest.ps1` script handles the full test lifecycle: install APK, launch activity, capture logcat, detect pass\u002Ffail, download artifacts.\n\n```bash\npwsh .\u002FUtilities\u002FAndroid\u002FAndroidTest.ps1 \\\n  -deviceAdb \u003Cadb-device-name> \\\n  -packageName com.ezengine.FoundationTest \\\n  -activityName android.app.NativeActivity \\\n  -outputFolder .\u002FOutput \\\n  -apk .\u002FOutput\u002FBin\u002FAndroidNinjaClangDebugArm64\u002FFoundationTest.apk\n```\n\n#### Passing Command-Line Arguments\n\nUse `-arguments` to pass the same flags you would use on desktop (e.g., `-noGui`, `-filter`):\n\n```bash\npwsh .\u002FUtilities\u002FAndroid\u002FAndroidTest.ps1 \\\n  -deviceAdb \u003Cadb-device-name> \\\n  -packageName com.ezengine.FoundationTest \\\n  -activityName android.app.NativeActivity \\\n  -outputFolder .\u002FOutput \\\n  -apk .\u002FOutput\u002FBin\u002FAndroidNinjaClangDebugArm64\u002FFoundationTest.apk \\\n  -arguments \"-noGui -filter Frustum\"\n```\n\nWithout `-filter` all tests run. `-filter` is not a regex, it does a case insensitive *contains* check against both test and sub-test names, with `*` and `?` available as shell style wildcards for a full match pattern.\n\nThe arguments are delivered to the native code via an Android Intent string extra (`args`), retrieved via JNI in `AndroidTestApplication.cpp`, parsed into argc\u002Fargv, and forwarded to `InitTestFramework`.\n\n#### AndroidTest.ps1 Parameters\n\n| Parameter | Required | Description |\n|---|---|---|\n| `-deviceAdb` | Yes | Device address for adb (e.g., `192.168.178.77:5555`) |\n| `-packageName` | Yes | Android package name (e.g., `com.ezengine.FoundationTest`) |\n| `-activityName` | Yes | Activity class name (always `android.app.NativeActivity`) |\n| `-outputFolder` | Yes | Local directory for logcat output and test artifacts |\n| `-apk` | No | Path to APK to install before running |\n| `-arguments` | No | Command-line arguments to pass to the test framework |\n| `-MessageBoxOnError` | No | Show error dialog on Windows (switch) |\n\n### Test Package Names\n\n| Test | Package Name |\n|---|---|\n| FoundationTest | `com.ezengine.FoundationTest` |\n| CoreTest | `com.ezengine.CoreTest` |\n| RendererTest | `com.ezengine.RendererTest` |\n| ToolsFoundationTest | `com.ezengine.ToolsFoundationTest` |\n\n\n### Manual Testing via ADB\n\nIf you need to launch a test manually without the script:\n\n```bash\nsource Utilities\u002FAndroid\u002FSetupAndroidEnvVars.sh\n\n# Install\nadb -s \u003Cadb-device-name> install -r -t Output\u002FBin\u002FAndroidNinjaClangDebugArm64\u002FFoundationTest.apk\n\n# Launch without arguments\nadb -s \u003Cadb-device-name> shell am start -n com.ezengine.FoundationTest\u002Fandroid.app.NativeActivity\n\n# Launch with arguments (note the quoting)\nadb -s \u003Cadb-device-name> shell \"am start -n com.ezengine.FoundationTest\u002Fandroid.app.NativeActivity --es args '-noGui -filter Frustum'\"\n\n# Watch logcat\nadb -s \u003Cadb-device-name> logcat -s ezEngine\n```\n\nImportant: When passing arguments containing dashes via `adb shell am start --es`, you **must** wrap the entire `am start` command in double quotes and the argument value in single quotes. Otherwise, `am` will misinterpret the dashes as its own flags.\n\n### Put the Device Back to Sleep\n\nAfter all test runs and artifact downloads have completed, turn off the display:\n\n```bash\nadb -s \u003Cadb-device-name> shell input keyevent KEYCODE_SLEEP\n```\n\nVerify that the device returned to sleep:\n\n```bash\nadb -s \u003Cadb-device-name> shell dumpsys power | grep 'mWakefulness='\n```\n\nThe expected output contains `mWakefulness=Asleep`.\n\n## Debugging\n\n### Reading Logcat\n\nAll ezEngine log output uses the tag `ezEngine`:\n\n```bash\n# Live logcat filtered to ezEngine\nadb -s \u003Cdevice>:5555 logcat -s ezEngine\n\n# Dump existing logcat\nadb -s \u003Cdevice>:5555 logcat -d -s ezEngine\n\n# Clear logcat before a test run\nadb -s \u003Cdevice>:5555 logcat --clear\n```\n\n### LLDB Remote Debugging\n\nUse the provided debug script:\n\n```bash\npwsh .\u002FUtilities\u002FAndroid\u002FDbgAndroidLldb.ps1\n```\n\n### Common Issues\n\n**Test runs all tests despite `-filter`**: The arguments must survive multiple quoting layers (PowerShell → adb → Android shell → `am`). When using `AndroidTest.ps1`, pass arguments as a single string: `-arguments \"-filter Frustum\"`. When using `adb` directly, wrap the whole `am start` command: `adb shell \"am start ... --es args '-filter Frustum'\"`.\n\n**APK install fails**: Ensure the device is connected (`adb devices`), USB debugging is enabled, and the device allows unknown sources. The script retries up to 6 times.\n\n**Activity crashes immediately**: Check logcat for the full stack trace. Common causes include missing Vulkan drivers (for RendererTest) or missing shader cache files.\n\n**Test times out without any ezEngine log output**: Check the device power state with `adb shell dumpsys power`. If the display is asleep, the native activity can remain stopped without receiving `APP_CMD_INIT_WINDOW`, so the engine and test framework never start. Wake and unlock the device before retrying.\n\n**Build fails with NDK not found**: Ensure dependencies are installed (`InstallAndroidDependencies.ps1`) and environment variables are set. The CMake presets expect the NDK at `Workspace\u002Fshared\u002Fandroid\u002Fndk\u002F26.1.10909125`.\n\n## CI Pipeline Reference\n\nThe CI pipeline in `Code\u002FBuildSystem\u002FAzurePipelines\u002FAndroid-arm64.yml` performs the following steps:\n\n1. Configure and build `linux-clang-dev` (host tools only, specifically `ShaderCompiler`)\n2. Compile Vulkan shaders using the host ShaderCompiler\n3. Install Android dependencies\n4. Configure and build `android-arm64-dev`\n5. Connect to the physical test device\n6. Run FoundationTest, CoreTest, RendererTest, ToolsFoundationTest sequentially\n7. Disconnect from device and publish test artifacts\n\n## Key Source Files\n\n- `Utilities\u002FAndroid\u002FAndroidTest.ps1` — Test runner script (install, launch, logcat, pass\u002Ffail detection)\n- `Utilities\u002FAndroid\u002FAndroidUtils.ps1` — Shared utilities (adb wrappers, retry logic, file copy)\n- `Utilities\u002FAndroid\u002FInstallAndroidDependencies.ps1` — SDK\u002FNDK\u002FJDK dependency installer\n- `Utilities\u002FAndroid\u002FCompileShaders.ps1` — Vulkan shader compiler wrapper\n- `Utilities\u002FAndroid\u002FSetupAndroidEnvVars.sh` — Bash environment variable setup\n- `Utilities\u002FAndroid\u002FSetupAndroidEnvVars.ps1` — PowerShell environment variable setup\n- `Utilities\u002FAndroid\u002FBuildApk.ps1` — APK packaging script (called by CMake)\n- `Code\u002FUnitTests\u002FTestFramework\u002FPlatform\u002FAndroid\u002FAndroidTestApplication.cpp` — Native activity lifecycle and Intent argument retrieval\n- `Code\u002FUnitTests\u002FTestFramework\u002FPlatform\u002FAndroid\u002FTestFrameworkEntryPoint_Platform.h` — Android test entry point macro\n- `Code\u002FEngine\u002FFoundation\u002FPlatform\u002FAndroid\u002FUtils\u002FAndroidJni.h` — JNI wrapper classes (ezJniAttachment, ezJniObject, ezJniString)\n- `CMakePresets.json` — Android CMake preset definitions\n",{"name":5,"description":7},"dev","fb0a2478e13846abdca29b67c73595619b27e6f3",".claude\u002Fskills\u002Fandroid-build-test",268,"https:\u002F\u002Fgithub.com\u002FezEngine\u002FezEngine","https:\u002F\u002FezEngine.net","https:\u002F\u002Fgithub.com\u002FezEngine","A free C++ game engine","2026-11-13 20:16:13",{"source":8,"skillName":5,"commands":59,"prompt":69,"zipAvailable":70},[60,63,66],{"tool":61,"command":62},"npx","npx skills add ezEngine\u002FezEngine --skill android-build-test",{"tool":64,"command":65},"bunx","bunx skills add ezEngine\u002FezEngine --skill android-build-test",{"tool":67,"command":68},"pnpm","pnpm dlx skills add ezEngine\u002FezEngine --skill android-build-test","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FezEngine\u002FezEngine\u002Fblob\u002Fdev\u002F.claude\u002Fskills\u002Fandroid-build-test\u002FSKILL.md",true,[72,78,82,86,92],{"path":73,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":76,"sourceHtmlUrl":77},"references\u002Fdepends-chains.md","REFERENCE","参考文档",722,"https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins\u002Fblob\u002Fmain\u002Ftaskwarrior-plugin\u002Fskills\u002Ftask-add\u002Freferences\u002Fdepends-chains.md",{"path":79,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":80,"sourceHtmlUrl":81},"references\u002Fproject-slug-verification.md",1582,"https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins\u002Fblob\u002Fmain\u002Ftaskwarrior-plugin\u002Fskills\u002Ftask-add\u002Freferences\u002Fproject-slug-verification.md",{"path":83,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":84,"sourceHtmlUrl":85},"references\u002Fquick-reference.md",3243,"https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins\u002Fblob\u002Fmain\u002Ftaskwarrior-plugin\u002Fskills\u002Ftask-add\u002Freferences\u002Fquick-reference.md",{"path":87,"resourceType":88,"resourceTypeDesc":89,"sizeBytes":90,"sourceHtmlUrl":91},"scripts\u002Ftests\u002Ftest-dup-check-exact-project.sh","SCRIPT","脚本",6678,"https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins\u002Fblob\u002Fmain\u002Ftaskwarrior-plugin\u002Fskills\u002Ftask-add\u002Fscripts\u002Ftests\u002Ftest-dup-check-exact-project.sh",{"path":93,"resourceType":88,"resourceTypeDesc":89,"sizeBytes":94,"sourceHtmlUrl":95},"scripts\u002Ftests\u002Ftest-uuid-capture.sh",3827,"https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins\u002Fblob\u002Fmain\u002Ftaskwarrior-plugin\u002Fskills\u002Ftask-add\u002Fscripts\u002Ftests\u002Ftest-uuid-capture.sh",[97,108,115,128,134,165],{"skillNo":98,"name":99,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":100,"categories":101,"keywords":105,"publishedAt":44},"01M6BVJ2JJSR8YPD6VHS3ZFHQ0","ez-mcp","https:\u002F\u002Fgithub.com\u002FezEngine\u002FezEngine\u002Fblob\u002Fdev\u002F.github\u002Fskills\u002Fez-mcp\u002FSKILL.md",[102],{"categoryNo":103,"categoryName":104,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[106,107],"MCP","ez mcp",{"skillNo":109,"name":110,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":111,"categories":112,"keywords":113,"publishedAt":44},"01M6BVJ0TWDRH3BGF3R9G9J4ZA","ez-ddl","https:\u002F\u002Fgithub.com\u002FezEngine\u002FezEngine\u002Fblob\u002Fdev\u002F.github\u002Fskills\u002Fez-ddl\u002FSKILL.md",[],[114],"ez ddl",{"skillNo":116,"name":117,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":118,"categories":119,"keywords":125,"publishedAt":44},"01M6BVHZ4QE8PNRVNF6Q029HWK","debug-pretty-printers","https:\u002F\u002Fgithub.com\u002FezEngine\u002FezEngine\u002Fblob\u002Fdev\u002F.github\u002Fskills\u002Fdebug-pretty-printers\u002FSKILL.md",[120],{"categoryNo":121,"categoryName":122,"taxonomyType":123,"taxonomyTypeDesc":124},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[126,127],"debug","debug pretty printers",{"skillNo":129,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":133,"publishedAt":44},"01M6BVHXGW8DXMB3XD3AK0GTWX","https:\u002F\u002Fgithub.com\u002FezEngine\u002FezEngine\u002Fblob\u002Fdev\u002F.github\u002Fskills\u002Fandroid-build-test\u002FSKILL.md",[132],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[24,28,26,29,27,25],{"skillNo":135,"name":99,"nameZh":6,"description":136,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":137,"categories":138,"keywords":140,"publishedAt":44},"01M6BVHTT1NVHJFSKGZ94VXJK7","Drive a running ezEditor or ezPlayer\u002Fgame from an agent over MCP - launch one with a port, then call tools to inspect and change a live project. Use for ezEngine tasks that need the running app rather than files on disk. Triggers - ezEditor, ezPlayer, ezEditorProcessor, MCP server, editor-mcpport, mcpport, transform asset, asset dependencies, asset browser, open document, edit scene, build a scene, game object, component, prefab, property grid, selection, reflected types, RTTI, CVar, editor action, play the game, screenshot, inject input, press key, step frames, export project, create project, build the C++ plugin.","https:\u002F\u002Fgithub.com\u002FezEngine\u002FezEngine\u002Fblob\u002Fdev\u002F.claude\u002Fskills\u002Fez-mcp\u002FSKILL.md",[139],{"categoryNo":103,"categoryName":104,"taxonomyType":21,"taxonomyTypeDesc":22},[107,106,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164],"play","tasks","browser","screenshot","server","Tools","disk","open","game","files","selection","project","app","press key","port","types","inspect","create","mcp server","editor","launch","change","component","plugin",{"skillNo":166,"name":110,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":168,"categories":169,"keywords":170,"publishedAt":44},"01M6BVHR3WC15VYQ9QTNVN67N2","Read and edit ezEngine documents on disk - scenes (.ezScene), prefabs (.ezPrefab) and assets (.ez*Asset) are OpenDDL text. Use Utilities\u002FScripts\u002Fezddl.py to convert GUIDs ('{ xxxxxxxx-... }' \u003C-> 'u4{low,high}') and hex floats (0x0000803F), resolve asset GUIDs to paths, find which documents use an asset, print a scene hierarchy, add game objects and components, set properties, validate a document, and make the editor re-transform a hand-edited asset. Triggers - ezScene, ezPrefab, ezMaterialAsset, ezTextureAsset, DDL, OpenDDL, asset GUID, Uuid u4, asset reference, hex float, edit scene file, add object to scene, which asset is this GUID, who references this asset, HeaderV2, Types section, type version.","https:\u002F\u002Fgithub.com\u002FezEngine\u002FezEngine\u002Fblob\u002Fdev\u002F.claude\u002Fskills\u002Fez-ddl\u002FSKILL.md",[],[114,171,172,173,174,175,176,147,149,177,178,179,180,181,182,183,156,184,185,186,187,188,160],"paths","components","validate","documents","file","SET","text","read","edit","references","objects","hex","scripts","re","which","hand","float","hierarchy"]