// This comment exists for a reason, do not delete apply plugin: 'com.android.application' apply plugin: 'kotlin-android' // kotlin apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' apply plugin: 'AndResGuard' import groovy.xml.XmlUtil android { androidExtensions { experimental = true } buildFeatures { viewBinding = true dataBinding = true } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = "1.8" } dexOptions { // jumboMode = true javaMaxHeapSize "4g" preDexLibraries true maxProcessCount 8 } aaptOptions { additionalParameters "--no-version-vectors" } kapt { useBuildCache = true javacOptions { // 增加注解处理器的最大错误次数,默认为 100 option("-Xmaxerrs", 500) } } defaultConfig { multiDexEnabled true javaCompileOptions { annotationProcessorOptions { arguments = [eventBusIndex: 'com.gh.EventBusIndex'] } } ndk { // 如果不添加 `arm64` 调用系统的 PackageManager 的方法读取安装包信息的时候会出现 native 层闪退,草 // 添加了 `arm64` 以后部分 5.0 的设备会报用错 so 的问题, // couldn't find DSO to load: libimagepipeline.so caused by: dlopen failed: "/data/data/com.gh.gamecenter/lib-main/libimagepipeline.so" is 64-bit instead of 32-bit result: 0 // 以 OPPO R7PLUS 为例,明明设备是骁龙 615,ARMv8-64 bit 的设备却不支持 arm64 的 abi // 惊了 abiFilters "armeabi-v7a", "x86" } renderscriptTargetApi 18 renderscriptSupportModeEnabled true // 由于app只针对中文用户,所以仅保留zh资源,其他删掉 resConfigs "zh" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode rootProject.ext.versionCode versionName rootProject.ext.versionName applicationId rootProject.ext.applicationId proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt' /** * All third-party appid/appkey */ buildConfigField "String", "API_HOST", "\"${API_HOST}\"" buildConfigField "String", "WECHAT_APPID", "\"${WECHAT_APPID}\"" buildConfigField "String", "WECHAT_SECRET", "\"${WECHAT_SECRET}\"" buildConfigField "String", "TENCENT_APPID", "\"${TENCENT_APPID}\"" buildConfigField "String", "WEIBO_APPKEY", "\"${WEIBO_APPKEY}\"" buildConfigField "String", "TD_APPID", "\"${TD_APPID}\"" buildConfigField "String", "LETO_APPID", "\"${LETO_APPID}\"" buildConfigField "String", "TTAD_APPID", "\"${TTAD_APPID}\"" buildConfigField "String", "DOUYIN_CLIENTKEY", "\"${DOUYIN_CLIENTKEY}\"" buildConfigField "String", "DOUYIN_CLIENTSECRET", "\"${DOUYIN_CLIENTSECRET}\"" buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\"" buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\"" /** * Build Time 供区分 jenkins 打包时间用 */ buildConfigField "long", "BUILD_TIME", "0" } // gradle 2.2以上默认同时启用v1和v2(优先用于Android N) signingConfigs { debug { v1SigningEnabled true v2SigningEnabled true } release { v1SigningEnabled true v2SigningEnabled true } } buildTypes { debug { debuggable true minifyEnabled false zipAlignEnabled false signingConfig signingConfigs.debug buildConfigField "String", "EXPOSURE_REPO", "\"test\"" buildConfigField "String", "EXPOSURE_VERSION", "\"E4\"" multiDexKeepProguard file("tinker_multidexkeep.pro") } release { debuggable false minifyEnabled true zipAlignEnabled true shrinkResources true signingConfig signingConfigs.release buildConfigField "String", "EXPOSURE_REPO", "\"exposure\"" buildConfigField "String", "EXPOSURE_VERSION", "\"E4\"" multiDexKeepProguard file("tinker_multidexkeep.pro") } } // Ignore useless variant variantFilter { variant -> def names = variant.flavors*.name def isDebugType = variant.buildType.name == "debug" if ((names.contains("tea") || name.contains("gdt")) && isDebugType) { setIgnore(true) } } flavorDimensions("env") sourceSets { publish { java.srcDirs = ['src/main/java'] } internal { java.srcDirs = ['src/main/java'] } tea { java.srcDirs = ['src/main/java', 'src/tea/java'] } gdt { java.srcDirs = ['src/main/java', 'src/gdt/java'] } } productFlavors { // internal test dev host internal { dimension "env" versionNameSuffix "-debug" buildConfigField "String", "DEV_API_HOST", "\"${DEV_API_HOST}\"" } // publish release host˛ publish { dimension "env" buildConfigField "String", "DEV_API_HOST", "\"${API_HOST}\"" } tea { dimension "env" buildConfigField "String", "DEV_API_HOST", "\"${API_HOST}\"" manifestPlaceholders.put("APPLOG_SCHEME", "rangersapplog.byAx6uYt".toLowerCase()) } gdt { dimension "env" buildConfigField "String", "DEV_API_HOST", "\"${API_HOST}\"" } } lintOptions { // For flutter release build, see https://github.com/flutter/flutter/issues/58247 checkReleaseBuilds false } } repositories { flatDir { dirs 'libs', 'libs/aars' } } dependencies { implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs') gdtImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/gdt/libs') testImplementation 'junit:junit:4.12' debugImplementation "com.squareup.leakcanary:leakcanary-android:${leakcanary}" debugImplementation "com.squareup.okhttp3:logging-interceptor:${okHttp}" // debugImplementation "com.gu.android:toolargetool:${toolargetool}" // 需要使用调试时才启用 debugImplementation "com.github.nichbar:WhatTheStack:${whatTheStack}" implementation "androidx.core:core-ktx:${core}" implementation "androidx.fragment:fragment-ktx:${fragment}" implementation "androidx.multidex:multidex:${multiDex}" implementation "androidx.appcompat:appcompat:${appCompat}" implementation "androidx.cardview:cardview:${cardView}" implementation "androidx.annotation:annotation:${annotation}" implementation "androidx.constraintlayout:constraintlayout:${constraintLayout}" implementation "androidx.recyclerview:recyclerview:${recyclerView}" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifeCycle" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifeCycle" implementation "androidx.lifecycle:lifecycle-common-java8:$lifeCycle" implementation "androidx.room:room-runtime:${room}" implementation "androidx.room:room-rxjava2:${room}" implementation "androidx.core:core-ktx:${ktx}" implementation "androidx.viewpager2:viewpager2:${viewpager2}" implementation "androidx.webkit:webkit:${webkit}" kapt "androidx.room:room-compiler:${room}" implementation "com.google.android.material:material:${material}" implementation "com.kyleduo.switchbutton:library:${switchButton}" implementation "com.facebook.fresco:fresco:${fresco}" implementation "com.facebook.fresco:animated-gif-lite:${fresco}" implementation "com.facebook.fresco:animated-drawable:${fresco}" implementation "com.facebook.fresco:animated-webp:${fresco}" implementation "com.facebook.fresco:webpsupport:${fresco}" implementation "com.squareup.okhttp3:okhttp:${okHttp}" implementation "com.leon.channel:helper:${apkChannelPackage}" implementation "com.squareup.retrofit2:retrofit:${retrofit}" implementation "com.squareup.retrofit2:converter-gson:${retrofit}" // include gson 2.7 implementation "com.squareup.retrofit2:adapter-rxjava2:${retrofit}" implementation "com.j256.ormlite:ormlite-android:${ormlite}" implementation "com.j256.ormlite:ormlite-core:${ormlite}" implementation "com.jakewharton:butterknife:${butterKnife}" kapt "com.jakewharton:butterknife-compiler:${butterKnife}" implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}" implementation "org.greenrobot:eventbus:${eventbus}" kapt "org.greenrobot:eventbus-annotation-processor:${eventbusApt}" implementation "io.reactivex.rxjava2:rxjava:${rxJava2}" implementation "io.reactivex.rxjava2:rxandroid:${rxAndroid2}" implementation "com.jakewharton.rxbinding2:rxbinding:${rxBinding2}" implementation "com.google.zxing:core:${zxing}" implementation "com.google.zxing:android-core:${zxing}" implementation "com.daimajia.swipelayout:library:${swipeLayout}" implementation "com.google.android:flexbox:${flexbox}" implementation "pub.devrel:easypermissions:${easypermissions}" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "com.contrarywind:Android-PickerView:${pickerView}" implementation "com.scwang.smartrefresh:SmartRefreshLayout:${smartRefreshLayout}" implementation "net.cachapa.expandablelayout:expandablelayout:${expandableLayout}" // 用于比较 versionName 是大于小于或等于 implementation "com.g00fy2:versioncompare:${versioncompare}" implementation "top.zibin:Luban:${luban}" implementation "com.squareup.picasso:picasso:${picasso}" // for video streaming implementation("com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-java:$gsyVideo", { exclude module: "gsyvideoplayer-androidvideocache" exclude group: "tv.danmaku.ijk.media" }) implementation "com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-exo_player2:$gsyVideo" implementation "android.arch.work:work-runtime:${workManager}" implementation "com.llew.huawei:verifier:${verifier}" implementation "com.github.tbruyelle:rxpermissions:${rxPermissions}" implementation "com.github.nichbar:skeleton:${skeleton}" implementation "io.supercharge:shimmerlayout:${shimmerlayout}" implementation "com.tencent.mm.opensdk:wechat-sdk-android-without-mta:${mta}" implementation "com.github.nichbar:AndroidRomChecker:${romChecker}" debugImplementation "com.github.nichbar.chucker:library:${chucker}" releaseImplementation "com.github.nichbar.chucker:library-no-op:${chucker}" teaImplementation "com.bytedance.applog:RangersAppLog-Lite-cn:${bytedanceApplog}" implementation "com.aliyun.dpa:oss-android-sdk:${oss}" implementation "com.airbnb.android:lottie:${lottie}" implementation "net.lingala.zip4j:zip4j:${zip4j}" implementation "io.sentry:sentry-android:${sentry}" implementation("com.github.piasy:BigImageViewer:${bigImageViewer}", { exclude group: 'com.squareup.okhttp3' exclude group: 'androidx.swiperefreshlayout' exclude group: 'com.github.bumptech.glide' exclude group: 'com.facebook.fresco' }) implementation "com.github.PhilJay:MPAndroidChart:${chart}" implementation "com.lahm.library:easy-protector-release:${easyProtector}" implementation "com.github.hsiafan:apk-parser:${apkParser}" implementation "org.nanohttpd:nanohttpd:${nanohttpd}" implementation "com.aliyun.openservices:aliyun-log-android-sdk:${aliyunLog}" implementation "com.github.princekin-f:EasyFloat:${easyFloat}" implementation "io.github.florent37:shapeofview:${shapeOfView}" implementation "io.github.sinaweibosdk:core:${weiboSDK}" implementation "com.lg:gid:1.3.0" implementation "com.louiscad.splitties:splitties-fun-pack-android-base-with-views-dsl:${splitties}" compileOnly "com.github.axen1314.lancet:lancet-base:$lancet_version" implementation project(':libraries:LGLibrary') implementation project(':libraries:QQShare') implementation project(':libraries:Matisse') } File propFile = file('sign.properties') if (propFile.exists()) { Properties props = new Properties() props.load(new FileInputStream(propFile)) if (props.containsKey('keyAlias') && props.containsKey('keyPassword') && props.containsKey('storeFile') && props.containsKey('storePassword')) { android.signingConfigs { // debug 不要使用正式签名,这样tinker才不会打补丁。 debug { keyAlias props.get('keyAlias') keyPassword props.get('keyPassword') storeFile file(props.get('storeFile')) storePassword props.get('storePassword') } release { keyAlias props.get('keyAlias') keyPassword props.get('keyPassword') storeFile file(props.get('storeFile')) storePassword props.get('storePassword') } } } else { android.buildTypes.release.signingConfig = null } } else { android.buildTypes.release.signingConfig = null } // 用于测试读取 META-INF 里的文件 //task generateMetaJson { // def resDir = new File(buildDir, 'generated/FILES_FOR_META_INF/') // def destDir = new File(resDir, 'META-INF/') // // Add resDir as a resource directory so that it is automatically included in the APK. // android { // sourceSets { // main.resources { // srcDir resDir // } // } // } // // doLast { // if (!destDir.exists()) destDir.mkdirs() // copy { // into destDir // from new File('generated/FILES_FOR_META_INF/META-INF/halo_skip.json') // } // } //} //// Specify when put_files_in_META_INF should run //project.afterEvaluate { // tasks.findAll { task -> // task.name.startsWith('merge') && task.name.endsWith('Resources') // }.each { t -> t.dependsOn generateMetaJson } //} andResGuard { mappingFile = null use7zip = true useSign = true // 打开这个开关,会keep住所有资源的原始路径,只混淆资源的名字 keepRoot = false // 设置这个值,会把arsc name列混淆成相同的名字,减少string常量池的大小 fixedResName = "arg" // 打开这个开关会合并所有哈希值相同的资源,但请不要过度依赖这个功能去除去冗余资源 mergeDuplicatedRes = true whiteList = [ "R.drawable.icon", "R.drawable.ic_bar_back", "R.drawable.toolbar_search_icon", "R.drawable.bg_notification_answer_style_1", "R.drawable.bg_notification_answer_style_2", "R.drawable.bg_notification_article_style_1", "R.drawable.bg_notification_article_style_2", "R.drawable.bg_notification_feedback_style_1", "R.drawable.bg_notification_feedback_style_2", "R.drawable.bg_notification_gift_style_1", "R.drawable.bg_notification_gift_style_2", "R.drawable.bg_notification_login_style_1", "R.drawable.bg_notification_login_style_2", "R.drawable.bg_notification_question_style_1", "R.drawable.bg_notification_question_style_2", "R.drawable.bg_notification_rating_style_1", "R.drawable.bg_notification_rating_style_2", "R.drawable.bg_notification_reserve_game_style_1", "R.drawable.bg_notification_reserve_game_style_2", "R.drawable.bg_notification_video_style_1", "R.drawable.bg_notification_video_style_2", "R.drawable.ic_search_no_1", "R.drawable.ic_search_no_2", "R.drawable.ic_search_no_3", "R.drawable.ic_search_no_4", "R.drawable.ic_search_no_5", "R.drawable.ic_search_no_6", "R.drawable.ic_search_no_7", "R.drawable.ic_search_no_8", "R.drawable.ic_search_no_9", "R.drawable.ic_search_no_10", "R.drawable.ic_search_no_11", "R.drawable.ic_search_no_12", "R.drawable.ic_search_no_13", "R.drawable.ic_search_no_14", "R.drawable.ic_search_no_15", "R.drawable.ic_search_no_16", "R.drawable.ic_search_no_17", "R.drawable.ic_search_no_18", "R.drawable.ic_search_no_19", "R.drawable.ic_search_no_20", "R.drawable.ic_recommend_activity", "R.drawable.ic_recommend_discount", "R.drawable.ic_recommend_function", "R.drawable.ic_recommend_gift", "R.drawable.ic_recommend_role", "R.drawable.login_btn_bg", "R.drawable.ic_quick_login_check", "R.drawable.ic_quick_login_uncheck", "R.anim.anim_auth_in", "R.anim.anim_auth_out", "R.id.download_speed", "R.id.download_percentage", "R.id.comment", "R.id.vote", "R.id.watermark_hint", "R.id.watermark_sb", "R.id.bottomShareIv", "R.id.bottomShareTv", "R.id.recommendStarPref", "R.id.recommendStar", "R.drawable.help_search_delete", "R.drawable.suggest_type_normal", "R.drawable.suggest_type_crash", "R.drawable.suggest_type_game_question", "R.drawable.suggest_type_game_collect", "R.drawable.suggest_type_function_suggest", "R.drawable.suggest_type_article_collect", "R.drawable.suggest_type_copyright", "R.drawable.help_result_empty", "R.drawable.news_comment_detail_read", "R.drawable.news_comment_detail_comment", "R.drawable.news_comment_detail_share", "R.drawable.ic_libao", "R.drawable.ic_link", "R.drawable.concern_message_icon", "R.drawable.reuse_blank_hint", "R.drawable.ic_concern", "R.drawable.concern_down", "R.drawable.concern_up", "R.drawable.ic_libao_more", "R.drawable.ic_libao_delete", "R.drawable.ic_dialog_close" ] compressFilePattern = [ "*.png", "*.jpg", "*.jpeg", "*.gif", ] sevenzip { artifact = 'com.tencent.mm:SevenZip:1.2.20' } } project.afterEvaluate { def variants = null try { variants = android.applicationVariants } catch (Throwable t) { t.printStackTrace() try { variants = android.libraryVariants } catch (Throwable tt) { tt.printStackTrace() } } if (variants != null) { variants.all { variant -> variant.outputs.each { output -> def task = output.processManifestProvider.get() if (task == null) { return } /** * 为 Manifest 的 Activity 的 configChanges 添加自己手动处理 configurationChanges 配置 [https://developer.android.com/guide/topics/resources/runtime-changes] * AGP 4.1.0 从 ProcessManifest task 里拿 manifest 的 API 变更调整可以参考这里 [https://github.com/Tencent/tinker/pull/1476/commits/d71645729b13d545ca4ba6826f93fbf558751434] * (搞半天还是不会抽离方法,有空再把 gradle 改成用 kotlin 实现吧) */ task.doLast { def manifestFile = new File(multiApkManifestOutputDirectory.get().asFile, "AndroidManifest.xml") if (manifestFile == null || !manifestFile.exists()) { return } String[] configChanges = [ "density", "fontScale", "keyboard", "keyboardHidden", "layoutDirection", "locale", "mcc", "mnc", "navigation", "orientation", "screenLayout", "screenSize", "smallestScreenSize", "touchscreen", "uiMode"] def parser = new XmlSlurper(false, true) def manifest = parser.parse(manifestFile) def app = manifest.'application'[0] app.'activity'.each { act -> String value = act.attributes()['android:configChanges'] if (value == null || value.isEmpty()) { if (value == null) value = "" configChanges.eachWithIndex { config, index -> if (index != configChanges.length - 1) { value += config + "|" } else { value += config } } act.attributes()['androidconfigChanges'] = value } else { String[] valueSplit = value.split("\\|") println configChanges configChanges.eachWithIndex { config, index -> if (!valueSplit.contains(config)) { value += ("|" + config) } } act.attributes()['android:configChanges'] = value } } def tmpManifest = XmlUtil.serialize(manifest).replaceAll("androidconfigChanges", "android:configChanges") manifest = parser.parseText(tmpManifest) manifestFile.setText(XmlUtil.serialize(manifest), "utf-8") } } } } }