最近因為項目要求,開始研究起iOS9推出的feature--App Search APIs。何為App Search?在iOS9之前,用戶通過spotlight只能搜索app的名字,或者蘋果自帶app的一些內(nèi)容,比如搜索通訊錄、備忘錄中的內(nèi)容。iOS9開始,用戶可以通過spotlight搜索網(wǎng)頁內(nèi)容或者任何app內(nèi)的數(shù)據(jù)。
1、search APIs主要包括三部分
1.1、NSUserActivity
NSUserActivity
在iOS8中就出現(xiàn)了,當(dāng)時用于Handoff。
在iOS9中,我們可以把想要在spotlight中搜出來的內(nèi)容放到NSUserActivity
中。userActivity
是UIResponser
的屬性,通常會在用戶訪問某一個頁面時,對UIViewController
的userActivity
屬性賦值。
NSUserActivity
可以用來對歷史訪問記錄。
1.2、Core Spotlight
通過該技術(shù),用戶可以通過spotlight搜到app中曾經(jīng)出現(xiàn)過或者現(xiàn)有的所有內(nèi)容。
1.3、Web Markup
當(dāng)你web頁面添加了標(biāo)記語言,蘋果的爬蟲會根據(jù)用戶在spotlight的輸入,去抓取你網(wǎng)站的數(shù)據(jù),如果有找到合適的結(jié)果,你的網(wǎng)站就可能會(蘋果有自己的權(quán)重計算方法)顯示在spotlight的結(jié)果列表中。這時候如果安裝了相對應(yīng)的app并且支持deep link,用戶就可以打開對應(yīng)的app內(nèi)容頁面。
對于經(jīng)常使用spotlight的用戶來說,這會很有助于提升app的曝光度。
蘋果官方推薦Web Markup
結(jié)合smart app banner
和universal links
使用。
這次花了很多時間在搞的這個東西,不難搞,但是需要web端和服務(wù)端配合。重要的是,你的web站點要支持https訪問,我們公司的還不支持,糾結(jié)再三之后,暫時放棄這個功能。
在本文會簡單記錄第一、二部分內(nèi)容的實現(xiàn)。至于第三部分內(nèi)容,雖然因為https不支持,無法成功實現(xiàn),但是還是會在下文中做一個學(xué)習(xí)整理。
2、NSUserActivity
2.1、創(chuàng)建NSUSerActivity實例
在viewModel層中創(chuàng)建的NSUSerActivity
實例
- (NSUserActivity *)serviceProjectUserActivity
{
if (!_serviceProjectUserActivity) {
_serviceProjectUserActivity = [[NSUserActivity alloc] initWithActivityType:@"com.xxxx.appIdentifier.serviceProject"];
_serviceProjectUserActivity.title = self.projectEntity.projectTitle ?: @"";
_serviceProjectUserActivity.userInfo = @{@"id" : self.projectEntity.projectId ?: @""};
_serviceProjectUserActivity.keywords = [NSSet setWithObjects:self.projectEntity.destination ?: @"", nil];
// 好像并沒有什么卵用,不知道哪里用錯了
_serviceProjectUserActivity.expirationDate = [NSDate dateWithTimeIntervalSinceNow:60 * 60 * 24 *31];
// 如果沒有顯示設(shè)置為yes,則不可搜索到
_serviceProjectUserActivity.eligibleForSearch = YES;
//
CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:CFBridgingRelease(kUTTypeContact)];
attributeSet.contentDescription = self.projectEntity.features ?: @"";
// ??????網(wǎng)絡(luò)路徑不可顯示
attributeSet.thumbnailURL = [NSURL URLWithString:self.projectEntity.backImgUrl ?: @""];
// 防止NSUserActivity和Core Spotlight可能重復(fù)索引,這里設(shè)置為nil
attributeSet.relatedUniqueIdentifier = nil;
_serviceProjectUserActivity.contentAttributeSet = attributeSet;
}
return _serviceProjectUserActivity;
}
2.2、賦值給UIViewController的userActivity屬性
在viewController層監(jiān)測,如果頁面數(shù)據(jù)請求完成,給userActivity
屬性賦值
__weak typeof(self)weakSelf = self;
[RACObserve(self.viewModel, projectEntity) subscribeNext:^(id x) {
if (x) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.userActivity = strongSelf.viewModel.serviceProjectUserActivity;
}
}];
2.3、在Appdelegate中處理頁面跳轉(zhuǎn)
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
{
if ([userActivity.activityType isEqualToString:@"com.xxxx.appIdentifier.serviceProject"]) {
NSString *projectID = userActivity.userInfo[@"id"];
if (projectID.length > 0) {
// 處理具體頁面跳轉(zhuǎn)
return YES;
}
return NO;
}
return NO;
}
3、Core Spotlight
3.1、創(chuàng)建要搜索的項,并將所有的項加入默認(rèn)索引空間
- (void)indexAllDomesticCityForAppSearch
{
// 把國內(nèi)一級城市從數(shù)據(jù)庫中拿出來
NSString *sql = [NSString stringWithFormat:@"select cn, zone_id from %@ where rank == '1' and zone_id <= 900000", self.tableName];
[self loadDestinationWithSQL:sql andResultSetHandler:^(FMResultSet *result) {
NSMutableArray *searchableItems = [[NSMutableArray alloc] init];
while ([result next]) {
NSString *zoneName = [result stringForColumnIndex:0];
NSString *zoneID = [result stringForColumnIndex:1];
// 創(chuàng)建對應(yīng)的CSSearchableItem
CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:kUTTypeContent];
attributeSet.title = zoneName;
attributeSet.contentDescription = @"專業(yè)旅游";
// 這個屬性主要是將NSUserActivity與Core Spotlight indexed object進(jìn)行一個關(guān)聯(lián),防止出現(xiàn)重復(fù)的內(nèi)容(如果出現(xiàn)重復(fù)內(nèi)容,是因為開始的時候測試NSUserActivity的時候沒有設(shè)置id,還原一下模擬器就好了)
attributeSet.relatedUniqueIdentifier = zoneID;
CSSearchableItem *item = [[CSSearchableItem alloc] initWithUniqueIdentifier:zoneID domainIdentifier:@"com.xxxx.appIndetifier.destinations" attributeSet:attributeSet];
[searchableItems addObject:item];
}
// 所有的items加入索引
CSSearchableIndex *defaultSearchableIndex = [CSSearchableIndex defaultSearchableIndex];
[defaultSearchableIndex indexSearchableItems:[searchableItems copy] completionHandler:^(NSError * _Nullable error) {
}];
}];
}
3.2、在Appdelegate中處理從spotlight打開app
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
{
if ([userActivity.activityType isEqualToString:@"com.xxxx.appIndetifier.destinations"]) {
NSString *zoneID = userActivity.userInfo[CSSearchableItemActivityIdentifier];
if (zoneID.length > 0) {
// 處理具體頁面跳轉(zhuǎn)
return YES;
}
return NO;
}
return NO;
}