diff --git a/CHANGELOG.md b/CHANGELOG.md
index c9b8c933a..8679417be 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,14 @@
 
 开发版本. 频繁更新, 不保证高稳定性
 
+## `0.15.2` 2020/2/18
+
+### mirai-core
+- 尝试修复 `atomicfu` 编译错误的问题
+
+### mirai-core-qqandroid
+- 查询群信息失败后重试
+
 ## `0.15.1` 2020/2/15
 
 ### mirai-core
diff --git a/README.md b/README.md
index 62d24d219..e8ed69843 100644
--- a/README.md
+++ b/README.md
@@ -55,7 +55,11 @@ TIM PC (2.3.2 版本,2019 年 8 月)协议的实现,相较于 core,仅
 本模块还未完善。
 
 ## Use as a library
-**mirai-core 为独立设计, 可以作为库内置于任意 Java(JVM)/Android 项目中使用.**   
+**mirai-core 为独立设计, 可以作为库内置于任意 Java(JVM)/Android 项目中使用.**
+
+请将 `VERSION` 替换为最新的版本(如 `0.15.0`):
+[![Download](https://api.bintray.com/packages/him188moe/mirai/mirai-core/images/download.svg)](https://bintray.com/him188moe/mirai/mirai-core/)  
+**Mirai 目前还处于实验性阶段, 我们无法保证任何稳定性, API 也可能会随时修改.**
 
 ### Maven
 Kotlin 在 Maven 上只支持 JVM 平台.
@@ -71,7 +75,7 @@ Kotlin 在 Maven 上只支持 JVM 平台.
 <dependencies>
     <dependency>
         <groupId>net.mamoe</groupId>
-        <artifactId>mirai-core-qqandroid-jvm</artifactId>
+        <artifactId>mirai-core-qqandroid</artifactId>
         <version>0.15.1</version> <!-- 替换版本为最新版本 -->
     </dependency>
 </dependencies>
@@ -85,25 +89,21 @@ repositories{
 }
 ```
 若您需要使用在跨平台项目, 则要对各个目标平台添加不同的依赖,这与 kotlin 相关多平台库的依赖是类似的。  
-**若您只需要使用在单一平台, 则只需要添加一项该平台的依赖. 如只在 JVM 运行则只需要`-jvm`的依赖**  
-
-请将 `VERSION` 替换为最新的版本(如 `0.15.0`):
-[![Download](https://api.bintray.com/packages/him188moe/mirai/mirai-core/images/download.svg)](https://bintray.com/him188moe/mirai/mirai-core/)  
-**Mirai 目前还处于实验性阶段, 我们无法保证任何稳定性, API 也可能会随时修改.**
+**若您只需要使用在单一平台, 则只需要添加一项该平台的依赖.**
 
 **注意:**
 Mirai 核心由 API 模块(`mirai-core`)和协议模块组成。  
 只添加 API 模块将无法正常工作。  
 现在只推荐使用 QQAndroid 协议,请参照下文选择对应目标平台的依赖添加。
 
+**jvm** (JVM 平台)
+```kotlin
+implementation("net.mamoe:mirai-core-qqandroid:VERSION")
+```
 **common** (通用平台)
 ```kotlin
 implementation("net.mamoe:mirai-core-qqandroid-common:VERSION")
 ```
-**jvm** (JVM 平台)
-```kotlin
-implementation("net.mamoe:mirai-core-qqandroid-jvm:VERSION")
-```
 **android** (Android 平台)
 ```kotlin
 implementation("net.mamoe:mirai-core-qqandroid-android:VERSION")
diff --git a/gradle.properties b/gradle.properties
index 443bedc54..525f0504f 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,7 +1,7 @@
 # style guide
 kotlin.code.style=official
 # config
-mirai_version=0.15.1
+mirai_version=0.15.2
 mirai_japt_version=1.0.1
 kotlin.incremental.multiplatform=true
 kotlin.parallel.tasks.in.project=true
diff --git a/gradle/publish.gradle b/gradle/publish.gradle
index f6fe1515b..6d58f8d23 100644
--- a/gradle/publish.gradle
+++ b/gradle/publish.gradle
@@ -1,4 +1,5 @@
 // 部分源码来自 kotlinx.coroutines
+// Source code from kotlinx.coroutines
 
 def pomConfig = {
     licenses {
@@ -12,6 +13,7 @@ def pomConfig = {
         developer {
             id "mamoe"
             name "Mamoe Technologies"
+            email "support@mamoe.net"
         }
     }
     scm {
diff --git a/mirai-console-graphical/build.gradle.kts b/mirai-console-graphical/build.gradle.kts
index 29e821737..557c0ea79 100644
--- a/mirai-console-graphical/build.gradle.kts
+++ b/mirai-console-graphical/build.gradle.kts
@@ -6,7 +6,7 @@ plugins {
 }
 
 javafx {
-    version = "11"
+    version = "13.0.2"
     modules = listOf("javafx.controls")
     //mainClassName = "Application"
 }
diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt
index d35d65ca6..939cd424d 100644
--- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt
+++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt
@@ -24,8 +24,8 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
     val botList = observableListOf<BotModel>()
     val consoleInfo = ConsoleInfo()
 
-    fun login(qq: String, psd: String) {
-        MiraiConsole.CommandListener.commandChannel.offer("/login $qq $psd")
+    suspend fun login(qq: String, psd: String) {
+        MiraiConsole.CommandListener.commandChannel.send("/login $qq $psd")
     }
 
     override fun pushLog(identity: Long, message: String) = Platform.runLater {
diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginFragment.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginFragment.kt
index c0f1b460c..437031ca4 100644
--- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginFragment.kt
+++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginFragment.kt
@@ -1,7 +1,7 @@
 package net.mamoe.mirai.console.graphical.view
 
-import com.jfoenix.controls.JFXTextField
 import javafx.beans.property.SimpleStringProperty
+import kotlinx.coroutines.runBlocking
 import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
 import net.mamoe.mirai.console.graphical.util.jfxButton
 import net.mamoe.mirai.console.graphical.util.jfxPasswordfield
@@ -24,7 +24,9 @@ class LoginFragment : Fragment() {
             }
         }
         jfxButton("登录").action {
-            controller.login(qq.value, psd.value)
+            runBlocking {
+                controller.login(qq.value, psd.value)
+            }
             close()
         }
     }
diff --git a/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt b/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt
index 7562c60a7..e20fc6372 100644
--- a/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt
+++ b/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt
@@ -10,7 +10,6 @@ import com.googlecode.lanterna.terminal.DefaultTerminalFactory
 import com.googlecode.lanterna.terminal.Terminal
 import com.googlecode.lanterna.terminal.TerminalResizeListener
 import com.googlecode.lanterna.terminal.swing.SwingTerminal
-import com.googlecode.lanterna.terminal.swing.SwingTerminalFontConfiguration
 import com.googlecode.lanterna.terminal.swing.SwingTerminalFrame
 import kotlinx.coroutines.*
 import kotlinx.coroutines.io.close
@@ -23,7 +22,6 @@ import net.mamoe.mirai.console.MiraiConsoleTerminalUI.LoggerDrawer.redrawLogs
 import net.mamoe.mirai.utils.LoginSolver
 import net.mamoe.mirai.utils.createCharImg
 import net.mamoe.mirai.utils.writeChannel
-import java.awt.Font
 import java.io.File
 import java.io.OutputStream
 import java.io.PrintStream
@@ -126,12 +124,12 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI {
     }
 
 
-    fun provideInput(input: String) {
+    suspend fun provideInput(input: String) {
         if (requesting) {
             requestResult = input
             requesting = false
         } else {
-            MiraiConsole.CommandListener.commandChannel.offer(
+            MiraiConsole.CommandListener.commandChannel.send(
                 commandBuilder.toString()
             )
         }
@@ -336,7 +334,9 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI {
                             update()
                         }
                         KeyType.Enter -> {
-                            provideInput(commandBuilder.toString())
+                            runBlocking {
+                                provideInput(commandBuilder.toString())
+                            }
                             emptyCommand()
                         }
                         KeyType.Escape -> {
diff --git a/mirai-console/README.MD b/mirai-console/README.MD
index 75bb84696..060fe54b9 100644
--- a/mirai-console/README.MD
+++ b/mirai-console/README.MD
@@ -6,9 +6,9 @@
 |  名字    | 介绍 |
 | --- | --- |
 | Mirai-Console-Pure  |  最纯净版, CLI环境, 通过标准输入与标准输出 交互 |
-| Mirai-Console-Terminal  |  (UNIX)Terminal环境 提供简介好用的富文本控制台 |
+| Mirai-Console-Terminal  |  (UNIX)Terminal环境 提供简洁的富文本控制台 |
 | Mirai-Console-Android   |  安卓APP (TODO) |
-| Mirai-Console-Graphical  |  JavaFX的图形化界面, 有Native版本(.jar/.exe/.dmg) |
+| Mirai-Console-Graphical  |  JavaFX的图形化界面 (.jar/.exe/.dmg) |
 | Mirai-Console-WebPanel  |   Web Panel操作(TODO) |
 | Mirai-Console-Ios   |  IOS APP (TODO) |
 
diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/Command.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/Command.kt
index 41dc5232a..2ec3f6a8e 100644
--- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/Command.kt
+++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/Command.kt
@@ -42,7 +42,7 @@ object CommandManager {
         registeredCommand.remove(commandName)
     }
 
-    fun runCommand(fullCommand: String): Boolean {
+    suspend fun runCommand(fullCommand: String): Boolean {
         val blocks = fullCommand.split(" ")
         val commandHead = blocks[0].replace("/", "")
         if (!registeredCommand.containsKey(commandHead)) {
@@ -66,7 +66,7 @@ interface ICommand {
     val name: String
     val alias: List<String>
     val description: String
-    fun onCommand(args: List<String>): Boolean
+    suspend fun onCommand(args: List<String>): Boolean
     fun register()
 }
 
@@ -77,9 +77,9 @@ abstract class Command(
 ) : ICommand {
     /**
      * 最高优先级监听器
-     * 如果return [false] 这次指令不会被[PluginBase]的全局onCommand监听器监听
+     * 如果 return `false` 这次指令不会被 [PluginBase] 的全局 onCommand 监听器监听
      * */
-    open override fun onCommand(args: List<String>): Boolean {
+    open override suspend fun onCommand(args: List<String>): Boolean {
         return true
     }
 
@@ -92,9 +92,9 @@ class AnonymousCommand internal constructor(
     override val name: String,
     override val alias: List<String>,
     override val description: String,
-    val onCommand: ICommand.(args: List<String>) -> Boolean
+    val onCommand: suspend ICommand.(args: List<String>) -> Boolean
 ) : ICommand {
-    override fun onCommand(args: List<String>): Boolean {
+    override suspend fun onCommand(args: List<String>): Boolean {
         return onCommand.invoke(this, args)
     }
 
@@ -107,9 +107,9 @@ class CommandBuilder internal constructor() {
     var name: String? = null
     var alias: List<String>? = null
     var description: String = ""
-    var onCommand: (ICommand.(args: List<String>) -> Boolean)? = null
+    var onCommand: (suspend ICommand.(args: List<String>) -> Boolean)? = null
 
-    fun onCommand(commandProcess: ICommand.(args: List<String>) -> Boolean) {
+    fun onCommand(commandProcess: suspend ICommand.(args: List<String>) -> Boolean) {
         onCommand = commandProcess
     }
 
diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt
index 3ea958463..c87126215 100644
--- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt
+++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt
@@ -9,20 +9,20 @@ package net.mamoe.mirai.console
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.Channel
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.api.http.MiraiHttpAPIServer
 import net.mamoe.mirai.api.http.generateSessionKey
+import net.mamoe.mirai.console.MiraiConsole.CommandListener.processNextCommandLine
 import net.mamoe.mirai.console.plugins.PluginManager
 import net.mamoe.mirai.console.plugins.loadAsConfig
 import net.mamoe.mirai.console.plugins.withDefaultWrite
 import net.mamoe.mirai.console.plugins.withDefaultWriteSave
 import net.mamoe.mirai.contact.sendMessage
-import net.mamoe.mirai.utils.*
+import net.mamoe.mirai.utils.SimpleLogger
 import java.io.File
 import java.util.*
-import java.util.concurrent.LinkedBlockingQueue
-import kotlin.concurrent.thread
 
 
 object MiraiConsole {
@@ -130,37 +130,35 @@ object MiraiConsole {
                     val qqPassword = it[1]
                     logger("[Bot Login]", 0, "login...")
                     try {
-                        runBlocking {
-                            frontEnd.prePushBot(qqNumber)
-                            val bot = Bot(qqNumber, qqPassword) {
-                                this.loginSolver = frontEnd.createLoginSolver()
-                                this.botLoggerSupplier = {
-                                    SimpleLogger("BOT $qqNumber]") { _, message, e ->
-                                        logger("[BOT $qqNumber]", qqNumber, message)
-                                        if (e != null) {
-                                            logger("[NETWORK ERROR]", qqNumber, e.toString())//因为在一页 所以可以不打QQ
-                                            e.printStackTrace()
-                                        }
-                                    }
-                                }
-                                this.networkLoggerSupplier = {
-                                    SimpleLogger("BOT $qqNumber") { _, message, e ->
-                                        logger("[NETWORK]", qqNumber, message)//因为在一页 所以可以不打QQ
-                                        if (e != null) {
-                                            logger("[NETWORK ERROR]", qqNumber, e.toString())//因为在一页 所以可以不打QQ
-                                            e.printStackTrace()
-                                        }
+                        frontEnd.prePushBot(qqNumber)
+                        val bot = Bot(qqNumber, qqPassword) {
+                            this.loginSolver = frontEnd.createLoginSolver()
+                            this.botLoggerSupplier = {
+                                SimpleLogger("BOT $qqNumber]") { _, message, e ->
+                                    logger("[BOT $qqNumber]", qqNumber, message)
+                                    if (e != null) {
+                                        logger("[NETWORK ERROR]", qqNumber, e.toString())//因为在一页 所以可以不打QQ
+                                        e.printStackTrace()
+                                    }
+                                }
+                            }
+                            this.networkLoggerSupplier = {
+                                SimpleLogger("BOT $qqNumber") { _, message, e ->
+                                    logger("[NETWORK]", qqNumber, message)//因为在一页 所以可以不打QQ
+                                    if (e != null) {
+                                        logger("[NETWORK ERROR]", qqNumber, e.toString())//因为在一页 所以可以不打QQ
+                                        e.printStackTrace()
                                     }
                                 }
                             }
-                            bot.login()
-                            logger(
-                                "[Bot Login]",
-                                0,
-                                "$qqNumber login successes"
-                            )
-                            frontEnd.pushBot(bot)
                         }
+                        bot.login()
+                        logger(
+                            "[Bot Login]",
+                            0,
+                            "$qqNumber login successes"
+                        )
+                        frontEnd.pushBot(bot)
                     } catch (e: Exception) {
                         logger(
                             "[Bot Login]",
@@ -288,20 +286,19 @@ object MiraiConsole {
         }
     }
 
-    object CommandListener {
-        val commandChannel: Queue<String> = LinkedBlockingQueue<String>()
-        fun start() {
-            thread {
-                processNextCommandLine()
-            }
+    object CommandListener : Job by {
+        GlobalScope.launch(start = CoroutineStart.LAZY) {
+            processNextCommandLine()
         }
+    }() {
+        val commandChannel: Channel<String> = Channel()
 
-        tailrec fun processNextCommandLine() {
+        suspend fun processNextCommandLine() {
             if (allDown) {
                 return
             }
-            var fullCommand = commandChannel.take(1)[0]
-            if (fullCommand != null) {
+            for (command in commandChannel) {
+                var fullCommand = command
                 if (!fullCommand.startsWith("/")) {
                     fullCommand = "/$fullCommand"
                 }
@@ -309,7 +306,6 @@ object MiraiConsole {
                     logger("未知指令 $fullCommand")
                 }
             }
-            processNextCommandLine();
         }
     }
 
diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleUIPure.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleUIPure.kt
index e968e7111..89c2c3205 100644
--- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleUIPure.kt
+++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleUIPure.kt
@@ -1,25 +1,28 @@
 package net.mamoe.mirai.console
 
 import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.utils.DefaultLoginSolver
 import net.mamoe.mirai.utils.LoginSolver
 import net.mamoe.mirai.utils.LoginSolverInputReader
 import kotlin.concurrent.thread
 
-class MiraiConsoleUIPure() : MiraiConsoleUI {
+class MiraiConsoleUIPure : MiraiConsoleUI {
     var requesting = false
     var requestStr = ""
 
     init {
         thread {
             while (true) {
-                val input = readLine() ?: ""
+                val input = readLine() ?: return@thread
                 if (requesting) {
                     requestStr = input
                     requesting = false
                 } else {
-                    MiraiConsole.CommandListener.commandChannel.offer(input)
+                    runBlocking {
+                        MiraiConsole.CommandListener.commandChannel.send(input)
+                    }
                 }
             }
         }
diff --git a/mirai-core-qqandroid/build.gradle.kts b/mirai-core-qqandroid/build.gradle.kts
index eb5a1af42..1ce814b42 100644
--- a/mirai-core-qqandroid/build.gradle.kts
+++ b/mirai-core-qqandroid/build.gradle.kts
@@ -118,5 +118,9 @@ kotlin {
         }
     }
 }
+//
+//tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
+//    kotlinOptions.jvmTarget = "1.8"
+//}
 
 apply(from = rootProject.file("gradle/publish.gradle"))
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
index 9ac70b87e..232e06e7a 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
@@ -215,11 +215,14 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
                     .sendAndExpect<FriendList.GetTroopListSimplify.Response>(retry = 2)
 
                 troopListData.groups.forEach { troopNum ->
-                    launch {
-                        try {
+                    // 别用 fun, 别 val, 编译失败警告
+                    lateinit var loadGroup: suspend () -> Unit
+
+                    loadGroup = suspend {
+                        tryNTimesOrException(3) {
                             bot.groups.delegate.addLast(
                                 @Suppress("DuplicatedCode")
-                                GroupImpl(
+                                (GroupImpl(
                                     bot = bot,
                                     coroutineContext = bot.coroutineContext,
                                     id = troopNum.groupCode,
@@ -241,12 +244,20 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
                                         this.delegate.groupCode = troopNum.groupCode
                                     },
                                     members = bot.queryGroupMemberList(troopNum.groupUin, troopNum.groupCode, troopNum.dwGroupOwnerUin)
-                                )
+                                ))
                             )
-                        } catch (e: Exception) {
+                        }?.let {
                             logger.error("群${troopNum.groupCode}的列表拉取失败, 一段时间后将会重试")
-                            logger.error(e)
+                            logger.error(it)
+                            this@QQAndroidBotNetworkHandler.launch {
+                                delay(10_000)
+                                loadGroup()
+                            }
                         }
+                        Unit // 别删, 编译失败警告
+                    }
+                    launch {
+                        loadGroup()
                     }
                 }
                 logger.info("群组列表与群成员加载完成, 共 ${troopListData.groups.size}个")
diff --git a/mirai-core/build.gradle.kts b/mirai-core/build.gradle.kts
index 882ecf7cc..ebecaf2f9 100644
--- a/mirai-core/build.gradle.kts
+++ b/mirai-core/build.gradle.kts
@@ -150,5 +150,9 @@ kotlin {
         }
     }
 }
+//
+//tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
+//    kotlinOptions.jvmTarget = "1.8"
+//}
 
 apply(from = rootProject.file("gradle/publish.gradle"))
diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/addSuppressed.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/addSuppressed.kt
new file mode 100644
index 000000000..b153e249b
--- /dev/null
+++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/addSuppressed.kt
@@ -0,0 +1,16 @@
+package net.mamoe.mirai.utils
+
+private var isAddSuppressedSupported: Boolean = true
+
+@MiraiInternalAPI
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+actual fun Throwable.addSuppressed(e: Throwable) {
+    if (!isAddSuppressedSupported) {
+        return
+    }
+    try {
+        this.addSuppressed(e)
+    } catch (e: Exception) {
+        isAddSuppressedSupported = false
+    }
+}
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt
index fb2a35ca0..a0e103fd0 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt
@@ -7,6 +7,9 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
+@file:JvmMultifileClass
+@file:JvmName("MessageUtils")
+
 @file:Suppress("EXPERIMENTAL_API_USAGE")
 
 package net.mamoe.mirai.message.data
@@ -14,6 +17,8 @@ package net.mamoe.mirai.message.data
 import net.mamoe.mirai.contact.Member
 import net.mamoe.mirai.contact.groupCardOrNick
 import net.mamoe.mirai.utils.MiraiInternalAPI
+import kotlin.jvm.JvmMultifileClass
+import kotlin.jvm.JvmName
 
 
 /**
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
index 69bb6c392..60dfdfecf 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
@@ -7,8 +7,14 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
+@file:JvmMultifileClass
+@file:JvmName("MessageUtils")
+
 package net.mamoe.mirai.message.data
 
+import kotlin.jvm.JvmMultifileClass
+import kotlin.jvm.JvmName
+
 /**
  * "@全体成员"
  *
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt
index fa9c0c70b..53a35641e 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt
@@ -7,8 +7,13 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
+@file:JvmMultifileClass
+@file:JvmName("MessageUtils")
+
 package net.mamoe.mirai.message.data
 
+import kotlin.jvm.JvmMultifileClass
+import kotlin.jvm.JvmName
 import kotlin.jvm.JvmStatic
 
 /**
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt
index 738786749..509dffe4a 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt
@@ -7,6 +7,9 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
+@file:JvmMultifileClass
+@file:JvmName("MessageUtils")
+
 @file:Suppress("EXPERIMENTAL_API_USAGE")
 
 package net.mamoe.mirai.message.data
@@ -14,13 +17,18 @@ package net.mamoe.mirai.message.data
 import kotlinx.serialization.Serializable
 import kotlinx.serialization.Transient
 import net.mamoe.mirai.utils.io.chunkedHexToBytes
+import kotlin.js.JsName
+import kotlin.jvm.JvmMultifileClass
 import kotlin.jvm.JvmName
+import kotlin.jvm.JvmStatic
 
 /**
  * 自定义表情 (收藏的表情), 图片
  */
 sealed class Image : Message {
     companion object Key : Message.Key<Image> {
+        @JvmStatic
+        @JsName("fromId")
         @JvmName("fromId")
         operator fun invoke(imageId: String): Image = when (imageId.length) {
             37 -> NotOnlineImageFromFile(imageId) // /f8f1ab55-bf8e-4236-b55e-955848d7069f
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt
index 274020408..4234275ce 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt
@@ -13,6 +13,7 @@ package net.mamoe.mirai.message.data
 
 import net.mamoe.mirai.contact.Contact
 import net.mamoe.mirai.contact.sendMessage
+import kotlin.jvm.JvmSynthetic
 
 /**
  * 可发送的或从服务器接收的消息.
@@ -82,6 +83,7 @@ interface Message {
      * println(c)// "Hello world!"
      * ```
      */
+    @JvmSynthetic // in java they should use `plus` instead
     fun followedBy(tail: Message): MessageChain {
         require(tail !is SingleOnly) { "SingleOnly Message cannot follow another message" }
         require(this !is SingleOnly) { "SingleOnly Message cannot be followed" }
@@ -92,6 +94,7 @@ interface Message {
     override fun toString(): String
 
     operator fun plus(another: Message): MessageChain = this.followedBy(another)
+
     operator fun plus(another: String): MessageChain = this.followedBy(another.toMessage())
     // `+ ""` will be resolved to `plus(String)` instead of `plus(CharSeq)`
     operator fun plus(another: CharSequence): MessageChain = this.followedBy(another.toString().toMessage())
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
index 5e1ff2061..e9412ab1f 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
@@ -7,6 +7,9 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
+@file:JvmMultifileClass
+@file:JvmName("MessageUtils")
+
 package net.mamoe.mirai.message.data
 
 import net.mamoe.mirai.message.data.NullMessageChain.toString
@@ -14,6 +17,9 @@ import net.mamoe.mirai.utils.MiraiExperimentalAPI
 import kotlin.contracts.ExperimentalContracts
 import kotlin.contracts.contract
 import kotlin.js.JsName
+import kotlin.jvm.JvmMultifileClass
+import kotlin.jvm.JvmName
+import kotlin.jvm.JvmSynthetic
 import kotlin.jvm.Volatile
 import kotlin.reflect.KProperty
 
@@ -35,10 +41,12 @@ interface MessageChain : Message, MutableList<Message> {
     override fun followedBy(tail: Message): MessageChain
     // endregion
 
+    @JvmSynthetic
     operator fun plusAssign(message: Message) {
         this.followedBy(message)
     }
 
+    @JvmSynthetic // make java user happier
     operator fun plusAssign(plain: String) {
         this.plusAssign(plain.toMessage())
     }
@@ -53,7 +61,7 @@ interface MessageChain : Message, MutableList<Message> {
     operator fun <M : Message> get(key: Message.Key<M>): M = first(key)
 
     override fun eq(other: Message): Boolean {
-        if(other is MessageChain && other.size != this.size)
+        if (other is MessageChain && other.size != this.size)
             return false
         return this.toString() == other.toString()
     }
@@ -67,13 +75,16 @@ inline operator fun <reified T : Message> MessageChain.getValue(thisRef: Any?, p
 /**
  * 构造无初始元素的可修改的 [MessageChain]. 初始大小将会被设定为 8
  */
-@JsName("emptyMessageChain")
+@JvmName("newChain")
+@JsName("newChain")
 @Suppress("FunctionName")
 fun MessageChain(): MessageChain = EmptyMessageChain()
 
 /**
  * 构造无初始元素的可修改的 [MessageChain]. 初始大小将会被设定为 [initialCapacity]
  */
+@JvmName("newChain")
+@JsName("newChain")
 @Suppress("FunctionName")
 fun MessageChain(initialCapacity: Int): MessageChain =
     if (initialCapacity == 0) EmptyMessageChain()
@@ -83,6 +94,8 @@ fun MessageChain(initialCapacity: Int): MessageChain =
  * 构造 [MessageChain]
  * 若仅提供一个参数, 请考虑使用 [Message.toChain] 以优化性能
  */
+@JvmName("newChain")
+@JsName("newChain")
 @Suppress("FunctionName")
 fun MessageChain(vararg messages: Message): MessageChain =
     if (messages.isEmpty()) EmptyMessageChain()
@@ -91,6 +104,8 @@ fun MessageChain(vararg messages: Message): MessageChain =
 /**
  * 构造 [MessageChain]
  */
+@JvmName("newChain")
+@JsName("newChain")
 @Suppress("FunctionName")
 fun MessageChain(messages: Iterable<Message>): MessageChain =
     MessageChainImpl(messages.toMutableList())
@@ -106,6 +121,8 @@ fun MessageChain(messages: Iterable<Message>): MessageChain =
  *
  * @see Message.toChain receiver 模式
  */
+@JvmName("newSingleMessageChain")
+@JsName("newChain")
 @MiraiExperimentalAPI
 @UseExperimental(ExperimentalContracts::class)
 @Suppress("FunctionName")
@@ -301,7 +318,7 @@ internal inline class MessageChainImpl constructor(
     constructor(vararg messages: Message) : this(messages.toMutableList())
 
     // region Message override
-    override fun toString(): String =  this.delegate.joinToString("") { it.toString() }
+    override fun toString(): String = this.delegate.joinToString("") { it.toString() }
 
     override operator fun contains(sub: String): Boolean = delegate.any { it.contains(sub) }
     override fun followedBy(tail: Message): MessageChain {
@@ -352,6 +369,7 @@ internal inline class SingleMessageChainImpl(
 
     // region Message override
     override operator fun contains(sub: String): Boolean = delegate.contains(sub)
+
     override fun followedBy(tail: Message): MessageChain {
         require(tail !is SingleOnly) { "SingleOnly Message cannot follow another message" }
         return if (tail is MessageChain) tail.apply { followedBy(delegate) }
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
index 3d1246dd5..3653cfabb 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
@@ -7,8 +7,14 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
+@file:JvmMultifileClass
+@file:JvmName("MessageUtils")
+
 package net.mamoe.mirai.message.data
 
+import kotlin.jvm.JvmMultifileClass
+import kotlin.jvm.JvmName
+
 /**
  * 消息源, 用于被引用. 它将由协议模块实现.
  * 消息源只用于 [QuoteReply]
@@ -18,7 +24,7 @@ package net.mamoe.mirai.message.data
  * @see MessageSource.quote 引用这条消息, 创建 [MessageChain]
  */
 interface MessageSource : Message {
-    companion object : Message.Key<MessageSource>
+    companion object Key : Message.Key<MessageSource>
 
     /**
      * 实际上是个随机数, 但服务器确实是用它当做 uid
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt
index 6277da651..c11c1e395 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt
@@ -7,9 +7,19 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
+@file:JvmMultifileClass
+@file:JvmName("MessageUtils")
+
 package net.mamoe.mirai.message.data
 
+import kotlin.jvm.JvmMultifileClass
+import kotlin.jvm.JvmName
 
+/**
+ * 纯文本. 可含 emoji 表情.
+ *
+ * 一般不需要主动构造 [PlainText], [Message] 可直接与 [String] 相加. Java 用户请使用 [MessageChain.plus]
+ */
 inline class PlainText(val stringValue: String) : Message {
     override operator fun contains(sub: String): Boolean = sub in stringValue
     override fun toString(): String = stringValue
@@ -17,7 +27,7 @@ inline class PlainText(val stringValue: String) : Message {
     companion object Key : Message.Key<PlainText>
 
     override fun eq(other: Message): Boolean {
-        if(other is MessageChain){
+        if (other is MessageChain) {
             return other eq this.toString()
         }
         return other is PlainText && other.stringValue == this.stringValue
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt
index 8921b1eca..b21a7d999 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt
@@ -7,10 +7,15 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
+@file:JvmMultifileClass
+@file:JvmName("MessageUtils")
+
 package net.mamoe.mirai.message.data
 
 import net.mamoe.mirai.contact.Member
 import net.mamoe.mirai.utils.MiraiInternalAPI
+import kotlin.jvm.JvmMultifileClass
+import kotlin.jvm.JvmName
 
 
 /**
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/XML.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/XML.kt
index 906b039e9..d8805a6d7 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/XML.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/XML.kt
@@ -7,10 +7,17 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
+@file:JvmMultifileClass
+@file:JvmName("MessageUtils")
+
 @file:Suppress("MemberVisibilityCanBePrivate")
 
 package net.mamoe.mirai.message.data
 
+import net.mamoe.mirai.utils.MiraiExperimentalAPI
+import kotlin.jvm.JvmMultifileClass
+import kotlin.jvm.JvmName
+
 /**
  * XML 消息, 如分享, 卡片等.
  *
@@ -30,6 +37,7 @@ inline class XMLMessage(val stringValue: String) : Message,
  * 构造一条 XML 消息
  */
 @XMLDsl
+@MiraiExperimentalAPI("还未支持")
 inline fun buildXMLMessage(block: @XMLDsl XMLMessageBuilder.() -> Unit): XMLMessage =
     XMLMessage(XMLMessageBuilder().apply(block).text)
 
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/tryNTimes.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/tryNTimes.kt
new file mode 100644
index 000000000..417d8536a
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/tryNTimes.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 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
+ */
+
+package net.mamoe.mirai.utils
+
+@MiraiInternalAPI
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+expect fun Throwable.addSuppressed(e: Throwable)
+
+@MiraiInternalAPI
+@Suppress("DuplicatedCode")
+inline fun <R> tryNTimes(repeat: Int, block: () -> R): R {
+    var lastException: Throwable? = null
+
+    repeat(repeat) {
+        try {
+            return block()
+        } catch (e: Throwable) {
+            if (lastException == null) {
+                lastException = e
+            }
+            lastException!!.addSuppressed(e)
+        }
+    }
+
+    throw lastException!!
+}
+
+@MiraiInternalAPI
+@Suppress("DuplicatedCode")
+inline fun <R> tryNTimesOrNull(repeat: Int, block: () -> R): R? {
+    var lastException: Throwable? = null
+
+    repeat(repeat) {
+        try {
+            return block()
+        } catch (e: Throwable) {
+            if (lastException == null) {
+                lastException = e
+            }
+            lastException!!.addSuppressed(e)
+        }
+    }
+
+    return null
+}
+
+@MiraiInternalAPI
+@Suppress("DuplicatedCode")
+inline fun <R> tryNTimesOrException(repeat: Int, block: () -> R): Throwable? {
+    var lastException: Throwable? = null
+
+    repeat(repeat) {
+        try {
+            block()
+            return null
+        } catch (e: Throwable) {
+            if (lastException == null) {
+                lastException = e
+            }
+            lastException!!.addSuppressed(e)
+        }
+    }
+
+    return lastException!!
+}
\ No newline at end of file
diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/addSuppressed.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/addSuppressed.kt
new file mode 100644
index 000000000..b153e249b
--- /dev/null
+++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/addSuppressed.kt
@@ -0,0 +1,16 @@
+package net.mamoe.mirai.utils
+
+private var isAddSuppressedSupported: Boolean = true
+
+@MiraiInternalAPI
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+actual fun Throwable.addSuppressed(e: Throwable) {
+    if (!isAddSuppressedSupported) {
+        return
+    }
+    try {
+        this.addSuppressed(e)
+    } catch (e: Exception) {
+        isAddSuppressedSupported = false
+    }
+}
\ No newline at end of file
diff --git a/mirai-demos/mirai-demo-1/build.gradle b/mirai-demos/mirai-demo-1/build.gradle
index 0afcdc380..0d0c910f1 100644
--- a/mirai-demos/mirai-demo-1/build.gradle
+++ b/mirai-demos/mirai-demo-1/build.gradle
@@ -2,9 +2,9 @@ apply plugin: "kotlin"
 apply plugin: "java"
 
 dependencies {
-    implementation files("../../mirai-core/build/classes/kotlin/jvm/main") // IDE bug
+    runtimeOnly files("../../mirai-core/build/classes/kotlin/jvm/main") // IDE bug
 
-    implementation files("../../mirai-core-qqandroid/build/classes/kotlin/jvm/main") // IDE bug
+    runtimeOnly files("../../mirai-core-qqandroid/build/classes/kotlin/jvm/main") // IDE bug
     implementation project(":mirai-core-qqandroid")
 
     api group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: kotlinVersion
diff --git a/mirai-demos/mirai-demo-java/build.gradle b/mirai-demos/mirai-demo-java/build.gradle
index e5e8fc5a1..77270e807 100644
--- a/mirai-demos/mirai-demo-java/build.gradle
+++ b/mirai-demos/mirai-demo-java/build.gradle
@@ -2,9 +2,9 @@ apply plugin: "java"
 apply plugin: "kotlin"
 
 dependencies {
-    implementation files("../../mirai-core/build/classes/kotlin/jvm/main") // IDE bug
+    runtimeOnly files("../../mirai-core/build/classes/kotlin/jvm/main") // IDE bug
 
-    implementation files("../../mirai-core-qqandroid/build/classes/kotlin/jvm/main") // IDE bug
+    runtimeOnly files("../../mirai-core-qqandroid/build/classes/kotlin/jvm/main") // IDE bug
     implementation project(":mirai-core-qqandroid")
     implementation project(":mirai-japt")
 }
diff --git a/mirai-demos/mirai-demo-java/src/main/java/demo/BlockingTest.java b/mirai-demos/mirai-demo-java/src/main/java/demo/BlockingTest.java
index b2f8614cf..7cef48600 100644
--- a/mirai-demos/mirai-demo-java/src/main/java/demo/BlockingTest.java
+++ b/mirai-demos/mirai-demo-java/src/main/java/demo/BlockingTest.java
@@ -5,6 +5,9 @@ import net.mamoe.mirai.japt.BlockingContacts;
 import net.mamoe.mirai.japt.BlockingQQ;
 import net.mamoe.mirai.japt.Events;
 import net.mamoe.mirai.message.GroupMessage;
+import net.mamoe.mirai.message.data.At;
+import net.mamoe.mirai.message.data.Image;
+import net.mamoe.mirai.message.data.MessageUtils;
 
 class BlockingTest {
 
@@ -19,8 +22,14 @@ class BlockingTest {
 
         Events.subscribeAlways(GroupMessage.class, (GroupMessage message) -> {
             final BlockingQQ sender = BlockingContacts.createBlocking(message.getSender());
+            sender.sendMessage("Hello World!");
+            System.out.println("发送完了");
 
-            sender.sendMessage("Hello");
+            sender.sendMessage(MessageUtils.newChain()
+                    .plus(new At(message.getSender()))
+                    .plus(Image.fromId("{xxxx}.jpg"))
+                    .plus("123465")
+            );
         });
 
         Thread.sleep(999999999);
diff --git a/mirai-japt/README.md b/mirai-japt/README.md
index 73586ab92..234ef52b6 100644
--- a/mirai-japt/README.md
+++ b/mirai-japt/README.md
@@ -32,7 +32,7 @@ Mirai Java Apt
 <dependencies>
     <dependency>
         <groupId>net.mamoe</groupId>
-        <artifactId>mirai-core-qqandroid-jvm</artifactId>
+        <artifactId>mirai-core-qqandroid</artifactId>
         <version>CORE_VERSION</version> <!-- 替换版本为最新版本 -->
     </dependency>
     
@@ -51,7 +51,7 @@ repositories {
 }
 
 dependencies {
-  implementation("net.mamoe:mirai-core-qqandroid-jvm:CORE_VERSION")
+  implementation("net.mamoe:mirai-core-qqandroid:CORE_VERSION")
   implementation("net.mamoe:mirai-japt:JAPT_VERSION")
 }
 ```
diff --git a/mirai-japt/build.gradle.kts b/mirai-japt/build.gradle.kts
index 1c4be4095..3bd7d20a5 100644
--- a/mirai-japt/build.gradle.kts
+++ b/mirai-japt/build.gradle.kts
@@ -18,9 +18,9 @@ buildscript {
 plugins {
     kotlin("jvm")
     java
+    id("com.jfrog.bintray") version "1.8.0"
     `maven-publish`
     // maven
-    id("com.jfrog.bintray") version "1.8.0"
 }
 
 val kotlinVersion: String by rootProject.ext
@@ -77,6 +77,10 @@ tasks.withType<JavaCompile>() {
     options.encoding = "UTF-8"
 }
 
+tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
+    kotlinOptions.jvmTarget = "1.8"
+}
+
 bintray {
     val keyProps = Properties()
     val keyFile = file("../keys.properties")
diff --git a/settings.gradle b/settings.gradle
index cd3ee4be4..03306c551 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -65,11 +65,11 @@ try{
             println("jdk版本为 "+ javaVersionNum)
             include(':mirai-console-graphical')
         } else {
-            println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 最低需要 JDK 11 才能引入模块 `:mirai-debug`")
+            println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 最低需要 JDK 11 才能引入模块 `:mirai-console-graphical`")
         }
     }
 }catch(Exception ignored){
-
+    println("无法确定 JDK 版本, 将不会引入 `:mirai-console-graphical`")
 }
 
 enableFeaturePreview('GRADLE_METADATA')
\ No newline at end of file