Spotlight
Kuring 1.4.3 버전에 해당 기능을 도입했습니다.
현재 public 레포지토리로 kuring-v2를 작업하고 있어서, 해당 기능을 v1 레포에서 작업했습니다.
Kuring은 app과 sdk로 이루어져 있는데, 해당 기능은 app단 작업만으로도 가능했습니다.
목차
- 개발환경
- 작동화면
- kuring에 적용한 코드 설명
- 개발 이슈 정리사항
개발 환경
Xcode 15.0
iOS 16.0 +
SwiftUI
🎉 벌써 프로젝트가 2년이 넘었네요!! 118번째 PR
🌟 쿠링 새로운 기능 🌟
https://kuring.notion.site/kuring/iOS-eef51c986b7f4320b97424df3f4a5e3c
작동화면 GIF
Core Spotlight 중 Search 기능을 사용하기 위해서는 2가지로 나뉩니다.
- 1. 검색 가능하도록 등록
- 2. 검색한 아이템을 클릭해 들어왔을 때의 처리
# 1. 검색 가능하도록 등록
기존 쿠링 북마크 등록 로직을 활용했습니다.
- 북마크 액션이 들어오면 인덱싱 가능하도록 아이템 추가
// MARK: - Bookmark
private func updateSpotlight(notice: Notice) {
let attributeSet = CSSearchableItemAttributeSet(contentType: .text) // 1. ✅ 컨텐츠 타입은 텍스트로! (성능 향상? 추측)
attributeSet.displayName = notice.subject // 2. ✅ 검색 화면에 보여질 부분 - 공지 제목
if !notice.tags.isEmpty {
// 3. ✅ 컨텐츠 설명에 보여질 부분 - 태그를 해시태그처럼 분자열 재조합
attributeSet.contentDescription = "#" + notice.tags.joined(separator: " #")
}
// 4. ✅ 썸네일 이미지
attributeSet.thumbnailData = UIImage(systemName: "AppIcon")?.pngData()
// 5. ✅ 검색 가능한 아이템으로 변경
let searchableItem = CSSearchableItem(
uniqueIdentifier: notice.id, // 5-1. ✅ 나중에 검색할 때 사용하는 유니크 한 아이디 지정
domainIdentifier: Kuring.appleID, // 5-2. ✅ 도메인 아이디 즉, 그룹화 가능
attributeSet: attributeSet // 5-3. ✅ 위에서 지정해준 속성 넣어주기
)
// 6. ✅ 검색 가능한 아이템 인덱싱 하여 등록!
CSSearchableIndex.default().indexSearchableItems([searchableItem]) { error in
if let error = error {
Logger.debug("인덱싱 실패 \(error.localizedDescription)")
} else {
Logger.debug("인덱싱 성공 \(searchableItem)")
}
}
}
검색 가능하도록 등록했습니다.
searchItem이 여러개인 경우에는 아래와 같이 표현됩니다.
등록이 가능하면 당연히 삭제도 가능합니다.
func deleteSearchableItems(
withDomainIdentifiers domainIdentifiers: [String],
completionHandler: ((Error?) -> Void)? = nil
)
func deleteAllSearchableItems(completionHandler: ((Error?) -> Void)? = nil)
func deleteSearchableItems(
withIdentifiers identifiers: [String],
completionHandler: ((Error?) -> Void)? = nil
)
하지만 이번 로직에서는 삭제를 별도로 처리하지 않았습니다.
해당 인덱스 아이템을 삭제하지 않더라도 한번 인덱싱 된 부분에 수정이 일어나지 않는다면 만료기간이 30일이라 자동으로 정리됩니다.
# 2. 검색한 아이템을 클릭했을 때의 처리
struct KuringApp: App {
var body: some View {
...
}
.onContinueUserActivity(CSSearchableItemActionType, perform: onContinueUserActivity)
/// core spotlihgt search api
private func onContinueUserActivity(_ userActivity: NSUserActivity) {
// ✅ 1. search를 사용하므로 해당 타입의 액션인지 체크
if userActivity.activityType == CSSearchableItemActionType {
// ✅ 2. 아까 지정한 유니크 한 키 값을 가져오기
if let identifier = userActivity.userInfo?[CSSearchableItemActivityIdentifier] as? String {
// ✅ 3. 앱 서비스 로직
let notices = Kuring.noticeBookmark // 로컬 디비에서 북마크 노티스를 가져와서
.filter { $0.id == identifier } // 해당 아이디 값을 찾고
if let notice = notices.first {
newNotice = notice // 웹뷰를 열 수 있도록 처리
}
}
}
}
}
홈에서 아이템을 검색해서 들어오면 해당 로직을 타게 됩니다.
아까 지정했던 유니크한 아이디 값을 기반으로 해당 데이터를 찾아서 사용하게 됩니다.
# 개발 이슈 정리사항
- 검색 결과가 노출되지 않는 현상에 대한 고민
- CSSearchbleItem에 Notice struct를 Data로 변환해서 넣어주려는 시도
- 이건 결국은 id값을 준 다음 그걸 찾는 방식으로 해결했음. 열린 시각으로 바라보면 손쉽게 문제를 해결할 수 있는 더 나은 방법이 존재하니까 개발에 과몰입 할 때는 잠깐 쉬어주자!!
- 애플의 검색 결과가 매우 우수하다.
- 💡 유의어를 포함하여 검색이 가능한데, 애플의 알고리즘을 활용해 우리 검색부분에 이를 적용하면 매우 좋지 않을까?
(공식문서)
https://developer.apple.com/documentation/corespotlight
(참고)
https://betterprogramming.pub/implement-core-spotlight-in-a-swiftui-app-859cb703f55d
'project > Kuring(공지알림)' 카테고리의 다른 글
[CI] 로컬 빌드 성공 하지만, Github Action 빌드 실패하던 문제 (0) | 2024.10.08 |
---|---|
[iOS] 학과 검색 알고리즘 개선 (초성검색) (1) | 2024.03.06 |
[Kuring] 1.4.0 release 개발일지 (0) | 2023.06.19 |
[iOS] Debug Scheme 분리하기 (3) | 2023.02.03 |
iOS SPM No Such Module (0) | 2022.08.24 |