diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt
index 181ebf761..d2fae3d0c 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt
@@ -77,6 +77,10 @@ internal open class QQAndroidClient(
     val device: DeviceInfo = SystemDeviceInfo(context),
     bot: QQAndroidBot
 ) {
+    @Suppress("INVISIBLE_MEMBER")
+    val subAppId: Long
+        get() = bot.configuration.protocol.id
+
     internal val serverList: MutableList<Pair<String, Int>> = DefaultServerList.toMutableList()
 
     val keys: Map<String, ByteArray> by lazy {
@@ -368,7 +372,7 @@ internal class WLoginSigInfo(
     val deviceToken: ByteArray
 ) {
     override fun toString(): String {
-        return "WLoginSigInfo(uin=$uin, encryptA1=${encryptA1?.toUHexString()}, noPicSig=${noPicSig?.toUHexString()}, G=${G.toUHexString()}, dpwd=${dpwd.toUHexString()}, randSeed=${randSeed.toUHexString()}, simpleInfo=$simpleInfo, appPri=$appPri, a2ExpiryTime=$a2ExpiryTime, loginBitmap=$loginBitmap, tgt=${tgt.toUHexString()}, a2CreationTime=$a2CreationTime, tgtKey=${tgtKey.toUHexString()}, userStSig=$userStSig, userStKey=${userStKey.toUHexString()}, userStWebSig=$userStWebSig, userA5=$userA5, userA8=$userA8, lsKey=$lsKey, sKey=$sKey, userSig64=$userSig64, openId=${openId.toUHexString()}, openKey=$openKey, vKey=$vKey, accessToken=$accessToken, d2=$d2, d2Key=${d2Key.toUHexString()}, sid=$sid, aqSig=$aqSig, psKey=${psKeyMap.toString()}, superKey=${superKey.toUHexString()}, payToken=${payToken.toUHexString()}, pf=${pf.toUHexString()}, pfKey=${pfKey.toUHexString()}, da2=${da2.toUHexString()}, wtSessionTicket=$wtSessionTicket, wtSessionTicketKey=${wtSessionTicketKey.toUHexString()}, deviceToken=${deviceToken.toUHexString()})"
+        return "WLoginSigInfo(uin=$uin, encryptA1=${encryptA1?.toUHexString()}, noPicSig=${noPicSig?.toUHexString()}, G=${G.toUHexString()}, dpwd=${dpwd.toUHexString()}, randSeed=${randSeed.toUHexString()}, simpleInfo=$simpleInfo, appPri=$appPri, a2ExpiryTime=$a2ExpiryTime, loginBitmap=$loginBitmap, tgt=${tgt.toUHexString()}, a2CreationTime=$a2CreationTime, tgtKey=${tgtKey.toUHexString()}, userStSig=$userStSig, userStKey=${userStKey.toUHexString()}, userStWebSig=$userStWebSig, userA5=$userA5, userA8=$userA8, lsKey=$lsKey, sKey=$sKey, userSig64=$userSig64, openId=${openId.toUHexString()}, openKey=$openKey, vKey=$vKey, accessToken=$accessToken, d2=$d2, d2Key=${d2Key.toUHexString()}, sid=$sid, aqSig=$aqSig, psKey=$psKeyMap, superKey=${superKey.toUHexString()}, payToken=${payToken.toUHexString()}, pf=${pf.toUHexString()}, pfKey=${pfKey.toUHexString()}, da2=${da2.toUHexString()}, wtSessionTicket=$wtSessionTicket, wtSessionTicketKey=${wtSessionTicketKey.toUHexString()}, deviceToken=${deviceToken.toUHexString()})"
     }
 }
 
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/HighwayHelper.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/HighwayHelper.kt
index dee0e811d..5cc703564 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/HighwayHelper.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/HighwayHelper.kt
@@ -159,6 +159,7 @@ internal object HighwayHelper {
         socket.use {
             createImageDataPacketSequence(
                 client = client,
+                appId = client.subAppId.toInt(),
                 command = "PicUp.DataUp",
                 commandId = commandId,
                 ticket = ticket,
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/highway.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/highway.kt
index c84bdcf61..59214a586 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/highway.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/highway.kt
@@ -32,7 +32,7 @@ internal fun createImageDataPacketSequence(
     // RequestDataTrans
     client: QQAndroidClient,
     command: String,
-    appId: Int = 537062845,
+    appId: Int,
     dataFlag: Int = 4096,
     commandId: Int,
     localId: Int = 2052,
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/Tlv.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/Tlv.kt
index 38b0dc56c..36181578d 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/Tlv.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/Tlv.kt
@@ -83,7 +83,7 @@ internal fun BytePacketBuilder.t18(
 @OptIn(MiraiInternalAPI::class)
 internal fun BytePacketBuilder.t106(
     appId: Long = 16L,
-    subAppId: Long = 537062845L,
+    subAppId: Long,
     appClientVersion: Int = 0,
     uin: Long,
     n5_always_1: Int = 1,
@@ -159,7 +159,7 @@ internal fun BytePacketBuilder.t116(
 
 internal fun BytePacketBuilder.t100(
     appId: Long = 16,
-    subAppId: Long = 537062845,
+    subAppId: Long,
     appClientVersion: Int
 ) {
     writeShort(0x100)
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt
index 0f3fc8474..6f3e15648 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt
@@ -100,7 +100,7 @@ internal class TroopManagement {
                         serviceType = 7,
                         result = 0,
                         bodybuffer = Oidb0x88d.ReqBody(
-                            appid = 537062845,
+                            appid = client.subAppId.toInt(),
                             stzreqgroupinfo = listOf(
                                 Oidb0x88d.ReqGroupInfo(
                                     stgroupinfo = Oidb0x88d.GroupInfo(
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/Heartbeat.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/Heartbeat.kt
index 0582d698a..4d2ed0ff6 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/Heartbeat.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/Heartbeat.kt
@@ -25,7 +25,7 @@ internal class Heartbeat {
         operator fun invoke(
             client: QQAndroidClient
         ): OutgoingPacket = buildLoginOutgoingPacket(client, 0, key = NO_ENCRYPT) {
-            writeSsoPacket(client, 537062845, commandName, sequenceId = it) {
+            writeSsoPacket(client, client.subAppId, commandName, sequenceId = it) {
 
             }
         }
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/StatSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/StatSvc.kt
index 3b5ed64f4..8fddfddbc 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/StatSvc.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/StatSvc.kt
@@ -88,8 +88,6 @@ internal class StatSvc {
             override fun toString(): String = "Response(StatSvc.register)"
         }
 
-        private const val subAppId = 537062845L
-
         @OptIn(MiraiInternalAPI::class)
         operator fun invoke(
             client: QQAndroidClient,
@@ -101,7 +99,7 @@ internal class StatSvc {
             key = client.wLoginSigInfo.d2Key
         ) { sequenceId ->
             writeSsoPacket(
-                client, subAppId = subAppId, commandName = commandName,
+                client, subAppId = client.subAppId, commandName = commandName,
                 extraData = client.wLoginSigInfo.tgt.toReadPacket(), sequenceId = sequenceId
             ) {
                 writeJceStruct(
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt
index 70c7d7fca..dbf39123a 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt
@@ -32,8 +32,6 @@ internal class WtLogin {
     @Suppress("FunctionName")
     @OptIn(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
     internal object Login : OutgoingPacketFactory<Login.LoginPacketResponse>("wtlogin.login") {
-        private const val subAppId = 537062845L
-
         /**
          * 提交验证码
          */
@@ -42,7 +40,7 @@ internal class WtLogin {
                 client: QQAndroidClient,
                 ticket: String
             ): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId ->
-                writeSsoPacket(client, subAppId, commandName, sequenceId = sequenceId) {
+                writeSsoPacket(client, client.subAppId, commandName, sequenceId = sequenceId) {
                     writeOicqRequestPacket(client, EncryptMethodECDH(client.ecdh), 0x0810) {
                         writeShort(2) // subCommand
                         writeShort(4) // count of TLVs
@@ -59,7 +57,7 @@ internal class WtLogin {
                 captchaSign: ByteArray,
                 captchaAnswer: String
             ): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId ->
-                writeSsoPacket(client, subAppId, commandName, sequenceId = sequenceId) {
+                writeSsoPacket(client, client.subAppId, commandName, sequenceId = sequenceId) {
                     writeOicqRequestPacket(client, EncryptMethodECDH(client.ecdh), 0x0810) {
                         writeShort(2) // subCommand
                         writeShort(4) // count of TLVs
@@ -78,7 +76,7 @@ internal class WtLogin {
                 client: QQAndroidClient,
                 t402: ByteArray
             ): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId ->
-                writeSsoPacket(client, subAppId, commandName, sequenceId = sequenceId) {
+                writeSsoPacket(client, client.subAppId, commandName, sequenceId = sequenceId) {
                     writeOicqRequestPacket(client, EncryptMethodECDH(client.ecdh), 0x0810) {
                         writeShort(20) // subCommand
                         writeShort(4) // count of TLVs, probably ignored by server?
@@ -100,7 +98,7 @@ internal class WtLogin {
             ): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId ->
                 writeSsoPacket(
                     client,
-                    subAppId,
+                    client.subAppId,
                     commandName,
                     sequenceId = sequenceId,
                     unknownHex = "01 00 00 00 00 00 00 00 00 00 01 00"
@@ -126,13 +124,12 @@ internal class WtLogin {
          */
         object SubCommand9 {
             private const val appId = 16L
-            private const val subAppId = 537062845L
 
             @OptIn(MiraiInternalAPI::class, MiraiExperimentalAPI::class)
             operator fun invoke(
                 client: QQAndroidClient
             ): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId ->
-                writeSsoPacket(client, subAppId, commandName, sequenceId = sequenceId) {
+                writeSsoPacket(client, client.subAppId, commandName, sequenceId = sequenceId) {
                     writeOicqRequestPacket(client, EncryptMethodECDH(client.ecdh), 0x0810) {
                         writeShort(9) // subCommand
                         writeShort(17) // count of TLVs, probably ignored by server?
@@ -142,7 +139,7 @@ internal class WtLogin {
                         t1(client.uin, client.device.ipAddress)
                         t106(
                             appId,
-                            subAppId /* maybe 1*/,
+                            client.subAppId /* maybe 1*/,
                             client.appClientVersion,
                             client.uin,
                             1,
@@ -166,7 +163,7 @@ internal class WtLogin {
                         if (ConfigManager.get_loginWithPicSt()) appIdList = longArrayOf(1600000226L)
                         */
                         t116(client.miscBitMap, client.subSigMap)
-                        t100(appId, subAppId, client.appClientVersion)
+                        t100(appId, client.subAppId, client.appClientVersion)
                         t107(0)
 
                         // t108(byteArrayOf())
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt
index 8c865b445..5cff3de0d 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt
@@ -15,6 +15,7 @@ import net.mamoe.mirai.network.BotNetworkHandler
 import kotlin.coroutines.CoroutineContext
 import kotlin.coroutines.EmptyCoroutineContext
 import kotlin.coroutines.coroutineContext
+import kotlin.jvm.JvmField
 import kotlin.jvm.JvmOverloads
 import kotlin.jvm.JvmStatic
 
@@ -75,6 +76,34 @@ open class BotConfiguration {
      */
     var loginSolver: LoginSolver = LoginSolver.Default
 
+    /**
+     * 使用协议类型
+     */
+    @SinceMirai("1.0.0")
+    val protocol: MiraiProtocol = MiraiProtocol.ANDROID_PAD
+
+    @SinceMirai("1.0.0")
+    enum class MiraiProtocol(
+        /** 协议模块使用的 ID */
+        @JvmField internal val id: Long
+    ) {
+        /**
+         * Android 手机.
+         *
+         * - 与手机冲突
+         * - 与平板和电脑不冲突
+         */
+        ANDROID_PHONE(537062845),
+
+        /**
+         * Android 平板.
+         *
+         * - 与平板冲突
+         * - 与手机和电脑不冲突
+         */
+        ANDROID_PAD(537062409)
+    }
+
     companion object {
         /**
          * 默认的配置实例