打造独特应用:外观设计与隐私保护全攻略
1. 应用外观设计要点
应用的外观和感觉主要由品牌和设计语言构成。应用图标之后,启动屏幕是向用户介绍品牌的重要地方。应用首次启动可以包含引导页,向用户介绍应用,引导页应简洁且信息丰富。
字体有助于定义应用基于文本部分的外观和感觉,特别是自定义字体,应易于访问和阅读。设计语言应支持暗黑模式,并相应调整颜色,颜色集在为暗黑模式适配应用时很有用。在整个设计语言中要力求一致,避免用户产生脱节感,误以为进入了另一个应用。国际化和本地化能为应用增添国际范,Xcode 为项目提供了本地化资源包等工具,Foundation 也有帮助以特定区域格式表达值的 API。
2. 隐私的重要性
如今,iPhone 让手机不再只是打电话的工具,而是一个功能强大的口袋电脑。App Store 改变了开发者向用户交付应用体验的方式,但随着开发者可获取的新功能增多,隐私成为大家关注的焦点。关于谁拥有用户数据以及公司如何使用这些数据的讨论永无止境。
苹果非常重视用户隐私,认为用户应该有权决定是否与开发者分享数据。为此,苹果在 iOS 和 App Store 中构建了新功能,让开发者更加透明,让 iOS 更加注重隐私保护。
3. iOS 隐私功能
iOS 的许多隐私功能都侧重于让应用和开发者保持透明。例如,当应用使用相机时,屏幕右上角会显示一个绿色圆点,控制中心顶部也会显示最近使用相机的应用名称;当应用使用麦克风时,右上角会出现橙色圆点。
此外,iOS 还有其他隐私功能,如剪贴板提示,会显示应用正在从剪贴板粘贴文本的横幅,以及访问用户相册、联系人或位置数据的权限提示。
4. 隐私视图修饰符
SwiftUI 有一些视图修饰符可用于保护敏感数据。例如,锁屏可以在不解锁 iPhone 的情况下访问小组件,如果小组件显示敏感信息,这就存在潜在问题。苹果引入了
redacted(reason:)
和
privacySensitive(_:)
视图修饰符以及环境变量
redactionReasons
来解决这个问题。
以下是一个展示虚拟信用卡的代码示例:
struct CreditCardView: View {
var body: some View {
VStack(alignment: .leading, spacing: 82) {
VStack(alignment: .leading) {
HStack {
Text("Ray Bank")
.font(.title2)
Spacer()
Text("platinum")
.font(.caption2)
}
Text("Credit Card")
.font(.caption)
}
VStack(alignment: .leading) {
HStack(alignment: .bottom) {
Text("1234 5678 9123 456")
Spacer()
Image(systemName: "flag.square.fill")
.font(.title)
.imageScale(.large)
}
HStack {
Text("Exp: 02/20")
Text("Valid: 02/21")
Text("Security Code:")
Text("123")
}
.font(.caption2)
}
}
.padding()
.background(.green)
.foregroundColor(.white)
.mask(RoundedRectangle(cornerRadius: 8))
.padding()
}
}
信用卡包含卡号、安全码等敏感信息,如果在小组件中使用这个视图,这些信息可能会被他人看到。可以通过添加
privacySensitive(_:)
到敏感视图,并在顶层视图中使用
redacted(reason:)
来隐藏这些信息。
Text("1234 5678 9123 456")
.privacySensitive()
Text("Security Code:")
Text("123")
.privacySensitive()
struct WidgetView: View {
var body: some View {
CreditCardView()
.redacted(reason: .privacy)
}
}
还可以使用环境变量
redactionReasons
来改变隐藏视图的方式:
if redactionReasons == .privacy {
Text("Hidden card number")
} else {
Text("1234 5678 9123 456")
}
5. 位置与隐私
用户的位置是非常敏感的数据,可能会暴露用户的居住、行走或通勤地点。目前,“附近的动物”功能没有使用用户位置来查找附近的宠物,只是随机列出宠物,但该功能的初衷是找到与用户匹配且在附近的宠物。因此,需要请求用户授权访问其位置数据,以改进“附近的动物”功能。
6. 构建请求权限视图
要访问用户的位置,首先需要以合理的理由请求用户授权。可以在
AnimalsNearYou/views
中创建一个新的 SwiftUI 视图
RequestLocationView.swift
。
以下是具体操作步骤:
1. 添加属性:
@EnvironmentObject var locationManager: LocationManager
LocationManager
用于管理用户的位置,使用
@EnvironmentObject
是因为要在整个项目中使用同一个
LocationManager
实例。
2. 添加方法:
func startUpdatingLocation() {
locationManager.startUpdatingLocation()
}
startUpdatingLocation
方法用于开始跟踪用户的位置,当用户授予位置数据访问权限后,
LocationManager
会跟踪用户位置并调用
locationManager(_:didUpdateLocations:)
方法。
3. 导入框架:
import CoreLocationUI
iOS 15 引入的
CoreLocationUI
框架主要与
CoreLocation
配合使用,以标准、已知的方式请求访问用户的位置数据。
4. 替换
body
代码:
VStack {
// 1
Image("creature_dog-and-bone")
.resizable()
.frame(width: 240, height: 240)
// 2
Text("""
To find pets near you, first, you need to
share your current location.
""")
.multilineTextAlignment(.center)
// 3
LocationButton {
locationManager.startUpdatingLocation()
}
.symbolVariant(.fill)
.foregroundColor(.white)
.cornerRadius(8)
}
.padding()
.onAppear {
// 4
locationManager.updateAuthorizationStatus()
}
代码解释如下:
- 添加一张狗的图片作为占位符。
- 一段文本解释用户为什么需要分享当前位置。
- 一个按钮用于请求用户分享位置,点击按钮会调用
startUpdatingLocation
方法开始跟踪用户位置。
-
onAppear(perform:)
视图修饰符,在视图首次出现时更新授权状态。
最后,在预览代码中添加
.environmentObject(LocationManager())
以使 Xcode 预览正常工作。
7. 新的位置按钮
LocationButton
是一个新的 SwiftUI 按钮,在请求访问用户位置权限方面有一些改进。它不需要在
info.plist
中添加解释访问用户位置数据原因的文本,点击按钮时会有默认的文本和提示框,也不需要手动调用方法。此外,它还能在 iOS 应用之间创建一致的设计语言,同时允许自定义外观。
8. 位置状态类型
iOS 有五种位置授权状态:
| 状态 | 描述 |
| ---- | ---- |
| notDetermined | 当
CLLocationManager
还不知道用户是否授予或拒绝访问其位置数据时返回此状态。 |
| restricted | 这并不意味着用户拒绝授权,而是表示用户有活动的家长控制限制,用户无法更改授权状态,但家长可以在“设置”>“屏幕使用时间”>“内容与隐私限制”>“隐私”>“定位服务”中更改。 |
| denied | 明确表示用户拒绝了此应用访问其位置数据的授权。 |
| authorizedAlways | iOS 8 引入,与
authorizedWhenInUse
一起用于改善用户隐私,表示应用可以随时访问位置数据,即使用户没有使用应用。 |
| authorizedWhenInUse | 表示应用仅在用户使用应用时可以访问其位置数据。 |
使用
LocationButton
时,如果用户授予权限,应用会获得临时的
authorizedWhenInUse
权限,这对于需要一次性授权的功能很有用。
9. 更新“附近的动物”以请求授权
在
AnimalsNearYouView.swift
中添加:
@EnvironmentObject var locationManager: LocationManager
然后替换
NavigationView
内的代码:
// 1
if locationManager.locationIsDisabled {
RequestLocationView()
.navigationTitle("Animals near you")
} else {
// 2
AnimalListView(animals: animals) {
if !animals.isEmpty && viewModel.hasMoreAnimals {
HStack(alignment: .center) {
LoadingAnimation()
.frame(maxWidth: 125, minHeight: 125)
Text("Loading more animals...")
}
.task {
await viewModel.fetchMoreAnimals()
}
}
}
.task {
await viewModel.fetchAnimals()
}
.listStyle(.plain)
.navigationTitle("Animals near you")
.overlay {
if viewModel.isLoading && animals.isEmpty {
ProgressView("Finding Animals near you...")
}
}
}
代码解释如下:
- 使用
locationIsDisabled
检查是否有访问用户位置的权限,如果没有,则显示
RequestLocationView
请求授权。
- 如果有访问位置服务的权限,则像以前一样显示动物列表。
最后,在预览代码中添加
.environmentObject(LocationManager())
以使 Xcode 预览正常工作。
在
ContentView.swift
中添加:
@StateObject var locationManager = LocationManager()
并在标签视图末尾添加
.environmentObject(locationManager)
,将
locationManager
传递给视图环境。同时,更新预览代码以确保预览正常工作。
构建并运行应用,点击“当前位置”按钮,会弹出请求用户授权访问其位置的提示框。如果用户点击“稍后”,提示框会一直显示,直到用户点击“好”,点击“好”后会再次显示动物列表。
10. 在请求中发送位置数据
目前,应用已经请求了访问用户位置的授权,但还没有使用这些数据。需要将位置数据添加到获取动物的请求体中。
具体操作步骤如下:
1. 在
AnimalsNearYouViewModel.swift
中找到
AnimalsFetcher
内的代码:
func fetchAnimals(page: Int) async -> [Animal]
更新为:
func fetchAnimals(
page: Int,
latitude: Double?,
longitude: Double?
) async -> [Animal]
-
在
services/FetchAnimalsService.swift中更新fetchAnimals(page:)方法以符合AnimalsFetcher协议:
func fetchAnimals(
page: Int,
latitude: Double?,
longitude: Double?
) async -> [Animal] {
找到
latitude: nil,
和
longitude: nil
并替换为:
latitude: latitude,
longitude: longitude
这样
FetchAnimalsService
就可以接受纬度和经度作为请求参数。向 Pet Finder 的 API 发送纬度和经度会让它搜索并返回该位置 100 英里半径内的宠物。
-
在
AnimalsNearYouViewModel.swift中导入CoreLocation,并将fetchAnimals()方法更新为:
func fetchAnimals(location: CLLocation?) async {
然后替换
fetchAnimals(location:)
方法的内容:
isLoading = true
do {
// 1
let animals = await animalFetcher.fetchAnimals(
page: page,
latitude: location?.coordinate.latitude,
longitude: location?.coordinate.longitude
)
// 2
try await animalStore.save(animals: animals)
// 3
hasMoreAnimals = !animals.isEmpty
} catch {
// 4
print("Error fetching animals... \(error.localizedDescription)")
}
isLoading = false
这里的操作包括:
- 将用户的纬度和经度传递给获取动物的请求。
- 像以前一样存储响应中的动物数据。
- 如果响应中没有动物,则将
hasMoreAnimals
设置为
false
。
- 捕获并打印获取动物时可能出现的错误。
-
更新
fetchMoreAnimals方法以传递位置数据:
func fetchMoreAnimals(location: CLLocation?) async {
将
await fetchAnimals()
替换为:
await fetchAnimals(location: location)
-
在
AnimalsNearYouView.swift中更新代码以获取用户位置并传递给视图模型调用:
await viewModel.fetchMoreAnimals(location: locationManager.lastSeenLocation)
await viewModel.fetchAnimals(location: locationManager.lastSeenLocation)
视图模型使用位置管理器的
lastSeenLocation
来获取宠物。
最后,更新
AnimalsFetcherMock.swift
以符合
AnimalsFetcher
协议:
func fetchAnimals(
page: Int,
latitude: Double?,
longitude: Double?
) async -> [Animal] {
构建并运行应用,点击“当前位置”即可列出附近的宠物。不过,每次关闭并重新启动应用后,都需要再次点击“当前位置”。
打造独特应用:外观设计与隐私保护全攻略
11. 总结与展望
通过上述一系列操作,我们成功地对应用的外观设计进行了优化,同时加强了隐私保护措施。在外观设计方面,注重品牌和设计语言的统一,支持暗黑模式,使用合适的字体等,让应用更具吸引力和独特性。在隐私保护方面,借助 iOS 的隐私功能、SwiftUI 的视图修饰符,以及合理处理用户位置数据,确保用户的隐私得到充分保护。
然而,应用开发是一个不断迭代和完善的过程。未来,我们可以进一步探索以下方面:
-
持续优化外观设计
:随着用户审美和市场趋势的变化,不断调整应用的外观,引入新的设计元素和交互方式,提升用户体验。
-
加强隐私保护
:关注隐私法规的更新,及时调整应用的隐私策略。探索更多的隐私保护技术,如数据加密、匿名化处理等。
-
拓展功能
:除了利用用户位置数据查找附近的宠物,还可以考虑结合其他数据,如用户的偏好、历史记录等,为用户提供更个性化的服务。
12. 流程图总结
下面是一个 mermaid 格式的流程图,总结了请求用户位置权限并使用位置数据获取附近宠物的流程:
graph LR
A[启动应用] --> B{是否有位置权限?}
B -- 否 --> C[显示请求位置权限视图]
C --> D{用户是否授予权限?}
D -- 是 --> E[获取用户位置]
D -- 否 --> C
B -- 是 --> E
E --> F[使用位置数据请求附近宠物]
F --> G[显示附近宠物列表]
13. 代码优化建议
在实际开发中,我们可以对现有的代码进行一些优化,以提高代码的可读性和可维护性。例如:
-
封装重复代码
:将一些重复的代码封装成函数或类,减少代码冗余。
-
添加注释
:为关键代码添加详细的注释,方便其他开发者理解代码的功能和逻辑。
-
错误处理
:进一步完善错误处理机制,给用户更友好的错误提示。
以下是一个简单的封装示例,将获取动物的代码封装到一个单独的函数中:
func fetchAnimalsWithLocation(location: CLLocation?) async {
isLoading = true
do {
let animals = await animalFetcher.fetchAnimals(
page: page,
latitude: location?.coordinate.latitude,
longitude: location?.coordinate.longitude
)
try await animalStore.save(animals: animals)
hasMoreAnimals = !animals.isEmpty
} catch {
print("Error fetching animals... \(error.localizedDescription)")
}
isLoading = false
}
14. 常见问题解答
在开发过程中,可能会遇到一些常见问题,下面是一些解答:
| 问题 | 解答 |
| ---- | ---- |
|
LocationButton
点击后没有反应怎么办? | 检查
LocationManager
是否正确初始化,以及
startUpdatingLocation
方法是否正常工作。确保在
info.plist
中添加了必要的权限描述。 |
| 应用获取不到用户位置怎么办? | 检查用户是否授予了位置权限,以及设备的定位服务是否开启。还可以检查
LocationManager
的配置是否正确。 |
| 暗黑模式下颜色显示异常怎么办? | 检查颜色集的配置,确保在暗黑模式下使用了正确的颜色。可以通过调试工具查看颜色值。 |
15. 总结
通过本文的介绍,我们了解了应用外观设计和隐私保护的重要性,并掌握了一系列实现方法。从应用的外观设计要点,到 iOS 的隐私功能和 SwiftUI 的视图修饰符,再到处理用户位置数据的具体步骤,每一个环节都对提升应用的质量和用户体验至关重要。
在开发过程中,我们要始终将用户的需求和隐私放在首位,不断优化应用的功能和性能。同时,要关注技术的发展和市场的变化,及时调整开发策略,让应用在激烈的市场竞争中脱颖而出。
希望本文能为开发者们提供一些有价值的参考,帮助大家打造出更优秀的应用。
超级会员免费看

被折叠的 条评论
为什么被折叠?



