最近因為項目要求,開始研究起iOS9推出的feature--App Search APIs。何為App Search?在iOS9之前,用戶通過spotlight只能搜索app的名字,或者蘋果自帶app的一些內容,比如搜索通訊錄、備忘錄中的內容。iOS9開始,用戶可以通過spotlight搜索網頁內容或者任何app內的數據。
1、search APIs主要包括三部分
1.1、NSUserActivity
NSUserActivity
在iOS8中就出現了,當時用于Handoff。
在iOS9中,我們可以把想要在spotlight中搜出來的內容放到NSUserActivity
中。userActivity
是UIResponser
的屬性,通常會在用戶訪問某一個頁面時,對UIViewController
的userActivity
屬性賦值。
NSUserActivity
可以用來對歷史訪問記錄。
1.2、Core Spotlight
通過該技術,用戶可以通過spotlight搜到app中曾經出現過或者現有的所有內容。
1.3、Web Markup
當你web頁面添加了標記語言,蘋果的爬蟲會根據用戶在spotlight的輸入,去抓取你網站的數據,如果有找到合適的結果,你的網站就可能會(蘋果有自己的權重計算方法)顯示在spotlight的結果列表中。這時候如果安裝了相對應的app并且支持deep link,用戶就可以打開對應的app內容頁面。
對于經常使用spotlight的用戶來說,這會很有助于提升app的曝光度。
蘋果官方推薦Web Markup
結合smart app banner
和universal links
使用。
這次花了很多時間在搞的這個東西,不難搞,但是需要web端和服務端配合。重要的是,你的web站點要支持https訪問,我們公司的還不支持,糾結再三之后,暫時放棄這個功能。
在本文會簡單記錄第一、二部分內容的實現。至于第三部分內容,雖然因為https不支持,無法成功實現,但是還是會在下文中做一個學習整理。
2、NSUserActivity
2.1、創建NSUSerActivity實例
在viewModel層中創建的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];
// 如果沒有顯示設置為yes,則不可搜索到
_serviceProjectUserActivity.eligibleForSearch = YES;
//
CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:CFBridgingRelease(kUTTypeContact)];
attributeSet.contentDescription = self.projectEntity.features ?: @"";
// ??????網絡路徑不可顯示
attributeSet.thumbnailURL = [NSURL URLWithString:self.projectEntity.backImgUrl ?: @""];
// 防止NSUserActivity和Core Spotlight可能重復索引,這里設置為nil
attributeSet.relatedUniqueIdentifier = nil;
_serviceProjectUserActivity.contentAttributeSet = attributeSet;
}
return _serviceProjectUserActivity;
}
2.2、賦值給UIViewController的userActivity屬性
在viewController層監測,如果頁面數據請求完成,給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中處理頁面跳轉
- (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) {
// 處理具體頁面跳轉
return YES;
}
return NO;
}
return NO;
}
3、Core Spotlight
3.1、創建要搜索的項,并將所有的項加入默認索引空間
- (void)indexAllDomesticCityForAppSearch
{
// 把國內一級城市從數據庫中拿出來
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];
// 創建對應的CSSearchableItem
CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:kUTTypeContent];
attributeSet.title = zoneName;
attributeSet.contentDescription = @"專業旅游";
// 這個屬性主要是將NSUserActivity與Core Spotlight indexed object進行一個關聯,防止出現重復的內容(如果出現重復內容,是因為開始的時候測試NSUserActivity的時候沒有設置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) {
// 處理具體頁面跳轉
return YES;
}
return NO;
}
return NO;
}