背景
平时空闲时间,乱七八糟的想法比较多,有时候希望能够快速记录一下当时的想法,每次拿手机打字感觉挺麻烦的,就想有个录音软件,但是系统自带的录音软件不支持iCloud
同步,就感觉挺鸡肋的。然后就去Apple Store
搜了下,找到了一个合适的APP
,不过这玩意居然卖38 RMB
,难以理解。当初搞APP
开发的时候,我估计3天
就能撸一个现成的。巅峰时期,心流状态下,帮一个朋友做APP
估的一个月的工作量,国庆5
天就做完了。
现在虽然7-8
年没搞过APP
开发了,加上iOS
开发的技术栈都迭代几轮了。不过我觉得在AI
加持下写个录音App
应该So Easy
。还有生成图片的大模型,UI
设计我都不用去麻烦别人。
功能拆解
功能需求一句话总结:我就是要一个录音App
,能方便的在我的iPhone
和Apple Watch
上录音,能够进行iCloud
同步,能够分享给其他人。
UI/UX
最开始想法很简单,我跟AI
说下我要做个什么APP
有什么功能,AI
帮我把所有的UI
都生成好。网上搜了下,相关的产品还不少随便贴一个 15 AI tools every UI/UX designer must try 。
试了一圈下来,稍微靠谱的不是很多,试用下来完成度比较高的是 uizard,但是生成的交互图太丑,如下图:
经过不断地优化调试Prompt
,我最终放弃了AI
生成交互的这条路。主要感受:
- 图片生成速度太慢(算力),一张图片平均下来
5~8s
,这东西跟抽盲盒
,不可能一次就满意,不满意来回换太耗时。也不支持细节调整。 - 做为用户我也很难通过一段
Prompt
非常清楚的描述出自己要什么,我只能通过录音
、简约
这些抽象的词来告知AI
我大致的需求。理想态是,AI
能一下生成10
或者100
套来给用户选。 - 总体感受,
AI for UI
目前最多只是能做个辅助(说辅助估计UI&UX
设计师都觉得高看它了),要想把所有的UI&UX
工作交给AI
来做基本不可能。
图标
想着UI
这边比较复杂的功能AI
表现不行,那简单的logo
、按钮图片应该没啥问题吧。国内支持生成图片的大模型还挺多的了。比如 豆包、文心一言 都支持。不过 豆包、文心一言 生成的图片都有水印,所以直接被我Pass
了。
AI
图片生成的网站挺多的,随便找了一些试用了下,跟上面生成UI
一样,虽然能生成图片,但是跟自己想要的天差地别。也不支持生成的图片微调,总的来说要生成一个让自己的满意的图片挺难的。
再就是一个APP
里面的所有的按钮图标,风格需要保持一致,但是这个也不支持生成套图。所以最后只是把APP Logo
这个工作外包给了AI
,APP
内的各种图片图标还是用了苹果官方自带的一套图标库 SF Symbols ,虽然很简陋,但是整体风格也会跟统一一些。
贴下AI
生成的一些图片:
画UI
以前我做iOS
开发的时候主要是用的Objective-C
来开发,当初主要是MVC
的模式,我一般都是在Controller
里面写画UI
的代码。demo
如下:
@property (nonatomic,assign) int count;
@property (nonatomic,strong) UIButton *btn;
- (void)viewDidLoad
{
[super viewDidLoad];
_btn = [UIButton buttonWithType:UIButtonTypeCustom];
_btn.frame = CGRectMake(100,100,100,100);
[_btn setTitle:[NSString stringWithFormat:@"%d", _count] forState:UIControlStateNormal];
[_btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_btn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_btn];
}
- (void)btnClick
{
self.count += 1;
[_btn setTitle:[NSString stringWithFormat:@"%d", _count] forState:UIControlStateNormal];
}
还有一种用的StoreBoard
,可以通过通过拖拽控件的方式来画UI
效果如下:
不过这2019
年苹果推出了一个新的画UI
的技术:SwiftUI
,与早期的UIKit
(上面介绍的两种都是UIKite
模式)不同,SwiftUI
使用声明式语法,这使得构建复杂界面和动画更加直观和简洁。支持实时预览,修改代码所见即所得(实际上大部分时候UI刷新比较慢)。SwiftUI
非常适合于实现MVVM(Model-View-ViewModel)
设计模式。
struct ContentView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Count: \(count)")
.font(.largeTitle)
Button(action: {
count += 1
}) {
Text("Increase")
}
.padding()
}
}
}
这个例子展示了如何使用@State
管理状态,并将其绑定到视图上。当按钮被点击时,计数器增加,视图也会相应地更新。相比上面的UIKit
的方式会简单直接很多。变量count
跟文本控件绑定了,修改count
就等于修改了Text
上显示的内容,的确是方便了很多。
虽然我没有学习过Swift
也不知道SwiftUI
任何基本用法,在AI
的加持下我觉得还是用SwiftUI
来画个界面问题不大。实际上AI
给了我很大的惊喜,结合gpt4o
的多模态的能力,我看到其他APP
好的交互形式,我直接可以截图发送给UI
,让他们帮我生成SwiftUI
,大多时候它都能帮我正确的识别出截图中字体
、颜色
、控件
等等,大大的提升了我在画界面时候的开发效率。 感觉AI
在生成这种胶水代码方面真的是大有可为。
但是在一些复杂的交互场景,AI
局限性还是体现出来了,比如我要实现一个根据录音时候说话声音大小来展示的声波图
,调教了很久,AI
始终不能给我一个Work
的Demo
出来。所以这个功能我还是放弃使用AI
了,最后自己实现。
我需要实现的声波图
iCloud 云同步
iCloud
支持三种类型数据同步:
Key-Value Storage
,是iCloud
提供的一种简单存储机制,用于存储少量数据,如用户设置和偏好。每个键值对都会同步到用户的所有设备上。iCloud Documents
,iCloud Documents
是用于在用户的所有设备上存储和共享文档的服务。它允许应用程序存储用户生成的内容并在所有设备上保持同步。CloudKit
,CloudKit
是iCloud
提供的高级云存储服务,用于存储结构化数据。它可以处理更复杂的数据模型和大规模数据同步需求,是一种更强大的解决方案。(看是很高大上,其实我感觉没啥用,我要云存储,我自己起个Server
,存我自己DB
不就行了,为毛要存你iCloud
, 官方CloudKit
文档晦涩难度,API
使用麻烦的要命,强烈不推荐用这玩意)
要调试iCloud
这功能,居然还要开个苹果开发者资格才行(668RMB
),这一点苹果不厚道。
我跟AI
说了下,我要做iCloud
文件同步的能力,AI
很快就给我一个可以用的代码:
func saveFileToICloud() {
// 获取iCloud文档目录的URL
guard let iCloudURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents") else {
print("iCloud is not available")
return
}
// 创建文本文件内容
let fileName = "example.txt"
let fileContent = "Hello, iCloud!"
// 构建文件路径
let fileURL = iCloudURL.appendingPathComponent(fileName)
// 将内容写入文件
do {
try fileContent.write(to: fileURL, atomically: true, encoding: .utf8)
print("File saved to iCloud")
} catch {
print("Failed to save file: \(error.localizedDescription)")
}
}
代码看出,如果只要用iCloud
的文件同步能力,接口很简单,只用使用FileManager.default.url(forUbiquityContainerIdentifier: nil)
去拿文件路径就行了,把文件写到这个路径下,iOS
系统会去帮你做同步和状态管理,对于程序员来说,就跟读写本地文件一样。离线都可以正常读写,这点要夸下苹果,封装的好,RD
心智负担小。
上面这个文件虽然保存在iCloud
里面了,但是我还想在Mac
和iOS
上ICloud
文件管理里面能够看到这个文件夹。这么小的一个功能点,我跟AI
来来回回交流了10
几轮,都没搞定。最好还是自己Google
搜了下,然后根据搜到的一些关键字,再加上我具体的意图,AI
总于给了我一个可用的答案:
在项目的info.plist
里面添加上这些配置就好了。
<key>NSUbiquitousContainers</key>
<dict>
<key>iCloud.fanlv.fun.Melody</key>
<dict>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerName</key>
<string>Melody</string>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>Any</string>
</dict>
</dict>
这个了这个配置以后,在iCloud
里面App
存到iCloud
的文件夹就能显示出来了。
ShortCut && Siri
iOS的快捷指令(ShortCut
),是一个很强大的功能,能够通知指令调度编排串联iOS
上各种APP
的各种能力,老互联人玩过IFTTT
的应该都不陌生。
举几个例子,我可以实现一个截屏翻译
的ShortCut
,他可以给我一键截屏 -> OCR
识别图片文字 -> 然后帮我翻译 -> 显示翻译的结果。
更高级一点玩法,可以跟智能家居联动,比如我指纹开门以后,自动打开我房间的灯/空调。
有了ShortCut
,就可以通过Siri
来唤醒和调用ShortCut
对应的能力。这样的好处是,我能通过我iPhone
或者AppleWatch
的Siri
来调用ShortCut
。比如控制家里任何智能家居
或者执行各种复杂的APP
功能。
在这里我主要想实现一个简单功能:“通过Siri
唤醒APP
然后开始录音”,就这么简单一个功能,让我跟AI
从周六晚上6
点一直纠缠到了凌晨1
点(话说写代码/搬砖 还是很容易进入心流模式的)。
我跟AI
说我要在我的APP
识别我是不是已经添加过这个快捷指令了,添加了就显示已经添加,没有添加就显示点击按钮添加到Siri
:
AI
这厮一直跟我说苹果因为隐私原因没有提供查询所有快捷指令的API
,不行最后还是各种Google
搜关键字,然后结合别人给的一些接口,再去问AI
,期间因为各种细节问题调了半天,最后实现其实很简单,核心代码如下:
// 添加 Shortcut 指令核心代码:
let activity = NSUserActivity(activityType: "LaunchMelodyAppIntent")
activity.title = NSLocalizedString("oneKeyRecord", comment: "")
activity.userInfo = ["fan": "lv"]
activity.isEligibleForSearch = true
activity.isEligibleForPrediction = true
let shortCut = INShortcut(userActivity: activity)
// 判断是否添加过这个指令核心代码:
INVoiceShortcutCenter.shared.getAllVoiceShortcuts { (shortcuts, error) in
guard error == nil else {
return
}
if let shortcuts = shortcuts {
for voiceShortcut in shortcuts {
if let userActivity = voiceShortcut.shortcut.userActivity,
let userInfo = userActivity.userInfo,
let fan = userInfo["fan"] as? String {
if fan == "lv" {
isAlreadyAddToSiri = true
}
}
}
}
}
参考了下这个方案 iOS-自定义Intent及ShortCut,能通过快捷指令唤醒APP并跳转到指定页面
DynamicIsland(灵动岛)
灵动岛功能实现相对较简单,AI
基本说的跟苹果官网的 Displaying live data with Live Activities
这个差不多。
也没费太多力气,唯一一点需要注意的就是动态更新的话需要在宿主APP
里面写代码定时更新灵动岛的数据,实现如下:
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
for activity in Activity<MelodyActivityAttributes>.activities where activity.id == self.activityID {
Task {
await activity.update(using: MelodyActivityAttributes.ContentState(timerLabel:self.recordSecond.toSimpleRecordTimeString()))
}
}
}
具体实现效果如下:
Apple Watch App
Apple Watch App
功能基本是iOS App
的阉割版,大部分代码都可以复用,唯一要说的就是,要想ShortCut
能在Apple Watch
上运行,也要新建一个。
不过也要吐槽一下iOS
和Apple Watch
共享代码的实现方法太ugly
了,在把对应的源码文件所属的项目,勾选下WatchApp
,在WatchApp
工程里面就可以用了,完全没有模块
的概念。
总结
UI&UX
,目前想要AI
来生成交互图,这个跟抽盲盒一样,可用性极低,还任重道远。UI
代码生成,gpt4o
这一块能力有点惊艳到我,我想“借鉴“一些App
设计,给他一个截图,很快就能给我生成相关的UI
代码,可用性极高,基本贴过来,调整下细节就可以了。- 新功能调试,像
Shortcut
、灵动岛
这种新功能,由于我之前没有开发过的,所以问的问题可能比较抽象(比如我要一个 xx 功能),这可能会让你在一个死胡同里面,跟AI
花费大量时间来回拉扯,这个其实挺痛苦的。需要自己扩宽一下思路(Google
了解基本的实现方式),再输入具体信息再来问,你又会发现柳暗花明又一村。
总的来说,AI
已经全面改变我的学习、生活方式了。想想当初学习新的技术时候,有AI
的话一定可以事半功倍。还有当时搞什么技术讨论群,大家在群里为了一些技术问题争论的面红耳赤,有时候甚至会上升到人生攻击。现在有了AI
,可以大大的减少一些技术上毫无意义的争论。
随着算法和算力的不断优化和提升,相信AI
以后还能有更大的突破。不拥抱变化,就要被变化淘汰。