CSSearchableItemAttributeSet init methods return nil - ios

I have some trouble with the new Core Spotlight API in iOS 9. The problem is that the init methods for CSSearchableItemAttributeSet returns nil. Here is an example that does not work for me:
CSSearchableItemAttributeSet* attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString *)kUTTypeImage];
attributeSet.title = movie.movieName;
attributeSet.contentDescription = movie.shortDescription ? movie.shortDescription : movie.longDescription;
attributeSet.thumbnailURL = [NSURL URLWithString: [movie posterURLStringWithWidth:100]];
the attributeSet is nil directly from start, so the last three lines does nothing. I have added the CoreSpotlight and MobileCoreService framework to the project and imported them in the same file. I have tried [[CSSearchableItemAttributeSet alloc] init] and this as well returns nil. I really can't figure out what I'm doing wrong. Using Xcode 7.0 beta 4. Any idea why it would return nil is highly appreciated!

From some trying back and forth I realised I did not have an iOS 9 beta installed on my phone which kind of explains why iOS 9 features does not work.. So, to answer my own question, you need to install iOS 9 (beta) when using CoreSpotlight.

Related

iMessage App - iOS 10 localParticipantIdentifier.UUIDString does not translate in simulator

Below is a snippet showing adding a subcaption to a previously created MSMessage. Upon running in the simulator, the string prefixed with $ does not translate to the contact name as expected.
Bug in my code?
MSMessageTemplateLayout *templateLayout = [[MSMessageTemplateLayout alloc] init];
NSString *messageText = [NSString stringWithFormat:#"Challenged by $%#",
currentConversation.localParticipantIdentifier.UUIDString];
[templateLayout setSubcaption:messageText];
There is an open radar for it: https://openradar.appspot.com/26877873

iOS 9 - NSUserActivity userinfo property showing null

I had a quick question about NSUserActivity's userInfo property.
NSString *activity = #"com.test.activity";
NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:activity];
userActivity.title = #"Test";
userActivity.keywords = [NSSet setWithArray:#[#"Test"];
userActivity.userInfo = #{#"location": location};
userActivity.eligibleForSearch = YES;
self.userActivity = userActivity;
[self.userActivity becomeCurrent];
I have the above snippet implemented in one of view controllers viewDidLoad(). When my item appears within spotlight search it calls the continueUserActivity delegate method.
I'm trying to access the userActivity.userInfo property but it's returning null even though it's been set above.
Here's the continueUserActivity snippet:
-(BOOL)application:(nonnull UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray * __nullable))restorationHandler {
NSString *locationName = [[userActivity.userInfo objectForKey:#"location"] valueForKey: #"name"];
// Do stuff with locationName
return NO;
}
EDIT: I changed the location object to return as a primitive type but I'm still getting null on the delegate method.
Is anyone else having this problem in iOS 9 beta 3?
I'm working in iOS 9 beta 5, and another way that userInfo may be nil within the application:continueUserActivity:restorationHandler: is if you have also set NSUserActivity's webPageURL property. If you set the webPageURL property and would like userInfo to not be nil, then you will need to include the appropriate keys in NSUserActivity's requiredUserInfoKeys property. This took me forever to figure out, but shame on me for missing this in the docs.
NSUserActivity *activity = [[NSUserActivity alloc] initWithActivityType:activityType];
activity.title = #"title";
activity.webpageURL = [NSURL URLWithString:webLinkUrlString];
activity.userInfo = #{#"id": webLinkUrlString, #"deep_link": deepLinkUrl};
// set requiredUserInfoKeys if you're also setting webPageURL !!
// otherwise, userInfo will be nil !!
activity.requiredUserInfoKeys = [NSSet setWithArrays:#[#"id", #"deep_link"]];
activity.eligibleForSearch = YES;
activity.eligibleForPublicIndexing = YES;
activity.contentAttributeSet = attributeSet;
activity.keywords = [NSSet setWithArray:keywordsArray];
self.activity = activity;
[self.activity becomeCurrent];
Hi could you check in your continueUserActivity snippet:
if ([userActivity.activityType isEqualToString:#"com.test.activity"])
{
NSString *locationName = [[userActivity.userInfo objectForKey:#"location"] valueForKey: #"name"];
}
If it doesn't go there I assume that you have Core Spotlight integrated in your app and you get in Spotlight exactly by these elements from Core Spotlight.
Hope it was helpful.
P.S. At the moment(Xcode 7 beta 3) many developers can't get Search API through NSUserActivity to work, including me.
It was a problem with beta 3 that was causing this error. Everything is working fine as of beta 5.
See this question:
NSUserActivity handoff not working for custom data
userInfo is non-null if you follow this guideline from Apple:
To update the activity object’s userInfo dictionary efficiently, configure its delegate and set its needsSave property to YES whenever the userInfo needs updating. At appropriate times, Handoff invokes the delegate’s userActivityWillSave: callback, and the delegate can update the activity state.
The doc does say that setting webpageURL requires that requiredUserInfoKeys also be set. However (a) handoff works fine without requiredUserInfoKeys, as long as the 'userActivityWillSave' set userInfo, and (b) webURL is an iOS 8 parameter, whereas requiredUserInfoKeys is iOS 9. So the delegate method allows handoff to be supported in iOS 8 / Xcode 6.
I noticed (in the simulator) that you can set either:
webpage URL
userInfo and requiredUserInfoKeys
But not both! If you set both an webpageURL and userInfo with requiredUserInfoKeys, your activity won't even show up in spotlight on iOS.
I think this is because Apple assumes if you set the webpage URL that you support universal links and thus don't need any additional user info.
It is, however, OK to set both the webpage and just userInfo, but in your app delegate you won't receive the userInfo.
I had the same problem that UserInfo was nil (on iOS 9.2). The problem was that the search result wasn't the latest NSUserActivity which I have tapped (older one with no UserInfo). So I renamed the title to clearly identify the correct search result.
Maybe this helps someone, too.
For me on iOS 14 the issue was fixed by changing NSNumber values inside userInfo to String. I reproduced this in a simple test project. Maybe this happens only in Swift code, I didn't check Objective-C.

Make App Activities and States Searchable by using NSUserActivity

Following is the code that I am trying to implement to make app activities and states searchable but not able to show on iOS search
NSUserActivity *userActivity = [[NSUserActivity alloc]initWithActivityType:#"com.mycompany.activity-type"];
userActivity.title = #"Hello world from in app search";
userActivity.keywords = [NSSet setWithArray:#[#"Hello",#"Welcome", #"search"]];
userActivity.userInfo = #{#"id":#"com.example.state"};
userActivity.eligibleForSearch = YES;
[userActivity becomeCurrent];
Link to make my question more clear.
From the Apple Forums:
One thing that has bitten a few people (myself included) is that the
activity must not be deallocated. If your code is only working with
NSUserActivities (i.e. not using CoreSpotlight in addition) then make
sure your activities aren't being deallocated immediately.
In my
case, I had code that was allocating the NSUA, setting some properties
on it, calling becomeCurrent, but then the object would go out of
scope and deallocated. If you're doing this, try tossing the activity
into a strong property to see if you can then see the results when you
search.
https://forums.developer.apple.com/message/13640#13640
What I have found is you have to assign the NSUserActivity instance you have created to your currently visible UIViewControllers's userActivity property before calling -becomeCurrent. It has fixed it for me and the items immediately appeared both for handoff on other devices and in spotlight search on the same device.
I was experiencing the same issue, and I read on the dev forums that in seed 1 it only works on the device. I was able to make it work on the device.
It might be that this, as with handoff, will only work on the device sadly.
I couldn't get it to work with beta 2 either.
Using a CSSearchableItemAttributeSet with
CSSearchableItemAttributeSet* attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString*)kUTTypeImage];
attributeSet.title = myobject.title;
attributeSet.keywords = [myobject.desc componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
attributeSet.contentDescription = myobject.desc;
if (myobject.images.count > 0) {
attributeSet.thumbnailData = myobject.myimagedata;
}
attributeSet.rating = #(myobject.rating.integerValue / 2);
CSSearchableItem* item;
item = [[CSSearchableItem alloc] initWithUniqueIdentifier:#"..." domainIdentifier:#"..." attributeSet:attributeSet];
[[CSSearchableIndex defaultSearchableIndex] indexSearchableItems:#[item] completionHandler: ^(NSError * __nullable error) {
NSLog(#"Search item indexed");
}];
works, though, even with images.
What I couldn't get to work was the rating to show up anywhere.

Apple rejected my app for crashing on iphone 5

I know this question has been asked several times, but Im looking for a more general answer.
I have developed an app for iOS 6, I tested it on simulator(Retina 3.5 and 4 inch) and also on an iPhone 4 device.
It has never crashed but when I submitted the app to Apple and they answered with:
We found that your app crashed upon launch on iPhone 5 running iOS 6.1.3,
Looking at the crash log
We see that it crashes in line 164 from a index out of bounds, which makes sense because I have this code there:
I added that "if" to stop the execution whenever the indexTimesArray was bigger than the length of the array and see why that happened, but I was unable to reproduce the error. I never get an index out of bounds as they do...
It's true that I haven't test it on a iPhone 5 device, but I have XCode 4.6 and iOS 6.1 on my computer, and also a iPhone 4 with iOS 6.1.3, but it's also true that the guys at Apple are getting the app crashed, so how to reproduce the error?
I tried to install the app from TestFlight because it installs it as a brand new app, just like they do when they test it, but still no errors...
How can I reproduce the error? Could it be a problem with th build settings?
Thanks
[EDIT]
I initialize the contents of timesArray in the init method of the object, like this:
- (id)init{
self = [super init];
df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"yyyy-MM-dd HH:mm"];
rangeDates = [[NSArray alloc]initWithObjects:#"2013-04-11 10:00", #"2013-04-12 10:00", #"2013-04-13 10:00", #"2013-04-14 10:00", nil];
timesArray = [[NSArray alloc]initWithArray:[NSArray arrayWithObjects:#"10:00", #"11:00", #"12:00", #"13:00", #"14:00", #"15:00", #"16:00", #"17:00", #"18:00", #"19:00", #"20:00", #"21:00", #"22:00", nil]];
colorDictio = [[NSDictionary alloc]initWithObjects:[NSArray arrayWithObjects:[UIColor colorWithRed:0.74 green:0.66 blue:0.37 alpha:1.0], [UIColor colorWithRed:0.64 green:0.15 blue:0.11 alpha:1.0], [UIColor colorWithRed:0.313 green:0.65 blue:0.69 alpha:1.0], [UIColor colorWithRed:0.79 green:0.4 blue:0.59 alpha:1.0], [UIColor colorWithRed:0.45 green:0.55 blue:0.53 alpha:1.0], [UIColor colorWithRed:0.14 green:0.27 blue:0.66 alpha:1.0], nil] forKeys:[NSArray arrayWithObjects:#"showers area", #"zinctalks", #"zincnetwork", #"zincshows", #"zinclabs", #"zinczone", nil] ];
return self;
}
To figure out how to reproduce that error you have to look at the code where you create timesArray.
The out of bounds error happens because [timesArray count] is less than 2 (or the whole array is nil). So you have to figure out which condition leads to an array with one or zero objects. Maybe it happens because there is no internet connection.
It's always a good idea to wrap objectAtIndex: in a check for the actual size of the array.
I would replace else { with else if ([timesArray count] >= 2) { and add an additional else that handles <2 arrays.
First of all this is not a OS related error. Your app is crashing because the wrong index of array is being accessed.
How can I reproduce the error? : Try to use the same credential which you must have provided to apple.
Could it be a problem with th build settings? : No.
To debug the error what you can do is try to print the value of indexTimesArray before the if. Also, try to print all the values you are passing to access the array element. Which will help you track the wrong index which is being sent.
Thanks to #mayur, his comment is the right answer, "I had faced a similar error earlier with arrays in Objective-C... My suggestion would be to use self with NSMutableArrays or NSArrays"

How to set lock screen , wallpaper and Ringtone programmatically in iPhone?

In iPhone can we set the lock screen, wallpaper and ringtone programmatically?
If Yes, then please let me know how to set them?
This can all be done easily, but will be rejected by Apple.
The ringtone can be changed by altering com.apple.SpringBoard.plist, specifically the ringtone key.
The following code can be used to read the actual ringtone title of custom ringtones (synced by iTunes).
NSMutableDictionary *custDict = [[NSMutableDictionary alloc] initWithContentsOfFile:#"/private/var/mobile/Media/iTunes_Control/iTunes/Ringtones.plist"];
NSMutableDictionary *dictionary = [custDict objectForKey:#"Ringtones"];
NSArray *keys = [dictionary allKeys];
id key = [keys objectAtIndex:indexPath.row];
NSMutableDictionary *customRingtone = [dictionary objectForKey:key];
NSString *name = [customRingtone objectForKey:#"Name"];
cell.textLabel.text = name;
The Wallpapers can be overwritten at:
NSString *homePath1 = #"/private/var/mobile/Library/SpringBoard/HomeBackground.jpg";
NSString *homePath2 = #"/private/var/mobile/Library/SpringBoard/HomeBackgroundPortrait.jpg";
NSString *lockPath1 = #"/private/var/mobile/Library/SpringBoard/LockBackground.jpg";
NSString *lockPath2 = #"/private/var/mobile/Library/SpringBoard/LockBackgroundPortrait.jpg";
These examples were used in one of my Cydia apps. Theres not really much more to them, but these should get you going in the right direction.
The answer by WrightsCS stopped working at some point due to a change in iOS. Unfortunately, this is something you have to live with if you wish to use undocumented features.
If you still need to do this, for non-App Store apps only, this code works in iOS 9.3. It could stop working in any future iOS release, though. (see comment below: no longer working in iOS 10)
#import "SBSUIWallpaperPreviewViewController.h"
#import <dlfcn.h>
// open the private framework dynamically
void *handle = dlopen("/System/Library/PrivateFrameworks/SpringBoardUIServices.framework/SpringBoardUIServices", RTLD_NOW);
UIImage *wallpaper = [UIImage imageNamed: #"background.jpg"];
Class sbClass = NSClassFromString(#"SBSUIWallpaperPreviewViewController");
// we create a view controller, but don't display it.
// just use it to load image and set wallpaper
SBSUIWallpaperPreviewViewController *controller = (SBSUIWallpaperPreviewViewController*)[[sbClass alloc] initWithImage: wallpaper];
[controller setWallpaperForLocations: 3]; // 3 -> set both for lock screen and home screen
dlclose(handle);
You'll need to add the private API header to your project. You can usually find these online with a little searching, for example, here.
In the example above, [SBSUIWallpaperPreviewViewController setWallpaperForLocations:] is called with an argument of 3: 3 indicates the image should be used for both lock and home screens. 1 indicates Lock screen only. 2 indicates Home screen only.
For an explanation of why I open this framework up dynamically, see my related answer here.
I don't have an answer regarding ringtones. This really should be a separate question: completely different APIs at work.
use private api if you can
check PLStaticWallpaperImageViewController

Resources