@file:Suppress("UnstableApiUsage", "SpellCheckingInspection") import com.android.build.api.variant.FilterConfiguration.FilterType.ABI import io.sentry.android.gradle.extensions.InstrumentationFeature import io.sentry.android.gradle.instrumentation.logcat.LogcatLevel import java.util.Properties plugins { // Gradle doesn't allow conditionally enabling/disabling plugins id("io.sentry.android.gradle") id("com.android.application") id("com.mikepenz.aboutlibraries.plugin") kotlin("android") kotlin("kapt") } // apply realm-android apply(plugin = "realm-android") val hasSentryConfig = File(rootProject.projectDir, "sentry.properties").exists() android { // functions to get git info: gitCommitHash, gitBranch, gitRemote val gitCommitHash = providers.exec { commandLine("git", "rev-parse", "--short", "HEAD") }.standardOutput.asText.get().toString().trim() val gitBranch = providers.exec { commandLine("git", "rev-parse", "--abbrev-ref", "HEAD") }.standardOutput.asText.get().toString().trim() val gitRemote = providers.exec { commandLine("git", "config", "--get", "remote.origin.url") }.standardOutput.asText.get().toString().trim() val timestamp = System.currentTimeMillis() namespace = "com.fox2code.mmm" compileSdk = 33 ndkVersion = "25.2.9519653" defaultConfig { applicationId = "com.fox2code.mmm" minSdk = 24 targetSdk = 33 versionCode = 70 versionName = "2.0.2" vectorDrawables { useSupportLibrary = true } multiDexEnabled = true resourceConfigurations.addAll(listOf("ar", "bs", "cs", "de", "es-rMX", "fr", "hu", "id", "ja", "nl", "pl", "pt", "pt-rBR", "ro", "ru", "tr", "uk", "zh", "zh-rTW", "en")) } splits { // Configures multiple APKs based on ABI. abi { // Enables building multiple APKs per ABI. isEnable = true // By default all ABIs are included, so use reset() // Resets the list of ABIs for Gradle to create APKs for to none. reset() // Specifies a list of ABIs for Gradle to create APKs for. include("x86", "x86_64", "arm64-v8a", "armeabi-v7a") // Specifies that you don't want to also generate a universal APK that includes all ABIs. isUniversalApk = true } } buildTypes { getByName("release") { isMinifyEnabled = true isShrinkResources = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) renderscriptOptimLevel = 3 } getByName("debug") { applicationIdSuffix = ".debug" isDebuggable = true versionNameSuffix = "-debug" isJniDebuggable = true isRenderscriptDebuggable = true // ONLY FOR TESTING SENTRY // minifyEnabled true // shrinkResources true // proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"),"proguard-rules.pro" } } flavorDimensions.add("type") productFlavors { create("default") { dimension = "type" // current timestamp of build buildConfigField("long", "BUILD_TIME", "$timestamp") // debug http requests. do not set this to true if you care about performance!!!!! buildConfigField("boolean", "DEBUG_HTTP", "false") // Latest commit hash as BuildConfig.COMMIT_HASH buildConfigField("String", "COMMIT_HASH", "\"$gitCommitHash\"") // Get the current branch name as BuildConfig.BRANCH_NAME buildConfigField("String", "BRANCH_NAME", "\"$gitBranch\"") // Get remote url as BuildConfig.REMOTE_URL buildConfigField("String", "REMOTE_URL", "\"$gitRemote\"") buildConfigField("boolean", "ENABLE_AUTO_UPDATER", "true") buildConfigField("boolean", "DEFAULT_ENABLE_CRASH_REPORTING", "true") buildConfigField("boolean", "DEFAULT_ENABLE_CRASH_REPORTING_PII", "true") buildConfigField("boolean", "DEFAULT_ENABLE_ANALYTICS", "true") val properties = Properties() if (project.rootProject.file("local.properties").exists()) { properties.load(project.rootProject.file("local.properties").reader()) // grab matomo.url buildConfigField( "String", "ANALYTICS_ENDPOINT", "\"" + properties.getProperty( "matomo.url", "https://s-api.androidacy.com/matomo.php" ) + "\"" ) } else { buildConfigField( "String", "ANALYTICS_ENDPOINT", "\"https://s-api.androidacy.com/matomo.php\"" ) } buildConfigField("boolean", "ENABLE_PROTECTION", "true") // Get the androidacy client ID from the androidacy.properties val propertiesA = Properties() // If androidacy.properties doesn"t exist, use the default client ID which is heavily // rate limited to 30 requests per minute if (project.rootProject.file("androidacy.properties").exists()) { propertiesA.load(project.rootProject.file("androidacy.properties").reader()) properties.setProperty( "client_id", "\"" + propertiesA.getProperty( "client_id", "5KYccdYxWB2RxMq5FTbkWisXi2dS6yFN9R7RVlFCG98FRdz6Mf5ojY2fyJCUlXJZ" ) + "\"" ) } else { properties.setProperty( "client_id", "5KYccdYxWB2RxMq5FTbkWisXi2dS6yFN9R7RVlFCG98FRdz6Mf5ojY2fyJCUlXJZ" ) } buildConfigField( "String", "ANDROIDACY_CLIENT_ID", "\"" + propertiesA.getProperty("client_id") + "\"" ) buildConfigField( "java.util.List", "ENABLED_REPOS", "java.util.Arrays.asList(\"androidacy_repo\")", ) } // play variant. pretty similiar to default, but with an empty inital online repo list, and use play_client_id instead of client_id create("play") { dimension = "type" applicationIdSuffix = ".play" // current timestamp of build buildConfigField("long", "BUILD_TIME", "$timestamp") // debug http requests. do not set this to true if you care about performance!!!!! buildConfigField("boolean", "DEBUG_HTTP", "false") // Latest commit hash as BuildConfig.COMMIT_HASH buildConfigField("String", "COMMIT_HASH", "\"$gitCommitHash\"") // Get the current branch name as BuildConfig.BRANCH_NAME buildConfigField("String", "BRANCH_NAME", "\"$gitBranch\"") // Get remote url as BuildConfig.REMOTE_URL buildConfigField("String", "REMOTE_URL", "\"$gitRemote\"") buildConfigField("boolean", "ENABLE_AUTO_UPDATER", "false") buildConfigField("boolean", "DEFAULT_ENABLE_CRASH_REPORTING", "true") buildConfigField("boolean", "DEFAULT_ENABLE_CRASH_REPORTING_PII", "true") buildConfigField("boolean", "DEFAULT_ENABLE_ANALYTICS", "true") val properties = Properties() if (project.rootProject.file("local.properties").exists()) { properties.load(project.rootProject.file("local.properties").reader()) // grab matomo.url buildConfigField( "String", "ANALYTICS_ENDPOINT", "\"" + properties.getProperty( "matomo.url", "https://s-api.androidacy.com/matomo.php" ) + "\"" ) } else { buildConfigField( "String", "ANALYTICS_ENDPOINT", "\"https://s-api.androidacy.com/matomo.php\"" ) } buildConfigField("boolean", "ENABLE_PROTECTION", "true") // Get the androidacy client ID from the androidacy.properties val propertiesA = Properties() // If androidacy.properties doesn"t exist, use the default client ID which is heavily // rate limited to 30 requests per minute if (project.rootProject.file("androidacy.properties").exists()) { propertiesA.load(project.rootProject.file("androidacy.properties").reader()) properties.setProperty( "client_id", "\"" + propertiesA.getProperty( "play_client_id", "5KYccdYxWB2RxMq5FTbkWisXi2dS6yFN9R7RVlFCG98FRdz6Mf5ojY2fyJCUlXJZ" ) + "\"" ) } else { properties.setProperty( "client_id", "5KYccdYxWB2RxMq5FTbkWisXi2dS6yFN9R7RVlFCG98FRdz6Mf5ojY2fyJCUlXJZ" ) } buildConfigField( "String", "ANDROIDACY_CLIENT_ID", "\"" + propertiesA.getProperty("client_id") + "\"" ) buildConfigField( "java.util.List", "ENABLED_REPOS", "java.util.Arrays.asList(\"\")", ) } create("fdroid") { dimension = "type" applicationIdSuffix = ".fdroid" // current timestamp of build buildConfigField("long", "BUILD_TIME", "$timestamp") // debug http requests. do not set this to true if you care about performance!!!!! buildConfigField("boolean", "DEBUG_HTTP", "false") // Latest commit hash as BuildConfig.COMMIT_HASH buildConfigField("String", "COMMIT_HASH", "\"$gitCommitHash\"") // Get the current branch name as BuildConfig.BRANCH_NAME buildConfigField("String", "BRANCH_NAME", "\"$gitBranch\"") // Get remote url as BuildConfig.REMOTE_URL buildConfigField("String", "REMOTE_URL", "\"$gitRemote\"") // Need to disable auto-updater for F-Droid flavor because their inclusion policy // forbids downloading blobs from third-party websites (and F-Droid APK isn"t signed // with our keys, so the APK wouldn"t install anyways). buildConfigField("boolean", "ENABLE_AUTO_UPDATER", "false") // Disable crash reporting for F-Droid flavor by default buildConfigField("boolean", "DEFAULT_ENABLE_CRASH_REPORTING", "false") buildConfigField("boolean", "DEFAULT_ENABLE_CRASH_REPORTING_PII", "false") buildConfigField("boolean", "DEFAULT_ENABLE_ANALYTICS", "false") val properties = Properties() if (project.rootProject.file("local.properties").exists()) { properties.load(project.rootProject.file("local.properties").reader()) // grab matomo.url buildConfigField( "String", "ANALYTICS_ENDPOINT", "\"" + properties.getProperty( "matomo.url", "https://s-api.androidacy.com/matomo.php" ) + "\"" ) } else { buildConfigField( "String", "ANALYTICS_ENDPOINT", "\"https://s-api.androidacy.com/matomo.php\"" ) } buildConfigField("boolean", "ENABLE_PROTECTION", "true") // Repo with ads or tracking feature are disabled by default for the // F-Droid flavor. at the same time, the alt repo isn"t particularly trustworthy buildConfigField( "java.util.List", "ENABLED_REPOS", "java.util.Arrays.asList(\"\")", ) // Get the androidacy client ID from the androidacy.properties val propertiesA = Properties() // If androidacy.properties doesn"t exist, use the fdroid client ID which is limited // to 50 requests per minute if (project.rootProject.file("androidacy.properties").exists()) { propertiesA.load(project.rootProject.file("androidacy.properties").inputStream()) } else { propertiesA.setProperty( "client_id", "dQ1p7X8bF14PVJ7wAU6ORVjPB2IeTinsuAZ8Uos6tQiyUdUyIjSyZSmN54QBbaTy" ) } buildConfigField( "String", "ANDROIDACY_CLIENT_ID", "\"" + propertiesA.getProperty( "client_id", "dQ1p7X8bF14PVJ7wAU6ORVjPB2IeTinsuAZ8Uos6tQiyUdUyIjSyZSmN54QBbaTy" ) + "\"" ) versionNameSuffix = "-froid" } } compileOptions { isCoreLibraryDesugaringEnabled = true sourceCompatibility = JavaVersion.VERSION_19 targetCompatibility = JavaVersion.VERSION_19 } lint { disable.add("MissingTranslation") } } sentry { includeProguardMapping.set(true) autoUploadProguardMapping.set(hasSentryConfig) experimentalGuardsquareSupport.set(true) uploadNativeSymbols.set(hasSentryConfig) includeNativeSources.set(true) tracingInstrumentation { enabled.set(true) features.set( setOf( InstrumentationFeature.DATABASE, InstrumentationFeature.FILE_IO, InstrumentationFeature.OKHTTP, InstrumentationFeature.COMPOSE ) ) logcat { enabled.set(true) minLevel.set(LogcatLevel.WARNING) } } autoInstallation { enabled.set(true) sentryVersion.set("6.18.1") } includeDependenciesReport.set(true) } val abiCodes = mapOf("armeabi-v7a" to 1, "x86" to 2, "x86_64" to 3) // For per-density APKs, create a similar map: // val densityCodes = mapOf("mdpi" to 1, "hdpi" to 2, "xhdpi" to 3) // For each APK output variant, override versionCode with a combination of // abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode // is equal to defaultConfig.versionCode. If you configure product flavors that // define their own versionCode, variant.versionCode uses that value instead. androidComponents { onVariants { variant -> // Assigns a different version code for each output APK // other than the universal APK. variant.outputs.forEach { output -> val name = output.filters.find { it.filterType == ABI }?.identifier // Stores the value of abiCodes that is associated with the ABI for this variant. val baseAbiCode = abiCodes[name] // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes, // the following code doesn't override the version code for universal APKs. // However, because you want universal APKs to have the lowest version code, // this outcome is desirable. if (baseAbiCode != null) { // Assigns the new version code to output.versionCode, which changes the version code // for only the output APK, not for the variant itself. val versioCode = output.versionCode.get() as Int output.versionCode.set(baseAbiCode * 1000 + versioCode) } } } } aboutLibraries { // Specify the additional licenses additionalLicenses = arrayOf("LGPL_3_0_only", "Apache_2_0") } configurations { // Access all imported libraries all { // Exclude all libraries with the following group and module exclude(group = "org.jetbrains", module = "annotations-java5") } } dependencies { // UI implementation("androidx.appcompat:appcompat:1.6.1") implementation("androidx.activity:activity-ktx:1.7.1") implementation("androidx.emoji2:emoji2:1.3.0") implementation("androidx.emoji2:emoji2-views-helper:1.3.0") implementation("androidx.preference:preference-ktx:1.2.0") implementation("androidx.constraintlayout:constraintlayout:2.1.4") implementation("androidx.recyclerview:recyclerview:1.3.0") implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") implementation("androidx.webkit:webkit:1.6.1") implementation("com.google.android.material:material:1.8.0") implementation("dev.rikka.rikkax.layoutinflater:layoutinflater:1.3.0") implementation("dev.rikka.rikkax.insets:insets:1.3.0") implementation("com.github.KieronQuinn:MonetCompat:0.4.1") implementation("com.github.Fox2Code:FoxCompat:0.2.0") implementation("com.mikepenz:aboutlibraries:10.6.2") // Utils implementation("androidx.work:work-runtime:2.8.1") implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.10") implementation("com.squareup.okhttp3:okhttp-dnsoverhttps:5.0.0-alpha.10") // logging interceptor implementation("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.10") // Chromium cronet from androidacy implementation("org.chromium.net:cronet-embedded:108.5359.79") // protobuf - fixes a crash on some devices // implementation("com.google.protobuf:protobuf-javalite:3.22.2") // google guava, maybe fix a bug implementation("com.google.guava:guava:31.1-jre") val libsuVersion = "5.0.5" // The core module that provides APIs to a shell implementation("com.github.topjohnwu.libsu:core:${libsuVersion}") // Optional: APIs for creating root services. Depends on ":core" implementation("com.github.topjohnwu.libsu:service:${libsuVersion}") // Optional: Provides remote file system support implementation("com.github.topjohnwu.libsu:io:${libsuVersion}") implementation("com.github.Fox2Code:RosettaX:1.0.9") implementation("com.github.Fox2Code:AndroidANSI:1.0.1") // sentry implementation("io.sentry:sentry-android:6.18.1") implementation("io.sentry:sentry-android-timber:6.18.1") implementation("io.sentry:sentry-android-fragment:6.18.1") implementation("io.sentry:sentry-android-okhttp:6.18.1") implementation("io.sentry:sentry-kotlin-extensions:6.18.1") implementation("io.sentry:sentry-android-ndk:6.18.1") // Markdown // TODO: switch to an updated implementation implementation("io.noties.markwon:core:4.6.2") implementation("io.noties.markwon:html:4.6.2") implementation("io.noties.markwon:image:4.6.2") implementation("io.noties.markwon:syntax-highlight:4.6.2") implementation("com.google.net.cronet:cronet-okhttp:0.1.0") implementation("com.caverock:androidsvg:1.4") implementation("androidx.core:core-ktx:1.10.0") // timber implementation("com.jakewharton.timber:timber:5.0.1") // encryption implementation("androidx.security:security-crypto:1.1.0-alpha06") // some utils implementation("commons-io:commons-io:20030203.000550") implementation("org.apache.commons:commons-compress:1.23.0") // analytics implementation("com.github.matomo-org:matomo-sdk-android:HEAD") // annotations implementation("org.jetbrains:annotations-java5:24.0.1") // debugging debugImplementation("com.squareup.leakcanary:leakcanary-android:2.10") // desugaring coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3") } android { ndkVersion = "25.2.9519653" dependenciesInfo { includeInApk = false includeInBundle = false } buildFeatures { viewBinding = true buildConfig = true } //noinspection GrDeprecatedAPIUsage buildToolsVersion = "34.0.0 rc3" @Suppress("DEPRECATION") packagingOptions { jniLibs { useLegacyPackaging = true } } } java { toolchain { languageVersion.set(JavaLanguageVersion.of(19)) } }