-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[TIMOB-23828] iOS 10: Expose the CSSearchQuery API #8276
Changes from 7 commits
976bbd4
7d0f43a
b4a0ffa
950d2e8
eb9bd6a
65ecd42
329c72d
3280538
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
--- | ||
name: Titanium.App.iOS.SearchQuery | ||
summary: | | ||
A search query object manages the criteria to apply when searching app content that you have previously | ||
indexed by using the Core Spotlight APIs. | ||
description: | | ||
You can use this API to search multiple <Titanium.App.iOS.SearchableItem> objects at the same time. You can do that | ||
by using the `queryString` parameter that has a special syntax to filter and index several items. Please refer | ||
to the official [Apple documentation](https://developer.apple.com/reference/corespotlight/cssearchquery) for detailed information on how to structure your search-query to get the | ||
best possible results. | ||
|
||
To use this feature make sure you have a compatible device running iOS 10 or later. | ||
|
||
To create a SearchableItem object, use the Titanium.App.iOS.createSearchableItem method. | ||
Pass a dictionary of properties to the method that will help identify the item. | ||
At minimum, you must set the [attributeSet](Titanium.App.iOS.SearchableItem.attributeSet) property, which associates | ||
the metadata with the SearchableItem object. | ||
extends: Titanium.Proxy | ||
platforms: [iphone,ipad] | ||
osver: {ios: {min: "10.0"}} | ||
since: "6.1.0" | ||
createable: true | ||
|
||
properties: | ||
- name: queryString | ||
summary: A formatted string that defines the matching criteria to apply to indexed items. | ||
description: This parameter cannot be null. | ||
type: String | ||
availability: creation | ||
osver: {ios: {min: "10.0"}} | ||
accessors: false | ||
|
||
- name: attributes | ||
summary: An array of strings that represent the attributes of indexed items. | ||
description: | | ||
Each string corresponds to a property name that can be set for an item. For a list of possible properties, see | ||
the <Titanium.App.iOS.SearchableItemAttributeSet> API. Passing null for this parameter means that the query does not use | ||
attributes to find matching items. | ||
type: Array<String> | ||
osver: {ios: {min: "10.0"}} | ||
accessors: false | ||
|
||
methods: | ||
- name: start | ||
summary: Asynchronously queries the index for items that match the query object's specifications. | ||
|
||
- name: cancel | ||
summary: Cancels a query operation. | ||
|
||
- name: isCancelled | ||
summary: A Boolean value that indicates if the query has been cancelled (`true`) or not (`false`). | ||
returns: | ||
type: Boolean | ||
summary: Returns `true` if the query was cancelled. | ||
|
||
events: | ||
- name: founditems | ||
summary: Fired when the query finds a new batch of matching items. | ||
properties: | ||
- name: items | ||
summary: An array of indexed items that match the specified query. | ||
type: Array<Titanium.App.iOS.SearchableItem> | ||
- name: foundItemsCount | ||
summary: The number of items that are currently fetched. | ||
type: Number | ||
|
||
- name: completed | ||
summary: | | ||
Fired when the query completes to inform you about it's success. | ||
To receive items, use the `founditems` event. | ||
properties: | ||
- name: success | ||
summary: Indicates if the operation succeeded. Returns true if download succeeded, false otherwise. | ||
type: Boolean | ||
- name: error | ||
summary: Error message, if any returned. Undefined otherwise. | ||
type: String | ||
|
||
examples: | ||
- title: Perform a simple search-query for all items at include a "Searchable" in it. | ||
example: | | ||
var win = Ti.UI.createWindow({ | ||
backgroundColor: "#fff" | ||
}); | ||
var btn = Ti.UI.createButton({ | ||
title: "Start search-query" | ||
}); | ||
|
||
var searchItems = []; | ||
var itemAttr = Ti.App.iOS.createSearchableItemAttributeSet({ | ||
itemContentType: Ti.App.iOS.UTTYPE_IMAGE, | ||
title: "Titanium Core Spotlight Tutorial" | ||
}); | ||
|
||
itemAttr.contentDescription = "Tech Example \nOn: " + String.formatDate(new Date(), "short"); | ||
itemAttr.keywords = ["Mobile", "Appcelerator", "Titanium"]; | ||
itemAttr.displayName = "Hello world"; | ||
|
||
var item = Ti.App.iOS.createSearchableItem({ | ||
uniqueIdentifier: "my-id", | ||
domainIdentifier: "com.mydomain", | ||
attributeSet: itemAttr | ||
}); | ||
searchItems.push(item); | ||
|
||
var indexer = Ti.App.iOS.createSearchableIndex(); | ||
|
||
indexer.addToDefaultSearchableIndex(searchItems, function(e) { | ||
if (e.success) { | ||
Ti.API.info("Press the home button and now search for your keywords"); | ||
} else { | ||
alert("Searchable index could not be created: " + JSON.stringify(e.error)); | ||
} | ||
}); | ||
|
||
btn.addEventListener("click", function() { | ||
// An array of found Ti.App.iOS.SearchableItem's | ||
var allItems = []; | ||
|
||
// The search-query | ||
var searchQuery = Ti.App.iOS.createSearchQuery({ | ||
queryString: 'title == "Titanium*"', | ||
attributes: ["title", "displayName", "keywords", "contentType"] | ||
}); | ||
|
||
// The event to be called when a new batch of items is found | ||
searchQuery.addEventListener("founditems", function(e) { | ||
for (var i = 0; i < e.items.length; i++) { | ||
allItems.push(e.items[i]); | ||
} | ||
}); | ||
|
||
// The event to be called when the search-query completes | ||
searchQuery.addEventListener("completed", function(e) { | ||
if (!e.success) { | ||
alert(e.error); | ||
} | ||
|
||
for (var i = 0; i < allItems.length; i++) { | ||
var attributeSet = allItems[i].attributeSet | ||
var foundTitle = attributeSet.title | ||
var foundDisplayName = attributeSet.displayName | ||
|
||
Ti.API.info("title: " + foundTitle + ", displayName: " + foundDisplayName); | ||
} | ||
}); | ||
|
||
// Start the search-query (or use searchQuery.cancel()) to abort it | ||
searchQuery.start(); | ||
}); | ||
|
||
win.add(btn); | ||
win.open(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,12 @@ | |
#import "TiAppiOSSearchableItemProxy.h" | ||
#import "TiAppiOSSearchableIndexProxy.h" | ||
|
||
#ifdef IS_XCODE_8 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
#ifdef USE_TI_APPIOSSEARCHQUERY | ||
#import "TiAppiOSSearchQueryProxy.h" | ||
#endif | ||
#endif | ||
|
||
#import <MobileCoreServices/MobileCoreServices.h> | ||
#import <CoreLocation/CLCircularRegion.h> | ||
|
||
|
@@ -190,8 +196,7 @@ -(id)createSearchableIndex:(id)unused | |
return nil; | ||
} | ||
|
||
TiAppiOSSearchableIndexProxy *proxy = [[[TiAppiOSSearchableIndexProxy alloc]init] autorelease]; | ||
return proxy; | ||
return [[[TiAppiOSSearchableIndexProxy alloc]init] autorelease];; | ||
} | ||
#endif | ||
|
||
|
@@ -218,10 +223,9 @@ -(id)createSearchableItem:(id)args | |
TiAppiOSSearchableItemAttributeSetProxy *attributeSet = nil; | ||
ENSURE_ARG_FOR_KEY(attributeSet, args, @"attributeSet", TiAppiOSSearchableItemAttributeSetProxy); | ||
|
||
TiAppiOSSearchableItemProxy *proxy = [[[TiAppiOSSearchableItemProxy alloc] | ||
initWithUniqueIdentifier:uniqueIdentifier | ||
withDomainIdentifier:domainIdentifier | ||
withAttributeSet:attributeSet.attributes] autorelease]; | ||
TiAppiOSSearchableItemProxy *proxy = [[[TiAppiOSSearchableItemProxy alloc] initWithUniqueIdentifier:uniqueIdentifier | ||
withDomainIdentifier:domainIdentifier | ||
withAttributeSet:attributeSet.attributes] autorelease]; | ||
return proxy; | ||
} | ||
#endif | ||
|
@@ -250,6 +254,27 @@ -(id)createSearchableItemAttributeSet:(id)args | |
} | ||
#endif | ||
|
||
#ifdef IS_XCODE_8 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
#ifdef USE_TI_APPIOSSEARCHQUERY | ||
-(id)createSearchQuery:(id)args | ||
{ | ||
if (![TiUtils isIOS10OrGreater]) { | ||
NSLog(@"[ERROR] Search-Queries are only available in iOS 10 and later."); | ||
return nil; | ||
} | ||
if (![NSThread isMainThread]) { | ||
__block id result; | ||
TiThreadPerformOnMainThread(^{result = [[self createSearchQuery:args] retain];}, YES); | ||
return [result autorelease]; | ||
} | ||
|
||
ENSURE_SINGLE_ARG(args, NSDictionary); | ||
|
||
return [[[TiAppiOSSearchQueryProxy alloc] _initWithPageContext:[self pageContext] andArguments:args] autorelease]; | ||
} | ||
#endif | ||
#endif | ||
|
||
#ifdef USE_TI_APPIOSUSERACTIVITY | ||
-(id)createUserActivity:(id)args | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/** | ||
* Appcelerator Titanium Mobile | ||
* Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved. | ||
* Licensed under the terms of the Apache Public License | ||
* Please see the LICENSE included with this distribution for details. | ||
*/ | ||
#ifdef IS_XCODE_8 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
#ifdef USE_TI_APPIOSSEARCHQUERY | ||
#import "TiProxy.h" | ||
#import <CoreSpotlight/CoreSpotlight.h> | ||
|
||
@interface TiAppiOSSearchQueryProxy : TiProxy { | ||
CSSearchQuery *query; | ||
NSString *queryString; | ||
NSArray<NSString*> *attributes; | ||
} | ||
|
||
- (id)_initWithPageContext:(id<TiEvaluator>)context andArguments:(NSDictionary*)args; | ||
|
||
- (CSSearchQuery*)query; | ||
|
||
- (void)start:(id)unused; | ||
|
||
- (void)cancel:(id)unused; | ||
|
||
- (NSNumber*)isCancelled:(id)unused; | ||
|
||
@end | ||
#endif | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/** | ||
* Appcelerator Titanium Mobile | ||
* Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved. | ||
* Licensed under the terms of the Apache Public License | ||
* Please see the LICENSE included with this distribution for details. | ||
*/ | ||
#ifdef IS_XCODE_8 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
#ifdef USE_TI_APPIOSSEARCHQUERY | ||
#import "TiAppiOSSearchQueryProxy.h" | ||
#import "TiAppiOSSearchableItemProxy.h" | ||
#import "TiAppiOSSearchableItemAttributeSetProxy.h" | ||
#import "TiUtils.h" | ||
|
||
@implementation TiAppiOSSearchQueryProxy | ||
|
||
- (void)dealloc | ||
{ | ||
RELEASE_TO_NIL(queryString); | ||
RELEASE_TO_NIL(attributes); | ||
RELEASE_TO_NIL(query); | ||
|
||
[super dealloc]; | ||
} | ||
|
||
- (id)_initWithPageContext:(id<TiEvaluator>)context andArguments:(NSDictionary*)args | ||
{ | ||
if (self == [super _initWithPageContext:context]) { | ||
ENSURE_TYPE([args objectForKey:@"queryString"], NSString); | ||
ENSURE_TYPE([args objectForKey:@"attributes"], NSArray); | ||
|
||
queryString = [[args objectForKey:@"queryString"] retain]; | ||
attributes = [[args objectForKey:@"attributes"] retain]; | ||
} | ||
|
||
return self; | ||
} | ||
|
||
- (CSSearchQuery*)query | ||
{ | ||
if (query == nil) { | ||
|
||
query = [[[CSSearchQuery alloc] initWithQueryString:queryString | ||
attributes:attributes] retain]; | ||
|
||
[query setFoundItemsHandler:^(NSArray<CSSearchableItem*> *items) { | ||
if ([self _hasListeners:@"founditems"]) { | ||
NSMutableArray *result = [NSMutableArray array]; | ||
|
||
for (CSSearchableItem *item in items) { | ||
[result addObject:[[[TiAppiOSSearchableItemProxy alloc] initWithUniqueIdentifier:[item uniqueIdentifier] | ||
withDomainIdentifier:[item domainIdentifier ] | ||
withAttributeSet:[item attributeSet]] autorelease]]; | ||
} | ||
|
||
[self fireEvent:@"founditems" withObject:@{ | ||
@"items": result, | ||
@"foundItemCount": NUMUINTEGER([query foundItemCount]) | ||
}]; | ||
} | ||
}]; | ||
|
||
[query setCompletionHandler:^(NSError *error) { | ||
if ([self _hasListeners:@"completed"]) { | ||
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:@{ | ||
@"success": NUMBOOL(error == nil), | ||
@"foundItemCount": NUMUINTEGER([query foundItemCount]) | ||
}]; | ||
|
||
if (error != nil) { | ||
[dict setValue:[error localizedDescription] forKey:@"error"]; | ||
} | ||
|
||
TiThreadPerformOnMainThread(^{ | ||
[self fireEvent:@"completed" withObject:dict]; | ||
}, NO); | ||
} | ||
}]; | ||
|
||
} | ||
|
||
return query; | ||
} | ||
|
||
- (void)start:(id)unused | ||
{ | ||
[[self query] start]; | ||
} | ||
|
||
- (void)cancel:(id)unused | ||
{ | ||
[[self query] cancel]; | ||
} | ||
|
||
- (NSNumber*)isCancelled:(id)unused | ||
{ | ||
return NUMBOOL([[self query] isCancelled]); | ||
} | ||
|
||
@end | ||
#endif | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change 'at' with 'that'