当前位置: 首页 > article >正文

我把 iOS 存钱 App 移植到鸿蒙:number 精度丢失坑了我两天

做了个什么东西我有一个独立开发的存钱 App 叫「聚沙攒钱」iOS 版上线快两年了。核心功能就是设一个储蓄目标比如攒钱买耳机或者攒旅行基金每次存钱会有硬币掉落动画配合成就徽章和连续打卡让存钱这件事不那么无聊。去年陆续有用户问鸿蒙能不能用我看了看 HarmonyOS NEXT 的应用数量存钱工具类几乎是空白就动手做了。目前鸿蒙版已经上架华为应用市场应用 ID6758853486迭代到 1.9 版本。这篇文章主要聊从 Swift SwiftUI 到 ArkTS ArkUI 适配过程中的技术细节和踩坑记录。持久化方案从 Preferences 到 relationalStoreiOS 版我用 SwiftData 做持久化Goal 和 Transaction 是一对多关系Query配合FetchDescriptor查询很方便。到鸿蒙这边一开始我试了ohos.data.preferences想着 KV 存储足够轻量。结果当我造了 50 个 Goal、每个 Goal 挂 30 条 Transaction 的测试数据后读取一次全量数据要将近 800ms而且按状态筛选、按时间排序这种需求得全部读进内存再手动过滤写起来又丑又慢。果断切到了ohos.data.relationalStore建关系型表。核心建表逻辑大概是这样const SQL_CREATE_GOALS CREATE TABLE IF NOT EXISTS goals ( id TEXT PRIMARY KEY, name TEXT NOT NULL, icon TEXT DEFAULT S, mode TEXT CHECK(mode IN (wish,free)) DEFAULT wish, status TEXT CHECK(status IN (active,archived)) DEFAULT active, strategy TEXT DEFAULT weekly, target_amount INTEGER DEFAULT 0, current_amount INTEGER DEFAULT 0, plan_amount INTEGER DEFAULT 0, total_periods INTEGER DEFAULT 0, created_at INTEGER NOT NULL, next_due_date INTEGER ); 所有金额字段都是 INTEGER单位是分。这就引出了移植过程中最蠢的一个 bug。 ## number 精度丢失标题里说的两天就花在这儿 iOS 版里 targetAmount 用的 Int64整数运算没有精度问题。移植到 ArkTS 的时候我图省事直接用了 number 类型存元 arkts // 错误写法 —— 别学我 let currentAmount: number 1999.99 let deposit: number 0.01 currentAmount deposit // 期望 2000.00实际可能是 1999.9999999999998这个问题在小金额测试的时候完全看不出来。我是用稍大的数做集成测试时才发现进度条百分比算出来不对——比如目标 2000 元、已存 2000 元进度条显示 99.99%。排查过程说实话挺折腾的。一开始我怀疑是relationalStore的resultSet.getDouble()返回值有精度截断花了大半天在数据库读写层打日志确认存进去的数和读出来的数是一致的。然后又怀疑是 ArkUI 的Progress组件渲染有 bug用Text直接展示百分比值才发现——数据库里的数是对的但在 TS 层做多笔存款累加后值就漂了。经典的 IEEE 754 浮点问题说出来谁都懂但定位的时候真的很难第一时间想到因为 Swift 端从来没出过这个事。解决方案很朴素所有金额统一用分为单位存整数显示的时候除以 100 格式化。数据库 schema 里全部用INTEGERArkTS 层做一次(amount / 100).toFixed(2)。改完之后再也没出现过精度问题。成就徽章系统currentStreak 的计算iOS 版有一套我挺喜欢的成就系统。BadgeLibrary里定义了十几个徽章比如streak_7连续打卡 7 天、night_owl夜间存款 10 次、collector同时维护 5 个目标。每个徽章的解锁条件是一个闭包拿StatsSummary做判断。移植到 ArkTS 问题不大箭头函数替代闭包就行。真正麻烦的是StatsSummary的计算——iOS 端用 SwiftData 的查询能力配合内存计算很顺畅鸿蒙这边得自己写 SQL 查出原始数据再在 TypeScript 层做二次处理。其中最复杂的是currentStreak当前连续打卡天数。我的做法是用 SQL 按天去重查出所有有存款记录的日期然后在 TS 里从今天往回倒推SQL 部分用created_at / 86400000做整数除法实现按天去重比在 TS 层遍历所有记录再 groupBy 高效得多。这个 streak 值算好之后塞进StatsSummary徽章解锁判断就很直白了。每日提醒notificationManager 的平台差异iOS 用UNUserNotificationCenter注册本地通知流程大家都很熟。鸿蒙这边用ohos.notificationManager有几个关键差异权限申请。鸿蒙的通知权限默认是关闭的需要用notificationManager.requestEnableNotification()触发系统弹窗。但这个 API 在部分设备上行为不太一致——我在 Mate 60 上测试正常在某款平板上弹窗死活不出来。最后加了 try-catch如果requestEnableNotification抛异常或者超时就弹一个自定义对话框引导用户手动跳转系统设置页。不算优雅但至少不会卡死流程。通知渠道是必须的。iOS 可以直接发本地通知鸿蒙需要先创建 NotificationSlot不创建就静默失败连报错都不给你排查了一会儿才意识到。我的提醒设置默认是每天 20:15 推送。这个时间点是我自己用下来觉得合适的——太早还在上班太晚已经准备睡了。用户可以在设置里自定义reminderHour和reminderMinute。备份稳定性测试iOS 上线后出过一次备份导入失败的问题——某个用户的 Goal 日期字段为 nilJSON 序列化直接挂了。吃过这个亏鸿蒙版从一开始就写了稳定性测试脚本核心思路是模拟大量数据验证序列化完整性配置了 1200 个 Goal每个带 10 条 PlanItem 和 10 条 Transaction共 20 条子记录总共两万多条数据跑一遍序列化 / 反序列化。脚本里用了自定义的assert工具函数ArkTS 没有原生 assert API自己封装的条件不满足直接 throw Error检查两件事序列化后 JSON 长度不超过 8MB、反序列化后 Goal 数量一致。备份数据结构里有个BACKUP_SCHEMA_VERSION字段当前值是 1以后加字段可以通过版本号做迁移而不破坏旧备份。真实数据和商业化实话说鸿蒙版上线后数据很冷。最近一周下载量个位数付费为零。说一下付费模式跟 iOS 版一样是订阅制免费版可以创建 3 个储蓄目标Pro 订阅解锁无限目标、主题切换和成就徽章系统。订阅走的华为 IAP。我分析下载冷的原因ASO 还没认真做截图和关键词都很粗糙鸿蒙纯血应用的存量用户还在增长期工具类 App 的自然流量本来就不大。但我翻了华为应用市场存钱储蓄关键词下的搜索结果原生鸿蒙应用确实很少大部分还是安卓套壳。我觉得只要产品做到位后面增长应该能起来。没做的事硬币掉落动画得坦白一下。iOS 版有个用 SpriteKit 做的硬币物理掉落动画硬币之间会碰撞弹跳堆叠配合 Haptic Feedback 触感反馈存钱那一刻特别爽。鸿蒙版暂时没做。HarmonyOS 目前没有 SpriteKit 这种现成的 2D 物理引擎框架如果要做得用 Canvas 组件手写碰撞检测和物理模拟。我评估了一下大概要额外两三周效果还不一定好。先上线核心功能动画后面再补。有点可惜但我觉得这个取舍是对的。下一步近期计划适配鸿蒙桌面卡片Widget显示今日存钱进度、补上深色模式主题、用 Canvas 实现一版简化的硬币物理动画。Canvas 物理引擎这块我打算单独写一篇会包括碰撞检测算法、帧率控制和 ArkUI Canvas 的性能调优。如果方案跑通了碰撞检测模块会开源出来。对这个方向感兴趣的可以先关注下篇发出来第一时间能看到。另外如果你在鸿蒙上做过 Canvas 2D 物理模拟或者有好用的引擎方案推荐评论区聊聊——我真的需要。

相关文章:

我把 iOS 存钱 App 移植到鸿蒙:number 精度丢失坑了我两天

做了个什么东西 我有一个独立开发的存钱 App 叫「聚沙攒钱」,iOS 版上线快两年了。核心功能就是设一个储蓄目标,比如攒钱买耳机或者攒旅行基金,每次存钱会有硬币掉落动画,配合成就徽章和连续打卡,让存钱这件事不那么无…...

土耳其语同义词识别优化:混合相似度与反义词过滤

1. 项目背景与核心挑战在自然语言处理领域,同义词识别一直是词向量应用的基础任务。传统方法普遍依赖余弦相似度进行词向量比对,但这种做法在土耳其语等黏着语中面临独特挑战。去年我在参与一个多语言搜索引擎优化项目时,发现土耳其语的同义词…...

#pragma pack设置后,整个程序的字节对齐规则都会应用吗

#pragma pack 不会 让整个程序的所有代码都应用同一对齐规则。它的作用范围是 受当前编译单元中该指令出现位置之后所定义的结构体/联合体 影响,并且 不会跨翻译单元(.cpp 文件)传播。 具体作用范围 从指令出现的位置开始,到文件末…...

Spring Boot 2.7+国产中间件兼容性红皮书:适配东方通TongWeb、普元EOS、金蝶Apusic的8类典型异常诊断矩阵

更多请点击: https://intelliparadigm.com 第一章:Spring Boot 2.7国产中间件适配的背景与战略意义 随着信创产业加速落地,Java 生态在政务、金融、能源等关键领域对自主可控提出刚性要求。Spring Boot 2.7 是最后一个支持 Java 8 的长期维护…...

STM32 ADC采集声音信号避坑指南:LM386放大电路设计、分贝计算与OLED动态显示

STM32音频采集实战:从信号放大到动态显示的完整避坑指南 当我们需要用STM32测量环境声音强度时,看似简单的ADC采集背后隐藏着不少技术陷阱。本文将带你深入解决LM386放大电路设计、ADC采样策略、分贝值计算和OLED动态显示中的典型问题。 1. LM386放大电路…...

大模型安全防护:典型攻击方法与防御策略

1. 大模型安全防护面临的挑战大型语言模型在各类应用场景中展现出强大能力的同时,其安全性问题也日益凸显。作为从业者,我们在实际部署和使用过程中发现,即使是最先进的防护措施,也可能存在被特定攻击手段绕过的风险。这些攻击手法…...

ACE框架:大语言模型上下文优化的智能解决方案

1. ACE框架概述:重新定义大语言模型上下文适应在自然语言处理领域,大语言模型(LLM)的上下文窗口就像人类的工作记忆——容量有限却至关重要。传统方法往往通过粗暴地扩大窗口尺寸来提升性能,这就像试图用更大的水桶接雨…...

PixelPanda MCP Server:为AI助手集成图像处理能力的完整指南

1. 项目概述:一个为AI助手打造的图像处理工具箱最近在折腾AI编程助手的时候,发现了一个挺有意思的项目——PixelPanda MCP Server。简单来说,它就是一个专门为Claude Desktop、Cursor、VS Code这类支持MCP(Model Context Protocol…...

WeiClaw:基于配置的Web自动化与数据采集框架实战指南

1. 项目概述与核心价值最近在折腾一个挺有意思的开源项目,叫“kellyvv/WeiClaw”。乍一看这个名字,可能有点摸不着头脑,但如果你对自动化、数据采集或者RPA(机器人流程自动化)感兴趣,那这个项目绝对值得你花…...

第8篇:模板与实例——面向对象编程入门(上)python中文编程

作者: 中文编程倡导者—— 李金雨 联系方式: wbtm2718qq.com 系列: python中文编程入门教程 ** 核心理念: AI时代必须使用中文编程,母语编程阅读效率极高" 第8篇:模板与实例——面向对象编程入门&…...

构建去中心化个人AI智能体:基于OpenClaw与Morpheus的本地化实践

1. 项目概述:构建一个真正属于你的个人AI智能体在AI工具日益普及的今天,我们似乎已经习惯了这样一种模式:注册一个账户,绑定一张信用卡,然后按月为API调用付费。你的每一次对话、每一次请求,都在为某个中心…...

别再瞎猜了!我用JavaScript模拟了100万次双色球购买,告诉你‘守号’到底有没有用

用JavaScript模拟百万次双色球:守号策略的数学真相 每次路过彩票站,总能看到有人拿着小本本认真记录往期开奖号码。作为程序员,我更习惯用代码来验证这些民间"秘籍"的实际效果。今天我们就用JavaScript构建一个双色球模拟系统&…...

如何快速掌握Flowframes:面向新手的完整AI视频插帧指南

如何快速掌握Flowframes:面向新手的完整AI视频插帧指南 【免费下载链接】flowframes Flowframes Windows GUI for video interpolation using DAIN (NCNN) or RIFE (CUDA/NCNN) 项目地址: https://gitcode.com/gh_mirrors/fl/flowframes 想让你的视频素材从3…...

GetNote开源数据抓取工具:智能解析与自动化内容收集实践

1. 项目概述:一个为“GetNote”而生的开源数据抓取利器如果你是一名笔记应用的重度用户,或者正在为团队寻找一个高效的信息收集与整理方案,那么“GetNote”这个名字你可能不会陌生。它是一个功能强大的笔记应用,以其出色的跨平台同…...

工业USB技术:挑战、解决方案与应用实践

1. USB技术在工业环境中的挑战与机遇 USB(通用串行总线)技术自1996年问世以来,凭借其即插即用、热插拔和供电能力等优势,已成为消费电子领域最成功的连接标准之一。在办公和家用环境中,USB接口的便利性无可争议——单端…...

AI智能体开发框架agent-pack-n-go:开箱即用的快速构建与部署指南

1. 项目概述:一个开箱即用的智能体开发与部署框架最近在探索AI智能体(Agent)的落地应用时,发现了一个痛点:从构思一个智能体到真正把它跑起来,中间隔着“十万八千里”。你需要考虑框架选型、环境配置、工具…...

BTL框架:基于生物认知的GUI设计优化实践

1. 项目概述:当生物认知遇上GUI设计在图形用户界面(GUI)领域深耕多年后,我发现一个有趣现象:尽管硬件性能每年都在提升,但用户操作效率的瓶颈往往不在计算速度,而在于人机交互过程中的认知摩擦。…...

AI编程助手时代,代码面试正在被重写#CHI2026论文解读

当 Copilot 能用几秒钟生成一段完整函数,候选人展示专业能力的方式正在发生根本性转变。一项针对 16 名软件工程师的实地研究发现:在 AI 编程助手介入后,现场编程面试(Live Coding Interview)的评估逻辑正在被彻底改写…...

MIL-STD-1553B军用数据总线协议详解与应用实践

1. MIL-STD-1553B协议深度解析1.1 军用数据总线的技术演进在20世纪50-60年代,航空电子系统采用简单的独立模拟系统架构,各子系统通过点对点布线连接。这种架构导致飞机内部布线复杂,重量增加,后期系统集成困难。随着数字技术的兴起…...

AI科学插图生成:技术挑战与优化实践

1. 项目背景与核心挑战在学术研究和工程实践中,高质量的科学插图(Figure)是传达复杂概念、展示实验结果的关键载体。传统科学插图的制作通常依赖专业设计软件(如Adobe Illustrator)或编程工具(如Matplotlib…...

从零开始:在180nm工艺下搭建一个12位50MHz的流水线ADC(Pipelined-ADC)

从零构建180nm工艺12位50MHz流水线ADC的工程实践指南 在模拟集成电路设计中,流水线型模数转换器(Pipelined-ADC)因其出色的速度-精度平衡特性,成为中高速高精度应用的首选架构。本文将基于180nm CMOS工艺,从工程实现角度详细解析一个12位50MH…...

Claude Code:AI智能体如何重塑开发工作流,从命令行到智能协作

1. 从命令行到智能体:为什么Claude Code是开发者的下一个必备工具如果你和我一样,每天有超过一半的时间是在终端里度过的,那么你肯定理解那种在命令行、代码编辑器和浏览器之间不断切换带来的割裂感。传统的开发流程中,我们手动执…...

为什么你的浏览器视频下载总是失败?Video DownloadHelper伴侣应用来帮你

为什么你的浏览器视频下载总是失败?Video DownloadHelper伴侣应用来帮你 【免费下载链接】vdhcoapp Companion application for Video DownloadHelper browser add-on 项目地址: https://gitcode.com/gh_mirrors/vd/vdhcoapp Video DownloadHelper伴侣应用是…...

万亿参数模型Ring-1T:MoE架构与强化学习突破

1. 万亿参数模型Ring-1T的技术突破在人工智能领域,大型语言模型的发展已经进入了一个全新的阶段。最近,Inclusion AI团队发布了Ring-1T,这是首个开源的、拥有万亿参数规模的思维模型。这个突破性的成果不仅在模型规模上创造了新的记录&#x…...

EFLA注意力机制:优化挑战与训练策略解析

1. EFLA模型架构与优化挑战EFLA(Exponential Filtered Linear Attention)是一种新型的注意力机制架构,其核心创新点在于通过指数滤波机制来替代传统的线性注意力计算。这种设计在理论上消除了类似DeltaNet等基于欧拉离散化方法固有的数值误差…...

CAT6500电源管理芯片特性与应用解析

1. CAT6500双向电源选择开关核心特性解析CAT6500是ON Semiconductor推出的一款集成化电源路径管理芯片,专为解决多电源输入系统的复杂切换需求而设计。这款芯片在便携式设备电源管理领域具有显著优势,其核心特性主要体现在三个方面:1.1 低损耗…...

Podinfo:云原生微服务样板间,从部署到集成的完整实践指南

1. 项目概述:为什么我们需要一个“样板间”微服务?在云原生和微服务架构成为主流的今天,无论是初创团队还是大型企业,启动一个新服务时都面临一个共同问题:如何快速搭建一个符合生产环境标准的“样板间”?这…...

gptree:高效向AI助手提供项目上下文的命令行工具

1. 项目概述:为什么我们需要 gptree?如果你和我一样,日常开发中重度依赖像 ChatGPT、Claude、Cursor 这类 AI 编程助手,那你肯定遇到过这个痛点:如何高效地把整个项目的上下文喂给 AI?复制粘贴单个文件太零…...

NoFences:免费开源的Windows桌面分区神器,终极解决图标杂乱问题

NoFences:免费开源的Windows桌面分区神器,终极解决图标杂乱问题 【免费下载链接】NoFences 🚧 Open Source Stardock Fences alternative 项目地址: https://gitcode.com/gh_mirrors/no/NoFences 还在为Windows桌面上满屏的图标而烦恼…...

LLM命名风格对Grimdark叙事影响的实验研究

1. 项目背景与核心目标这个实验项目源于我在测试大型语言模型(LLM)时的一个有趣发现:当我们给模型输入相同提示词但使用不同名称时,模型的输出风格和内容会产生微妙变化。为了系统性地研究这种现象,我设计了一个名为"Grimdark Trilogy&q…...