17、iOS开发:联系人展示、扩展功能与内容搜索

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)
}
  1. 创建 CNContactViewController 实例。将获取到的联系人实例传递给 forContact 初始化器。
  2. 设置控制器属性。
    • 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"]
    }
  }
]
  1. 导入框架并更新拦截器。在应用委托中导入 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")
  }
}
  1. 测试拦截器。重置模拟器并运行应用,将应用置于后台,打开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)
  }

}
  1. 测试共享链接。运行代码,打开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?
}
  1. 扩展序列类型。为 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
  }
}
  1. 构建索引项数组。
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

}()
  1. 实现索引方法。在 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
  1. 删除现有索引项。使用 CSSearchableIndex 类的 deleteAllSearchableItems(completionHandler:) 方法删除所有现有索引项:
// delete the existing indexed items
CSSearchableIndex.default()
  .deleteAllSearchableItems {err in
    if let err = err{
      print("Error in deleting \(err)")
    }
}
  1. 创建元数据对象。实例化 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)
}
  1. 创建可搜索项。创建 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)))
  1. 索引项。使用 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")

}
  1. 处理用户点击事件。在应用委托中实现 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应用开发提供了丰富的交互和搜索能力,能够提升用户体验。开发者可以根据具体的应用需求,选择合适的功能进行实现,并结合注意事项和技巧,确保功能的稳定和高效运行。在实际开发中,还可以进一步探索这些功能的组合使用,创造出更具特色的应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值