20
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

and factoryAdvent Calendar 2019

Day 1

iOSのSpotlight検索で自分のアプリ内コンテンツを検索対象にする方法

Last updated at Posted at 2019-12-01

#Spotlight検索とは・・・?
ホーム画面で下にスワイプしたりすると出るあれです。

スクリーンショット 2019-11-30 14.14.00.png

入力欄にキーワードを入力すると、各アプリのコンテンツなどから、一致するものを探してもらえるので、横断的にアプリのコンテンツを検索できるので便利です。

今回は、このSpotlight検索に、自分のアプリのコンテンツを表示させる方法についての記事です。

TodayExtensionやリッチプッシュなどのように、追加で証明書などもいらず、簡単に実装できてアプリへの導線が増やせるので、やってみてはいかがでしょうか🤔

#実装方法

##1.準備
プロジェクトにMobileCoreServiceとCoreSpotlightのFrameworkを入れます。
スクリーンショット 2019-11-30 13.11.59.png

##2.保存処理を実装する

今回は、例として映画の情報である以下のMovie構造体をSpotlight検索に保存してみましょう。

Movie.swift
struct Movie {

    /// 映画固有の識別番号
    let id: Int = 0

    /// 名前
    let title: String = "スパイダーマン"

    /// あらすじ
    let summary: String = "平凡な少年、ピーター・パーカーは放射能汚染された蜘蛛に噛まれたことで、超人的な能力を得てしまう・・・"

    /// 画像
    let thumbnail: UIImage? = UIImage(named: "spider")

    /// 役者名の配列
    let actorNames: [String] = ["トビー・マグワイア", "キルスティン・ダンスト", "ジェームズ・フランコ"]
}
SpotlightManager.swift
import Foundation
import MobileCoreService
import CoreSpotlight

final class SpotlightManager {
    
    func save(_ movie: Movie) {
        let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeData as String)

        // ①タイトル
        attributeSet.title = movie.title

        // ②説明文
        attributeSet.contentDescription = movie.summary
        
        // ③画像
        attributeSet.thumbnailData = movie.thumbnail.pngData()
        
        // キーワード(表示されないが、タイトルや説明文に入ってない文言をここに入れておけば、検索した時に引っかかるようになる)
        attributeSet.keywords = movie.actorNames

        /* 
         uniqueIdentifierはAppDelegateで取り出すことができるので、
         Spotlight検索経由でアプリを開いた時のためのURLスキームを入れておく
        */
        let item = CSSearchableItem(
            uniqueIdentifier: "my-app://open/movie?id=\(movie.id)",          
            domainIdentifier: "my-app",
            attributeSet: attributeSet
        )
        CSSearchableIndex.default().indexSearchableItems([item], completionHandler: nil)
    }
}

実際の表示された際は以下の様になります。
スクリーンショット_2019-11-30_14_51_52.png

##3.起動時の処理を実装する

AppDelegate.swift
import CoreSpotlight

extension AppDelegate {

    func application(_ application: UIApplication,
                     continue userActivity: NSUserActivity,
                     restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> 
Bool {
        // Spotlightで開かれたかどうかをチェックする
        switch userActivity.activityType {
        case CSSearchableItemActionType:
            return self.openApplicationFromSpotlight(userActivity)
        default:
            return false
        }
    }

    private func openApplicationFromSpotlight(_ userActivity: NSUserActivity) -> Bool {
        // userActivityからURLスキームを取得する
        guard let urlScheme = userActivity.userInfo?[CSSearchableItemActivityIdentifier] as? String else {
            return false
        }
        
        // URLスキームを開いた時の処理を実装する
        return true
    }
}

##4.保存処理を作る

ViewController.swift

final class ViewController: UIViewController {
    
    let spotlightManager = SpotlightManager()
   
    private func show(_ movie: Movie) {
        self.spotlightManager.save(movie)
    }
}

##5.確認する
titledescriptionkeywordに設定した文字列を検索欄に入力すると表示されます。
スクリーンショット 2019-11-30 14.19.11.png

部分検索でもヒットします。
スクリーンショット 2019-11-30 14.20.05.png

以上で、ざっくりとした実装は以上です。

#おまけ

今回紹介した実装では、Spotlightに保存する画像をローカルのものを使用しましたが、URLで画像を取得して表示することも可能です。
例として画像キャッシュライブラリのNukeを使用した方法を記載しておきます。

SpotlightManager.swift
import Foundation
import MobileCoreService
import CoreSpotlight
import Nuke

func save(_ movie: Movie) {
    ImagePipeline.shared.loadImage(
        with: movie.thumbnailUrl,
        progress: nil) { response, _ in
            guard let thumbnail = response?.image else {
                return
            }
                
            let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeData as String)

            attributeSet.title = movie.title

            attributeSet.contentDescription = movie.summary
            
            attributeSet.thumbnailData = thumbnail.pngData()
            
            attributeSet.keywords = movie.actorNames

            let item = CSSearchableItem(
                uniqueIdentifier: "my-app://open/movie?id=\(movie.id)",          
                domainIdentifier: "my-app",
                attributeSet: attributeSet
            )
            CSSearchableIndex.default().indexSearchableItems([item], completionHandler: nil)    
    }
}
20
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?