iOS开发:联系人展示、扩展功能与内容搜索
1. 展示联系人信息
在iOS开发中,若想使用内置系统UI展示现有联系人信息,可利用
CNContactViewController
类。传递给其初始化器的联系人参数是可选的。若传入
nil
,用户看到的“新建联系人”对话框将为空,需手动填写UI中的每个字段。
操作步骤如下:
1. 获取所需的联系人信息。使用自定义的
firstUnifiedContactMatching(name:toFetch:output:)
方法来获取联系人。
let toFetch = [CNContactViewController.descriptorForRequiredKeys()]
store.firstUnifiedContactMatching(name: "john", toFetch: toFetch){
guard let contact = $0 else{
print("No contact was found")
return
}
let controller = CNContactViewController(for: contact)
controller.contactStore = self.store
controller.allowsEditing = false
controller.displayedPropertyKeys =
[CNContactEmailAddressesKey, CNContactPostalAddressesKey]
self.navigationController?
.pushViewController(controller, animated: true)
}
-
创建
CNContactViewController实例。将获取到的联系人实例传递给forContact初始化器。 -
设置控制器属性。
-
contactStore:需将其设置为获取联系人的同一存储库。 -
allowsEditing:默认情况下,联系人控制器允许用户编辑联系人,可将此属性设置为false来禁用该功能。 -
displayedPropertyKeys:可指定要显示的联系人属性键,其他属性将被隐藏。
-
2. 创建Safari内容拦截器
若要创建一个内容拦截器,让用户可添加到Safari浏览器以阻止特定网页内容,可使用Safari内容拦截器扩展。
操作步骤如下:
1. 创建应用并添加扩展。创建一个简单的单视图控制器应用,然后添加新目标,选择“应用程序扩展”,再选择“内容拦截器扩展”。
2. 定义拦截规则。在新扩展的
blockerList.json
文件中定义内容拦截规则。例如,以下规则将阻止
edition.cnn.com
域名下的所有图像:
[
{
"action": {
"type": "block"
},
"trigger": {
"url-filter": ".*",
"resource-type" : ["image"],
"if-domain" : ["edition.cnn.com"]
}
}
]
-
导入框架并更新拦截器。在应用委托中导入
SafariServices框架,并在applicationDidBecomeActive方法中添加代码以自动更新内容拦截器:
func applicationDidBecomeActive(_ application: UIApplication) {
// TODO: replace this with your own content blocker's identifier
let id = "se.pixolity.Creating-Safari-Content-Blockers.Image-Blocker"
SFContentBlockerManager.reloadContentBlocker(withIdentifier: id) {error in
guard error == nil else {
// an error happened, handle it
print("Failed to reload the blocker")
return
}
print("Reloaded the blocker")
}
}
- 测试拦截器。重置模拟器并运行应用,将应用置于后台,打开Safari并访问相关网页,观察拦截效果。
3. 创建Safari共享链接
若想在用户设备的Safari共享链接中显示自己的链接,可添加新的共享链接扩展目标到现有应用并编写扩展代码。
操作步骤如下:
1. 创建扩展。创建一个单视图控制器项目,添加新目标,选择“应用程序扩展”,再选择“共享链接扩展”。
2. 添加图标。为应用包和共享链接扩展添加合适的图标。
3. 编写代码。在新创建的
RequestHandler.swift
文件中,对代码进行修改以显示共享链接:
import Foundation
class RequestHandler: NSObject, NSExtensionRequestHandling {
func beginRequest(with context: NSExtensionContext) {
let extensionItem = NSExtensionItem()
extensionItem.userInfo = [
"uniqueIdentifier": "uniqueIdentifierForSampleItem",
"urlString": "http://reddit.com/r/askreddit",
"date": Date()
]
extensionItem.attributedTitle = NSAttributedString(string: "Reddit")
extensionItem.attributedContentText = NSAttributedString(
string: "AskReddit, one of the best subreddits there is")
guard let img = Bundle.main.url(forResource: "ExtIcon",
withExtension: "png") else {
context.completeRequest(returningItems: nil, completionHandler: nil)
return
}
extensionItem.attachments = [NSItemProvider(contentsOf: img)!]
context.completeRequest(returningItems: [extensionItem],
completionHandler: nil)
}
}
- 测试共享链接。运行代码,打开Safari,导航到书签按钮,然后点击共享链接,查看链接是否显示。
4. 维护应用的索引内容
若想知道iOS何时即将删除索引项,并能够为搜索索引提供新内容,可添加Spotlight索引扩展到应用,并在扩展中更新索引。
操作步骤如下:
1. 创建扩展。创建Spotlight索引扩展,可自行命名。
2. 实现协议和结构。定义
Indexable
协议和
Indexed
结构:
protocol Indexable{
var id: String {get set}
var title: String {get set}
var description: String {get set}
var url: URL? {get set}
var thumbnail: UIImage? {get set}
}
struct Indexed : Indexable{
// Indexable conformance
var id: String
var title: String
var description: String
var url: URL?
var thumbnail: UIImage?
}
-
扩展序列类型。为
Sequence添加扩展方法allIds:
extension Sequence where Iterator.Element : Indexable{
func allIds() -> [String]{
var ids = [String]()
for (_, v) in self.enumerated(){
ids.append(v.id)
}
return ids
}
}
- 构建索引项数组。
lazy var indexedItems: [Indexed] = {
var items = [Indexed]()
for n in 1...10{
items.append(
Indexed(id: "id \(n)", title: "Item \(n)",
description: "Description \(n)", url: nil, thumbnail: nil))
}
return items
}()
-
实现索引方法。在
IndexRequestHandler类中实现searchableIndex方法:
override func searchableIndex(_ searchableIndex: CSSearchableIndex,
reindexAllSearchableItemsWithAcknowledgementHandler
acknowledgementHandler: @escaping () -> Void) {
for _ in indexedItems{
// TODO: you can index the item here.
}
// call this handler once you are done
acknowledgementHandler()
}
override func searchableIndex(_ searchableIndex: CSSearchableIndex,
reindexSearchableItemsWithIdentifiers identifiers: [String],
acknowledgementHandler: @escaping () -> Void) {
// get all the identifiers strings that we have
let ourIds = indexedItems.allIds()
// go through the items that we have and look for the given id
var n = 0
for i in identifiers{
if let index = ourIds.index(of: i){
let _ = indexedItems[index]
// TODO: reindex this item.
}
n += 1
}
acknowledgementHandler()
}
5. 使应用内容可搜索
若想让用户能够通过iOS的搜索功能在应用内容中进行搜索,可按以下步骤操作:
操作步骤如下:
1. 导入框架。导入
CoreSpotlight
和
MobileCoreServices
框架。
import CoreSpotlight
import MobileCoreServices
-
删除现有索引项。使用
CSSearchableIndex类的deleteAllSearchableItems(completionHandler:)方法删除所有现有索引项:
// delete the existing indexed items
CSSearchableIndex.default()
.deleteAllSearchableItems {err in
if let err = err{
print("Error in deleting \(err)")
}
}
-
创建元数据对象。实例化
CSSearchableItemAttributeSet对象,并设置其属性:
let attr = CSSearchableItemAttributeSet(
itemContentType: kUTTypeText as String)
attr.title = "My item"
attr.contentDescription = "My description"
attr.path = "http://reddit.com"
attr.contentURL = URL(string: attr.path!)!
attr.keywords = ["reddit", "subreddit", "today", "i", "learned"]
if let url = Bundle(for: type(of: self))
.url(forResource: "Icon", withExtension: "png"){
attr.thumbnailData = try? Data(contentsOf: url)
}
-
创建可搜索项。创建
CSSearchableItem实例,并设置其过期日期:
// searchable item
let item = CSSearchableItem(
uniqueIdentifier: attr.contentURL!.absoluteString,
domainIdentifier: nil, attributeSet: attr)
let cal = Calendar.current
// our content expires in 20 seconds
item.expirationDate = cal.date(from: cal
.dateComponents(in: cal.timeZone, from:
Date().addingTimeInterval(20)))
-
索引项。使用
CSSearchableIndex类的indexSearchableItems(_:)方法索引项:
// now index the item
CSSearchableIndex.default()
.indexSearchableItems([item]) {err in
guard err == nil else{
print("Error occurred \(err!)")
return
}
print("We successfully indexed the item. Will expire in 20 seconds")
}
-
处理用户点击事件。在应用委托中实现
application(_:continue:restorationHandler:)方法:
func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
guard userActivity.activityType == CSSearchableItemActionType,
let id = userActivity
.userInfo?[CSSearchableItemActivityIdentifier] as? String
else{
return false
}
// now we have access to id of the activity. and that is the URL
print(id)
return true
}
综上所述,通过上述方法和步骤,开发者可以在iOS应用中实现联系人展示、内容拦截、共享链接、索引维护和内容搜索等功能,为用户提供更丰富的交互体验。
iOS开发:联系人展示、扩展功能与内容搜索
6. 各项功能对比分析
为了更清晰地了解上述各项功能的特点和适用场景,下面通过表格进行对比分析:
| 功能 | 核心类 | 关键操作 | 适用场景 |
| ---- | ---- | ---- | ---- |
| 展示联系人信息 |
CNContactViewController
| 获取联系人、创建控制器实例、设置控制器属性 | 需要展示已有联系人信息,不想手动编写复杂UI |
| 创建Safari内容拦截器 |
Safari Content Blocker
扩展 | 定义拦截规则、更新拦截器 | 阻止特定网页的内容,如图片、链接等 |
| 创建Safari共享链接 |
Shared Links Extension
| 添加扩展、编写代码展示链接 | 在Safari共享链接中展示自己的链接 |
| 维护应用的索引内容 |
Spotlight Index Extension
| 创建扩展、实现索引方法 | 响应iOS对索引项的删除和更新需求 |
| 使应用内容可搜索 |
CSSearchableItemAttributeSet
、
CSSearchableItem
、
CSSearchableIndex
| 导入框架、删除旧索引、创建元数据和可搜索项、索引项、处理点击事件 | 让用户能在iOS搜索功能中搜索应用内内容 |
7. 功能实现流程图
下面是使应用内容可搜索功能的mermaid流程图:
graph LR
A[导入框架] --> B[删除现有索引项]
B --> C[创建元数据对象]
C --> D[创建可搜索项]
D --> E[索引项]
E --> F{索引是否成功}
F -- 是 --> G[等待用户点击]
F -- 否 --> H[处理错误]
G --> I[处理用户点击事件]
8. 注意事项与技巧
-
联系人展示
:
- 确保获取联系人时,包含所有必要的键,否则控制器可能无法正确显示联系人信息。
-
合理设置
allowsEditing和displayedPropertyKeys属性,以满足不同的展示和交互需求。
-
Safari内容拦截器
:
-
blockerList.json文件的规则编写要准确,可参考示例规则进行扩展。 - 每次修改拦截规则后,需要在模拟器的设置应用中重新开启拦截器,也可使用代码自动化该过程。
-
-
Safari共享链接
:
- 为应用和扩展添加合适的图标,提升用户体验。
-
在
RequestHandler.swift文件中,注意资源文件的路径和名称要正确。
-
维护应用的索引内容
:
-
定义
Indexable协议和Indexed结构时,根据实际需求调整属性。 -
在
IndexRequestHandler类的索引方法中,实现具体的索引逻辑。
-
定义
-
使应用内容可搜索
:
- 为可搜索项设置合理的过期日期,避免占用过多空间。
- 在处理用户点击事件时,准确获取和处理索引项的标识符。
9. 总结
通过对iOS开发中联系人展示、扩展功能与内容搜索等功能的详细介绍,我们了解了各个功能的实现步骤、关键类和注意事项。这些功能为iOS应用开发提供了丰富的交互和搜索能力,能够提升用户体验。开发者可以根据具体的应用需求,选择合适的功能进行实现,并结合注意事项和技巧,确保功能的稳定和高效运行。在实际开发中,还可以进一步探索这些功能的组合使用,创造出更具特色的应用。
超级会员免费看

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



