Is there an example code for corespotlight search feature - iOS 9 API? - objective-c

Is there an example code for corespotlight search feature - iOS 9 API? Really appreciate if can look at sample code to implement/test.

Create a new iOS project and add CoreSpotlight and MobileCoreServices framework to your project.
Create the actual CSSearchableItem and associating the uniqueIdentifier, domainIdentifier and the attributeSet. Finally index the CSSearchableItem using [[CSSearchableIndex defaultSearchableIndex]...] as show below.
OK!Test the index!

CSSearchableItemAttributeSet *attributeSet;
attributeSet = [[CSSearchableItemAttributeSet alloc]
initWithItemContentType:(NSString *)kUTTypeImage];
attributeSet.title = #"My First Spotlight Search";
attributeSet.contentDescription = #"This is my first spotlight Search";
attributeSet.keywords = #[#"Hello", #"Welcome",#"Spotlight"];
UIImage *image = [UIImage imageNamed:#"searchIcon.png"];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(image)];
attributeSet.thumbnailData = imageData;
CSSearchableItem *item = [[CSSearchableItem alloc]
initWithUniqueIdentifier:#"com.deeplink"
domainIdentifier:#"spotlight.sample"
attributeSet:attributeSet];
[[CSSearchableIndex defaultSearchableIndex] indexSearchableItems:#[item]
completionHandler: ^(NSError * __nullable error) {
if (!error)
NSLog(#"Search item indexed");
}];
Note: kUTTypeImage requires that you import the MobileCoreServices framework.

To complete the spotlight search functionality, once you have implemented mayqiyue's answer, you'll be able to see the results in the search but on selection of the result simply your app would open not the related view with related content.
In order to do so, go to your AppDelegate.m and add the following method.
-(BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
{
//check if your activity has type search action(i.e. coming from spotlight search)
if ([userActivity.activityType isEqualToString:CSSearchableItemActionType ] == YES) {
//the identifier you'll use to open specific views and the content in those views.
NSString * identifierPath = [NSString stringWithFormat:#"%#",[userActivity.userInfo objectForKey:CSSearchableItemActivityIdentifier]];
if (identifierPath != nil) {
// go to YOUR VIEWCONTROLLER
// use notifications or whatever you want to do so
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
MyViewController *myViewController = [storyboard instantiateViewControllerWithIdentifier:#"MyViewController"];
// this notification must be registered in MyViewController
[[NSNotificationCenter defaultCenter] postNotificationName:#"OpenMyViewController" object: myViewController userInfo:nil];
return YES;
}
}
return NO;
}
Make sure to import in AppDelegate.m :
#import <MobileCoreServices/MobileCoreServices.h>
#import <CoreSpotlight/CoreSpotlight.h>
UPDATE for Swift 2.1
func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool {
if #available(iOS 9.0, *) {
if userActivity.activityType == CSSearchableItemActionType {
//the identifier you'll use to open specific views and the content in those views.
let dict = userActivity.userInfo! as NSDictionary
let identifierPath = dict.objectForKey(CSSearchableItemActivityIdentifier) as! String
if identifierPath.characters.count > 0 {
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let mvc: MyViewController = storyboard.instantiateViewControllerWithIdentifier("MyViewController") as! MyViewController
NSNotificationCenter.defaultCenter().postNotificationName("OpenMyViewController", object: mvc, userInfo: nil)
}
return true
}
} else {
// Fallback on earlier versions
return false
}
return false
}
Make sure to import in AppDelegate.swift :
import CoreSpotlight
import MobileCoreServices

I am using similar implementation as mentioned by #mayqiyue but I am also checking the existence of the item variable for backwards compatibility with iOS 8.
- (void)setupCoreSpotlightSearch
{
CSSearchableItemAttributeSet *attibuteSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(__bridge NSString *)kUTTypeImage];
attibuteSet.title = NSLocalizedString(#"Be happy!", #"Be happy!");
attibuteSet.contentDescription = #"Just like that";
attibuteSet.keywords = #[#"example", #"stackoverflow", #"beer"];
UIImage *image = [UIImage imageNamed:#"Image"];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(image)];
attibuteSet.thumbnailData = imageData;
CSSearchableItem *item = [[CSSearchableItem alloc] initWithUniqueIdentifier:#"1"
domainIdentifier:#"album-1"
attributeSet:attibuteSet];
if (item) {
[[CSSearchableIndex defaultSearchableIndex] indexSearchableItems:#[item] completionHandler:^(NSError * _Nullable error) {
if (!error) {
NSLog(#"Search item indexed");
}
}];
}
}
To handle the tap on the search item from Spotlight you need to implement following method in your AppDelegate:
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
{
if ([userActivity.activityType isEqualToString:CSSearchableItemActionType]) {
NSString *uniqueIdentifier = userActivity.userInfo[CSSearchableItemActivityIdentifier];
// Handle 'uniqueIdentifier'
NSLog(#"uniqueIdentifier: %#", uniqueIdentifier);
}
return YES;
}

Write in your main controller Class
-(void)storeValueForSpotligtSearch {
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
// **Your Model Array that Contain Data Like attributes Make, Model, Variant and Year and Images**
for (MyCatalogeModel *myCatalogeModelObj in yourDataContainer) {
NSMutableArray *arrKeywords = [[NSMutableArray alloc] initWithObjects: myCatalogeModelObj.year, myCatalogeModelObj.make, myCatalogeModelObj.model, myCatalogeModelObj.variant, nil];
NSString *strIdentifier = [NSString stringWithFormat:#"%#.%#",bundleIdentifier, myCatalogeModelObj.carId];
self.userActivity = [[NSUserActivity alloc]initWithActivityType:strIdentifier];
self.userActivity.title = myCatalogeModelObj.year;
self.userActivity.title = myCatalogeModelObj.make;
self.userActivity.title = myCatalogeModelObj.model;
self.userActivity.title = myCatalogeModelObj.variant;
self.userActivity.eligibleForSearch = YES;
self.userActivity.eligibleForPublicIndexing = YES;
self.userActivity.eligibleForHandoff = YES;
CSSearchableItemAttributeSet * attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString *)kUTTypeJSON];
attributeSet.title = myCatalogeModelObj.make;
attributeSet.thumbnailData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[myCatalogeModelObj.imageArray objectAtIndex:0]]];
attributeSet.contentDescription = [NSString stringWithFormat:#"%# %# %# %#", myCatalogeModelObj.year, myCatalogeModelObj.make, myCatalogeModelObj.model, myCatalogeModelObj.variant];
attributeSet.keywords = arrKeywords;
CSSearchableItem *item = [[CSSearchableItem alloc] initWithUniqueIdentifier:strIdentifier domainIdentifier:#"spotlight.CARS24ChannelPartnerapp" attributeSet:attributeSet];
[[CSSearchableIndex defaultSearchableIndex] indexSearchableItems:#[item] completionHandler: ^(NSError * __nullable error) {
}];
self.userActivity.contentAttributeSet = attributeSet;
[self.userActivity becomeCurrent];
[self updateUserActivityState:self.userActivity];
}
}
Write in App Delegate
-(BOOL)application:(nonnull UIApplication *) application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray * __nullable))restorationHandler {
#try {
NSString *strIdentifier;
NSNumber *numScreenId;
NSNumberFormatter *numFormatter = [[NSNumberFormatter alloc] init];
NSLog(#"Activity = %#",userActivity.userInfo);
if (userActivity.userInfo[#"vc"]) {
numScreenId = userActivity.userInfo[#"vc"];
}
else{
strIdentifier = [userActivity.userInfo objectForKey:#"kCSSearchableItemActivityIdentifier"];
NSLog(#"strIdentifier : %#",strIdentifier);
NSArray *arr = [strIdentifier componentsSeparatedByString:#"."];
NSString *strScreenId = [arr objectAtIndex:3];
NSLog(#"ID -= %#",strScreenId);
**// On Click in Spotlight search item move your particular view.**
[self moveToParticular:[strScreenId intValue]];
numScreenId = [numFormatter numberFromString:strScreenId];
}
}
#catch (NSException *exception) {}
return YES;
}

let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeImage as String)
attributeSet.title = "Searchable Item"
attributeSet.contentDescription = "Code for creating searchable item"
attributeSet.keywords = ["Item","Searchable","Imagine"]
attributeSet.thumbnailURL = NSURL(string: "https://blog.imagine.com/")
let searchableItem = CSSearchableItem(uniqueIdentifier: "com.imagine.objectA", domainIdentifier: "spotlight.search", attributeSet: attributeSet)
CSSearchableIndex.defaultSearchableIndex().indexSearchableItems([searchableItem]) {_ in}

Related

Can't load local JS file after migrate from UIWebView to WKWebView in objective-C

I have UIWebView like this:
#import <UIKit/UIKit.h>
#import "DataProvider.h"
#implementation QHArticle
{
UIWebView *_helperWebView;
}
-(instancetype)init
{
self = [super init];
if (self)
{
_helperWebView = [[UIWebView alloc] init];
[_helperWebView loadHTMLString:#"<html><script src='Article.js'></script><body onload='Article.init();'></body></html>" baseURL:[[NSBundle mainBundle] bundleURL]];
}
return self;
}
-(NSString*)callJSMethod:(NSString*)method
{
return [_helperWebView stringByEvaluatingJavaScriptFromString:method];
}
-(NSArray *)listArticle
{
NSString *json = [self callJSMethod:#"(function() {return JSON.stringify(Article._data.news)})()"];
;
NSError *error;
NSArray *result = [NSJSONSerialization JSONObjectWithData:[json dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
return [result subarrayWithRange:NSMakeRange(1, result.count-2)];
}
The codes above is working fine when i tried it. But, after the codes changed to WKWebView like this:
#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>
#import "DataProvider.h"
#implementation QHArticle
{
WKWebView *_helperWebView;
}
-(instancetype)init
{
self = [super init];
if (self)
{
_helperWebView = [[WKWebView alloc] init];
[_helperWebView loadHTMLString:#"<html><script src='Article.js'></script><body onload='Article.init();'></body></html>" baseURL:[[NSBundle mainBundle] bundleURL]];
}
return self;
}
- (NSString *)callJSMethod:(NSString *)method
{
__block NSString *resultString = nil;
__block BOOL finished = NO;
[_helperWebView evaluateJavaScript:method completionHandler:^(id result, NSError *error) {
if (error == nil) {
if (result != nil) {
resultString = [NSString stringWithFormat:#"%#", result];
}
} else {
NSLog(#"evaluateJavaScript error : %#", error.localizedDescription);
}
finished = YES;
}];
while (!finished)
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
return resultString;
}
I got an error message, "evaluateJavaScript error : .... Can't find Article object" and got white blank screen on the phone.
I still can't find the issues after i migrated it to WKWebView, please help.
I just want to use Objective-C, not Swift because this is the legacy code.
Thank you.
The WKWebView won't load anything from a file:// URL.
Start by loading your Article.js script into a string; you can use evaluateJavaScript: to run it.
To inject a string into every page that a particular WKWebView loads, you would create a WKUserScript, attach it to a WKUserContentController, and attach THAT to a WKWebViewConfiguration.
Then create your WKWebView with [WKWebView initWithFrame:configuration:]

Importing SimpleAuth ForSquareWeb - 9 build time errors

I'm relatively new to objective-c and hardly know much of swift.
I've been trying to make an app which will implement simpleAuth in order to create a link to the ForsquareWeb API.
I'm using cocoapods and have imported the SimpleAuth related files into my product.
Every file seems to be fine except the SimpleAuth target, specifically the SimpleAuthForSquareWebProvider.m file. This is what the file itself looks like;
//
// SimpleAuthFoursquareWebProvider.m
// SimpleAuth
//
// Created by Julien Seren-Rosso on 23/01/2014.
// Copyright (c) 2014 Byliner, Inc. All rights reserved.
//
#import "SimpleAuthFoursquareWebProvider.h"
#import "SimpleAuthFoursquareWebLoginViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
#import "UIViewController+SimpleAuthAdditions.h"
#implementation SimpleAuthFoursquareWebProvider
#pragma mark - SimpleAuthProvider
+ (NSString *)type {
return #"foursquare-web";
}
+ (NSDictionary *)defaultOptions {
// Default present block
SimpleAuthInterfaceHandler presentBlock = ^(UIViewController *controller) {
UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:controller];
navigation.modalPresentationStyle = UIModalPresentationFormSheet;
UIViewController *presented = [UIViewController SimpleAuth_presentedViewController];
[presented presentViewController:navigation animated:YES completion:nil];
};
// Default dismiss block
SimpleAuthInterfaceHandler dismissBlock = ^(id controller) {
[controller dismissViewControllerAnimated:YES completion:nil];
};
NSMutableDictionary *options = [NSMutableDictionary dictionaryWithDictionary:[super defaultOptions]];
options[SimpleAuthPresentInterfaceBlockKey] = presentBlock;
options[SimpleAuthDismissInterfaceBlockKey] = dismissBlock;
return options;
}
- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion {
[[[self accessToken]
flattenMap:^RACStream *(NSString *response) {
NSArray *signals = #[
[self accountWithAccessToken:response],
[RACSignal return:response]
];
return [self rac_liftSelector:#selector(dictionaryWithAccount:accessToken:) withSignalsFromArray:signals];
}]
subscribeNext:^(NSDictionary *response) {
completion(response, nil);
}
error:^(NSError *error) {
completion(nil, error);
}];
}
#pragma mark - Private
- (RACSignal *)accessToken {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
dispatch_async(dispatch_get_main_queue(), ^{
SimpleAuthFoursquareWebLoginViewController *login = [[SimpleAuthFoursquareWebLoginViewController alloc] initWithOptions:self.options];
login.completion = ^(UIViewController *login, NSURL *URL, NSError *error) {
SimpleAuthInterfaceHandler dismissBlock = self.options[SimpleAuthDismissInterfaceBlockKey];
dismissBlock(login);
// Parse URL
NSString *fragment = [URL fragment];
NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:fragment];
NSString *token = dictionary[#"access_token"];
// Check for error
if (![token length]) {
[subscriber sendError:error];
return;
}
// Send completion
[subscriber sendNext:token];
[subscriber sendCompleted];
};
SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey];
block(login);
});
return nil;
}];
}
- (RACSignal *)accountWithAccessToken:(NSString *)accessToken {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSDictionary *parameters = #{ #"oauth_token" : accessToken };
NSString *query = [CMDQueryStringSerialization queryStringWithDictionary:parameters];
NSString *URLString = [NSString stringWithFormat:#"https://api.foursquare.com/v2/users/self?v=20140210&%#", query];
NSURL *URL = [NSURL URLWithString:URLString];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
[NSURLConnection sendAsynchronousRequest:request queue:self.operationQueue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 99)];
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if ([indexSet containsIndex:statusCode] && data) {
NSError *parseError = nil;
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&parseError];
if (dictionary) {
[subscriber sendNext:dictionary];
[subscriber sendCompleted];
}
else {
[subscriber sendError:parseError];
}
}
else {
[subscriber sendError:connectionError];
}
}];
return nil;
}];
}
- (NSDictionary *)dictionaryWithAccount:(NSDictionary *)account accessToken:(NSString *)accessToken {
NSMutableDictionary *dictionary = [NSMutableDictionary new];
NSDictionary *userData = account[#"response"][#"user"];
// Provider
dictionary[#"provider"] = [[self class] type];
// Credentials
dictionary[#"credentials"] = #{
#"token" : accessToken
};
// User ID
dictionary[#"uid"] = userData[#"id"];
// Raw response
dictionary[#"extra"] = #{
#"raw_info" : userData
};
// User info
NSMutableDictionary *user = [NSMutableDictionary new];
if (userData[#"contact"][#"email"]) {
user[#"email"] = userData[#"contact"][#"email"];
}
if (userData[#"firstName"]) {
user[#"first_name"] = userData[#"firstName"];
}
if (userData[#"lastName"]) {
user[#"last_name"] = userData[#"lastName"];
}
user[#"name"] = [NSString stringWithFormat:#"%# %#", user[#"first_name"], user[#"last_name"]];
user[#"gender"] = userData[#"gender"];
if ([userData[#"photo"] isKindOfClass:NSDictionary.class]) {
user[#"image"] = [NSString stringWithFormat:#"%#500x500%#", userData[#"photo"][#"prefix"], userData[#"photo"][#"suffix"]];
} else if ([userData[#"photo"] isKindOfClass:NSString.class]) {
user[#"image"] = userData[#"photo"];
}
if (userData[#"photo"]) {
user[#"photo"] = userData[#"photo"];
}
if (userData[#"homeCity"]) {
NSString *homecity = [[userData[#"homeCity"] componentsSeparatedByString:#","] firstObject];
user[#"location"] = homecity;
}
user[#"urls"] = #{
#"Foursquare" : [NSString stringWithFormat:#"https://foursquare.com/user/%#", userData[#"id"]],
};
dictionary[#"info"] = user;
return dictionary;
}
#end
I think it would be easier to show you just a screen shot of the errors and where they're arising in the code itself;
I would really appreciate some insight into where the problem lies. I'm not sure why many of the errors say use of undeclared identifiers, are the imported files not correct?
After trying to re-install the pod file as it was suggested a class hadn't been installed I still have the same problem. Here are screen shots of my podfile and the terminals output when installing the pods;
I just used the Cocoapods application rather than terminal. I got additional information when clicking install.
"[!] The dPicDid [Debug] target overrides the ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES build setting defined in `Pods/Target Support Files/Pods-dPicDid/Pods-dPicDid.debug.xcconfig'. This can lead to problems with the CocoaPods installation
[!] The dPicDid [Release] target overrides the ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES build setting defined in Pods/Target Support Files/Pods-dPicDid/Pods-dPicDid.release.xcconfig'. This can lead to problems with the CocoaPods installation
- Use the$(inherited)flag, or
- Remove the build settings from the target.
- Use the$(inherited)` flag, or
- Remove the build settings from the target.

Getting mp3 artwork crashes on iOS 8 but works on iOS 7

EDIT: The culprit was iOS 8, not the simulator (which I didn't realize was already running iOS 8) I've renamed the title to reflect this.
I was happily using the code from this SO question to load album artwork from mp3 files. This was on my iPhone 5 with iOS 7.1.
But then I traced crashing in the iOS simulator to this code. Further investigation revealed that this code also crashed on my iPad. It crashed on my iPad after upgrading it to iOS 8.
It appears the dictionary containing the image is corrupted.
I created a dummy iOS project that only loads album art and got the same result. Below is the code from that viewcontroller.
- (void) viewDidAppear:(BOOL)animated
{
self.titleText = #"Overkill"; // Set song filename here
NSString *filePath = [[NSBundle mainBundle] pathForResource:self.titleText ofType:#"mp3"];
if (!filePath) {
return;
}
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
NSLog(#"Getting song metadata for %#", self.titleText);
AVAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
if (asset != nil) {
NSArray *keys = [NSArray arrayWithObjects:#"commonMetadata", nil];
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
NSArray *artworks = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata
withKey:AVMetadataCommonKeyArtwork
keySpace:AVMetadataKeySpaceCommon];
UIImage *albumArtWork;
for (AVMetadataItem *item in artworks) {
if ([item.keySpace isEqualToString:AVMetadataKeySpaceID3]) {
NSDictionary *dict = [item.value copyWithZone:nil];
// **********
// Crashes here with SIGABRT. dict is not a valid dictionary.
// **********
if ([dict objectForKey:#"data"]) {
albumArtWork = [UIImage imageWithData:[dict objectForKey:#"data"]];
}
}
else if ([item.keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
// This doesn't appear to get called for images set (ironically) in iTunes
albumArtWork = [UIImage imageWithData:[item.value copyWithZone:nil]];
}
}
if (albumArtWork != nil) {
dispatch_sync(dispatch_get_main_queue(), ^{
[self.albumArtImageView setImage:albumArtWork];
});
}
}];
}
}
I've marked the line with the crash. It expects a file Overkill.mp3 to be in the bundle. I tested with multiple mp3's and m4a's exported from iTunes and Amazon, so I know the files themselves are correctly encoded.
Tested in Xcode 6.0 and 6.1.
Any ideas why it would work on iPhone but not the simulator or iPad?
EDIT / UPDATE:
Logging the item.value reveals differences.
On iPhone 5 (works):
(lldb) po item.value
{
MIME = JPG;
data = <ffd8ffe0 .... several Kb of data ..... 2a17ffd9>;
identifier = "";
picturetype = Other;
}
On Simulator (crashes)
(lldb) po item.value
<ffd8ffe0 .... several Kb of data ..... 2a17ffd9>
So it appears that on the simulator there is no dictionary, just the raw artwork.
Changing the code to not expect a dictionary, but take item.value as a UIImage works!
for (AVMetadataItem *item in artworks) {
if ([item.keySpace isEqualToString:AVMetadataKeySpaceID3]) {
NSData *newImage = [item.value copyWithZone:nil];
albumArtWork = [UIImage imageWithData:newImage];
}
...
}
It seems the returned data structure has changed in iOS 8. The value of the AVMetadataItem object is no longer a dictionary, but the actual raw UIImage data.
Adding a test for the NSFoundationVersionNumber solves the problem. There is probably a cleaner solution.
- (void) viewDidAppear:(BOOL)animated
{
self.titleText = #"Overkill";
NSString *filePath = [[NSBundle mainBundle] pathForResource:self.titleText ofType:#"mp3"];
if (!filePath) {
return;
}
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
NSLog(#"Getting song metadata for %#", self.titleText);
AVAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
if (asset != nil) {
NSArray *keys = [NSArray arrayWithObjects:#"commonMetadata", nil];
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
NSArray *artworks = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata
withKey:AVMetadataCommonKeyArtwork
keySpace:AVMetadataKeySpaceCommon];
UIImage *albumArtWork;
for (AVMetadataItem *item in artworks) {
if ([item.keySpace isEqualToString:AVMetadataKeySpaceID3]) {
// *** WE TEST THE IOS VERSION HERE ***
if (TARGET_OS_IPHONE && NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1) {
NSData *newImage = [item.value copyWithZone:nil];
albumArtWork = [UIImage imageWithData:newImage];
}
else {
NSDictionary *dict = [item.value copyWithZone:nil];
if ([dict objectForKey:#"data"]) {
albumArtWork = [UIImage imageWithData:[dict objectForKey:#"data"]];
}
}
}
else if ([item.keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
// This doesn't appear to get called for images set (ironically) in iTunes
albumArtWork = [UIImage imageWithData:[item.value copyWithZone:nil]];
}
}
if (albumArtWork != nil) {
dispatch_sync(dispatch_get_main_queue(), ^{
[self.albumArtImageView setImage:albumArtWork];
});
}
}];
}
}

kindly advice me to display x number of annotation points in mkmap

Good morning, I am very new to objective-c now I am developing my first app. It's a vehicle tracking app. I received the x-number of lat & long from the json service. Now I displayed a single annotation but I need to display all the annotation points which i received from the service here I search for a whole day to find this but am fails to find displaying x-num of annotations. So kindly advice me by using some sample codes. Thanks in Advance... My code is..
- (void)viewDidLoad
{
[super viewDidLoad];
//MAP VIEW WebService
NSString *urlMapString=[NSString stringWithFormat:#"http://www.logix.com/logix_webservice/map.php?format=json&truckno=%#",nam2];
NSURL *urlMap=[NSURL URLWithString:urlMapString];
NSData *dataMap=[NSData dataWithContentsOfURL:urlMap];
NSError *errorMap;
NSDictionary *jsonMap = [NSJSONSerialization JSONObjectWithData:dataMap options:kNilOptions error:&errorMap]; NSArray *resultsMap = [jsonMap valueForKey:#"posts"];
NSArray *resMap = [resultsMap valueForKey:#"post"];
NSArray *latitudeString=[resMap valueForKey:#"latitude"];
if([resMap count]){
NSString *latOrgstring = [latitudeString objectAtIndex:0];
double latitude=[latOrgstring doubleValue];
NSArray *longitudeString=[resMap valueForKey:#"longitude"];
NSString *longOrgstring = [longitudeString objectAtIndex:0];
double longitude=[longOrgstring doubleValue];
NSString *ignation=[[resMap valueForKey:#"ignition"]objectAtIndex:0];
i=[ignation intValue];
//MAP VIEW Point
MKCoordinateRegion myRegion;
//Center
CLLocationCoordinate2D center;
center.latitude=latitude;
center.longitude=longitude;
//Span
MKCoordinateSpan span;
span.latitudeDelta=0.01f;
span.longitudeDelta=0.01f;
myRegion.center=center;
myRegion.span=span;
//Set our mapView
[MapViewC setRegion:myRegion animated:YES];
//Annotation
//1.create coordinate for use with the annotation
CLLocationCoordinate2D wimbLocation;
wimbLocation.latitude=latitude;
wimbLocation.longitude=longitude;
Annotation * myAnnotation= [Annotation alloc];
CLLocation *someLocation=[[CLLocation alloc]initWithLatitude:latitude longitude:longitude];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:someLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSDictionary *dictionary = [[placemarks objectAtIndex:0] addressDictionary];
addressOutlet=[dictionary valueForKey:#"Street"];
City=[dictionary valueForKey:#"City"];
State=[dictionary valueForKey:#"State"];
myAnnotation.coordinate=wimbLocation;
if (addressOutlet!=NULL&&City!=NULL)
{
myAnnotation.title=addressOutlet;
myAnnotation.subtitle=[NSString stringWithFormat:#"%#,%#", City, State];
}
else if (addressOutlet==NULL&&City!=NULL)
{
myAnnotation.title=City;
myAnnotation.subtitle=[NSString stringWithFormat:#"%#,%#", City, State];
}
else if (addressOutlet!=NULL&&City==NULL)
{
myAnnotation.title=addressOutlet;
myAnnotation.subtitle=[NSString stringWithFormat:#"%#", State];
}
else if(addressOutlet==NULL&&City==NULL)
{
myAnnotation.title=State;
myAnnotation.subtitle=[NSString stringWithFormat:#"%#",State];
}
[self.MapViewC addAnnotation:myAnnotation];
}];
}
}
Please make an individual class and use by importing .
Now use
-(id)initWithCoordinate:(CLLocationCoordinate2D)c;
and its .m file
-(id)initWithCoordinate:(CLLocationCoordinate2D)c
{
coordinate=c;
}
Now call this class anywhere and call this method and send your location coordinates.
and then add its objects into NSArray.
Now call [YourMapView addAnnotations:arrayOfAnnotations];
You will get it what you want.It works in my case I hope you will find it supportive.
Now add annotations on mapView:
-(MKAnnotationView *) mapView:(MKMapView *)mapV
viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[pinAnnotation class]])
{
static NSString *defaultPinID = #"com.ABC.pin";//Your unique identifier anything
MKAnnotationView *pinView = nil;
if(!pinView)
{
pinView = (MKAnnotationView *)
[self.mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
pinView = [[MKAnnotationView alloc] initWithAnnotation:
annotation reuseIdentifier:defaultPinID] ;
return pinView;
}
static NSString *AnnotationViewID = #"annotationViewID";
MKAnnotationView* pin =
(MKAnnotationView*) [mapV dequeueReusableAnnotationViewWithIdentifier:
AnnotationViewID];
if ( pin == nil ) {
pin = [(MKAnnotationView*) [MKAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier: AnnotationViewID] ;
pin.canShowCallout = YES;
}
else
{
[pin setAnnotation: annotation];
}
((MKUserLocation *)annotation).title = #"You are here";
return pin;
}

Pick Music from iOS Library and Send / Save

I have a query regarding Music Files.
I want to select 1/more Music files from the Music Library of iPhone/iTouch/iPad and Save in my Documents Folder or Send it to Server.
I roughly went through MPMediaPickerController and AddMusic(Sample Code).
But, I could only get details of selecting Songs and Playing it.
Is it possible to Save those selected Songs, which I can also use to Send to Server ?
Thanks
Yes, it is possible.
I think it will help you
// Have to add this framework
//CoreMedia.framework
//AudioToolbox.framework
//CoreAudio.framework
//MediaPlayer.framework
//AVFoundation.framework
//in UploadAudioViewController.h file
#import <UIKit/UIKit.h>
#import <CoreAudio/CoreAudioTypes.h>
#import <AudioToolbox/AudioToolbox.h>
#import <MediaPlayer/MediaPlayer.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreMedia/CoreMedia.h>
#interface UploadAudioViewController : UIViewController<UIActionSheetDelegate,UINavigationControllerDelegate,UIImagePickerControllerDelegate,MPMediaPickerControllerDelegate,AVAudioRecorderDelegate, AVAudioPlayerDelegate,AVAudioSessionDelegate>{
MPMediaItem *song;
NSURL *exportURL;
}
#property (nonatomic, retain) NSData *audioData;
// in UploadAudioViewController.m file
#import "UploadAudioViewController.h"
//#import < AudioToolbox/AudioToolbox.h>
#interface UploadAudioViewController ()
#end
#implementation UploadAudioViewController
#synthesize musicPlayer,audioData;
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
-(void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.title = #"Upload Audio";
self.musicPlayer = [MPMusicPlayerController iPodMusicPlayer];
self.audioData=nil;
}
#pragma mark Browse Audio from Device
-(void)PickAudioForIndex_iPhone
{
if ([[[UIDevice currentDevice] model] isEqualToString:#"iPhone Simulator"]) {
//device is simulator
UIAlertView *alert1;
alert1 = [[UIAlertView alloc] initWithTitle:#"Alert" message:#"There is no Audio file in the Device" delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok",nil];
alert1.tag=2;
[alert1 show];
//[alert1 release],alert1=nil;
}else{
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeMusic];
mediaPicker.delegate = self;
mediaPicker.allowsPickingMultipleItems = NO; // this is the default
[self presentViewController:mediaPicker animated:YES completion:nil];
}
}
#pragma mark Media picker delegate methods
-(void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection {
// We need to dismiss the picker
[self dismissViewControllerAnimated:YES completion:nil];
// Assign the selected item(s) to the music player and start playback.
if ([mediaItemCollection count] < 1) {
return;
}
song = [[mediaItemCollection items] objectAtIndex:0];
[self handleExportTapped];
}
-(void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker {
// User did not select anything
// We need to dismiss the picker
[self dismissViewControllerAnimated:YES completion:nil ];
}
-(void)handleExportTapped{
// get the special URL
if (! song) {
return;
}
//[self startLoaderWithLabel:#"Preparing for upload..."];
NSURL *assetURL = [song valueForProperty:MPMediaItemPropertyAssetURL];
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil];
NSLog (#"Core Audio %# directly open library URL %#",
coreAudioCanOpenURL (assetURL) ? #"can" : #"cannot",
assetURL);
NSLog (#"compatible presets for songAsset: %#",
[AVAssetExportSession exportPresetsCompatibleWithAsset:songAsset]);
/* approach 1: export just the song itself
*/
AVAssetExportSession *exporter = [[AVAssetExportSession alloc]
initWithAsset: songAsset
presetName: AVAssetExportPresetAppleM4A];
NSLog (#"created exporter. supportedFileTypes: %#", exporter.supportedFileTypes);
exporter.outputFileType = #"com.apple.m4a-audio";
NSString *exportFile = [myDocumentsDirectory() stringByAppendingPathComponent: #"exported.m4a"];
// end of approach 1
// set up export (hang on to exportURL so convert to PCM can find it)
myDeleteFile(exportFile);
//[exportURL release];
exportURL = [NSURL fileURLWithPath:exportFile];
exporter.outputURL = exportURL;
// do the export
[exporter exportAsynchronouslyWithCompletionHandler:^{
int exportStatus = exporter.status;
switch (exportStatus) {
case AVAssetExportSessionStatusFailed: {
// log error to text view
NSError *exportError = exporter.error;
NSLog (#"AVAssetExportSessionStatusFailed: %#", exportError);
//errorView.text = exportError ? [exportError description] : #"Unknown failure";
//errorView.hidden = NO;
//[self stopLoader];
//[self showAlertWithMessage:#"There ia an error!"];
break;
}
case AVAssetExportSessionStatusCompleted: {
NSLog (#"AVAssetExportSessionStatusCompleted");
//fileNameLabel.text = [exporter.outputURL lastPathComponent];
// set up AVPlayer
//[self setUpAVPlayerForURL: exporter.outputURL];
///////////////// get audio data from url
//[self stopLoader];
//[self showAlertWithMessage:#"There ia an error!"];
NSURL *audioUrl = exportURL;
NSLog(#"Audio Url=%#",audioUrl);
self.audioData = [NSData dataWithContentsOfURL:audioUrl];
break;
}
case AVAssetExportSessionStatusUnknown: {
NSLog (#"AVAssetExportSessionStatusUnknown");
//[self stopLoader];
//[self showAlertWithMessage:#"There ia an error!"];
break;
}
case AVAssetExportSessionStatusExporting: {
NSLog (#"AVAssetExportSessionStatusExporting");
//[self stopLoader];
//[self showAlertWithMessage:#"There ia an error!"];
break;
}
case AVAssetExportSessionStatusCancelled: {
NSLog (#"AVAssetExportSessionStatusCancelled");
//[self stopLoader];
//[self showAlertWithMessage:#"There ia an error!"];
break;
}
case AVAssetExportSessionStatusWaiting: {
NSLog (#"AVAssetExportSessionStatusWaiting");
//[self stopLoader];
//[self showAlertWithMessage:#"There ia an error!"];
break;
}
default: {
NSLog (#"didn't get export status");
//[self stopLoader];
//[self showAlertWithMessage:#"There ia an error!"];
break;
}
}
}];
}
#pragma mark conveniences
NSString* myDocumentsDirectory(){
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [paths objectAtIndex:0];;
}
void myDeleteFile (NSString* path){
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
NSError *deleteErr = nil;
[[NSFileManager defaultManager] removeItemAtPath:path error:&deleteErr];
if (deleteErr) {
NSLog (#"Can't delete %#: %#", path, deleteErr);
}
}
}
// generic error handler from upcoming "Core Audio" book (thanks, Kevin!)
// if result is nonzero, prints error message and exits program.
static void CheckResult(OSStatus result, const char *operation)
{
if (result == noErr) return;
char errorString[20];
// see if it appears to be a 4-char-code
*(UInt32 *)(errorString + 1) = CFSwapInt32HostToBig(result);
if (isprint(errorString[1]) && isprint(errorString[2]) && isprint(errorString[3]) && isprint(errorString[4])) {
errorString[0] = errorString[5] = '\'';
errorString[6] = '\0';
} else
// no, format it as an integer
sprintf(errorString, "%d", (int)result);
fprintf(stderr, "Error: %s (%s)\n", operation, errorString);
exit(1);
}
#pragma mark core audio test
BOOL coreAudioCanOpenURL (NSURL* url){
OSStatus openErr = noErr;
AudioFileID audioFile = NULL;
openErr = AudioFileOpenURL((__bridge CFURLRef) url,
kAudioFileReadPermission ,
0,
&audioFile);
if (audioFile) {
AudioFileClose (audioFile);
}
return openErr ? NO : YES;
}
I have tried and succeed in exporting the ipod library song . Please find my code below:
extension AudioPostViewController: MPMediaPickerControllerDelegate {
func mediaPicker(mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
dismissViewControllerAnimated(true, completion: {
print("You selected \(mediaItemCollection)")
let item: MPMediaItem = mediaItemCollection.items[0]
let pathURL: NSURL? = item.valueForProperty(MPMediaItemPropertyAssetURL) as? NSURL
if pathURL == nil {
Alert.showPopupWithMessage("Unable to read DRM protected file.")
return
}
let title = item.valueForProperty(MPMediaItemPropertyTitle) as? String ?? "Now Playing..."
print("\(pathURL), title : \(title) ")
// get file extension andmime type
let str = pathURL!.absoluteString
let str2 = str.stringByReplacingOccurrencesOfString("ipod-library://item/item", withString: "")
let arr = str2.componentsSeparatedByString("?")
var mimeType = arr[0]
mimeType = mimeType.stringByReplacingOccurrencesOfString(".", withString: "")
// Export the ipod library as .m4a file to local directory for remote upload
let exportSession = AVAssetExportSession(asset: AVAsset(URL: pathURL!), presetName: AVAssetExportPresetAppleM4A)
exportSession?.shouldOptimizeForNetworkUse = true
exportSession?.outputFileType = AVFileTypeAppleM4A
FilePath.removeAudioFile() // Remove file if it exists
let fileUrl = FilePath.testFilePathURL()
exportSession?.outputURL = fileUrl
exportSession?.exportAsynchronouslyWithCompletionHandler({ () -> Void in
if exportSession!.status == AVAssetExportSessionStatus.Completed {
dispatch_async(dispatch_get_main_queue(), {
// Prepare audio to play
self.audioTitle = title
self.audioPath = fileUrl
self.mimeType = "audio/m4a"
self.audioFileName = "audio.m4a"
UIView.animateWithDuration(0.45, animations: {
if Platform.DeviceType.iPhone4 {
self.libraryBottomSpacing.constant = 5
self.view.layoutIfNeeded()
} else {
self.libraryBottomSpacing.constant = 25
self.view.layoutIfNeeded()
}
}, completion: {
(v: Bool) in
self.loadJukeBox(self.audioPath!, title: title)
})
})
} else {
dispatch_async(dispatch_get_main_queue(), {
Alert.showPopupWithMessage("Unable to read file as its DRM protected.")
})
}
})
})
}
func mediaPickerDidCancel(mediaPicker: MPMediaPickerController) {
dismissViewControllerAnimated(true, completion: nil)
}
}
Is it possible to save those selected songs, which I can also use to send to server?
No, you can only play songs from the iTunes library.
The raw audio files are not accessible, probably due to copyright protection.