================================================================================ UTS-Android 兼容性开发规范 ================================================================================ > 以下为 uni-app-x (UTS) Android 端开发常见注意事项与踩坑点,建议所有开发成员遵循: ================================================================================ 一、基础语法规范 ================================================================================ 1. 变量声明 - 只能使用 let 和 const,不能使用 var - 变量声明必须有显式类型或初始化值 - 不支持 undefined 类型,变量未赋值就是 null - 不支持 undefined 关键字,判断是否存在要用 != null 2. 类型定义 - 只适合转 type,不适合使用 interface(interface 在 kotlin/swift 中另有不同) - 不支持 Intersection Type(交叉类型) - 不支持 Index Signature(索引签名) - 类型推断严格,必要时用 as Type 明确类型 - 不支持内联对象类型(Object Literal Type),需要单独定义 type 3. 函数定义 - 函数必须在使用前定义(不支持函数提升) - 在 setup 模式下,调用的函数必须在调用之前定义 - 依赖关系需要明确:被调用的函数必须先定义 - 这与 JavaScript 的函数提升行为不同,UTS 更接近 C/Java 的编译方式 4. 循环 - for 循环的 i 必须写明类型:let i: Int = 0 - 不要用 forEach、map,数组遍历用 for 循环 - 嵌套的数组方法调用可能导致类型推断失败,应改用 for 循环 ================================================================================ 二、类型与对象访问 ================================================================================ 1. any 类型访问 - 不能直接访问 any 类型对象的属性 - 需要将对象转换为 UTSJSONObject 类型后使用 getString()、getNumber() 等方法访问属性 - any 类型属性访问需转换为 Record 后用索引访问 - 使用索引访问属性时,推荐使用方括号语法 obj['property'] 而非点语法 obj.property - any 类型不支持索引访问 obj['key'],必须先转换为 UTSJSONObject 2. UTSJSONObject 使用 - 用 utils/utis 下的 UTSJSONObject 做类型转换 - 不要用 safeget,只要 UTSJSONObject 就好了 - 需要创建动态对象时,应使用 new UTSJSONObject() 然后调用 .set() 方法 - 对于 type 定义的对象类型,同样需要使用 UTSJSONObject - 使用 getString()、getNumber() 方法获取属性值 3. 数组类型 - 数组类型建议写成 Array,不要用 Type[] 简写 - 空数组需要明确指定类型,如 [] as string[] - 数组元素需要明确的类型定义才能在模板中正确访问属性 - 对于 any[] 或 reactive 数组,访问元素属性时需要先转换为 Record 或 any[] 4. 对象操作 - 不支持 Object.keys()、Object.values()、Object.entries() - 不支持 Record 对象字面量语法 - 对象字面量 {...} 只能用于构造类型(class),不能用于接口(interface) - reactive 对象在 UTS 中不支持索引器赋值操作 ================================================================================ 三、条件判断与逻辑运算 ================================================================================ 1. if 条件 - if 判断只接受 boolean 类型,不能是其他类型的值 - 判断空要用 !== null,不能用 !变量(uts android 不支持 !在变量前面的判断空方式) - 模板中的 || 运算符左边必须是 boolean 类型 - 可空类型使用可选链 ?. 和空值合并 ?? - 字符串判断空要用:variable != null && variable !== '' 2. 逻辑运算符 - || 表示逻辑或 - && 表示逻辑与 - ! 表示逻辑非(但 !变量 不支持用于判断空) - ?? 表示空值合并运算符(当左侧为 null 时返回右侧值) - ts 的为空则使用默认值的语法在 uts 中不能用 ||,要用 ?? 来代替 ================================================================================ 四、组件与模板 ================================================================================ 1. 表单与输入 - 表单优先用 form 组件 - 不支持 uni-easyinput,用 input 代替 - 时间选择用 uni_modules/lime-date-time-picker 2. 选择器 - uts android 不支持 picker,用 picker-view 或 uni.showActionSheet - 一维的优先用 uni.showActionSheet - picker-view 的事件用 UniPickerViewChangeEvent 3. 导航与布局 - 不支持 uni-nav-bar,先删除 - 不支持 uni-data-select,用 picker-view 代替 - 不支持 uni-datetime-picker,用 components/picker-date 或 components/picker-time 代替 - 不支持 uni-icons 4. 模板注意事项 - 跟 template 交互的变量尽量用一维变量(不要嵌套对象) - 模板中可空类型必须使用 ?. 安全访问 - 模板中访问可空类型属性前必须先判空 v-if="order != null" ================================================================================ 五、CSS 样式限制 ================================================================================ 1. 布局方式 - 只支持 display: flex - 不支持 display: grid - 不支持 gap - 不支持 table、grid、grid-template-columns 2. 单位与计算 - 不支持 calc() - 不支持的单位: vh - property value `100%` is not supported for min-height (supported values are: number|pixel) - property value `calc(33.33% - 10px)` is not supported for min-width 3. 选择器 - [APP-ANDROID] 不支持伪类选择器 - [APP-IOS] 不支持伪类选择器 - ERROR: Selector `.login-button[disabled]` is not supported. uvue only support classname selector 4. 其他样式 - WARNING: `backdrop-filter` is not a standard property name - style property `white-space` is only supported on `| ``` 3. Map 类型访问限制 - UTS Android 不支持 Map 类型的 get() 方法访问属性 - 应统一使用 UTSJSONObject - 示例: ```typescript // 错误 const m = item as Map const idVal = m.get('id') // 正确 const itemObj = item as UTSJSONObject const id = itemObj.getString('id') ?? '' ``` 4. 函数内取反操作符 - if (!isValid.value) 不支持取反 - 使用 if (isValid.value === false) - 示例: ```typescript // 错误 if (!isValid.value) return // 正确 if (isValid.value === false) return ``` ================================================================================ 二十一、2026-02-25 user 目录页面修复记录 ================================================================================ 1. change-password.uvue 修复 - 问题:!oldPassword.value 取反操作不支持 - 修复:改为 oldPassword.value == '' 显式判断 - 问题:const { error } = await ... 解构赋值不支持 - 修复:改为 const result = await ... 然后 result.error 访问 2. login.uvue 修复 - 问题:as unknown as number 双重类型转换不支持 - 修复:改为 as number 单一类型转换 - 问题:typeof err === 'object' 不支持 - 修复:使用 try-catch 包裹类型转换 3. forgot-password.uvue 修复 - 问题:!emailRegex.test(this.email) 取反操作不支持 - 修复:改为 emailRegex.test(this.email) == false - 问题:typeof err === 'object' 不支持 - 修复:使用 try-catch 包裹类型转换 4. register.uvue 修复 - 问题:!protocol.value 取反操作不支持 - 修复:改为 protocol.value == false - 问题:!validateEmail() 等取反操作不支持 - 修复:改为 validateEmail() == false ================================================================================ 二十二、常见修复模式速查 ================================================================================ 1. 取反操作修复模式 ```typescript // 错误 if (!variable) { ... } if (!isValid.value) { ... } if (!validate()) { ... } // 正确 - 根据类型选择 if (variable == null || variable == '') { ... } // 字符串判空 if (isValid.value == false) { ... } // 布尔值取反 if (validate() == false) { ... } // 函数返回布尔值取反 ``` 2. 解构赋值修复模式 ```typescript // 错误 const { data, error } = await someAsyncCall() // 正确 const result = await someAsyncCall() const data = result.data const error = result.error ``` 3. typeof 检查修复模式 ```typescript // 错误 if (typeof err === 'object') { ... } if (typeof xxx === 'function') { ... } // 正确 try { const e = err as Error // 使用 e } catch (e2) { // 处理转换失败 } ``` 4. as unknown as 修复模式 ```typescript // 错误 const timer = setInterval(...) as unknown as number // 正确 const timer = setInterval(...) as number ``` ================================================================================ 二十三、错误处理最佳实践 ================================================================================ 1. 统一错误处理模式 ```typescript try { const result = await someAsyncCall() if (result.error != null) { const errorMsg = (result.error as Error).message uni.showToast({ title: errorMsg, icon: 'none' }) return } // 处理成功结果 } catch (e) { console.error('操作失败:', e) uni.showToast({ title: '操作失败', icon: 'none' }) } ``` 2. 可空类型安全访问 ```typescript // 安全访问对象属性 const value = obj != null ? obj.property : null // 安全调用方法 const result = obj != null ? obj.method() : null ``` 3. 数组安全访问 ```typescript // 安全访问数组元素 if (arr.length > index) { const item = arr[index] // 使用 item } ``` ================================================================================ 文档结束 ================================================================================