做跨平台客户端开发久了,你就会发现一个定律:越是不起眼的小功能,越容易在真机联调时给你来一下狠的。地址管理就是个典型。增删改查在需求文档里就占三行,但一旦落到代码里,你要面对的是数据边界、交互确认、多端行为差异和一堆真机上的诡异现象。这个项目标题里的三件事——删除地址时增加边界校验、确保至少保留一个地址、退出登录采用二次确认,每一件单拎出来都不复杂,但它们组合在一起时,恰恰是把一个"能用"的功能打磨成"好用"的关键。而当你把这些逻辑跑在 React Native 上,又要同时适配鸿蒙系统的时候,那才是真正考验功力的时候。这篇文章我就把这套需求的完整设计思路、代码实现和鸿蒙适配过程掰开揉碎讲一遍。
1. 需求背景与整体设计思路拆解
1.1 这个功能到底在解决什么问题
先说地址管理的场景。电商、外卖、物流这类应用,收货地址是交易闭环的地基。用户下单前必须选择或新增一个地址,如果地址列表被删空了,整个下单流程就会卡在"请先添加收货地址"这一步,非常影响转化率。更恶心的是,有些数据同步策略会在用户重新登录后把本地缓存拉取过来,如果本地删空了,下一次冷启动时用户看到的是一片空白,甚至会出现"地址存在却显示不出来"的脏数据。
所以在删除地址这条链路上做"至少保留一个"的校验,不是为了限制用户操作,而是保护数据完整性和后续业务可用性。这个校验是前置的,也就是在删除动作真正执行之前,先把数量边界卡住。如果用户只有一个地址,那就明确告诉他删不了,同时给他一个解释文案"至少需要保留一个收货地址"。用户体验上虽然多了一次阻挡,但总比让他删完所有地址、再去下单时发现没地址可选要体面得多。
这个思路本质上是"集合非空约束",在计算机科学里是很常见的状态不变量。比如银行卡列表至少要保留一张、团队成员至少要有一个管理员权限、服务器集群至少保留一台主节点,业务规则不同,但校验逻辑的骨架是一模一样的。把这一次的实现抽象出来,你会发现它适用于任何"删除操作不能把集合清空"的场景。
1.2 为什么"至少保留一个地址"必须放在删除链路里做前端校验
这时候会有同学问:这种边界校验不是后端也要做吗?前端做到底有没有必要?我的答案是,三层防线,一层都不能省。
第一层是前端交互层。用户点击删除按钮的瞬间,前端本地就能判断当前 list.length,如果只剩一条,直接拦截并提示。这一层响应最快,体验最好,不会让用户产生"按了删除却没反应"的困惑。
第二层是后端接口层。前端拦截只是第一道闸门,但接口本身必须也要做同样的校验。原因很简单:客户端的请求可能是被 Hack 的、可能是旧版本客户端发出的、也可能是并发请求导致的状态覆盖。后端如果只做"删除指定 id"这一个动作而不校验删除后列表是否为空,那么两条并发请求就可能同时删掉仅剩的两条地址,返回 200,数据库里一条都不剩。所以服务端必须保证删除后的数量 >= 1。
第三层是本地状态兜底层。删除接口调用成功后,前端还要把本地 store 里的地址同步掉。但网络请求返回失败怎么办?本地状态不能跟着乐观更新走,必须回滚。也就是说,删除接口失败的时候,列表里那条地址要原封不动留在原地,甚至要弹一个 Toast 告诉用户"网络异常,请重试"。这层兜底决定了状态一致性,做不好就会出现"列表里看着删了,刷新一下又回来了"的灵异事件。
顺便说一句,前端边界校验的具体阈值要根据真实数据来定。如果你做的是多端同步场景,地址列表在本地是有初始值的,那判断条件就应该是list.length <= 1,而不是list.length === 1。因为有极少数情况本地数据没拉全,临时显示 0 条或者 1 条,但此时如果把这条唯一的地址删掉,后端同步回来发现原来的地址还在但本地以为删了,就会出现状态分裂。
1.3 退出登录为什么必须二次确认
退出登录这个动作,我一直觉得是移动端交互设计里最容易被敷衍的一个环节。很多 App 直接在设置页给一个"退出登录"按钮,点了就退,连个确认都没有。但退出登录其实是彻底改变应用状态的破坏性操作,它涉及三件事:清除本地登录凭证、重置用户级数据缓存、跳转回登录页。一旦执行,用户想要恢复原状态,就得重新输入账号密码,有些还涉及多因子验证,成本很高。
如果用户是无意中触发了这个按钮,尤其是按钮位置在设置页底部、手势操作容易误触的场景下,没有二次确认的结果就是:用户莫名其妙被登出,然后带着一肚子火重新登录。而二次确认的意义恰恰在于给用户一个"紧急刹车"的机会。弹窗里面明确告诉他"退出后需要重新登录,是否继续?",用户如果只是误触,直接点取消就完事。
但这里有个容易走偏的设计倾向,就是给所有操作都套二次确认。像点赞、收藏这种高频低风险操作,你要是也加弹窗,用户会烦死。我的判断标准是看三个维度:不可逆性(退出的影响范围是否覆盖全 App)、状态影响深度(是否清数据、清缓存)、恢复成本(重新进入是否需要额外验证)。三者只要有一个显著偏高,就必须做二次确认。退出登录在这三个维度上都拉满了,所以它天然是二次确认的典型场景。
2. 核心交互设计:删除校验与二次确认的状态模型
2.1 地址数据模型与状态管理设计
先说数据层。跨端开发里,地址列表的状态一定不能直接散落在各个组件里的 useState 中,因为它会被多个页面共享,比如地址列表页、下单页、结算页都可能依赖它。项目里我用 Zustand 做全局状态管理,它足够轻量,在 React Native 和鸿蒙壳工程之间的桥接成本也很低。
地址对象本身我定义为AddressItem,字段包括 id、联系人姓名、电话、省市区、详细地址、经纬度、是否默认地址。这个模型在 RN、iOS、Android、鸿蒙四个端上都通用,不需要任何平台特有字段。
interface AddressItem { id: string; name: string; phone: string; province: string; city: string; district: string; detail: string; latitude?: number; longitude?: number; isDefault: boolean; } interface AddressStore { list: AddressItem[]; setList: (list: AddressItem[]) => void; removeAddress: (id: string) => Promise<boolean>; resetAddress: () => void; // 退出登录时清空 }状态管理的核心诉求有两个:一是保证多个页面读到的地址数据始终一致,二是在删除、编辑、新增操作后能同步通知所有订阅方刷新。用 Zustand 的话,任何组件调用useAddressStore()拿到的都是同一个响应式状态,某个页面删掉一条地址后,下单页会立刻感知到列表变化。
2.2 删除地址的完整校验流程
删除地址的校验流程我把它画成一个决策序列,每一步拦截掉一类非法操作。直白地说,就是一个"先拦数量、再确认意图、然后请求、最后同步"的四步走。
第一步,数量边界校验。进入删除方法后,立刻检查当前列表长度。如果不大于 1,直接提示用户,删除流程终止。这个提示文案我建议用"收货地址至少需要保留一个",而不是干巴巴的"无法删除"。人话版本是告诉用户为什么,而不是只说"不行"。
第二步,确认删除意图。即使通过了数量校验,也不能直接删。需要弹出一个确认框,文案类似"删除后不可恢复,确定要删除这条地址吗?",按钮用"取消"和"删除",其中删除按钮要走危险操作的红色样式(在 RN 里对应style: 'destructive')。这一步的意义在于:给误触一个撤销机会。
第三步,后端请求。确认后调用删除接口。这里要注意的一点是,如果用户在确认弹窗出现之后、点击"删除"按钮之前,他可能已经切换到别的页面,组件卸载了、页面 onBlur 了,但删除回调仍然会执行。所以删除请求必须绑定到 store 方法,而不是绑定到页面组件实例。
第四步,本地状态同步。接口返回成功后更新 list,失败则回滚并提示。回滚不是把删除的元素再塞回去,而是压根不要从本地 list 里过滤掉它。最稳妥的写法是:接口成功后再过滤,失败就保持原样并把错误信息展示给用户。
这里还有一个隐蔽的边界条件需要处理:如果要删除的地址是默认地址,而列表里还有其他地址,那删除后默认地址会悬空。我在实际项目里是这样处理的:删除默认地址前,弹窗文案额外追加一句"删除该默认地址后,系统将自动为你选择一条地址作为默认",后端返回删除成功后,前端立即把 list 中剩余的第一条地址设置为 isDefault = true。这样做用户体验是最顺滑的,否则用户删完默认地址后,下次下单时默认地址变成了一个不存在的 id,那是真正的灾难。
2.3 退出登录二次确认的交互落地
退出登录的交互模式,在 React Native 里最直接的做法是使用内置的Alert.alert弹出对话框。很多团队在这里会踩一个坑:把"退出登录"的确认按钮和取消按钮的顺序放反。按照移动端惯例,取消按钮应该放在左侧,危险操作按钮放在右侧,而且危险操作按钮的颜色必须区别于主按钮。在 RN 的 Alert 里,这个差异就是通过style: 'destructive'来实现的。
const confirmLogout = () => { Alert.alert('退出登录', '退出后需要重新输入账号密码登录,确定要继续退出吗?', [ { text: '取消', style: 'cancel' }, { text: '退出', style: 'destructive', onPress: doLogout }, ]); };另外,退出登录的 "onPress" 里不要做太多同步工作。实际的退出逻辑包括清理 token、清理地址缓存、重置全局状态、路由重置跳转登录页,这些任务的耗时可能在几十毫秒到几百毫秒之间。所以弹窗确认之后最好有一步 loading 过渡,避免用户看到屏幕停顿怀疑是不是 App 卡死了。
比较稳妥的做法是:确认退出后,先展示一个全屏 loading 或者对话框 loading,然后在异步任务全部执行完成后,再跳转登录页。路由重置用 navigation 的reset方法,不然用户按系统的返回键会回到登录前的页面,又看到残留的登录态页面,这在鸿蒙上尤其容易出问题,因为鸿蒙的返回手势默认会保留页面栈。
3. React Native + 鸿蒙端的关键代码实现
3.1 代码工程结构:RN 业务工程与鸿蒙壳工程
先说明一下当前 RN 跑鸿蒙的主流姿势。以我实际使用过的方案为例:业务侧保持 React Native 工程不变,用 TypeScript 写业务逻辑;鸿蒙侧用 DevEco Studio 建一个壳工程,通过社区的react-native-harmony或@react-native-oh/react-native包把 RN 实例嵌入到 ArkTS 的容器页面中。大概的工程结构是这样的:
HarmonyShell/ # DevEco Studio 鸿蒙壳工程 AppScope/ entry/ src/main/ets/ # ArkTS 层入口 pages/ RNPage.ets # 承载 RN 组件的容器 entryability/ EntryAbility.ets # 启动时初始化 RN 环境 oh-package.json5 rn-address-app/ # React Native 业务工程 src/ store/addressStore.ts pages/AddressList.tsx pages/Login.tsx index.js # RN 入口,注册业务组件 metro.config.js实际运行时,鸿蒙壳工程会加载 RN 打包出来的业务 bundle,然后通过运行时桥接把 React 组件渲染到原生页面上。业务层写一套 JS/TS 逻辑,通过 Platform API 区分平台差异,就能做到 Android、iOS、HarmonyOS 三端共享代码。但需要说明的是,鸿蒙的 RN 适配目前对新架构(Fabric)支持还不完整,我实测下来必须关闭新架构,使用旧架构才能稳定跑通。
3.2 删除地址边界校验核心代码
下面这段代码是从项目里抽出来的核心逻辑,Zustand 的 store 方法实现了"数量校验 + 意图确认 + 请求 + 本地同步"四步流程。
// store/addressStore.ts import { create } from 'zustand'; import type { AddressItem } from '../types/address'; import { request } from '../utils/request'; interface AddressStore { list: AddressItem[]; setList: (list: AddressItem[]) => void; removeAddressById: (id: string) => Promise<boolean>; resetAddress: () => void; } export const useAddressStore = create<AddressStore>((set, get) => ({ list: [], setList: (list) => set({ list }), // 删除方法的完整实现,注意它不是页面组件方法,而是全局 store 方法 removeAddressById: async (id) => { const { list } = get(); // 第一层:数量边界校验 if (list.length <= 1) { Alert.alert('无法删除', '收货地址至少需要保留一个,请先添加其他地址'); return false; } // 第二层:意图确认,这里不直接用 Alert 是因为它本身是 UI 逻辑 // 但是在 store 层直接调用 Alert 也没问题,RN 的 Alert 是全局单例 const confirmed = await new Promise<boolean>((resolve) => { Alert.alert('删除地址', '删除后不可恢复,确定要删除这条地址吗?', [ { text: '取消', style: 'cancel', onPress: () => resolve(false) }, { text: '删除', style: 'destructive', onPress: () => resolve(true), }, ]); }); if (!confirmed) return false; // 记录删除目标的默认地址状态,方便后面重设默认地址 const target = list.find((item) => item.id === id); if (!target) return false; // 第三层:后端请求。这里的 request 封装里做了超时处理, // 实测鸿蒙端网络超时时间设置比 Android 要短,建议单独调大。 try { await request.post('/api/address/delete', { id }); // 第四层:本地同步 set((state) => { const next = state.list.filter((item) => item.id !== id); // 如果删除的是默认地址,自动设置剩余第一条为默认 if (target.isDefault && next.length > 0) { next[0] = { ...next[0], isDefault: true }; } return { list: next }; }); return true; } catch (err) { // 回滚:什么都不改,让原列表保持原状,只提示错误 Alert.alert('删除失败', '网络异常,请稍后重试'); return false; } }, resetAddress: () => set({ list: [] }), }));这段代码里有个容易忽略的设计点:我把删除方法放在 store 层,意味着它可以在任何页面被调用,而不会因为页面卸载导致回调失效。同时请求失败以后 return false,调用方可以根据返回值决定是否更新依赖该地址的其他 UI 状态。比如下单页如果发现删除的是当前选中地址,就可以重新 pick 一条默认地址。
3.3 退出登录二次确认代码实现
退出登录我封装成了一个独立的封装函数,不只是调用 store 里一个清空方法。因为退出登录按标题要求是"二次确认"的交互模式,但确认之后的实际退出动作很可能还要清掉登录态 token、清掉本地缓存的地址数据、跳转登录页等等。
// utils/logout.ts import Alert from 'react-native'; import { useAddressStore } from '../store/addressStore'; import { authStorage } from '../utils/authStorage'; import { navigationRef } from '../navigation'; export const confirmLogout = () => { Alert.alert('退出登录', '退出后需要重新输入账号密码登录,确定要退出吗?', [ { text: '取消', style: 'cancel' }, { text: '退出', style: 'destructive', onPress: () => doLogout() }, ]); }; const doLogout = () => { // 第一步:清登录凭证。这里如果用 MMKV,要格外注意异步写入和同步读取的时机 authStorage.clear(); // 第二步:清全局用户级数据,包括地址列表、购物车、历史记录等 useAddressStore.getState().resetAddress(); // 第三步:重置路由栈,避免用户按返回键回到已退出页面 navigationRef.reset({ index: 0, routes: [{ name: 'Login' }], }); };这里的navigationRef是 React Navigation 的 NavigationContainer 反射引用,它在鸿蒙上的表现我实测比较稳定。需要注意一点:鸿蒙端如果用了@react-native-oh/react-native的适配,部分导航库的原生依赖可能没有完全跟随新架构适配,所以在鸿蒙上跑 React Navigation 时要留意依赖版本,尽量选混编入口纯 JS 的方案,而不是依赖原生 tab 容器的方案。
退出登录二次确认的替代交互是自定义一个半屏弹窗组件,这个好处是可以控制样式、圆角、遮罩层透明度,在一套视觉体系里保持和 Android/iOS 一致。需求里要求的是"二次确认的交互模式",用 RN 内置 Alert 已经满足了,但如果产品要求弹窗里还有"同步清除本地缓存"之类的说明文字,那建议直接上自定义 Dialog 组件。关键点是 Dialog 必须在最顶层渲染,并且要处理好返回键逻辑。
3.4 鸿蒙端的适配差异点
把同一套代码从 Android/iOS 迁移到鸿蒙上跑,最烦的不是业务逻辑,而是平台差异。我列几个在这次实践中遇到的要点。
Alert 的行为差异。在 Android 上Alert.alert默认最多支持三个按钮,取消按钮顺序可由开发者控制;鸿蒙上基于 ArkUI 实现的 Alert 框在按钮数量、按钮颜色表现上会有细微差异,个别版本中destructive按钮不会显示红色。真机测试时如果发现颜色不对,不要怀疑代码,这是适配层的问题。解决方式是封装一个自定义showConfirm方法,在鸿蒙平台直接渲染自定义 Dialog,在 Android/iOS 上走原生 Alert。
存储方案差异。地址列表和登录态的本地缓存,我一开始用的 react-native-mmkv,在鸿蒙上需要安装适配版本的包,并且初始化代码要显式调用MMKV.initialize()。如果初始化时序不对,App 冷启动时读缓存会拿到 null,导致地址列表闪烁一下再渲染出来。建议把存储初始化放进 App 入口最早的生命周期里执行,并在鸿蒙壳工程的EntryAbility里做并行初始化。
平台判断逻辑。能用Platform.OS === 'harmony'判断时,尽量把它收敛到一个独立的 platform.ts 文件里,而不是散落在各处。因为 RN 鸿蒙适配层的 Platform 字段在不同版本里可能返回'harmony'或'ohos',统一收敛后,需要改动时只改一个文件。
4. 实操过程与踩坑记录
4.1 RN 接入鸿蒙的工程搭建要点
如果你是从零开始接入,先确定好鸿蒙侧的 RN 容器工程需要用什么版本。当前社区里@react-native-oh/react-native是有配套脚手架的,比如@react-native-oh/cli,可以直接用来初始化鸿蒙壳工程和 RN 工程。初始化完成后,RN 业务工程负责打包 JS bundle,鸿蒙壳工程通过加载这个 bundle 把 JavaScript 渲染到 ArkUI 上。
工程搭建过程中最值得注意的问题有两个。第一是版本锁定。鸿蒙适配层对 RN 版本非常敏感,react-native 主版本号一旦不匹配,编译时会出现一堆未定义符号、找不到头文件的错误。我的建议是首次搭建时严格跟着插件 README 里示例的版本组合来锁定 package.json,不要擅自升级 RN 版本。第二是打包产物路径。鸿蒙壳工程加载 bundle 时,路径写错是最常见的启动失败原因。比如 debug 模式和 release 模式的 bundle 路径往往不同,Configure 里配置错误的话,App 启动后就是一个纯白屏,没有任何报错提示,排查起来特别费劲。
构建完成后,用 DevEco Studio 直接构建 hap 包,然后通过 hdc(鸿蒙的调试工具,类似 adb)安装到模拟器或真机执行。这一步不需要额外操作,只要在 DevEco 里配置好签名证书即可。
4.2 启动白屏问题排查
React Native 项目在鸿蒙上"启动白屏"是出现频率最高的运行时问题,热词里也经常有人搜。这里的白屏原因和 Android 上常见的原因不太一样,我分析下来大体是三类。
第一类是 bundle 加载超时或路径错误。鸿蒙壳工程在启动时如果迟迟拿不到业务 bundle,整个 RN 容器就一直停在透明状态,界面看起来就是白屏。排查方法是看系统日志,有没有出现Unable to load script之类的关键字,以及确认 bundle 文件有没有被正确打到 hap 包内并从正确的相对路径加载。
第二类是容器页和 RN 实例的生命周期衔接问题。鸿蒙侧容器页虽然已经创建,但 RN 环境还没有 ready,这时 JS 代码也没有被解释执行。出现这种情况我一般会建议先检查容器页有没有主动调用RNInstance.start()这类初始化方法,或者是否因为同步阻塞导致初始化代码迟迟没有执行。实践中发现,如果 ArkTS 层执行了耗时的同步 I/O 操作,RN 环境初始化会被拖到很晚,视觉上就是白屏时间格外长。
第三类是 JS 层首屏渲染被阻塞。React Native 进入鸿蒙后,如果首屏组件树非常重、依赖了过多同步操作或原生模块调用未就绪,JS 线程就会卡住。这个和 Android 的低端机白屏现象类似。解决方案是把首屏组件做轻量化处理,延迟渲染非关键区块,并确保所有原生模块调用都在componentDidMount之后进行。
总体来说,启动白屏最重要的排查原则是:先在 ArkTS 壳工程日志确认 RN 环境初始化状态,再进 JS 侧确认 bundle 是否加载成功,最后才怀疑业务代码性能问题。按这个顺序排查能省很多时间。
4.3 鸿蒙端网络请求错误与调试
这次实施过程中最诡异的一个问题是:同样的删除地址请求,Android 上跑通,鸿蒙上却报2300056错误。这个错误码并不是 RN 层报出来的,而是鸿蒙底层网络模块抛出的错误,常见情况是网络安全配置和 Android 不一样。
Android 的网络安全配置允许开发者在network_security_config.xml里灵活配置信任范围,而鸿蒙对网络安全更严格,尤其是 API 9 及以上版本对纯 HTTP 明文请求和自签名证书有默认限制。如果你的 App 在开发环境使用了 HTTP 或自签名证书,Android 正常但鸿蒙请求报错是很正常的。
排查手段是抓包。鸿蒙端抓包和 Android 差不多,但需要先完成证书安装步骤。用 Charles 这类工具时,要确保根证书已经安装到鸿蒙系统的"用户信任凭据"中,并且目标请求走的代理模式正确。另外,鸿蒙上 Android 常用的adb reverse或全局代理设置不完全适用,推荐直接走hdc端口转发,把鸿蒙设备的流量代理到本地开发机上的监听端口。
请求配好后,如果确认是证书问题,可以在鸿蒙的网络安全配置中临时信任开发证书,或者把请求切到 HTTPS 并配置正确的 CA。注意这只是开发调试时的临时手段,生产环境一定要用合规的证书链。
4.4 鸿蒙模拟器与真机调试技巧
热词里经常有人搜鸿蒙模拟器怎么用、无线调试怎么开,简单说一下实际操作。
鸿蒙模拟器资源占用比 Android 模拟器可观得多,启动一次可能要一两分钟,而且模拟器对 RN 桥接的性能表现和真机有区别。我一般是先跑模拟器做大部分业务功能自测,最后在真机焦点验证 Alert 样式、网络请求、导航栈这些和系统能力强相关的功能点,因为模拟器在渲染效果和原生能力模拟上不如真机准确。
无线调试的开启步骤是:在鸿蒙设备上打开"开发者选项"里的无线调试开关,记录设备 IP 和端口,然后用hdc tconn ip:port建立连接。连接成功后的用法和 USB 连接基本一致,hap 包安装、日志抓取都能在无线模式下完成。
真机调试还有一个建议:鸿蒙设备的系统日志输出比 Android 更零散,建议在 DevEco Studio 里直接用 HiLog 工具过滤进程,关键字用你自己的应用包名或者ReactNativeJS,能很快定位业务 JS 层的 console 日志。RN 层 console.log 在鸿蒙上的输出默认不一定走系统日志,需要在初始化代码里把 console 重定向到鸿蒙日志系统,否则你会发现在 DevEco 里根本看不到 JS 侧的日志输出。
5. 常见问题排查速查表
下面是一份按本次实践整理的排查速查表,覆盖了需求实现过程中大家容易卡壳的问题。
| 现象 | 可能原因 | 排查方向与解决方案 |
|---|---|---|
| App 启动白屏,无报错 | bundle 路径配置错误 | 检查鸿蒙壳工程加载 bundle 的相对路径及产物是否打入 hap 包 |
| App 启动白屏但系统日志有报错 | RN 版本与鸿蒙适配层不匹配 | 锁版本组合,参照社区插件的示例依赖锁定 package.json |
| 删除地址后列表没有更新 | 接口失败但本地没有回滚 | 检查删除请求返回码,删除成功后再过滤本地 list |
| 删除最后一个地址仍执行了删除 | 前端边界校验缺失 | 在调用删除接口前判断list.length <= 1,拦截并提示 |
| 删除默认地址后出现空默认值 | 未处理默认地址转移 | 删除后立刻设置剩余第一条为 isDefault |
| 退出登录后按返回键回到已退出页面 | 路由栈没有重置 | 使用 navigation reset 替代 navigation push |
| Alert 按钮顺序或样式和设计稿不一致 | 鸿蒙 Alert 适配层样式差异 | 统一封装自定义 Dialog 组件,跨平台保持一致 |
| 鸿蒙端请求报 2300056 | 网络安全配置/证书校验不通过 | 检查 HTTPS 配置、证书可信链,使用抓包工具复现 |
| 地址列表从本地缓存恢复时闪烁 | MMKV 初始化时序不正确 | 将 MMKV.initialize 提前到 App 生命周期最前 |
| React Native 包在鸿蒙上找不到原生模块 | 使用了新架构不支持的模块 | 切换到旧架构,或者使用适配鸿蒙的社区库版本 |
结束前一点个人经验
最后聊两句我在实际落地中的体会。边界校验这类功能,不要觉得"不就是加个 if 判断嘛"就掉以轻心。真正的坑永远在边界条件的组合上:只有一个地址、默认地址被删、并发删除、网络失败回滚、退出登录后缓存残留,每一个单点拿出来都简单,但合在一起就会咬人。写完代码之后,我强烈建议把地址列表的删除场景整理成一个测试用例清单,每个 case 都在三端上跑一遍,尤其是鸿蒙端,不然你永远不知道自己是在救火还是在挖坑。
二次确认的交互也要克制。它只应该出现在真正不可逆、影响范围大的操作上。退出登录算一个,删除地址算半个——删除地址本身也破坏性,但它能通过"至少保留一个"和"删除确认"两层缓冲控制住风险。交互设计不是做得越多越好,而是该挡住的时候挡得住、该放行的时候不拖泥带水。你在真机上把这两个逻辑跑顺了,这套方案就可以直接复用到其他相似需求上,比如清空缓存、解绑设备、注销账号,思路是通的。