pipeline { agent any parameters { string(name: 'VERSION', defaultValue: '', description: '发布版本号(留空使用 gradle.properties 中的 PUBLISH_VERSION)') booleanParam(name: 'RUN_TESTS', defaultValue: true, description: '是否运行自动化测试') booleanParam(name: 'PUBLISH', defaultValue: true, description: '是否发布到 Nexus') } environment { NEXUS_USER = credentials('nexus-android-user') NEXUS_PASS = credentials('nexus-android-pass') } stages { stage('Checkout') { steps { checkout([ $class: 'GitSCM', branches: [[name: 'main']], extensions: [[$class: 'CleanBeforeCheckout']], userRemoteConfigs: scm.userRemoteConfigs ]) script { if (params.VERSION?.trim()) { bat "powershell -Command \"(Get-Content gradle.properties) -replace '^PUBLISH_VERSION=.*', 'PUBLISH_VERSION=${params.VERSION}' | Set-Content gradle.properties\"" } } } } stage('Build AARs & APKs') { steps { bat 'gradlew.bat :sample-app:assembleDebug :sample-app:assembleDebugAndroidTest --no-daemon' } } stage('Start Emulators') { when { expression { return params.RUN_TESTS } } steps { bat ''' start /B emulator -avd Pixel_9_Pro -no-audio -no-boot-anim -no-snapshot-save -no-window start /B emulator -avd Pixel_9_Pro_2 -no-audio -no-boot-anim -no-snapshot-save -no-window adb wait-for-device timeout /t 20 /nobreak >nul adb devices ''' } } stage('Install APKs') { when { expression { return params.RUN_TESTS } } steps { bat ''' set APK=sample-app\\build\\outputs\\apk\\debug\\sample-app-debug.apk set TEST_APK=sample-app\\build\\outputs\\apk\\androidTest\\debug\\sample-app-debug-androidTest.apk for %%D in (emulator-5554 emulator-5556) do ( adb -s %%D install -r "%APK%" adb -s %%D install -r "%TEST_APK%" ) ''' } } stage('Single-Device Tests') { when { expression { return params.RUN_TESTS } } steps { bat ''' set ALL_SINGLE=com.xuqm.sdk.sample.SdkIntegrationTest,com.xuqm.sdk.sample.PushSdkTest,com.xuqm.sdk.sample.NetworkResilienceTest adb -s emulator-5554 shell am instrument -w -r -e class "%ALL_SINGLE%" "com.xuqm.demo.test/androidx.test.runner.AndroidJUnitRunner" > test-results-5554.txt findstr /C:"FAILURES" test-results-5554.txt && exit 1 || exit 0 ''' } } stage('Cross-Device Tests') { when { expression { return params.RUN_TESTS } } parallel { stage('Sender (5554)') { steps { bat ''' adb -s emulator-5554 shell am instrument -w -r -e class "com.xuqm.sdk.sample.CrossDeviceSenderTest" "com.xuqm.demo.test/androidx.test.runner.AndroidJUnitRunner" > cross-sender.txt findstr /C:"FAILURES" cross-sender.txt && exit 1 || exit 0 ''' } } stage('Receiver (5556)') { steps { bat ''' adb -s emulator-5556 shell am instrument -w -r -e class "com.xuqm.sdk.sample.CrossDeviceReceiverTest" "com.xuqm.demo.test/androidx.test.runner.AndroidJUnitRunner" > cross-receiver.txt findstr /C:"FAILURES" cross-receiver.txt && exit 1 || exit 0 ''' } } } } stage('Publish to Nexus') { when { expression { return params.PUBLISH } } steps { script { def versionArg = params.VERSION?.trim() ? "-PPUBLISH_VERSION=${params.VERSION}" : '' bat "gradlew.bat publish ${versionArg} -PNEXUS_USER=%NEXUS_USER% -PNEXUS_PASSWORD=%NEXUS_PASS% --no-daemon" } } } } post { always { bat 'adb emu kill || exit 0' archiveArtifacts artifacts: 'test-results-*.txt, cross-*.txt', allowEmptyArchive: true } failure { bat ''' adb -s emulator-5554 logcat -d -s XuqmImSDK:D XuqmPushSDK:W XuqmUpdateSDK:D > logcat-5554.txt || exit 0 adb -s emulator-5556 logcat -d -s XuqmImSDK:D XuqmPushSDK:W XuqmUpdateSDK:D > logcat-5556.txt || exit 0 ''' archiveArtifacts artifacts: 'logcat-*.txt', allowEmptyArchive: true } success { echo "✅ Android SDK 构建成功" } } }