mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-28 09:30:23 +08:00
[build] Support both configuring Android targets by Android SDK or JVM
- try to fix sdk dir when android is desired - Do not printAndroidNotInstalled multiple times
This commit is contained in:
parent
2cf97a181f
commit
4ed551027a
12
.github/workflows/release.yml
vendored
12
.github/workflows/release.yml
vendored
@ -74,6 +74,18 @@ jobs:
|
|||||||
GPG_PRIVATE: ${{ secrets.GPG_PRIVATE_KEY }}
|
GPG_PRIVATE: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
GPG_PUBLIC_: ${{ secrets.GPG_PUBLIC_KEY }}
|
GPG_PUBLIC_: ${{ secrets.GPG_PUBLIC_KEY }}
|
||||||
|
|
||||||
|
- name: Setup Android SDK Ubuntu
|
||||||
|
if: ${{ env.isUbuntu == 'true' }}
|
||||||
|
run: 'touch local.properties && echo sdk.dir=/usr/local/lib/android/sdk >> local.properties'
|
||||||
|
|
||||||
|
- name: Setup Android SDK macOS
|
||||||
|
if: ${{ env.isMac == 'true' }}
|
||||||
|
run: 'touch local.properties && echo sdk.dir=/Users/runner/Library/Android/sdk >> local.properties'
|
||||||
|
|
||||||
|
- name: Setup Android SDK Windows
|
||||||
|
if: ${{ env.isWindows == 'true' }}
|
||||||
|
run: 'echo sdk.dir=C:\Android\android-sdk >> local.properties'
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/gradle-build-action@v2
|
uses: gradle/gradle-build-action@v2
|
||||||
|
|
||||||
|
268
buildSrc/src/main/kotlin/Android.kt
Normal file
268
buildSrc/src/main/kotlin/Android.kt
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2023 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("UNUSED_VARIABLE")
|
||||||
|
|
||||||
|
import com.android.build.api.dsl.LibraryExtension
|
||||||
|
import org.gradle.api.JavaVersion
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.kotlin.dsl.*
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
const val PROP_MIRAI_ENABLE_ANDROID_INSTRUMENTED_TESTS = "mirai.enable.android.instrumented.tests"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use [usingAndroidInstrumentedTests] instead.
|
||||||
|
*/
|
||||||
|
val ENABLE_ANDROID_INSTRUMENTED_TESTS by projectLazy {
|
||||||
|
val name = PROP_MIRAI_ENABLE_ANDROID_INSTRUMENTED_TESTS
|
||||||
|
(System.getProperty(name)
|
||||||
|
?: System.getenv(name)
|
||||||
|
?: rootProject.getLocalProperty(name)
|
||||||
|
?: "true").toBooleanStrict()
|
||||||
|
}
|
||||||
|
|
||||||
|
val Project.usingAndroidInstrumentedTests
|
||||||
|
get() = ENABLE_ANDROID_INSTRUMENTED_TESTS && isAndroidSdkAvailable
|
||||||
|
|
||||||
|
fun Project.configureAndroidTarget() {
|
||||||
|
if (ENABLE_ANDROID_INSTRUMENTED_TESTS && !isAndroidSdkAvailable) {
|
||||||
|
if (!ProjectAndroidSdkAvailability.tryFixAndroidSdk(this)) {
|
||||||
|
printAndroidNotInstalled()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions.getByType(KotlinMultiplatformExtension::class.java).apply {
|
||||||
|
if (project.usingAndroidInstrumentedTests) {
|
||||||
|
configureAndroidTargetWithSdk()
|
||||||
|
} else {
|
||||||
|
configureAndroidTargetWithJvm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Project.configureAndroidTargetWithJvm() {
|
||||||
|
extensions.getByType(KotlinMultiplatformExtension::class.java).apply {
|
||||||
|
jvm("android") {
|
||||||
|
jvmToolchain(JVM_TOOLCHAIN_VERSION)
|
||||||
|
attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.androidJvm)
|
||||||
|
|
||||||
|
if (IDEA_ACTIVE) {
|
||||||
|
attributes.attribute(MIRAI_PLATFORM_ATTRIBUTE, "android") // workaround for IDE bug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets.getByName("androidTest").configureJvmTest("configureAndroidTargetWithJvm")
|
||||||
|
sourceSets.getByName("androidTest").kotlin.srcDir(projectDir.resolve("src/androidUnitTest/kotlin"))
|
||||||
|
|
||||||
|
sourceSets.getByName("androidMain").apply {
|
||||||
|
dependencies {
|
||||||
|
compileOnly(`android-runtime`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
private fun Project.configureAndroidTargetWithSdk() {
|
||||||
|
extensions.getByType(KotlinMultiplatformExtension::class.java).apply {
|
||||||
|
android {
|
||||||
|
if (IDEA_ACTIVE) {
|
||||||
|
attributes.attribute(MIRAI_PLATFORM_ATTRIBUTE, "android") // workaround for IDE bug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmBaseMain = sourceSets.maybeCreate("jvmBaseMain")
|
||||||
|
val jvmBaseTest = sourceSets.maybeCreate("jvmBaseTest")
|
||||||
|
|
||||||
|
val androidMain by sourceSets.getting
|
||||||
|
androidMain.dependsOn(jvmBaseMain)
|
||||||
|
|
||||||
|
// don't use androidTest, deprecated by Kotlin
|
||||||
|
|
||||||
|
// this can cause problems on sync
|
||||||
|
// for (s in arrayOf("androidDebug", "androidRelease")) {
|
||||||
|
// sourceSets.all { if (name in s) dependsOn(androidMain) }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// we should have added a "androidBaseTest" (or "androidTest") for "androidUnitTest" and "androidInstrumentedTest",
|
||||||
|
// but this currently cause bugs in IntelliJ (2023.2)
|
||||||
|
// val androidBaseTest = sourceSets.maybeCreate("androidBaseTest").apply {
|
||||||
|
// dependsOn(jvmBaseTest)
|
||||||
|
// }
|
||||||
|
val androidUnitTest by sourceSets.getting {
|
||||||
|
dependsOn(jvmBaseTest)
|
||||||
|
}
|
||||||
|
// for (s in arrayOf("androidUnitTestDebug", "androidUnitTestRelease")) {
|
||||||
|
// sourceSets.all { if (name in s) dependsOn(androidUnitTest) }
|
||||||
|
// }
|
||||||
|
val androidInstrumentedTest by sourceSets.getting {
|
||||||
|
dependsOn(jvmBaseTest)
|
||||||
|
}
|
||||||
|
// for (s in arrayOf("androidInstrumentedTestDebug")) {
|
||||||
|
// sourceSets.all { if (name in s) dependsOn(androidInstrumentedTest) }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// afterEvaluate {
|
||||||
|
//// > androidDebug dependsOn commonMain
|
||||||
|
//// androidInstrumentedTest dependsOn jvmBaseTest
|
||||||
|
//// androidInstrumentedTestDebug dependsOn
|
||||||
|
//// androidMain dependsOn commonMain, jvmBaseMain
|
||||||
|
//// androidRelease dependsOn commonMain
|
||||||
|
//// androidUnitTest dependsOn commonTest, jvmBaseTest
|
||||||
|
//// androidUnitTestDebug dependsOn commonTest
|
||||||
|
//// androidUnitTestRelease dependsOn commonTest
|
||||||
|
// error(this@apply.sourceSets.joinToString("\n") {
|
||||||
|
// it.name + " dependsOn " + it.dependsOn.joinToString { it.name }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
configure(
|
||||||
|
listOf(
|
||||||
|
sourceSets.getByName("androidInstrumentedTest"),
|
||||||
|
sourceSets.getByName("androidUnitTest"),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
dependencies { implementation(kotlin("test-annotations-common"))?.because("configureAndroidTargetWithSdk") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// trick for compiler bug
|
||||||
|
this.sourceSets.apply {
|
||||||
|
removeIf { it.name == "androidAndroidTestRelease" }
|
||||||
|
removeIf { it.name == "androidTestFixtures" }
|
||||||
|
removeIf { it.name == "androidTestFixturesDebug" }
|
||||||
|
removeIf { it.name == "androidTestFixturesRelease" }
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions.getByType(LibraryExtension::class.java).apply {
|
||||||
|
compileSdk = 33
|
||||||
|
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
||||||
|
defaultConfig {
|
||||||
|
minSdk = rootProject.extra["mirai.android.target.api.level"]!!.toString().toInt()
|
||||||
|
targetSdk = 33
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
buildTypes.getByName("release") {
|
||||||
|
isMinifyEnabled = true
|
||||||
|
isShrinkResources = false
|
||||||
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions.getByType(LibraryExtension::class.java).apply {
|
||||||
|
defaultConfig {
|
||||||
|
// 1) Make sure to use the AndroidJUnitRunner, or a subclass of it. This requires a dependency on androidx.test:runner, too!
|
||||||
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
// 2) Connect JUnit 5 to the runner
|
||||||
|
testInstrumentationRunnerArguments["runnerBuilder"] = "de.mannodermaus.junit5.AndroidJUnit5Builder"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// val sourceSets = arrayOf("androidInstrumentedTest", "androidUnitTest")
|
||||||
|
// .map { kotlin.sourceSets.getByName(it) }
|
||||||
|
|
||||||
|
// for (sourceSet in sourceSets) {
|
||||||
|
// sourceSet.dependencies {
|
||||||
|
// implementation("androidx.test:runner:1.5.2")
|
||||||
|
// implementation("org.junit.jupiter:junit-jupiter-api:5.9.2")
|
||||||
|
// runtimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
||||||
|
//
|
||||||
|
// implementation("de.mannodermaus.junit5:android-test-core:1.3.0")
|
||||||
|
// implementation("de.mannodermaus.junit5:android-test-runner:1.3.0")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// 4) Jupiter API & Test Runner, if you don't have it already
|
||||||
|
"androidTestImplementation"("androidx.test:runner:1.5.2")
|
||||||
|
"androidTestImplementation"("org.junit.jupiter:junit-jupiter-api:${Versions.junit}")
|
||||||
|
"androidTestRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:${Versions.junit}")
|
||||||
|
|
||||||
|
// 5) The instrumentation test companion libraries
|
||||||
|
"androidTestImplementation"("de.mannodermaus.junit5:android-test-core:1.3.0")
|
||||||
|
"androidTestRuntimeOnly"("de.mannodermaus.junit5:android-test-runner:1.3.0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Project.printAndroidNotInstalled() {
|
||||||
|
logger.warn(
|
||||||
|
"""
|
||||||
|
你设置了启用 Android Instrumented Test, 但是未配置 Android SDK. $name 的 Android 目标将会使用桌面 JVM 编译和测试.
|
||||||
|
Android Instrumented Test 将不会进行. 这不会影响 Android 以外的平台的编译和测试.
|
||||||
|
|
||||||
|
如果你要给 mirai PR 并且你修改了 Android 部分, 建议解决此警告.
|
||||||
|
如果你没有修改 Android 部分, 则可以忽略, 或者在项目根目录 local.properties (如果不存在就创建一个) 添加 `$PROP_MIRAI_ENABLE_ANDROID_INSTRUMENTED_TESTS=false`.
|
||||||
|
|
||||||
|
在安装 Android SDK 后, 请在项目根目录 local.properties 中添加 `sdk.dir=/path/to/Android/sdk` 指向本机 Android SDK 安装路径.
|
||||||
|
|
||||||
|
若要关闭 Android Instrumented Test, 在项目根目录 local.properties 添加 `$PROP_MIRAI_ENABLE_ANDROID_INSTRUMENTED_TESTS=false`.
|
||||||
|
-------
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
// logger.warn(
|
||||||
|
// """Android SDK might not be installed. Android target of $name will not be compiled. It does no influence on the compilation of other platforms.
|
||||||
|
// """.trimIndent()
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private object ProjectAndroidSdkAvailability {
|
||||||
|
val map: MutableMap<String, Boolean> by projectLazy { mutableMapOf() }
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
operator fun get(project: Project): Boolean {
|
||||||
|
if (map[project.path] != null) return map[project.path]!!
|
||||||
|
|
||||||
|
val projectAvailable = project.runCatching {
|
||||||
|
val keyProps = Properties().apply {
|
||||||
|
file("local.properties").takeIf { it.exists() }?.inputStream()?.use { load(it) }
|
||||||
|
}
|
||||||
|
keyProps.getProperty("sdk.dir", "").isNotEmpty()
|
||||||
|
}.getOrElse { false }
|
||||||
|
|
||||||
|
|
||||||
|
fun impl(): Boolean {
|
||||||
|
if (project === project.rootProject) return projectAvailable
|
||||||
|
return projectAvailable || get(project.rootProject)
|
||||||
|
}
|
||||||
|
map[project.path] = impl()
|
||||||
|
return map[project.path]!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tryFixAndroidSdk(project: Project): Boolean {
|
||||||
|
val androidHome = System.getenv("ANDROID_HOME") ?: kotlin.run {
|
||||||
|
project.logger.info("tryFixAndroidSdk: environment `ANDROID_HOME` does not exist")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val escaped = androidHome
|
||||||
|
.replace(""":""", """\:""")
|
||||||
|
.replace("""\""", """\\""")
|
||||||
|
.trim()
|
||||||
|
|
||||||
|
project.rootDir.resolve("local.properties")
|
||||||
|
.apply { if (!exists()) createNewFile() }
|
||||||
|
.appendText("sdk.dir=$escaped")
|
||||||
|
|
||||||
|
project.logger.info("tryFixAndroidSdk: fixed sdk.dir in local.properties: $escaped")
|
||||||
|
|
||||||
|
map.clear()
|
||||||
|
return get(project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val Project.isAndroidSdkAvailable: Boolean get() = ProjectAndroidSdkAvailability[this]
|
@ -9,12 +9,13 @@
|
|||||||
|
|
||||||
@file:Suppress("UNUSED_VARIABLE")
|
@file:Suppress("UNUSED_VARIABLE")
|
||||||
|
|
||||||
import com.android.build.api.dsl.LibraryExtension
|
|
||||||
import com.google.gradle.osdetector.OsDetector
|
import com.google.gradle.osdetector.OsDetector
|
||||||
import org.gradle.api.JavaVersion
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.attributes.Attribute
|
import org.gradle.api.attributes.Attribute
|
||||||
import org.gradle.kotlin.dsl.*
|
import org.gradle.kotlin.dsl.get
|
||||||
|
import org.gradle.kotlin.dsl.getting
|
||||||
|
import org.gradle.kotlin.dsl.provideDelegate
|
||||||
|
import org.gradle.kotlin.dsl.withType
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPILATION_NAME
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPILATION_NAME
|
||||||
@ -155,6 +156,16 @@ val NATIVE_TARGETS by projectLazy { UNIX_LIKE_TARGETS + WIN_TARGETS }
|
|||||||
|
|
||||||
private val POSSIBLE_NATIVE_TARGETS by lazy { setOf("mingwX64", "macosX64", "macosArm64", "linuxX64") }
|
private val POSSIBLE_NATIVE_TARGETS by lazy { setOf("mingwX64", "macosX64", "macosArm64", "linuxX64") }
|
||||||
|
|
||||||
|
const val JVM_TOOLCHAIN_VERSION = 8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ## Android Test 结构
|
||||||
|
*
|
||||||
|
* 如果[启用 Android Instrumented Test][ENABLE_ANDROID_INSTRUMENTED_TESTS], 将会配置使用 Android SDK 配置真 Android target,
|
||||||
|
* `androidMain` 将能访问 Android SDK, 也能获得针对 Android 的 IDE 错误检查.
|
||||||
|
*
|
||||||
|
* @see configureNativeTargetsHierarchical
|
||||||
|
*/
|
||||||
fun Project.configureJvmTargetsHierarchical() {
|
fun Project.configureJvmTargetsHierarchical() {
|
||||||
extensions.getByType(KotlinMultiplatformExtension::class.java).apply {
|
extensions.getByType(KotlinMultiplatformExtension::class.java).apply {
|
||||||
val commonMain by sourceSets.getting
|
val commonMain by sourceSets.getting
|
||||||
@ -162,15 +173,21 @@ fun Project.configureJvmTargetsHierarchical() {
|
|||||||
|
|
||||||
if (IDEA_ACTIVE) {
|
if (IDEA_ACTIVE) {
|
||||||
jvm("jvmBase") { // dummy target for resolution, not published
|
jvm("jvmBase") { // dummy target for resolution, not published
|
||||||
|
jvmToolchain(JVM_TOOLCHAIN_VERSION)
|
||||||
compilations.all {
|
compilations.all {
|
||||||
this.compileTaskProvider.configure { // IDE complain
|
// magic to help IDEA
|
||||||
|
this.compileTaskProvider.configure {
|
||||||
enabled = false
|
enabled = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.common) // magic
|
attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.common) // magic
|
||||||
attributes.attribute(MIRAI_PLATFORM_ATTRIBUTE, "jvmBase") // avoid resolution
|
|
||||||
attributes.attribute(MIRAI_PLATFORM_INTERMEDIATE, true)
|
// avoid resolution when other modules dependsOn this project
|
||||||
|
attributes.attribute(MIRAI_PLATFORM_ATTRIBUTE, "jvmBase")
|
||||||
|
attributes.attribute(MIRAI_PLATFORM_INTERMEDIATE, true) // no shadow
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// if not in IDEA, no need to create intermediate targets.
|
||||||
}
|
}
|
||||||
|
|
||||||
val jvmBaseMain by lazy {
|
val jvmBaseMain by lazy {
|
||||||
@ -185,62 +202,12 @@ fun Project.configureJvmTargetsHierarchical() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isTargetEnabled("android")) {
|
if (isTargetEnabled("android")) {
|
||||||
if (isAndroidSDKAvailable) {
|
configureAndroidTarget()
|
||||||
// apply(plugin = "com.android.library")
|
|
||||||
android {
|
|
||||||
if (IDEA_ACTIVE) {
|
|
||||||
attributes.attribute(MIRAI_PLATFORM_ATTRIBUTE, "android") // avoid resolution
|
|
||||||
}
|
|
||||||
}
|
|
||||||
configureAndroidTarget()
|
|
||||||
val androidMain by sourceSets.getting
|
|
||||||
for (s in arrayOf("androidMain")) {
|
|
||||||
sourceSets.all { if (name in s) dependsOn(jvmBaseMain) }
|
|
||||||
}
|
|
||||||
// this can cause problems on sync
|
|
||||||
// for (s in arrayOf("androidDebug", "androidRelease")) {
|
|
||||||
// sourceSets.all { if (name in s) dependsOn(androidMain) }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// we should have added a "androidBaseTest" (or "androidTest") for "androidUnitTest" and "androidInstrumentedTest",
|
|
||||||
// but this currently cause bugs in IntelliJ (2023.2)
|
|
||||||
// val androidBaseTest = sourceSets.maybeCreate("androidBaseTest").apply {
|
|
||||||
// dependsOn(jvmBaseTest)
|
|
||||||
// }
|
|
||||||
val androidUnitTest by sourceSets.getting {
|
|
||||||
dependsOn(jvmBaseTest)
|
|
||||||
}
|
|
||||||
// for (s in arrayOf("androidUnitTestDebug", "androidUnitTestRelease")) {
|
|
||||||
// sourceSets.all { if (name in s) dependsOn(androidUnitTest) }
|
|
||||||
// }
|
|
||||||
val androidInstrumentedTest by sourceSets.getting {
|
|
||||||
dependsOn(jvmBaseTest)
|
|
||||||
}
|
|
||||||
// for (s in arrayOf("androidInstrumentedTestDebug")) {
|
|
||||||
// sourceSets.all { if (name in s) dependsOn(androidInstrumentedTest) }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// afterEvaluate {
|
|
||||||
//// > androidDebug dependsOn commonMain
|
|
||||||
//// androidInstrumentedTest dependsOn jvmBaseTest
|
|
||||||
//// androidInstrumentedTestDebug dependsOn
|
|
||||||
//// androidMain dependsOn commonMain, jvmBaseMain
|
|
||||||
//// androidRelease dependsOn commonMain
|
|
||||||
//// androidUnitTest dependsOn commonTest, jvmBaseTest
|
|
||||||
//// androidUnitTestDebug dependsOn commonTest
|
|
||||||
//// androidUnitTestRelease dependsOn commonTest
|
|
||||||
// error(this@apply.sourceSets.joinToString("\n") {
|
|
||||||
// it.name + " dependsOn " + it.dependsOn.joinToString { it.name }
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
} else {
|
|
||||||
printAndroidNotInstalled()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTargetEnabled("jvm")) {
|
if (isTargetEnabled("jvm")) {
|
||||||
jvm("jvm") {
|
jvm("jvm") {
|
||||||
|
jvmToolchain(JVM_TOOLCHAIN_VERSION)
|
||||||
}
|
}
|
||||||
val jvmMain by sourceSets.getting
|
val jvmMain by sourceSets.getting
|
||||||
val jvmTest by sourceSets.getting
|
val jvmTest by sourceSets.getting
|
||||||
@ -250,67 +217,9 @@ fun Project.configureJvmTargetsHierarchical() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UnstableApiUsage")
|
|
||||||
fun Project.configureAndroidTarget() {
|
|
||||||
extensions.getByType(KotlinMultiplatformExtension::class.java).apply {
|
|
||||||
|
|
||||||
// trick
|
|
||||||
this.sourceSets.apply {
|
|
||||||
removeIf { it.name == "androidAndroidTestRelease" }
|
|
||||||
removeIf { it.name == "androidTestFixtures" }
|
|
||||||
removeIf { it.name == "androidTestFixturesDebug" }
|
|
||||||
removeIf { it.name == "androidTestFixturesRelease" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extensions.getByType(LibraryExtension::class.java).apply {
|
|
||||||
compileSdk = 33
|
|
||||||
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
|
||||||
defaultConfig {
|
|
||||||
minSdk = rootProject.extra["mirai.android.target.api.level"]!!.toString().toInt()
|
|
||||||
targetSdk = 33
|
|
||||||
}
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
buildTypes.getByName("release") {
|
|
||||||
isMinifyEnabled = true
|
|
||||||
isShrinkResources = false
|
|
||||||
proguardFiles(
|
|
||||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (USE_JUNIT5_FOR_ANDROID_TEST) {
|
|
||||||
// extensions.getByType(LibraryExtension::class.java).apply {
|
|
||||||
// defaultConfig {
|
|
||||||
// // 1) Make sure to use the AndroidJUnitRunner, or a subclass of it. This requires a dependency on androidx.test:runner, too!
|
|
||||||
// testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
|
||||||
// // 2) Connect JUnit 5 to the runner
|
|
||||||
// testInstrumentationRunnerArguments["runnerBuilder"] = "de.mannodermaus.junit5.AndroidJUnit5Builder"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// dependencies {
|
|
||||||
// // 4) Jupiter API & Test Runner, if you don't have it already
|
|
||||||
// "androidTestImplementation"("androidx.test:runner:1.5.2")
|
|
||||||
// "androidTestImplementation"("org.junit.jupiter:junit-jupiter-api:5.9.2")
|
|
||||||
// runtimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
|
||||||
//
|
|
||||||
// // 5) The instrumentation test companion libraries
|
|
||||||
// "androidTestImplementation"("de.mannodermaus.junit5:android-test-core:1.3.0")
|
|
||||||
// "androidTestRuntimeOnly"("de.mannodermaus.junit5:android-test-runner:1.3.0")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private const val USE_JUNIT5_FOR_ANDROID_TEST = true
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Target 结构:
|
||||||
* ```
|
* ```
|
||||||
* common
|
* common
|
||||||
* |
|
* |
|
||||||
@ -326,7 +235,9 @@ private const val USE_JUNIT5_FOR_ANDROID_TEST = true
|
|||||||
* <darwin targets>
|
* <darwin targets>
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* `<darwin targets>`: macosX64, macosArm64, tvosX64, iosArm64, iosArm32...
|
* `<darwin targets>`: macosX64, macosArm64
|
||||||
|
*
|
||||||
|
* @see configureJvmTargetsHierarchical
|
||||||
*/
|
*/
|
||||||
fun KotlinMultiplatformExtension.configureNativeTargetsHierarchical(
|
fun KotlinMultiplatformExtension.configureNativeTargetsHierarchical(
|
||||||
project: Project
|
project: Project
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
* Copyright 2019-2023 Mamoe Technologies and contributors.
|
||||||
*
|
*
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
@ -16,35 +16,6 @@ import org.gradle.api.artifacts.component.ComponentSelector
|
|||||||
import org.gradle.api.plugins.ExtensionAware
|
import org.gradle.api.plugins.ExtensionAware
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
|
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
private object ProjectAndroidSdkAvailability {
|
|
||||||
val map: MutableMap<String, Boolean> = mutableMapOf()
|
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER", "UNREACHABLE_CODE")
|
|
||||||
@Synchronized
|
|
||||||
operator fun get(project: Project): Boolean {
|
|
||||||
return true
|
|
||||||
if (map[project.path] != null) return map[project.path]!!
|
|
||||||
|
|
||||||
val projectAvailable = project.runCatching {
|
|
||||||
val keyProps = Properties().apply {
|
|
||||||
file("local.properties").takeIf { it.exists() }?.inputStream()?.use { load(it) }
|
|
||||||
}
|
|
||||||
keyProps.getProperty("sdk.dir", "").isNotEmpty()
|
|
||||||
}.getOrElse { false }
|
|
||||||
|
|
||||||
|
|
||||||
fun impl(): Boolean {
|
|
||||||
if (project === project.rootProject) return projectAvailable
|
|
||||||
return projectAvailable || get(project.rootProject)
|
|
||||||
}
|
|
||||||
map[project.path] = impl()
|
|
||||||
return map[project.path]!!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val Project.isAndroidSDKAvailable: Boolean get() = ProjectAndroidSdkAvailability[this]
|
|
||||||
|
|
||||||
val <T> NamedDomainObjectCollection<T>.androidMain: NamedDomainObjectProvider<T>
|
val <T> NamedDomainObjectCollection<T>.androidMain: NamedDomainObjectProvider<T>
|
||||||
get() = named("androidMain")
|
get() = named("androidMain")
|
||||||
@ -61,16 +32,6 @@ val <T> NamedDomainObjectCollection<T>.jvmTest: NamedDomainObjectProvider<T>
|
|||||||
val <T> NamedDomainObjectCollection<T>.commonMain: NamedDomainObjectProvider<T>
|
val <T> NamedDomainObjectCollection<T>.commonMain: NamedDomainObjectProvider<T>
|
||||||
get() = named("commonMain")
|
get() = named("commonMain")
|
||||||
|
|
||||||
fun Project.printAndroidNotInstalled() {
|
|
||||||
println(
|
|
||||||
"""Android SDK 可能未安装. $name 的 Android 目标编译将不会进行. 这不会影响 Android 以外的平台的编译.
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
println(
|
|
||||||
"""Android SDK might not be installed. Android target of $name will not be compiled. It does no influence on the compilation of other platforms.
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun forMppModules(action: (suffix: String) -> Unit) {
|
inline fun forMppModules(action: (suffix: String) -> Unit) {
|
||||||
arrayOf(
|
arrayOf(
|
||||||
|
@ -92,21 +92,6 @@ fun Project.configureJvmTarget() {
|
|||||||
|
|
||||||
allKotlinTargets().all {
|
allKotlinTargets().all {
|
||||||
if (this !is KotlinJvmTarget) return@all
|
if (this !is KotlinJvmTarget) return@all
|
||||||
when (this.attributes.getAttribute(KotlinPlatformType.attribute)) { // mirai does magic, don't use target.platformType
|
|
||||||
KotlinPlatformType.androidJvm -> {
|
|
||||||
this.compilations.all {
|
|
||||||
/*
|
|
||||||
* Kotlin JVM compiler generates Long.hashCode witch is available since API 26 when targeting JVM 1.8 while IR prefer member function hashCode always.
|
|
||||||
*/
|
|
||||||
// kotlinOptions.useIR = true
|
|
||||||
|
|
||||||
// IR cannot compile mirai. We'll wait for Kotlin 1.5 for stable IR release.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.testRuns["test"].executionTask.configure { useJUnitPlatform() }
|
this.testRuns["test"].executionTask.configure { useJUnitPlatform() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,37 +120,23 @@ fun Project.configureKotlinTestSettings() {
|
|||||||
isKotlinMpp -> {
|
isKotlinMpp -> {
|
||||||
kotlinSourceSets?.all {
|
kotlinSourceSets?.all {
|
||||||
val sourceSet = this
|
val sourceSet = this
|
||||||
fun configureJvmTest(sourceSet: KotlinSourceSet) {
|
|
||||||
sourceSet.dependencies {
|
|
||||||
implementation(kotlin("test-junit5"))?.because(b)
|
|
||||||
|
|
||||||
implementation(`junit-jupiter-api`)?.because(b)
|
|
||||||
runtimeOnly(`junit-jupiter-engine`)?.because(b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val target = allKotlinTargets()
|
val target = allKotlinTargets()
|
||||||
.find { it.name == sourceSet.name.substringBeforeLast("Main").substringBeforeLast("Test") }
|
.find { it.name == sourceSet.name.substringBeforeLast("Main").substringBeforeLast("Test") }
|
||||||
|
|
||||||
when {
|
if (sourceSet.name.contains("test", ignoreCase = true)) {
|
||||||
sourceSet.name == "commonTest" -> {
|
if (isJvmFinalTarget(target)) {
|
||||||
if (target?.platformType == KotlinPlatformType.jvm &&
|
// For android, this should be done differently. See Android.kt
|
||||||
target.attributes.getAttribute(MIRAI_PLATFORM_INTERMEDIATE) != true
|
sourceSet.configureJvmTest(b)
|
||||||
) {
|
} else {
|
||||||
configureJvmTest(sourceSet)
|
if (sourceSet.name == "commonTest") {
|
||||||
} else {
|
|
||||||
sourceSet.dependencies {
|
sourceSet.dependencies {
|
||||||
implementation(kotlin("test"))?.because(b)
|
implementation(kotlin("test"))?.because(b)
|
||||||
implementation(kotlin("test-annotations-common"))?.because(b)
|
implementation(kotlin("test-annotations-common"))?.because(b)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
}
|
// can be an Android sourceSet
|
||||||
|
// Do not even add "kotlin-test" for Android sourceSets. IDEA can't resolve them on sync
|
||||||
sourceSet.name.contains("test", ignoreCase = true) -> {
|
|
||||||
if (target?.platformType == KotlinPlatformType.jvm &&
|
|
||||||
target.attributes.getAttribute(MIRAI_PLATFORM_INTERMEDIATE) != true
|
|
||||||
) {
|
|
||||||
configureJvmTest(sourceSet)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,6 +145,19 @@ fun Project.configureKotlinTestSettings() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isJvmFinalTarget(target: KotlinTarget?) =
|
||||||
|
target?.platformType == KotlinPlatformType.jvm &&
|
||||||
|
target.attributes.getAttribute(MIRAI_PLATFORM_INTERMEDIATE) != true // jvmBase is intermediate
|
||||||
|
|
||||||
|
fun KotlinSourceSet.configureJvmTest(because: String) {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-junit5"))?.because(because)
|
||||||
|
|
||||||
|
implementation(`junit-jupiter-api`)?.because(because)
|
||||||
|
runtimeOnly(`junit-jupiter-engine`)?.because(because)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun isJvmLikePlatform(target: KotlinTarget?) =
|
private fun isJvmLikePlatform(target: KotlinTarget?) =
|
||||||
target?.platformType == KotlinPlatformType.jvm || target?.platformType == KotlinPlatformType.androidJvm
|
target?.platformType == KotlinPlatformType.jvm || target?.platformType == KotlinPlatformType.androidJvm
|
||||||
|
|
||||||
|
@ -71,19 +71,13 @@ kotlin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
getByName("androidUnitTest") {
|
findByName("androidUnitTest")?.apply {
|
||||||
dependencies {
|
dependencies {
|
||||||
runtimeOnly(`slf4j-api`)
|
runtimeOnly(`slf4j-api`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findByName("androidMain")?.apply {
|
|
||||||
dependencies {
|
|
||||||
// compileOnly(`android-runtime`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
findByName("jvmMain")?.apply {
|
findByName("jvmMain")?.apply {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
~ Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
~
|
|
||||||
~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
|
||||||
~
|
|
||||||
~ https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
-->
|
|
||||||
|
|
||||||
<manifest package="net.mamoe.mirai" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
|
||||||
</manifest>
|
|
@ -64,13 +64,6 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findByName("androidMain")?.apply {
|
|
||||||
dependencies {
|
|
||||||
compileOnly(`android-runtime`)
|
|
||||||
// api1(`ktor-client-android`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
findByName("jvmMain")?.apply {
|
findByName("jvmMain")?.apply {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -77,17 +77,8 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findByName("androidMain")?.apply {
|
|
||||||
dependencies {
|
|
||||||
compileOnly(`android-runtime`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
findByName("androidTest")?.apply {
|
findByName("androidTest")?.apply {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(kotlin("test", Versions.kotlinCompiler))
|
|
||||||
implementation(kotlin("test-junit5", Versions.kotlinCompiler))
|
|
||||||
implementation(kotlin("test-annotations-common"))
|
|
||||||
implementation(kotlin("test-common"))
|
|
||||||
implementation(bouncycastle)
|
implementation(bouncycastle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user