You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MyQRCode/docs/CONTACT_FEATURE_ENHANCEMENT...

317 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# VCard和MCard联系人功能增强
## 概述
为二维码详情界面添加了VCard和MCard类型的联系人功能包括添加通讯录、打电话、发短信等功能。
## 新增功能
### 1. 联系人管理器 (ContactManager)
**文件**: `MyQrCode/Utils/ContactManager.swift`
#### 主要功能:
- **添加联系人到通讯录**: 解析vCard/MeCard数据并添加到系统通讯录
- **打电话**: 直接拨打电话号码
- **发短信**: 打开短信应用并预填电话号码
- **联系人信息解析**: 支持vCard和MeCard格式的解析
#### 核心方法:
```swift
// 添加联系人
func addContactToAddressBook(vcardContent: String, completion: @escaping (Bool, String?) -> Void)
// 打电话
func makePhoneCall(phoneNumber: String, completion: @escaping (Bool, String?) -> Void)
// 发短信
func sendSMS(phoneNumber: String, completion: @escaping (Bool, String?) -> Void)
// 解析联系人信息
func parseContactInfo(from content: String) -> ContactInfo?
```
### 2. 联系人信息结构体
```swift
struct ContactInfo {
var name: String = ""
var phoneNumber: String = ""
var email: String = ""
var organization: String = ""
var title: String = ""
var address: String = ""
var displayName: String
var hasPhoneNumber: Bool
var hasEmail: Bool
}
```
### 3. 二维码详情界面增强
**文件**: `MyQrCode/Views/History/QRCodeDetailView.swift`
#### 新增按钮:
- **添加联系人按钮**: `person.badge.plus` 图标,蓝色主题
- **打电话按钮**: `phone` 图标,绿色主题(仅在有电话号码时显示)
- **发短信按钮**: `message` 图标,紫色主题(仅在有电话号码时显示)
#### 条件显示逻辑:
```swift
if parsedData.type == .vcard || parsedData.type == .mecard {
// 添加联系人按钮(始终显示)
// 打电话按钮(仅在有电话号码时显示)
// 发短信按钮(仅在有电话号码时显示)
}
```
### 4. 权限配置
**文件**: `MyQrCode/Info.plist`
添加了通讯录访问权限和URL schemes配置
```xml
<key>NSContactsUsageDescription</key>
<string>$(PRODUCT_NAME) needs access to contacts to add contact information</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.abe.example.demo.MyQrCode.phone</string>
<key>CFBundleURLSchemes</key>
<array>
<string>tel</string>
<string>sms</string>
</array>
</dict>
</array>
```
**本地化权限描述**:
为所有支持的语言添加了本地化的权限描述:
#### 中文 (zh-Hans.lproj/InfoPlist.strings)
```strings
"NSContactsUsageDescription" = "此应用需要访问通讯录以添加联系人信息";
```
#### 英文 (en.lproj/InfoPlist.strings)
```strings
"NSContactsUsageDescription" = "This app needs access to contacts to add contact information";
```
#### 泰语 (th.lproj/InfoPlist.strings)
```strings
"NSContactsUsageDescription" = "แอปนี้ต้องการเข้าถึงรายชื่อติดต่อเพื่อเพิ่มข้อมูลรายชื่อติดต่อ";
```
#### 日语 (ja.lproj/InfoPlist.strings)
```strings
"NSContactsUsageDescription" = "このアプリは連絡先情報を追加するために連絡先へのアクセスが必要です";
```
#### 韩语 (ko.lproj/InfoPlist.strings)
```strings
"NSContactsUsageDescription" = "이 앱은 연락처 정보를 추가하기 위해 연락처에 대한 액세스가 필요합니다";
```
#### 法语 (fr.lproj/InfoPlist.strings)
```strings
"NSContactsUsageDescription" = "Cette application a besoin d'accéder aux contacts pour ajouter des informations de contact";
```
#### 德语 (de.lproj/InfoPlist.strings)
```strings
"NSContactsUsageDescription" = "Diese App benötigt Zugriff auf Kontakte, um Kontaktinformationen hinzuzufügen";
```
#### 西班牙语 (es.lproj/InfoPlist.strings)
```strings
"NSContactsUsageDescription" = "Esta aplicación necesita acceso a los contactos para agregar información de contacto";
```
#### 意大利语 (it.lproj/InfoPlist.strings)
```strings
"NSContactsUsageDescription" = "Questa app ha bisogno di accedere ai contatti per aggiungere informazioni di contatto";
```
#### 葡萄牙语 (pt.lproj/InfoPlist.strings)
```strings
"NSContactsUsageDescription" = "Este aplicativo precisa acessar os contatos para adicionar informações de contato";
```
#### 俄语 (ru.lproj/InfoPlist.strings)
```strings
"NSContactsUsageDescription" = "Это приложение требует доступ к контактам для добавления контактной информации";
```
### 5. 本地化支持
#### 中文 (zh-Hans.lproj/Localizable.strings)
```strings
"contact_added_successfully" = "联系人已成功添加到通讯录";
"contact_add_failed" = "添加联系人失败";
"contact_permission_denied" = "需要通讯录权限才能添加联系人";
"contact_permission_limited" = "通讯录权限受限";
"contact_permission_unknown" = "通讯录权限状态未知";
"contact_parse_failed" = "解析联系人信息失败";
"phone_call_initiated" = "正在拨打电话...";
"phone_call_failed" = "拨打电话失败";
"phone_call_not_supported" = "设备不支持拨打电话";
"invalid_phone_number" = "无效的电话号码";
"sms_app_opened" = "已打开短信应用";
"sms_app_failed" = "打开短信应用失败";
"sms_app_not_supported" = "设备不支持短信功能";
"contact" = "联系人";
```
#### 英文 (en.lproj/Localizable.strings)
```strings
"contact_added_successfully" = "Contact added to address book successfully";
"contact_add_failed" = "Failed to add contact";
"contact_permission_denied" = "Contact permission required to add contact";
"contact_permission_limited" = "Contact permission limited";
"contact_permission_unknown" = "Contact permission status unknown";
"contact_parse_failed" = "Failed to parse contact information";
"phone_call_initiated" = "Initiating phone call...";
"phone_call_failed" = "Failed to make phone call";
"phone_call_not_supported" = "Device does not support phone calls";
"invalid_phone_number" = "Invalid phone number";
"sms_app_opened" = "SMS app opened";
"sms_app_failed" = "Failed to open SMS app";
"sms_app_not_supported" = "Device does not support SMS";
"contact" = "Contact";
```
#### 泰语 (th.lproj/Localizable.strings)
```strings
"contact_added_successfully" = "เพิ่มรายชื่อติดต่อในสมุดที่อยู่สำเร็จแล้ว";
"contact_add_failed" = "เพิ่มรายชื่อติดต่อล้มเหลว";
"contact_permission_denied" = "ต้องการสิทธิ์สมุดที่อยู่เพื่อเพิ่มรายชื่อติดต่อ";
"contact_permission_limited" = "สิทธิ์สมุดที่อยู่ถูกจำกัด";
"contact_permission_unknown" = "สถานะสิทธิ์สมุดที่อยู่ไม่ทราบ";
"contact_parse_failed" = "แยกวิเคราะห์ข้อมูลรายชื่อติดต่อล้มเหลว";
"phone_call_initiated" = "กำลังโทรออก...";
"phone_call_failed" = "โทรออกล้มเหลว";
"phone_call_not_supported" = "อุปกรณ์ไม่รองรับการโทรออก";
"invalid_phone_number" = "หมายเลขโทรศัพท์ไม่ถูกต้อง";
"sms_app_opened" = "เปิดแอป SMS แล้ว";
"sms_app_failed" = "เปิดแอป SMS ล้มเหลว";
"sms_app_not_supported" = "อุปกรณ์ไม่รองรับ SMS";
"contact" = "รายชื่อติดต่อ";
```
## 技术实现细节
### 1. 权限处理
- 使用 `CNContactStore.authorizationStatus(for: .contacts)` 检查权限状态
- 支持 `.authorized`, `.denied`, `.restricted`, `.notDetermined`, `.limited` 状态
- 自动请求权限并处理用户拒绝的情况
### 2. vCard/MeCard解析
- **vCard解析**: 支持vCard 2.1和3.0格式自动标准化为3.0版本
- **MeCard解析**: 解析MeCard格式的联系人信息
- 提取姓名、电话号码、邮箱、组织、职位、地址等信息
### 3. 联系人保存
- 使用 `CNContactVCardSerialization` 解析vCard数据
- 创建 `CNMutableContact` 对象
- 使用 `CNSaveRequest` 保存到系统通讯录
### 4. 电话和短信功能
- **打电话**: 使用 `tel://` URL scheme
- 自动清理电话号码格式(移除空格、括号等)
- 支持国际号码格式
- 使用系统电话应用拨打电话
- **发短信**: 使用 `sms://` URL scheme
- 自动清理电话号码格式
- 支持预填短信内容
- 使用系统短信应用发送短信
- **URL Schemes配置**: 在Info.plist中配置了tel和sms URL schemes
### 5. 错误处理
- 完善的错误处理和用户反馈
- 支持权限被拒绝、解析失败、保存失败等情况的处理
- 提供清晰的错误信息给用户
## 用户体验
### 1. 智能按钮显示
- 根据联系人信息智能显示相关按钮
- 只有在有电话号码时才显示打电话和发短信按钮
- 避免显示无用的功能按钮
### 2. 权限引导
- 首次使用时自动请求通讯录权限
- 权限被拒绝时提供清晰的提示信息
- 引导用户到系统设置中开启权限
### 3. 操作反馈
- 所有操作都有相应的成功/失败提示
- 使用本地化字符串提供多语言支持
- 操作结果通过Alert显示给用户
## 兼容性
- 支持iOS 15.6及以上版本
- 兼容vCard 2.1和3.0格式
- 支持MeCard格式
- 适配不同权限状态包括iOS 14+的有限权限)
## 测试建议
1. **权限测试**:
- 首次使用时的权限请求
- 权限被拒绝后的处理
- 权限被限制时的处理
2. **功能测试**:
- vCard格式的解析和保存
- MeCard格式的解析和保存
- 打电话功能
- 发短信功能
3. **错误处理测试**:
- 无效的vCard/MeCard数据
- 网络连接问题
- 系统通讯录访问失败
## 权限描述最佳实践
### 1. 本地化支持
- 为所有支持的语言提供本地化的权限描述
- 使用 `InfoPlist.strings` 文件进行权限描述的本地化
- 确保描述内容符合各语言的文化习惯
### 2. 描述内容要求
- **明确性**: 清楚说明为什么需要这个权限
- **具体性**: 解释权限的具体用途
- **用户友好**: 使用用户容易理解的语言
- **简洁性**: 避免冗长的描述
### 3. 技术实现
-`Info.plist` 中使用 `$(PRODUCT_NAME)` 变量
- 通过本地化文件提供各语言的权限描述
- 确保编译时正确引用本地化字符串
### 4. 合规性
- 符合 Apple 的隐私政策要求
- 遵循 App Store 审核指南
- 提供透明的权限使用说明
## 总结
这次功能增强为VCard和MCard类型的二维码提供了完整的联系人管理功能包括
- ✅ 添加联系人到通讯录
- ✅ 直接打电话
- ✅ 发送短信
- ✅ 完善的权限处理
- ✅ 多语言支持(包括权限描述)
- ✅ 智能UI显示
- ✅ 错误处理和用户反馈
- ✅ 符合隐私政策的最佳实践
所有功能都已经过编译测试,确保代码质量和稳定性。