apply plugin: 'com.android.application' def appName() { return "XwadOSHonor" } def releaseTime() { return new Date().format("yyyyMMdd_HHmmss", TimeZone.getDefault()) } android { namespace "com.xwad.os" buildToolsVersion "36.0.0" compileSdkVersion 29 defaultConfig { applicationId "com.xwad.os" //There are no CERT files because If the mini sdk version is 23+, the AGP will ignore the V1 scheme signature. minSdkVersion 23 targetSdkVersion 29 versionCode 45 versionName "1.4.4" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" ndk { //根据需要 自行选择添加的对应cpu类型的.so库。 abiFilters 'armeabi-v7a', 'arm64-v8a' // 还可以添加 'armeabi', 'x86', 'x86_64', 'mips', 'mips64' } lintOptions { checkReleaseBuilds false // Or, if you prefer, you can continue to check for errors in release builds, // but continue the build even when errors are found: abortOnError false } multiDexEnabled true vectorDrawables.useSupportLibrary = true aaptOptions.cruncherEnabled = false aaptOptions.useNewCruncher = false packagingOptions { // 根据错误信息,排除具体的重复文件 exclude 'META-INF/DEPENDENCIES' // 如果还有其他类似冲突(如NOTICE, LICENSE文件),可以一并排除 exclude 'META-INF/NOTICE' exclude 'META-INF/LICENSE' exclude 'META-INF/LICENSE.txt' exclude 'META-INF/NOTICE.txt' } manifestPlaceholders = [ AMAP_KEY: "db082446a68db8e3ffdc8277313c2e6a" ] } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } buildFeatures { dataBinding true buildConfig true aidl true } externalNativeBuild { cmake { path file('CMakeLists.txt') } } signingConfigs { tuixin { storeFile file("keystore/tuixin.jks") storePassword "123456" keyAlias "universal" keyPassword "123456" v2SigningEnabled false } } // def cerFile = file("E:\\Xuewang365\\HonorCer\\HONOR.CER") applicationVariants.all { variant -> def variantName = variant.name.capitalize() // 建议使用 packageApplication 任务,它更明确指向 APK 生成 def packageTask = tasks.findByName("package${variantName}") if (packageTask) { packageTask.doLast { try { // 1. 配置路径优化:尽量使用 project 属性,避免写死 E:\ 盘符 def cerFile = file("E:\\Xuewang365\\HonorCer\\HONOR.CER") if (!cerFile.exists()) { println "⚠️ 未找到证书文件: ${cerFile.path},跳过注入步骤" return } def sdkDir = android.sdkDirectory.path // def buildToolsVersion = android.buildToolsVersion // 建议动态获取,除非有特定版本要求 def buildToolsVersion = "36.0.0" def buildToolsPath = "${sdkDir}/build-tools/${buildToolsVersion}" def aaptPath = "${buildToolsPath}/aapt${org.gradle.internal.os.OperatingSystem.current().isWindows() ? '.exe' : ''}" def apksignerPath = "${buildToolsPath}/apksigner${org.gradle.internal.os.OperatingSystem.current().isWindows() ? '.bat' : ''}" // 验证工具是否存在 if (!file(aaptPath).exists()) { println "❌ 未找到 aapt 工具: ${aaptPath}" return } if (!file(apksignerPath).exists()) { println "❌ 未找到 apksigner 工具: ${apksignerPath}" return } // 2. 关键优化:精准定位当前 Variant 的输出文件 // 使用 variant.outputs 获取当前构建生成的特定文件 variant.outputs.each { output -> def apkFile = output.outputFile if (apkFile == null) { println "⚠️ APK 文件为 null,跳过处理" return } if (!apkFile.exists()) { println "⚠️ APK 文件不存在: ${apkFile.absolutePath},跳过处理" return } println "APK地址:${apkFile.absolutePath}" if (apkFile.name.endsWith(".apk")) { println "🛠️ 开始对当前 APK 注入: ${apkFile.name}" try { // 3. 准备 META-INF 临时结构 def tempBaseDir = new File(project.buildDir, "intermediates/honor_cer_temp/${variant.name}") def metaInfDir = new File(tempBaseDir, "META-INF") // 确保清理旧数据 if (metaInfDir.exists()) { metaInfDir.deleteDir() } metaInfDir.mkdirs() def targetFile = new File(metaInfDir, cerFile.name) ant.copy(file: cerFile, tofile: targetFile) // 4. 调用 aapt 注入 - 添加错误输出捕获 println "执行命令: ${aaptPath} add ${apkFile.absolutePath} META-INF/${cerFile.name}" def aaptResult = exec { workingDir tempBaseDir commandLine aaptPath, "add", apkFile.absolutePath, "META-INF/${cerFile.name}" ignoreExitValue = true // 不立即失败,让我们自己处理 standardOutput = new ByteArrayOutputStream() errorOutput = new ByteArrayOutputStream() } if (aaptResult.exitValue != 0) { def errorMsg = aaptResult.errorOutput.toString() println "❌ aapt 执行失败 (退出码: ${aaptResult.exitValue})" println "错误信息: ${errorMsg}" println "尝试继续重新签名..." } else { println "✅ aapt 注入成功" } // 5. 重新签名 (Apksigner) def signingConfig = variant.signingConfig if (signingConfig != null && signingConfig.storeFile != null && signingConfig.storeFile.exists()) { println "执行签名..." def signResult = exec { commandLine apksignerPath, "sign", "--ks", signingConfig.storeFile.absolutePath, "--ks-pass", "pass:${signingConfig.storePassword}", "--ks-key-alias", signingConfig.keyAlias, "--key-pass", "pass:${signingConfig.keyPassword}", "--v2-signing-enabled", "true", "--v3-signing-enabled", "true", apkFile.path ignoreExitValue = true standardOutput = new ByteArrayOutputStream() errorOutput = new ByteArrayOutputStream() } if (signResult.exitValue == 0) { println "✅ [${variant.name}] 注入并修复签名成功!" } else { def errorMsg = signResult.errorOutput.toString() println "❌ [${variant.name}] 签名失败 (退出码: ${signResult.exitValue})" println "错误信息: ${errorMsg}" } } else { println "❌ [${variant.name}] 签名失败:SigningConfig 配置无效" } // 清理临时目录 if (tempBaseDir.exists()) { tempBaseDir.deleteDir() } } catch (Exception e) { println "❌ 处理 APK 时发生异常: ${e.message}" e.printStackTrace() } } } } catch (Exception e) { println "❌ 证书注入过程发生严重错误: ${e.message}" e.printStackTrace() // 不中断构建流程 } } } } buildTypes { debug { versionNameSuffix "-debug" minifyEnabled false buildConfigField "String", "platform", '"HONOR"' signingConfig signingConfigs.tuixin } release { minifyEnabled false //前一部分代表系统默认的android程序的混淆文件,该文件已经包含了基本的混淆声明,后一个文件是自己的定义混淆文件 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' signingConfig signingConfigs.tuixin buildConfigField "String", "platform", '"HONOR"' } } // Add application variant configuration here instead applicationVariants.all { variant -> variant.outputs.each { output -> def buildType = variant.buildType.name if (buildType.contains("debug")) { // fileName = "${appName()}_V${defaultConfig.versionName}_${releaseTime()}.apk" output.outputFileName = "app_debug.apk" } else { output.outputFileName = "${appName()}_${variant.versionCode}_V${variant.versionName}_${releaseTime()}_${buildType}.apk" } } } } dependencies { // implementation fileTree(dir: 'libs', include: ['*.jar']) // compileOnly files('libs/framework.jar') compileOnly files('libs/magic-android-31.35.6.300.jar') implementation project(path: ':niceimageview') implementation project(path: ':FlycoTabLayoutZ_Lib') implementation project(path: ':verification-view') implementation project(path: ':PhotoPreview') //保持1.3.1 更新会报错 implementation 'androidx.appcompat:appcompat:1.3.1' //2.0.4以上无法预览 implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation "androidx.recyclerview:recyclerview:1.2.1" // For control over item selection of both touch and mouse driven selection implementation "androidx.recyclerview:recyclerview-selection:1.1.0" implementation "androidx.viewpager2:viewpager2:1.0.0" // Java language implementation implementation "androidx.fragment:fragment:1.4.1" implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.multidex:multidex:2.0.1' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' implementation "androidx.room:room-runtime:2.4.3" annotationProcessor "androidx.room:room-compiler:2.4.3" //内存泄漏检测 debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14' //磁盘缓存 implementation 'com.jakewharton:disklrucache:2.0.2' //Java WebSocket implementation "org.java-websocket:Java-WebSocket:1.5.3" //glide implementation 'com.github.bumptech.glide:glide:4.13.1' annotationProcessor 'com.github.bumptech.glide:compiler:4.13.1' //RxJava implementation 'io.reactivex.rxjava3:rxjava:3.0.0' implementation 'io.reactivex.rxjava3:rxandroid:3.0.0' // implementation 'com.squareup.okhttp3:okhttp:4.9.1' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' implementation "com.squareup.retrofit2:adapter-rxjava3:2.9.0" //Gson implementation 'com.google.code.gson:gson:2.9.0' implementation 'com.google.zxing:core:3.5.0' //生命周期管理 implementation 'com.trello.rxlifecycle4:rxlifecycle:4.0.2' implementation 'com.trello.rxlifecycle4:rxlifecycle-android:4.0.2' implementation 'com.trello.rxlifecycle4:rxlifecycle-components:4.0.2' implementation 'com.trello.rxlifecycle4:rxlifecycle-components-preference:4.0.2' implementation 'com.trello.rxlifecycle4:rxlifecycle-android-lifecycle:4.0.2' implementation 'com.jakewharton.rxbinding4:rxbinding:4.0.0' implementation 'com.jeremyliao:live-event-bus-x:1.7.3' //MMKV implementation 'com.tencent:mmkv-static:1.2.14' //bugly implementation 'com.tencent.bugly:crashreport:4.1.9.2' //阿里云推送 implementation 'com.aliyun.ams:alicloud-android-push:3.8.0' //高德地图定位 implementation 'com.amap.api:location:5.1.0' //状态栏透明 implementation 'com.gitee.zackratos:UltimateBarX:0.8.0' //指示器 implementation 'com.github.hackware1993:MagicIndicator:1.7.0' // for androidx // implementation 'io.github.h07000223:flycoTabLayout:3.0.0' // implementation 'com.github.liyujiang-gzu:FlycoTabLayout:781b8829a7' implementation 'com.king.view:circleprogressview:1.1.2' //工具类 implementation 'com.blankj:utilcodex:1.31.0' //aria implementation 'com.arialyy.aria:core:3.8.15' annotationProcessor 'com.arialyy.aria:compiler:3.8.15' //videoplayer implementation 'cn.jzvd:jiaozivideoplayer:7.7.0' implementation 'com.github.wseemann:FFmpegMediaMetadataRetriever-core:1.0.16' implementation 'com.github.wseemann:FFmpegMediaMetadataRetriever-native:1.0.16' //验证码输入 // implementation 'com.jacktuotuo.customview:verificationcodeview:1.0.5' //动态权限框架 implementation 'com.github.getActivity:XXPermissions:18.63' // 吐司框架:https://github.com/getActivity/Toaster implementation 'com.github.getActivity:Toaster:12.6' //autosize会改变第三方view的大小 //https://github.com/JessYanCoding/AndroidAutoSize implementation 'me.jessyan:autosize:1.2.1' //图片选择 implementation 'io.github.lucksiege:pictureselector:v3.11.1' // implementation 'com.github.wanglu1209:PhotoViewer:0.50' // implementation 'com.github.wanggaowan:PhotoPreview:2.5.5' /*jxw依赖*/ // implementation 'io.github.cymchad:BaseRecyclerViewAdapterHelper4:4.3.2' // implementation "io.github.cymchad:BaseRecyclerViewAdapterHelper:3.0.14" implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.47' implementation 'io.github.youth5201314:banner:2.2.3' implementation 'com.google.android.exoplayer:exoplayer:2.9.4' implementation 'com.google.android.exoplayer:exoplayer-core:2.9.4' implementation 'com.tencent.tav:libpag:latest.release' implementation 'com.ufreedom.uikit:FloatingTextLibrary:0.2.0' implementation 'org.apache.httpcomponents:httpcore:4.4.9' implementation 'org.apache.httpcomponents:httpclient:4.5.5' implementation 'org.greenrobot:eventbus:3.3.1' } // 在 dependencies 之后添加 project.afterEvaluate { android.applicationVariants.all { variant -> variant.javaCompileProvider.get().options.bootstrapClasspath = files( file('libs/framework.jar'), android.getBootClasspath() ) } } //preBuild { // doLast { // def imlFile = file(project.name + ".iml") //// def imlFile = file("..\\.idea\\modules\\" + project.name + "\\" + rootProject.name + "." + project.name + ".iml") // println 'Change ' + project.name + '.iml order' // try { // def parsedXml = (new XmlParser()).parse(imlFile) // def jdkNode = parsedXml.component[1].orderEntry.find { it.'@type' == 'jdk' } // parsedXml.component[1].remove(jdkNode) // def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform" // println 'what' + sdkString // new Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK']) // groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile)) // } catch (FileNotFoundException e) { // // nop, iml not found // println "no iml found" // } // } //}