안녕하세요. Team Teheran Slippers의 모바일 개발자 Donutt 입니다. 오늘 소개해드릴 이야기는 요즘 모바일에 떠오르는 핫이슈! App Indexing에 관한 이야기입니다. 그 중에서도 오늘은 Apple이 WWDC15에서 발표한 iOS Search API에 대해서 이야기를 나눠볼까 합니다.

iOS Search API?

아이폰을 쓰시는 분들은 간혹 아이폰 화면을 밑으로 드래그해서 검색을 해보신적이 있으실겁니다. 이 기능을 Spotlight라고 합니다. iOS8 이하 버전에서 Spotlight에서 검색되는 데이터는 문자메시지, 메모, 연락처, 앱스토어 등의 아이폰 기본 어플리케이션에 저장된 정보만 검색이 되었죠.

<기존 iOS8까지의 spotlight>

이번 iOS9 에서 애플은 Spotlight에 서드파티 앱 개발사가 배포한 앱의 데이터를 검색하게 할 수 있을뿐 아니라 아이폰 내장 웹브라우저 'Safari'에서도 또한 앱 내부 데이터를 검색 할 수 있게 하였습니다. 심지어 앱이 설치가 안되어있더라도 앱에 대한 정보를 검색가능하도록 할 수 있죠. 게다가 놀라운 점은 여기서 검색된 컨텐츠를 통해 앱을 실행시켰을경우, 언제든지 검색화면으로 돌아 갈수 있다는 점입니다.

< iOS9 Beta4에서 팟캐스트 앱 내부가 검색되는 모습 >

< Spotlight을 통해 앱이 실행되는 모습 >

이 강력한 기능을 개발 할 수 있게 제공하는 API, iOS Search API입니다.

어떤 API 가 제공될까요?

Search API 는 크게 3가지로 제공이 됩니다.
(1)NSUserActivity, (2)CoreSpotlight Framework, (3)Web Markup 이 그 3가지입니다. (1)NSUserActivity는 iOS8에 발표된 Handoff기능에 spotlight용 속성이 확장된 Class 이고, (2)CoreSpotlight은 새롭게 제공되는 Spotlight전용 Framework, (3)Web Markup은 앱과 미러링된 웹데이터를 애플이 인덱싱 해갈수 있는 마크업 언어와 그 표준을 말합니다. 하나하나 살펴보시죠.

NSUserActivity ?

위에 간단하게 소개했듯이 NSUserActivity 는 iOS8에 발표한 Handoff 기능에 사용하는 Class 로 Foundation Framework에서 제공되는 Class입니다. iOS8에서 개발자는 NSUserActivity를 이용해 사용자의 State를 저장해놓고 기기간 이동해가며 작업을 계속 할 수 있게 프로그램을 설계할 수 있었습니다.
애플은 iOS9부터 NSUserActivity 가 저장해놓은 State를 Spotlight 에서도 검색하여 확인 할 수 있게 몇가지 Property를 추가했습니다.

eligibleForPublicIndexing Property (New in iOS 9.0)

eligibleForSearch Property (New in iOS 9.0)

expirationDate Property (New in iOS 9.0)

위와 같은 속성들이 확장된 속성의 일부인데요, eligibleForSearch 사용자의 iPhone안에서 Search가 되도록 ( on-device index ) 만들어 주며 Boolean value 입니다.
eligibleForPublicIndexing 은 모든 iPhone 사용자가 Search를 할 수 있도록 ( public device index ) 설정 할 수 있으며 Boolean value 입니다.
그리고 expirationDate 는 Spotlight에서 해당 날짜이후 검색되지 않도록 설정 할 수 있죠. 여기서 하나 더 짚고 넘어갈것은 public index 에 관한 것 입니다. 애플은 민감한 유저 개인 정보가 개발사에 의해 공개적으로 검색되지 않게하기 위해 zero-knowledge proof method를 사용한다고 합니다.

위의 사진과 같이 eligibleForPublicIndexing값이 true로 설정되어 있으면 UserActivity 정보는 apple cloud server로 one way hash암호화를 하여 전송됩니다. cloud server에서는 같은 hash값이 여러차례 들어와 일정 수치가 넘으면 그때 정보를 아이폰으로 요청하여 공개 데이터를 indexing하게 됩니다.
( 자세한 지원 속성들은 이쪽에서 확인해주세요 -> https://developer.apple.com/library/prerelease/ios/documentation/Foundation/Reference/NSUserActivity_Class)

// 예제코드
NSUserActivity *activity = [[NSUserActivity alloc]initWithActivityType:@"com.teheranslippers.narr"];  
activity.title = [self.detailItem objectForKey:@"title"];  
activity.keywords = [NSSet setWithArray:@[@"narr",@"cat"]];

activity.eligibleForSearch = YES;

[activity becomeCurrent];

위와 같이 indexing된 정보를 spotlight에서 클릭하면 UIApplicationDelegate Method인 application:continueUserActivity:restorationHandler: 이 호출됩니다. ( Handoff를 개발해보셨다면, 그 Delegate Method와 동일합니다. ㅎ )

- (BOOL) application:(nonnull UIApplication *)application
continueUserActivity:(nonnull NSUserActivity *)userActivity  
  restorationHandler:(nonnull void (^)(NSArray * __nullable))restorationHandler {

    if ([[userActivity activityType] isEqualToString:@"com.teheranslippers.narr"]) {

        // Launch Detail controller
        return YES;
    }
}

CoreSpotlight Framework !

CoreSpotlight Framework는 일종의 DB like Framework 로 정적인 앱 컨텐츠( 사진, 문서 등 )나 유저가 개인적으로 생성한 컨텐츠를 Indexing하기 위해 디자인된 api 입니다.

[self.objects enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        // Index될 Metadata를 생성
        CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc]initWithItemContentType:(NSString*)kUTTypeImage];
        NSString *title = [obj objectForKey:@"title"];
        [attributeSet setTitle:title];

        NSString *desc = [NSString stringWithFormat:@“%@’s image.",title];
        [attributeSet setContentDescription:desc];

        NSData *imgData= UIImagePNGRepresentation([obj valueForKey:@"thumbnail"]);
        [attributeSet setThumbnailData:imgData];

        // Index Item을 생성
        CSSearchableItem *item = [[CSSearchableItem alloc]
                                  initWithUniqueIdentifier:[NSString stringWithFormat:@"%lu",(unsigned long)idx] domainIdentifier:@"com.teheranslippers.narr" attributeSet:attributeSet];

        // 생성한 Item을 CS Device Index에 추가
        [[CSSearchableIndex defaultSearchableIndex] indexSearchableItems:@[item] completionHandler:^(NSError *error) {
            if (!error) {
                NSLog(@"Item Indexed %@ (with Spotlight Framework)",title);
            }
        }];
    }];

NSUserActivity와 마찬가지로 검색된 정보를 클릭했을때 앱에선 application:continueUserActivity:restorationHandler: 이 호출됩니다.

- (BOOL) application:(nonnull UIApplication *)application
continueUserActivity:(nonnull NSUserActivity *)userActivity  
  restorationHandler:(nonnull void (^)(NSArray * __nullable))restorationHandler {
    if ([[userActivity activityType] isEqualToString:CSSearchableItemActionType]) {
        NSString *uniqueIdentifier = [userActivity.userInfo objectForKey:CSSearchableItemActivityIdentifier];
        NSLog(@"%@",uniqueIdentifier);

        // Launch Detail controller
    }
    return YES;
}

나르는 제 고양이 입니다 ㅎ

CoreSpotlight 사용할 때 주의해야 할 점은, CoreSpotlight 으로 indexing된 컨텐츠는 on-device index이라는 겁니다. 즉, 개개인의 폰에서 사용하는 Spotlight에서만 검색 할 수 있게 만들어 줄 뿐, 모든 유저에게 검색되게 할 데이터는 NSUserActivity를 이용해야 합니다.
또한 앞서 설명드리지 않았지만 NSUserActivity 에서 Indexing 된 정보를 삭제하려면 CoreSpotlight Framework를 이용해야 하죠. 자세한 기능은 링크를 첨부하겠습니다. (죄송합니다..) (https://developer.apple.com/library/prerelease/ios/documentation/CoreSpotlight/Reference/CoreSpotlight_Framework )

Web Markup (웹 마크업)

웹 마크업을 사용하면 웹페이지로 제공하는 앱데이터를 애플에서 만든 웹크롤러인 Applebot이 크롤링합니다. ( applebot : https://support.apple.com/ko-kr/HT204683 ) 크롤링된 정보는 apple cloud 에 index되어 spotlight과 safari에서 검색이 되죠. 이는 NSUserActivity와 다르게 유저가 해당 웹페이지를 접근하지 않더라도 항상 public하게 검색이 됩니다. 웹마크업은 크게 2가지의 표준 마크업을 사용하면 되는데요, schema.org에 정의된 마크업의 일부와 오픈그래프에서 제공하는 마크업의 일부를 이용하면 된다고 합니다. ( 제공되는 스키마는 https://developer.apple.com/library/prerelease/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS9.html 이곳에서 확인하실수 있습니다.)

CoreSpotlight & NSUserAcitivity & Web Markup

앞서 설명한 세가지의 api가 제공하는 기능이 다르기 때문에 앱 개발사 입장에서는 세가지 모두 사용한다면 효율적으로 app indexing을 제공 할 수 있겠죠 ? 애플에서도 세가지 프레임워크를 모두 사용하는 앱일수록 spotlight과 safari에서 검색되는 랭킹이 올라간다고 설명하고 있습니다.

마치며

iOS9 에서 추가된 Search Api들을 살펴보았습니다.
Flurry의 조사결과에 따르면 사용자가 웹과 앱에 시간을 쓰는 비율이 14% vs 86%로 앱이 월등하게 앞선다고 합니다. 그만큼 앱에서 사용되는 컨텐츠와 정보는 늘어 갈 것 이고, 그렇기 때문에 앱플랫폼 개발사들도 앞다투어 deep link와 app indexing을 지원하고 있습니다. 검색엔진이 주 서비스인 구글은 그만큼 더 강력하게 app indexing을 지원하고 있겠죠. 다음 글에는 구글에서 지원하는 app indexing 에 관련하여 글을 써보도록 하겠습니다.

제가 부족하여 글의 내용은 잘 전달되게 썼는지, 내용은 틀린게 없는지 많은 검토후에도 잘 모르겠습니다. 혹여라도 이해가 안되시는 부분은 메일로 보내주시거나 답글을 달아주시면 부족하나마 최선을 다해 답해보도록 하겠습니다. 읽어주셔서 감사합니다.

Appendix

#### 필자는 Team Teheran Slippers의 개발자 최현수입니다. (donutt@udl.io)

쉬운 앱마케팅을 위한 무료 그로스해킹 툴, 에어브릿지

에어브릿지는 앱마케팅 캠페인의 실시간 성과 측정부터 유입경로까지 분석가능한 원스톱 앱마케팅 솔루션입니다. 모바일 앱마케팅 분석, 지금 바로 무료로 시작하세요!