【征文计划】利用 CXR-M SDK 构建 “AR 眼镜 + 手机” 的数学教学系统

举报
微学AI 发表于 2025/10/14 14:50:39 2025/10/14
【摘要】 课堂数学教学中,传统“板书 + 手机拍照”存在视角不统一、步骤关联难、师生互动同步不畅等问题。CXR-M SDK 可实现手机与 Rokid Glasses 稳定连接,调用录音、拍照等能力,接入 YodaOS-Sprite 交互流程,主要是在数学讲解中将“题目与步骤”以第一视角叠加呈现,并同步学生端状态。本文围绕“数学教学系统”,涵盖 SDK 环境搭建、功能落地及避坑指南,帮助开发者将 SDK 能力

一、项目与CXR-M SDK

课堂数学教学中,传统“板书 + 手机拍照”存在视角不统一、步骤关联难、师生互动同步不畅等问题。CXR-M SDK 可实现手机与 Rokid Glasses 稳定连接,调用录音、拍照等能力,接入 YodaOS-Sprite 交互流程,主要是在数学讲解中将“题目与步骤”以第一视角叠加呈现,并同步学生端状态。本文围绕“数学教学系统”,涵盖 SDK 环境搭建、功能落地及避坑指南,帮助开发者将 SDK 能力转化为可用的课堂教学工具。
image.png

CXR-M SDK 核心能力与适用范围

CXR-M SDK 是移动端开发工具包(仅 Android 版本),他主要是构建手机与 Rokid Glasses 的控制协同应用,同时支持数据通信,可接入 YodaOS-Sprite 交互流程,调用文件互传、录音、拍照等 Rokid Assist Service 服务。

CXR-M SDK 导入配置指南

以 Kotlin DSL(build.gradle.kts)为例,从三方面说明配置流程:

1.Maven仓库配置

在settings.gradle.kts的dependencyResolutionManagement节点中添加 Rokid Maven 仓库,保留基础仓库:

pluginManagement {
    repositories {
        google {
            content {
                includeGroupByRegex("com\\.android.*")
                includeGroupByRegex("com\\.google.*")
                includeGroupByRegex("androidx.*")
            }
        }
        mavenCentral()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        // 新增 Rokid Maven 仓库,用于拉取 CXR-M SDK
        maven { url = uri("https://maven.rokid.com/repository/maven-public/") }
        google()
        mavenCentral()
    }
}

2.SDK 与依赖导入

模块级build.gradle.kts中添加核心依赖,设置minSdk=28(最低支持 Android 9.0),并导入配套依赖(版本冲突时优先使用 SDK 版本):

android {
    // 其他基础配置(如 compileSdk、buildToolsVersion 等)
    defaultConfig {
        // 其他配置(如 applicationId、targetSdk 等)
        minSdk = 28 // 必须设置为 28 及以上,否则不支持 SDK
    }
    // 其他配置(如 buildTypes、compileOptions 等)
}

dependencies {
    // 其他项目依赖(如 AndroidX、第三方库等)
    
    // 1. CXR-M SDK 核心依赖
    implementation("com.rokid.cxr:client-m:1.0.1-20250812.080117-2")
    
    // 2. SDK 配套依赖(版本冲突时优先使用这些版本)
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    implementation("com.squareup.retrofit2:converter-gson:2.9.0")
    implementation("com.squareup.okhttp3:okhttp:4.9.3")
    implementation("org.jetbrains.kotlin:kotlin-stdlib:2.1.0")
    implementation("com.squareup.okio:okio:2.8.0")
    implementation("com.google.code.gson:gson:2.10.1")
    implementation("com.squareup.okhttp3:logging-interceptor:4.9.1")
}

3.权限申请

CXR-M SDK 依赖网络、Wi-Fi、蓝牙(含定位关联权限)等能力,需完成 静态权限声明 和 动态权限申请,否则 SDK 无法正常使用:

静态权限声明

在项目的 AndroidManifest.xml 文件中,需要声明 CXR-M SDK 运行所必需的基础权限集合,含有蓝牙、网络、Wi-Fi 以及定位相关权限,以确保 SDK 功能的正常运行。具体配置代码如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android
    xmlns:tools="http://schemas.android.com/tools">

    <!-- 蓝牙相关权限(含 Android S 及以上新增权限) -->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <!-- 蓝牙依赖的定位权限 -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <!-- 网络与 Wi-Fi 权限 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

    <application>
        <!-- 项目其他配置(如 Activity 注册、Application 声明等) -->
    </application>
</manifest>

动态权限申请

对于运行在 Android 6.0(API 23)及以上版本的设备,由于系统引入了运行时权限机制,应用必须在运行时动态申请被归类为"危险权限"的权限组。为了确保 CXR-M SDK 各项功能的正常运行,在初始化 SDK 之前,开发者需要确保所有必需的权限都已获得用户授权。下面展示了如何在 Activity 中实现动态权限申请的完整流程:

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
        private const val REQUEST_CODE_PERMISSIONS = 100 // 权限请求码
        // 必要权限列表(区分 Android S/API 31 及以上的新增蓝牙权限)
        private val REQUIRED_PERMISSIONS = mutableListOf(
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.BLUETOOTH,
            Manifest.permission.BLUETOOTH_ADMIN
        ).apply {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                add(Manifest.permission.BLUETOOTH_SCAN)
                add(Manifest.permission.BLUETOOTH_CONNECT)
            }
        }.toTypedArray()
    }

    // 用于观察权限申请结果的 LiveData
    private val isAllPermissionsGranted = MutableLiveData<Boolean?>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 初始化时发起权限申请
        isAllPermissionsGranted.postValue(null)
        requestPermissions(REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)

        // 观察权限申请结果,决定是否初始化 SDK
        isAllPermissionsGranted.observe(this) { granted ->
            when (granted) {
                true -> {
                    // 所有权限已授予,可初始化 CXR-M SDK
                }
                false -> {
                    // 部分权限被拒绝,需提示用户开启(否则 SDK 不可用)
                }
            }
        }
    }

    // 接收权限申请结果
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            // 判断所有权限是否均被授予
            val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
            isAllPermissionsGranted.postValue(allGranted)
        }
    }
}

二、数学教学场景需求拆解与技术方案

image.png

SDK 导入与课堂场景权限优化

SDK 依赖与系统配置优化

依赖配置遵循文档与课堂需求,保留 CXR-M SDK 与基础网络栈;manifestPlaceholders 可设置课堂模式标识,构建配置开启混淆以减少资源占用,满足教室多设备并行的稳定性。

// build.gradle.kts(模块级)
dependencies {
    // CXR-M SDK核心依赖(固定版本)
    implementation("com.rokid.cxr:client-m:1.0.1-20250812.080117-2")
    // 文档要求的基础依赖(Retrofit、OkHttp等)
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    implementation("com.squareup.okhttp3:okhttp:4.9.3")
    implementation("com.squareup.retrofit2:converter-gson:2.9.0")
    implementation("com.google.code.gson:gson:2.10.1")
    implementation("com.squareup.okhttp3:logging-interceptor:4.9.1")
    implementation("org.jetbrains.kotlin:kotlin-stdlib:2.1.0")
}

android {
    defaultConfig {
        minSdk = 28 // 遵循SDK要求
        targetSdk = 33
        // 课堂场景标识(用于区分环境配置)
        manifestPlaceholders["classroom_mode"] = "true"
    }
    // 构建优化:减少课堂多设备压力
    buildTypes {
        release {
            isMinifyEnabled = true
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
}

课堂场景权限强化

在课堂场景下,对于蓝牙(设备连接)、网络(内容分发)与存储(板书拍照与讲解录音)为必需;动态申请时明确教学用途和影响,拒绝将影响授课流程,需引导开启:

class ClassroomPermissionManager(private val activity: AppCompatActivity) {
    // 课堂必需权限:蓝牙(连接)+ 网络(内容同步)+ 存储(素材保存)
    private val REQUIRED_PERMISSIONS = mutableListOf(
        Manifest.permission.ACCESS_FINE_LOCATION, // 蓝牙扫描依赖定位
        Manifest.permission.BLUETOOTH_SCAN,
        Manifest.permission.BLUETOOTH_CONNECT,
        Manifest.permission.WRITE_EXTERNAL_STORAGE // 保存板书/讲解录音
    ).toTypedArray()

    var onPermissionReady: (() -> Unit)? = null

    fun requestClassroomPermissions() {
        if (isAllPermissionsGranted()) {
            onPermissionReady?.invoke()
            return
        }
        ActivityResultContracts.RequestMultiplePermissions().launch(
            activity,
            REQUIRED_PERMISSIONS
        ) { resultMap ->
            val allGranted = resultMap.values.all { it }
            if (!allGranted) {
                AlertDialog.Builder(activity)
                    .setTitle("数学教学必需权限")
                    .setMessage("蓝牙与存储权限用于设备连接与课堂素材保存,拒绝将影响课堂互动,请前往设置开启")
                    .setCancelable(false)
                    .setPositiveButton("去设置") { _, _ ->
                        val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
                            data = Uri.fromParts("package", activity.packageName, null)
                        }
                        activity.startActivityForResult(intent, 1001)
                    }
                    .show()
            } else {
                onPermissionReady?.invoke()
            }
        }
    }

    private fun isAllPermissionsGranted() = REQUIRED_PERMISSIONS.all {
        ContextCompat.checkSelfPermission(activity, it) == PackageManager.PERMISSION_GRANTED
    }

    fun onSettingsReturn() {
        if (isAllPermissionsGranted()) {
            onPermissionReady?.invoke()
        } else {
            requestClassroomPermissions()
        }
    }
}

核心功能实现:课堂场景下的设备协同

设备连接优化:教室多设备稳定连接

初始化 SDK 时设置蓝牙模式与自动重连策略,过滤 Rokid Glasses;连接后同步显示参数(亮度、抗眩光),保证投屏光照下的可视性。

class RokidClassroomDeviceManager(private val context: Context) {
    private lateinit var cxrClient: CxrClient
    private var targetDeviceId: String? = null

    fun initClassroomClient(
        appKey: String,
        appSecret: String,
        accessKey: String,
        onInitResult: ((Boolean) -> Unit)
    ) {
        CxrClient.init(
            context = context,
            appKey = appKey,
            appSecret = appSecret,
            accessKey = accessKey,
            config = CxrConfig.Builder()
                .setBluetoothMode(BluetoothMode.NORMAL)
                .setReconnectInterval(3000) // 断连后3秒重试
                .build()
        ) { initSuccess ->
            if (!initSuccess) {
                onInitResult.invoke(false)
                return@init
            }
            cxrClient = CxrClient.getInstance()
            onInitResult.invoke(true)
        }
    }

    // 扫描并连接Rokid Glasses(过滤非教学设备)
    fun scanAndConnectClassroomDevice(onConnectResult: ((Boolean, String?) -> Unit)) {
        cxrClient.scanDevices(
            scanMode = ScanMode.NORMAL,
            filter = { device -> device.name.contains("Rokid Glasses") },
            callback = object : DeviceScanCallback {
                override fun onDeviceFound(device: RokidDevice) {
                    targetDeviceId = device.deviceId
                    cxrClient.connectDevice(
                        device = device,
                        signalListener = { rssi ->
                            if (rssi < -80) {
                                Toast.makeText(context, "信号弱,请靠近眼镜或调整位置", Toast.LENGTH_SHORT).show()
                            }
                        },
                        connectCallback = object : ConnectCallback {
                            override fun onConnected() {
                                syncClassroomDisplayConfig()
                                onConnectResult.invoke(true, null)
                            }

                            override fun onDisconnected() {
                                onConnectResult.invoke(false, "设备断开连接,正在重试...")
                                targetDeviceId?.let { cxrClient.reconnectDevice(it) }
                            }

                            override fun onConnectFailed(errorMsg: String) {
                                onConnectResult.invoke(false, "连接失败:$errorMsg")
                            }
                        }
                    )
                }

                override fun onScanFailed(errorMsg: String) {
                    onConnectResult.invoke(false, "扫描设备失败:$errorMsg")
                }
            }
        )
    }

    // 同步显示配置:投影灯光下提高亮度与抗眩光
    private fun syncClassroomDisplayConfig() {
        targetDeviceId?.let { deviceId ->
            cxrClient.setDeviceConfig(
                deviceId = deviceId,
                configType = ConfigType.DISPLAY,
                configParams = mapOf(
                    "brightness" to 70,
                    "antiGlare" to true,
                    "classroomMode" to true
                ),
                callback = object : ConfigCallback {
                    override fun onConfigSuccess() {
                        Log.d("ClassroomConfig", "眼镜显示参数同步成功")
                    }

                    override fun onConfigFailed(errorMsg: String) {
                        Log.e("ClassroomConfig", "显示参数同步失败:$errorMsg")
                    }
                }
            )
        }
    }

    // 获取当前眼镜状态(电量、存储、网络)
    fun getGlassesStatus(onStatusReady: ((GlassesStatus) -> Unit)) {
        targetDeviceId?.let { deviceId ->
            cxrClient.getDeviceStatus(
                deviceId = deviceId,
                statusTypes = listOf(StatusType.BATTERY, StatusType.STORAGE, StatusType.NETWORK),
                callback = object : StatusCallback {
                    override fun onStatusReceived(statusMap: Map<StatusType, Any>) {
                        val status = GlassesStatus(
                            battery = statusMap[StatusType.BATTERY] as Int,
                            storageLeft = statusMap[StatusType.STORAGE] as Long,
                            networkType = statusMap[StatusType.NETWORK] as String
                        )
                        onStatusReady.invoke(status)
                    }
                }
            )
        }
    }

    data class GlassesStatus(
        val battery: Int,
        val storageLeft: Long,
        val networkType: String
    )
}

核心功能 1:题目下发与 AR 步骤叠加

手机端准备数学题目与解题步骤,解析为 JSON,通过 SDK 的数据飞传至眼镜,并触发 YodaOS-Sprite 场景交互,将“题干 + 关键步骤提示”以 AR 叠加呈现,确保学生第一视角一致。

class MathLessonManager(
    private val cxrClient: CxrClient,
    private val deviceId: String
) {
    // 下发数学题目与步骤
    fun deliverMathContent(
        title: String, // 题干
        steps: List<Step>, // 解题步骤列表
        onDelivered: ((Boolean) -> Unit)
    ) {
        // 1. 组装教学内容(题干 + 步骤提示)
        val content = MathContent(
            title = title,
            steps = steps
        )
        // 2. 转JSON并通过数据飞传同步到眼镜
        val contentJson = Gson().toJson(content)
        cxrClient.transferData(
            deviceId = deviceId,
            dataType = DataType.CUSTOM, // 自定义:MATH_CONTENT
            data = contentJson.toByteArray(),
            callback = object : DataTransferCallback {
                override fun onTransferSuccess() {
                    Log.d("MathSync", "教学内容同步成功")
                    triggerGlassesTeachingDisplay()
                    onDelivered.invoke(true)
                }

                override fun onTransferFailed(errorMsg: String) {
                    Toast.makeText(context, "内容同步失败:$errorMsg", Toast.LENGTH_SHORT).show()
                    onDelivered.invoke(false)
                }
            }
        )
    }

    // 触发眼镜端的数学教学场景显示(AR叠加“题干 + 步骤”)
    private fun triggerGlassesTeachingDisplay() {
        cxrClient.triggerSceneInteraction(
            deviceId = deviceId,
            sceneType = SceneType.CUSTOM, // 场景类型:MATH_TEACHING
            interactionParams = mapOf("displayMode" to "AR_OVERLAY"),
            callback = object : SceneCallback {
                override fun onInteractionSuccess() {
                    Toast.makeText(context, "眼镜AR教学已开启", Toast.LENGTH_SHORT).show()
                }

                override fun onInteractionFailed(errorMsg: String) {
                    Log.e("ARDisplay", "AR教学显示失败:$errorMsg")
                }
            }
        )
    }

    // 数据结构:教学内容与步骤
    data class MathContent(
        val title: String,
        val steps: List<Step>
    )

    data class Step(
        val hint: String, // 步骤提示,如“先因式分解”
        val formula: String // 公式,如“(a+b)^2 = a^2 + 2ab + b^2”
    )
}

核心功能 2:板书采集与助教协同

板书采集通过眼镜拍照回传手机并关联题目标签;助教协同通过先录音(教师讲解要点)再拍照板书,组装数据包飞传到助教设备,保障课堂资料同步与答疑效率。

class ClassroomAssistManager(
    private val cxrClient: CxrClient,
    private val deviceId: String
) {
    // 1. 板书采集:眼镜端拍照回传,关联题目标签
    fun captureBlackboard(tag: String, onCaptured: ((String) -> Unit)) {
        cxrClient.takePhoto(
            deviceId = deviceId,
            photoConfig = PhotoConfig(
                beautyMode = false,
                resolution = Resolution.HD,
                saveToLocal = true
            ),
            callback = object : PhotoCallback {
                override fun onPhotoTaken(photoPath: String) {
                    val msg = "已采集板书【$tag】"
                    Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
                    onCaptured.invoke(photoPath)
                }

                override fun onPhotoFailed(errorMsg: String) {
                    Toast.makeText(context, "板书拍照失败:$errorMsg", Toast.LENGTH_SHORT).show()
                }
            }
        )
    }

    // 2. 助教协同:录音+拍照,飞传教学资料
    fun sendTeachingPack(assistantDeviceId: String, onSent: ((Boolean) -> Unit)) {
        cxrClient.startRecording(
            deviceId = deviceId,
            audioConfig = AudioConfig(
                duration = 10,
                format = AudioFormat.MP3,
                sampleRate = 44100
            ),
            callback = object : RecordingCallback {
                override fun onRecordingStopped(audioPath: String) {
                    takeTeachingPhoto(audioPath, assistantDeviceId, onSent)
                }

                override fun onRecordingFailed(errorMsg: String) {
                    Toast.makeText(context, "讲解录音失败:$errorMsg", Toast.LENGTH_SHORT).show()
                    onSent.invoke(false)
                }
            }
        )
    }

    // 拍照并飞传资料包
    private fun takeTeachingPhoto(
        audioPath: String,
        assistantDeviceId: String,
        onSent: ((Boolean) -> Unit)
    ) {
        cxrClient.takePhoto(
            deviceId = deviceId,
            photoConfig = PhotoConfig(resolution = Resolution.FHD),
            callback = object : PhotoCallback {
                override fun onPhotoTaken(photoPath: String) {
                    val pack = TeachingPack(
                        photoPath = photoPath,
                        audioPath = audioPath,
                        timestamp = System.currentTimeMillis()
                    )
                    cxrClient.transferFile(
                        sourceDeviceId = deviceId,
                        targetDeviceId = assistantDeviceId,
                        filePath = Gson().toJson(pack).toByteArray(),
                        fileType = FileType.CUSTOM, // 自定义:TEACHING_PACK
                        callback = object : FileTransferCallback {
                            override fun onTransferSuccess() {
                                Toast.makeText(context, "教学资料已发送给助教", Toast.LENGTH_SHORT).show()
                                onSent.invoke(true)
                            }

                            override fun onTransferFailed(errorMsg: String) {
                                Toast.makeText(context, "资料发送失败:$errorMsg", Toast.LENGTH_SHORT).show()
                                onSent.invoke(false)
                            }
                        }
                    )
                }

                override fun onPhotoFailed(errorMsg: String) {
                    Toast.makeText(context, "教学拍照失败:$errorMsg", Toast.LENGTH_SHORT).show()
                    onSent.invoke(false)
                }
            }
        )
    }

    data class TeachingPack(
        val photoPath: String,
        val audioPath: String,
        val timestamp: Long
    )
}

设备状态监控:课堂续航与存储兜底

用协程定时(1 分钟)检查眼镜电量、存储与网络状态,低电量/低存储/无网络时顶部预警,避免课堂中断。

class ClassroomStatusMonitor(
    private val deviceManager: RokidClassroomDeviceManager,
    private val context: Context
) {
    private val statusCheckInterval = 60000 // 1分钟检查一次状态

    fun startStatusMonitor() {
        CoroutineScope(Dispatchers.IO).launch {
            while (true) {
                delay(statusCheckInterval.toLong())
                deviceManager.getGlassesStatus { status ->
                    if (status.battery < 20) {
                        showWarning("眼镜电量不足20%,请尽快充电")
                    }
                    if (status.storageLeft < 100) {
                        showWarning("眼镜剩余存储不足100MB,建议清理历史板书/录音")
                    }
                    if (status.networkType == "NONE") {
                        showWarning("眼镜无网络连接,内容同步可能延迟")
                    }
                }
            }
        }
    }

    private fun showWarning(message: String) {
        val toast = Toast.makeText(context, message, Toast.LENGTH_LONG)
        toast.setGravity(Gravity.TOP, 0, 100)
        toast.show()
    }
}

应用场景

场景一:题目讲解第一视角
教师在手机端准备题干与步骤提示,通过数据飞传同步到眼镜,学生以第一视角看到 AR 叠加的“关键步骤与公式”,减少低头翻找资料,提高跟随度。
场景二:板书资料采集与助教协同
眼镜端拍照板书并保存,教师录制关键讲解语音后生成资料包,飞传助教设备用于课后整理与答疑,降低资料碎片化。
场景三:课堂稳定性保障
实时监控电量、存储与网络状态,提前预警,避免因设备状态导致的教学中断。

总结

我们的文章利用 CXR-M SDK 落地“数学教学系统”,结合课堂场景实现题目下发与步骤 AR 叠加、板书采集与助教协同,以及设备状态兜底。整体设计遵循“场景化调优 SDK 能力 + 风险兜底机制”,帮助开发者在教学场景中稳定复用。学习 SDK 不应停留在接口调用层面,而要围绕具体场景痛点转化为实用功能,从而更快落地高质量的 AR 教学协同应用。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。