diff --git a/mirai-core-api/src/commonMain/kotlin/utils/DeviceInfo.kt b/mirai-core-api/src/commonMain/kotlin/utils/DeviceInfo.kt
index 24cdbbd2c..659b5b50f 100644
--- a/mirai-core-api/src/commonMain/kotlin/utils/DeviceInfo.kt
+++ b/mirai-core-api/src/commonMain/kotlin/utils/DeviceInfo.kt
@@ -7,12 +7,15 @@
  * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
-@file:Suppress("MemberVisibilityCanBePrivate")
+@file:Suppress("MemberVisibilityCanBePrivate", "DEPRECATION_ERROR")
 
 package net.mamoe.mirai.utils
 
 import io.ktor.utils.io.core.*
-import kotlinx.serialization.*
+import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
 import kotlinx.serialization.builtins.serializer
 import kotlinx.serialization.json.Json
 import kotlinx.serialization.json.JsonElement
@@ -21,9 +24,11 @@ import kotlinx.serialization.json.jsonPrimitive
 import kotlinx.serialization.protobuf.ProtoBuf
 import kotlinx.serialization.protobuf.ProtoNumber
 import net.mamoe.mirai.utils.DeviceInfoManager.Version.Companion.trans
-import kotlin.jvm.JvmInline
-import kotlin.jvm.JvmStatic
-import kotlin.jvm.JvmSynthetic
+import net.mamoe.mirai.utils.jvm.CompatibilityOnlyJvmFile
+import net.mamoe.mirai.utils.jvm.JvmFile
+import net.mamoe.mirai.utils.jvm.readText
+import net.mamoe.mirai.utils.jvm.writeText
+import kotlin.jvm.*
 import kotlin.random.Random
 
 internal const val DeviceInfoConstructorDeprecationMessage =
@@ -36,89 +41,133 @@ internal const val DeviceInfoConstructorDeprecationMessage =
  *
  * ## 自定义设备信息
  */
-public expect class DeviceInfo
-@Deprecated(DeviceInfoConstructorDeprecationMessage, level = DeprecationLevel.WARNING)
-@DeprecatedSinceMirai(warningSince = "2.15") // planned internal
-public constructor(
-    display: ByteArray,
-    product: ByteArray,
-    device: ByteArray,
-    board: ByteArray,
-    brand: ByteArray,
-    model: ByteArray,
-    bootloader: ByteArray,
-    fingerprint: ByteArray,
-    bootId: ByteArray,
-    procVersion: ByteArray,
-    baseBand: ByteArray,
-    version: Version,
-    simInfo: ByteArray,
-    osType: ByteArray,
-    macAddress: ByteArray,
-    wifiBSSID: ByteArray,
-    wifiSSID: ByteArray,
-    imsiMd5: ByteArray,
-    imei: String,
-    apn: ByteArray,
-    androidId: ByteArray,
+@Serializable(DeviceInfoV1LegacySerializer::class)
+public class DeviceInfo public constructor(
+    public val display: ByteArray,
+    public val product: ByteArray,
+    public val device: ByteArray,
+    public val board: ByteArray,
+    public val brand: ByteArray,
+    public val model: ByteArray,
+    public val bootloader: ByteArray,
+    public val fingerprint: ByteArray,
+    public val bootId: ByteArray,
+    public val procVersion: ByteArray,
+    public val baseBand: ByteArray,
+    public val version: Version,
+    public val simInfo: ByteArray,
+    public val osType: ByteArray,
+    public val macAddress: ByteArray,
+    public val wifiBSSID: ByteArray,
+    public val wifiSSID: ByteArray,
+    public val imsiMd5: ByteArray,
+    public val imei: String,
+    public val apn: ByteArray,
+    public val androidId: ByteArray,
 ) {
-    public val display: ByteArray
-    public val product: ByteArray
-    public val device: ByteArray
-    public val board: ByteArray
-    public val brand: ByteArray
-    public val model: ByteArray
-    public val bootloader: ByteArray
-    public val fingerprint: ByteArray
-    public val bootId: ByteArray
-    public val procVersion: ByteArray
-    public val baseBand: ByteArray
-    public val version: Version
-    public val simInfo: ByteArray
-    public val osType: ByteArray
-    public val macAddress: ByteArray
-    public val wifiBSSID: ByteArray
-    public val wifiSSID: ByteArray
-    public val imsiMd5: ByteArray
-    public val imei: String
-    public val apn: ByteArray
-    public val androidId: ByteArray
+    @Deprecated(
+        "This DeviceInfo constructor may randomize field `androidId` without your random instance. " +
+                "It is better to specify `android` id explicitly.",
+        replaceWith = ReplaceWith(
+            "net.mamoe.mirai.utils.DeviceInfo(display, product, device, board, brand, model, " +
+                    "bootloader, fingerprint, bootId, procVersion, baseBand, version, simInfo, osType, " +
+                    "macAddress, wifiBSSID, wifiSSID, imsiMd5, imei, apn, androidId)"
+        ),
+        level = DeprecationLevel.WARNING
+    )
+    @DeprecatedSinceMirai(warningSince = "2.15")
+    public constructor(
+        display: ByteArray,
+        product: ByteArray,
+        device: ByteArray,
+        board: ByteArray,
+        brand: ByteArray,
+        model: ByteArray,
+        bootloader: ByteArray,
+        fingerprint: ByteArray,
+        bootId: ByteArray,
+        procVersion: ByteArray,
+        baseBand: ByteArray,
+        version: Version,
+        simInfo: ByteArray,
+        osType: ByteArray,
+        macAddress: ByteArray,
+        wifiBSSID: ByteArray,
+        wifiSSID: ByteArray,
+        imsiMd5: ByteArray,
+        imei: String,
+        apn: ByteArray
+    ) : this(
+        display, product, device, board, brand, model, bootloader,
+        fingerprint, bootId, procVersion, baseBand, version, simInfo,
+        osType, macAddress, wifiBSSID, wifiSSID, imsiMd5, imei, apn,
+        androidId = display
+    )
 
-    public val ipAddress: ByteArray
+    public val ipAddress: ByteArray get() = byteArrayOf(192.toByte(), 168.toByte(), 1, 123)
+
+    init {
+        require(imsiMd5.size == 16) { "Bad `imsiMd5.size`. Required 16, given ${imsiMd5.size}." }
+    }
 
     @Transient
     @MiraiInternalApi
-    public val guid: ByteArray
+    public val guid: ByteArray = generateGuid(androidId, macAddress)
 
-    // @Serializable: use DeviceInfoVersionSerializer in commonMain.
-    public class Version(
-        incremental: ByteArray = "5891938".toByteArray(),
-        release: ByteArray = "10".toByteArray(),
-        codename: ByteArray = "REL".toByteArray(),
-        sdk: Int = 29
+    @Serializable
+    public class Version constructor(
+        public val incremental: ByteArray = "5891938".toByteArray(),
+        public val release: ByteArray = "10".toByteArray(),
+        public val codename: ByteArray = "REL".toByteArray(),
+        public val sdk: Int = 29
     ) {
-        public val incremental: ByteArray
-        public val release: ByteArray
-        public val codename: ByteArray
-        public val sdk: Int
+        /**
+         * @since 2.9
+         */
+        override fun equals(other: Any?): Boolean {
+            if (this === other) return true
+            if (other !is Version) return false
+
+            if (!incremental.contentEquals(other.incremental)) return false
+            if (!release.contentEquals(other.release)) return false
+            if (!codename.contentEquals(other.codename)) return false
+            return sdk == other.sdk
+        }
 
         /**
          * @since 2.9
          */
-        override fun equals(other: Any?): Boolean
-
-        /**
-         * @since 2.9
-         */
-        override fun hashCode(): Int
-
-        internal companion object {
-            fun serializer(): KSerializer<Version>
+        override fun hashCode(): Int {
+            var result = incremental.contentHashCode()
+            result = 31 * result + release.contentHashCode()
+            result = 31 * result + codename.contentHashCode()
+            result = 31 * result + sdk
+            return result
         }
     }
 
     public companion object {
-        internal val logger: MiraiLogger
+        internal val logger = MiraiLogger.Factory.create(DeviceInfo::class, "DeviceInfo")
+
+        /**
+         * 加载一个设备信息. 若文件不存在或为空则随机并创建一个设备信息保存.
+         */
+        @JvmOverloads
+        @JvmStatic
+        @JvmName("from")
+        @OptIn(CompatibilityOnlyJvmFile::class)
+        public fun JvmFile.loadAsDeviceInfo(
+            json: Json = DeviceInfoManager.format
+        ): DeviceInfo {
+            if (!this.exists() || this.length() == 0L) {
+                return random().also {
+                    this.writeText(DeviceInfoManager.serialize(it, json))
+                }
+            }
+            return DeviceInfoManager.deserialize(this.readText(), json) { upg ->
+                this.writeText(DeviceInfoManager.serialize(upg, json))
+            }
+        }
 
         /**
          * 生成随机 [DeviceInfo]
@@ -126,7 +175,7 @@ public constructor(
          * @since 2.0
          */
         @JvmStatic
-        public fun random(): DeviceInfo
+        public fun random(): DeviceInfo = random(Random.Default)
 
         /**
          * 使用特定随机数生成器生成 [DeviceInfo]
@@ -134,11 +183,9 @@ public constructor(
          * @since 2.9
          */
         @JvmStatic
-        public fun random(random: Random): DeviceInfo
-
-        @Deprecated(DeviceInfoConstructorDeprecationMessage, level = DeprecationLevel.WARNING)
-        @DeprecatedSinceMirai(warningSince = "2.15") // planned internal
-        public fun serializer(): KSerializer<DeviceInfo>
+        public fun random(random: Random): DeviceInfo {
+            return DeviceInfoCommonImpl.randomDeviceInfo(random)
+        }
 
         /**
          * 将此 [DeviceInfo] 序列化为字符串. 序列化的字符串可以在以后通过 [DeviceInfo.deserializeFromString] 反序列化为 [DeviceInfo].
@@ -148,7 +195,7 @@ public constructor(
          * @since 2.15
          */
         @JvmStatic
-        public fun serializeToString(deviceInfo: DeviceInfo): String
+        public fun serializeToString(deviceInfo: DeviceInfo): String = DeviceInfoManager.serialize(deviceInfo)
 
         /**
          * 将通过 [serializeToString] 序列化得到的字符串反序列化为 [DeviceInfo].
@@ -156,19 +203,29 @@ public constructor(
          * @since 2.15
          */
         @JvmStatic
-        public fun deserializeFromString(string: String): DeviceInfo
+        public fun deserializeFromString(string: String): DeviceInfo = DeviceInfoManager.deserialize(string)
     }
 
     /**
      * @since 2.9
      */
     @Suppress("DuplicatedCode")
-    override fun equals(other: Any?): Boolean
+    override fun equals(other: Any?): Boolean {
+        return DeviceInfoCommonImpl.equalsImpl(this, other)
+    }
+
 
     /**
      * @since 2.9
      */
-    override fun hashCode(): Int
+    override fun hashCode(): Int {
+        return DeviceInfoCommonImpl.hashCodeImpl(this)
+    }
+
+    @Suppress("ClassName", "WRONG_ANNOTATION_TARGET")
+    @Deprecated("For binary compatibility", level = DeprecationLevel.HIDDEN)
+    @JvmName("\$serializer")
+    public object serializer : KSerializer<DeviceInfo> by DeviceInfoV1LegacySerializer
 }
 
 /**
diff --git a/mirai-core-api/src/commonMain/kotlin/utils/DeviceInfoV1LegacySerializer.kt b/mirai-core-api/src/commonMain/kotlin/utils/DeviceInfoV1LegacySerializer.kt
index b7fc01f5e..376e41522 100644
--- a/mirai-core-api/src/commonMain/kotlin/utils/DeviceInfoV1LegacySerializer.kt
+++ b/mirai-core-api/src/commonMain/kotlin/utils/DeviceInfoV1LegacySerializer.kt
@@ -50,7 +50,6 @@ internal class DeviceInfoV1LegacyVersion(
 internal object DeviceInfoV1LegacySerializer : KSerializer<DeviceInfo> by DeviceInfoV1Legacy.serializer().map(
     DeviceInfoV1Legacy.serializer().descriptor.copy("DeviceInfo"),
     deserialize = {
-        @Suppress("DEPRECATION")
         DeviceInfo(
             display,
             product,
diff --git a/mirai-core-api/src/jvmBaseMain/kotlin/utils/DeviceInfo.kt b/mirai-core-api/src/jvmBaseMain/kotlin/utils/DeviceInfo.kt
deleted file mode 100644
index 5c4d85ae3..000000000
--- a/mirai-core-api/src/jvmBaseMain/kotlin/utils/DeviceInfo.kt
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * 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
- */
-
-package net.mamoe.mirai.utils
-
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.Serializable
-import kotlinx.serialization.Transient
-import kotlinx.serialization.json.Json
-import java.io.File
-import kotlin.random.Random
-
-@Serializable(DeviceInfoV1LegacySerializer::class)
-public actual class DeviceInfo public actual constructor(
-    public actual val display: ByteArray,
-    public actual val product: ByteArray,
-    public actual val device: ByteArray,
-    public actual val board: ByteArray,
-    public actual val brand: ByteArray,
-    public actual val model: ByteArray,
-    public actual val bootloader: ByteArray,
-    public actual val fingerprint: ByteArray,
-    public actual val bootId: ByteArray,
-    public actual val procVersion: ByteArray,
-    public actual val baseBand: ByteArray,
-    public actual val version: Version,
-    public actual val simInfo: ByteArray,
-    public actual val osType: ByteArray,
-    public actual val macAddress: ByteArray,
-    public actual val wifiBSSID: ByteArray,
-    public actual val wifiSSID: ByteArray,
-    public actual val imsiMd5: ByteArray,
-    public actual val imei: String,
-    public actual val apn: ByteArray,
-    public actual val androidId: ByteArray,
-) {
-    @Deprecated(
-        "This DeviceInfo constructor may randomize field `androidId` without your random instance. " +
-                "It is better to specify `android` id explicitly.",
-        replaceWith = ReplaceWith(
-            "net.mamoe.mirai.utils.DeviceInfo(display, product, device, board, brand, model, " +
-                    "bootloader, fingerprint, bootId, procVersion, baseBand, version, simInfo, osType, " +
-                    "macAddress, wifiBSSID, wifiSSID, imsiMd5, imei, apn, androidId)"
-        ),
-        level = DeprecationLevel.WARNING
-    )
-    @DeprecatedSinceMirai(warningSince = "2.15")
-    public constructor(
-        display: ByteArray,
-        product: ByteArray,
-        device: ByteArray,
-        board: ByteArray,
-        brand: ByteArray,
-        model: ByteArray,
-        bootloader: ByteArray,
-        fingerprint: ByteArray,
-        bootId: ByteArray,
-        procVersion: ByteArray,
-        baseBand: ByteArray,
-        version: Version,
-        simInfo: ByteArray,
-        osType: ByteArray,
-        macAddress: ByteArray,
-        wifiBSSID: ByteArray,
-        wifiSSID: ByteArray,
-        imsiMd5: ByteArray,
-        imei: String,
-        apn: ByteArray
-    ) : this(
-        display, product, device, board, brand, model, bootloader,
-        fingerprint, bootId, procVersion, baseBand, version, simInfo,
-        osType, macAddress, wifiBSSID, wifiSSID, imsiMd5, imei, apn,
-        androidId = display
-    )
-
-    public actual val ipAddress: ByteArray get() = byteArrayOf(192.toByte(), 168.toByte(), 1, 123)
-
-    init {
-        require(imsiMd5.size == 16) { "Bad `imsiMd5.size`. Required 16, given ${imsiMd5.size}." }
-    }
-
-    @Transient
-    @MiraiInternalApi
-    public actual val guid: ByteArray = generateGuid(androidId, macAddress)
-
-    @Serializable
-    public actual class Version actual constructor(
-        public actual val incremental: ByteArray,
-        public actual val release: ByteArray,
-        public actual val codename: ByteArray,
-        public actual val sdk: Int
-    ) {
-        /**
-         * @since 2.9
-         */
-        actual override fun equals(other: Any?): Boolean {
-            if (this === other) return true
-            if (other !is Version) return false
-
-            if (!incremental.contentEquals(other.incremental)) return false
-            if (!release.contentEquals(other.release)) return false
-            if (!codename.contentEquals(other.codename)) return false
-            if (sdk != other.sdk) return false
-
-            return true
-        }
-
-        /**
-         * @since 2.9
-         */
-        actual override fun hashCode(): Int {
-            var result = incremental.contentHashCode()
-            result = 31 * result + release.contentHashCode()
-            result = 31 * result + codename.contentHashCode()
-            result = 31 * result + sdk
-            return result
-        }
-    }
-
-    public actual companion object {
-        internal actual val logger = MiraiLogger.Factory.create(DeviceInfo::class, "DeviceInfo")
-
-        /**
-         * 加载一个设备信息. 若文件不存在或为空则随机并创建一个设备信息保存.
-         */
-        @JvmOverloads
-        @JvmStatic
-        @JvmName("from")
-        public fun File.loadAsDeviceInfo(
-            json: Json = DeviceInfoManager.format
-        ): DeviceInfo {
-            if (!this.exists() || this.length() == 0L) {
-                return random().also {
-                    this.writeText(DeviceInfoManager.serialize(it, json))
-                }
-            }
-            return DeviceInfoManager.deserialize(this.readText(), json) { upg ->
-                this.writeText(DeviceInfoManager.serialize(upg, json))
-            }
-        }
-
-        /**
-         * 生成随机 [DeviceInfo]
-         *
-         * @since 2.0
-         */
-        @JvmStatic
-        public actual fun random(): DeviceInfo = random(Random.Default)
-
-        /**
-         * 使用特定随机数生成器生成 [DeviceInfo]
-         *
-         * @since 2.9
-         */
-        @JvmStatic
-        public actual fun random(random: Random): DeviceInfo {
-            return DeviceInfoCommonImpl.randomDeviceInfo(random)
-        }
-
-        /**
-         * 将此 [DeviceInfo] 序列化为字符串. 序列化的字符串可以在以后通过 [DeviceInfo.deserializeFromString] 反序列化为 [DeviceInfo].
-         *
-         * 序列化的字符串有兼容性保证, 在旧版 mirai 序列化的字符串, 可以在新版 mirai 使用. 但新版 mirai 序列化的字符串不一定能在旧版使用.
-         *
-         * @since 2.15
-         */
-        @JvmStatic
-        public actual fun serializeToString(deviceInfo: DeviceInfo): String = DeviceInfoManager.serialize(deviceInfo)
-
-        /**
-         * 将通过 [serializeToString] 序列化得到的字符串反序列化为 [DeviceInfo].
-         * 此函数兼容旧版 mirai 序列化的字符串.
-         * @since 2.15
-         */
-        @JvmStatic
-        public actual fun deserializeFromString(string: String): DeviceInfo = DeviceInfoManager.deserialize(string)
-    }
-
-    /**
-     * @since 2.9
-     */
-    @Suppress("DuplicatedCode")
-    actual override fun equals(other: Any?): Boolean {
-        return DeviceInfoCommonImpl.equalsImpl(this, other)
-    }
-
-
-    /**
-     * @since 2.9
-     */
-    actual override fun hashCode(): Int {
-        return DeviceInfoCommonImpl.hashCodeImpl(this)
-    }
-
-    @Suppress("ClassName")
-    @Deprecated("For binary compatibility", level = DeprecationLevel.HIDDEN)
-    public object `$serializer` : KSerializer<DeviceInfo> by DeviceInfoV1LegacySerializer
-}
\ No newline at end of file
diff --git a/mirai-core-api/src/jvmBaseTest/kotlin/utils/JvmDeviceInfoTest.kt b/mirai-core-api/src/jvmBaseTest/kotlin/utils/JvmDeviceInfoTest.kt
index b73cccd1a..afb13ac5f 100644
--- a/mirai-core-api/src/jvmBaseTest/kotlin/utils/JvmDeviceInfoTest.kt
+++ b/mirai-core-api/src/jvmBaseTest/kotlin/utils/JvmDeviceInfoTest.kt
@@ -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 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -10,7 +10,6 @@
 package net.mamoe.mirai.utils
 
 import kotlinx.serialization.json.Json
-import net.mamoe.mirai.utils.DeviceInfo.Companion.loadAsDeviceInfo
 import net.mamoe.mirai.utils.DeviceInfoManager.Version.Companion.trans
 import org.junit.jupiter.api.io.TempDir
 import java.io.File
diff --git a/mirai-core-api/src/nativeMain/kotlin/utils/DeviceInfo.kt b/mirai-core-api/src/nativeMain/kotlin/utils/DeviceInfo.kt
deleted file mode 100644
index 7df3318fd..000000000
--- a/mirai-core-api/src/nativeMain/kotlin/utils/DeviceInfo.kt
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * 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
- */
-
-package net.mamoe.mirai.utils
-
-import kotlinx.serialization.Serializable
-import kotlinx.serialization.Transient
-import kotlin.random.Random
-
-@Serializable(DeviceInfoV1LegacySerializer::class)
-public actual class DeviceInfo public actual constructor(
-    public actual val display: ByteArray,
-    public actual val product: ByteArray,
-    public actual val device: ByteArray,
-    public actual val board: ByteArray,
-    public actual val brand: ByteArray,
-    public actual val model: ByteArray,
-    public actual val bootloader: ByteArray,
-    public actual val fingerprint: ByteArray,
-    public actual val bootId: ByteArray,
-    public actual val procVersion: ByteArray,
-    public actual val baseBand: ByteArray,
-    public actual val version: Version,
-    public actual val simInfo: ByteArray,
-    public actual val osType: ByteArray,
-    public actual val macAddress: ByteArray,
-    public actual val wifiBSSID: ByteArray,
-    public actual val wifiSSID: ByteArray,
-    public actual val imsiMd5: ByteArray,
-    public actual val imei: String,
-    public actual val apn: ByteArray,
-    public actual val androidId: ByteArray,
-) {
-    public actual val ipAddress: ByteArray get() = byteArrayOf(192.toByte(), 168.toByte(), 1, 123)
-
-    init {
-        require(imsiMd5.size == 16) { "Bad `imsiMd5.size`. Required 16, given ${imsiMd5.size}." }
-    }
-
-    @Transient
-    @MiraiInternalApi
-    public actual val guid: ByteArray = generateGuid(androidId, macAddress)
-
-    @Serializable
-    public actual class Version actual constructor(
-        public actual val incremental: ByteArray,
-        public actual val release: ByteArray,
-        public actual val codename: ByteArray,
-        public actual val sdk: Int
-    ) {
-        /**
-         * @since 2.9
-         */
-        actual override fun equals(other: Any?): Boolean {
-            if (this === other) return true
-            if (other !is Version) return false
-
-            if (!incremental.contentEquals(other.incremental)) return false
-            if (!release.contentEquals(other.release)) return false
-            if (!codename.contentEquals(other.codename)) return false
-            if (sdk != other.sdk) return false
-
-            return true
-        }
-
-        /**
-         * @since 2.9
-         */
-        actual override fun hashCode(): Int {
-            var result = incremental.contentHashCode()
-            result = 31 * result + release.contentHashCode()
-            result = 31 * result + codename.contentHashCode()
-            result = 31 * result + sdk
-            return result
-        }
-    }
-
-    public actual companion object {
-        internal actual val logger = MiraiLogger.Factory.create(DeviceInfo::class, "DeviceInfo")
-
-        /**
-         * 生成随机 [DeviceInfo]
-         *
-         * @since 2.0
-         */
-        public actual fun random(): DeviceInfo = random(Random.Default)
-
-        /**
-         * 使用特定随机数生成器生成 [DeviceInfo]
-         *
-         * @since 2.9
-         */
-        public actual fun random(random: Random): DeviceInfo {
-            return DeviceInfoCommonImpl.randomDeviceInfo(random)
-        }
-
-        /**
-         * 将此 [DeviceInfo] 序列化为字符串. 序列化的字符串可以在以后通过 [DeviceInfo.deserializeFromString] 反序列化为 [DeviceInfo].
-         *
-         * 序列化的字符串有兼容性保证, 在旧版 mirai 序列化的字符串, 可以在新版 mirai 使用. 但新版 mirai 序列化的字符串不一定能在旧版使用.
-         *
-         * @since 2.15
-         */
-        public actual fun serializeToString(deviceInfo: DeviceInfo): String = DeviceInfoManager.serialize(deviceInfo)
-
-        /**
-         * 将通过 [serializeToString] 序列化得到的字符串反序列化为 [DeviceInfo].
-         * 此函数兼容旧版 mirai 序列化的字符串.
-         * @since 2.15
-         */
-        public actual fun deserializeFromString(string: String): DeviceInfo = DeviceInfoManager.deserialize(string)
-    }
-
-    /**
-     * @since 2.9
-     */
-    @Suppress("DuplicatedCode")
-    actual override fun equals(other: Any?): Boolean {
-        return DeviceInfoCommonImpl.equalsImpl(this, other)
-    }
-
-
-    /**
-     * @since 2.9
-     */
-    actual override fun hashCode(): Int {
-        return DeviceInfoCommonImpl.hashCodeImpl(this)
-    }
-}
diff --git a/mirai-core-utils/src/commonMain/kotlin/jvm/JvmFile.kt b/mirai-core-utils/src/commonMain/kotlin/jvm/JvmFile.kt
index 299f8775a..a45285f3a 100644
--- a/mirai-core-utils/src/commonMain/kotlin/jvm/JvmFile.kt
+++ b/mirai-core-utils/src/commonMain/kotlin/jvm/JvmFile.kt
@@ -11,7 +11,7 @@ package net.mamoe.mirai.utils.jvm
 
 import io.ktor.utils.io.errors.*
 
-@CompatibilityOnlyJvmFile
+@Suppress("DEPRECATION_ERROR")
 public expect class JvmFile {
     public constructor(pathname: String)
     public constructor(parent: String, child: String)
@@ -36,6 +36,7 @@ public expect class JvmFile {
 
     public fun length(): Long
     public fun delete(): Boolean
+    public fun exists(): Boolean
 
     public fun listFiles(): Array<JvmFile>?
 
@@ -44,6 +45,14 @@ public expect class JvmFile {
     public fun renameTo(file: JvmFile): Boolean
 }
 
+@Suppress("DEPRECATION_ERROR")
+@CompatibilityOnlyJvmFile
+public expect fun JvmFile.writeText(text: String)
+
+@Suppress("DEPRECATION_ERROR")
+@CompatibilityOnlyJvmFile
+public expect fun JvmFile.readText(): String
+
 @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPEALIAS, AnnotationTarget.FUNCTION)
 @RequiresOptIn(
     "JvmFile is only used for compatibility and for simplifying expect/actual structure. " +
diff --git a/mirai-core-utils/src/jvmBaseMain/kotlin/jvm/JvmFile.kt b/mirai-core-utils/src/jvmBaseMain/kotlin/jvm/JvmFile.kt
index 903abf305..3de728808 100644
--- a/mirai-core-utils/src/jvmBaseMain/kotlin/jvm/JvmFile.kt
+++ b/mirai-core-utils/src/jvmBaseMain/kotlin/jvm/JvmFile.kt
@@ -9,5 +9,18 @@
 
 package net.mamoe.mirai.utils.jvm
 
+import kotlin.io.readText as readTextKt
+import kotlin.io.writeText as writeTextKt
+
 @CompatibilityOnlyJvmFile
-public actual typealias JvmFile = java.io.File 
\ No newline at end of file
+public actual typealias JvmFile = java.io.File
+
+@CompatibilityOnlyJvmFile
+public actual fun JvmFile.writeText(text: String) {
+    return this.writeTextKt(text)
+}
+
+@CompatibilityOnlyJvmFile
+public actual fun JvmFile.readText(): String {
+    return this.readTextKt()
+}
diff --git a/mirai-core-utils/src/nativeMain/kotlin/jvm/JvmFile.kt b/mirai-core-utils/src/nativeMain/kotlin/jvm/JvmFile.kt
index cc6d0ba53..e9aafd1f6 100644
--- a/mirai-core-utils/src/nativeMain/kotlin/jvm/JvmFile.kt
+++ b/mirai-core-utils/src/nativeMain/kotlin/jvm/JvmFile.kt
@@ -39,6 +39,7 @@ public actual class JvmFile {
     public actual fun length(): Long = throw NotImplementedError()
 
     public actual fun delete(): Boolean = throw NotImplementedError()
+    public actual fun exists(): Boolean = throw NotImplementedError()
 
     public actual fun listFiles(): Array<JvmFile>? = throw NotImplementedError()
 
@@ -55,4 +56,18 @@ public actual class JvmFile {
     public actual constructor(parent: String, child: String) {
         throw NotImplementedError()
     }
-}
\ No newline at end of file
+}
+
+@Suppress("DEPRECATION_ERROR")
+@Deprecated("JvmFile is not implemented on native", level = DeprecationLevel.HIDDEN)
+@CompatibilityOnlyJvmFile
+public actual fun JvmFile.writeText(text: String) {
+    throw NotImplementedError()
+}
+
+@Suppress("DEPRECATION_ERROR")
+@Deprecated("JvmFile is not implemented on native", level = DeprecationLevel.HIDDEN)
+@CompatibilityOnlyJvmFile
+public actual fun JvmFile.readText(): String {
+    throw NotImplementedError()
+}