Does the SDK provide an API for retrieving the current Macbook's UUID?
So, if you don't care about the new AppStore rules etc... here you go:
- (NSString *)getSystemUUID {
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,IOServiceMatching("IOPlatformExpertDevice"));
if (!platformExpert)
return nil;
CFTypeRef serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert,CFSTR(kIOPlatformUUIDKey),kCFAllocatorDefault, 0);
if (!serialNumberAsCFString)
return nil;
IOObjectRelease(platformExpert);
return (__bridge NSString *)(serialNumberAsCFString);;
}
Please Note:
You need to add IOKit.framework to your project in order for this
to work.
This code is ARC compliant;
This code is safe and it will return a nil NSString if something goes wrong;
Apple does not guarantee that all future systems will have a software-readable serial number.
Developers should not make any assumptions about the
format of the serial number such as its length or what characters it
may contain.
Related
I would like to detect if a given provisioning profile is a development profile or a distribution (adhoc or app store) profile. I need to do this purely programmatically.
I already understand how to detect adhoc vs appstore. And am specifically interested in dev vs. distribution.
I've examined the plists internal to each type of profile and cannot find a discernable difference (via security cms -D -i #{#profilePath}). I've also looked into the openssl api and am using this for some certificate manipulation.
This is for a custom xcode automated build system. As part of pre-build validation I need to ensure that the specified profile is not for development.
Is this even possible? If so, how can I programmatically differentiate between the two?
Thanks in advance for any ideas!
I've build a more concise and efficient version of Toom's code:
I'll maintain code snippets like this in a gist, you might find a more up to date version here: https://gist.github.com/steipete/7668246
static BOOL PSPDFIsDevelopmentBuild(void) {
#if TARGET_IPHONE_SIMULATOR
return YES;
#else
static BOOL isDevelopment = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// There is no provisioning profile in AppStore Apps.
NSData *data = [NSData dataWithContentsOfFile:[NSBundle.mainBundle pathForResource:#"embedded" ofType:#"mobileprovision"]];
if (data) {
const char *bytes = [data bytes];
NSMutableString *profile = [[NSMutableString alloc] initWithCapacity:data.length];
for (NSUInteger i = 0; i < data.length; i++) {
[profile appendFormat:#"%c", bytes[i]];
}
// Look for debug value, if detected we're a development build.
NSString *cleared = [[profile componentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet] componentsJoinedByString:#""];
isDevelopment = [cleared rangeOfString:#"<key>get-task-allow</key><true/>"].length > 0;
}
});
return isDevelopment;
#endif
}
This was something I tackled in one of my own build systems for much the same purpose...let's take a trip back in time to Day 1 of the then 'iPhone Developer Program'. If you were around the community at that time, you may remember that the toolchain was...shall we say less friendly...than it is today.
When you wanted to build for the AppStore or for AdHoc builds you had to make this curious entitlements.plist file, then paste a blob of XML into the body of that file. You then ran the build and at that time what appeared to be magic occurred and the sheer presence of that file made the build work, allowed you to manually construct your IPA, and carry on with business as usual. Now that we are a few years older and hopefully a bit wiser than in those early days of the SDK, we have come to recognize that the magic XML blob wasn't actually so magical at all -- the 'get-task-allow' key is a setting to indicate if the binary should allow other processes (like perhaps a debugger) to attach to the binary. When signing apps using a Development Provisioning Profile, this key will be set to 'true' (and thus allow LLDB to attach and interact with your app)...and naturally when signing apps using a Distribution Provisioning Profile, this key will be set to 'false'.
Apple has provided some updates in Tech Note TN2250 about reading the XML (and by extension the entitlements) out of Provisioning Profiles:
security cms -D -i /path/to/the.app/embedded.mobileprovision
This will return the XML in the Provisioning profile -- from there you can parse out the key value pair for 'get-task-allow' and use that value to determine if the Provisioning Profile is Development or Distribution.
I absolutely agree that it would be nice to have a tool that would tell us that directly so we don't have to sniff through the profile for clues, but at the same time, at least we have a highly reliable, albeit roundabout way to make that distinction before running off and making a build we can't use.
Good luck and let me know if you need any more clarification or have other questions.
Based on Bryan Musial great answer I wrote some code that allow you to check "get-task-allow" directly from application at runtime. In my case I'm using this boolean to only log in debug apps :
+ (BOOL)isDevelopmentApp
{
// Special case of simulator
if (isSimulator)
{
return YES;
}
// There is no provisioning profile in AppStore Apps
NSString *profilePath = [[NSBundle mainBundle] pathForResource:#"embedded" ofType:#"mobileprovision"];
// Check provisioning profile existence
if (profilePath)
{
// Get hex representation
NSData *profileData = [NSData dataWithContentsOfFile:profilePath];
NSString *profileString = [NSString stringWithFormat:#"%#", profileData];
// Remove brackets at beginning and end
profileString = [profileString stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:#""];
profileString = [profileString stringByReplacingCharactersInRange:NSMakeRange(profileString.length - 1, 1) withString:#""];
// Remove spaces
profileString = [profileString stringByReplacingOccurrencesOfString:#" " withString:#""];
// Convert hex values to readable characters
NSMutableString *profileText = [NSMutableString new];
for (int i = 0; i < profileString.length; i += 2)
{
NSString *hexChar = [profileString substringWithRange:NSMakeRange(i, 2)];
int value = 0;
sscanf([hexChar cStringUsingEncoding:NSASCIIStringEncoding], "%x", &value);
[profileText appendFormat:#"%c", (char)value];
}
// Remove whitespaces and new lines characters
NSArray *profileWords = [profileText componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *profileClearText = [profileWords componentsJoinedByString:#""];
// Look for debug value
NSRange debugRange = [profileClearText rangeOfString:#"<key>get-task-allow</key><true/>"];
if (debugRange.location != NSNotFound)
{
return YES;
}
}
// Return NO by default to avoid security leaks
return NO;
}
Here is a version for Swift 3, based on #steipete's answer:
static func isDevelopmentProvisioningProfile() -> Bool {
#if IOS_SIMULATOR
return true
#else
// there will be no provisioning profile in AppStore Apps
guard let fileName = Bundle.main.path(forResource: "embedded", ofType: "mobileprovision") else {
return false
}
let fileURL = URL(fileURLWithPath: fileName)
// the documentation says this file is in UTF-8, but that failed
// on my machine. ASCII encoding worked ¯\_(ツ)_/¯
guard let data = try? String(contentsOf: fileURL, encoding: .ascii) else {
return false
}
let cleared: String = data.components(separatedBy: .whitespacesAndNewlines).joined()
return cleared.contains("<key>get-task-allow</key><true/>")
#endif
}
If curious, get-task-allow is a flag that the build uses to determine whether you should be able to hook up a debugger and other processes like that - so it's quite accurate for whether it is a dev build or no.
NSError *error;
NSString *string = [[NSString alloc]
initWithContentsOfURL:URL
encoding:NSUTF8StringEncoding
error:&error];
When I test this on my iPhone it always works when I have wifi turned on. However when I'm on 3G I often get nil. If I try perhaps 15 times in a row (I have an update button for this) I finally get the desired result.
My question is, is this problem located at the server side or is my code unstable? Should I use a different approach to get a more secure fetch of data?
You haven't provided enough information to give anything but a vague answer, but you do have some options here.
Most importantly, you have an "error" parameter that you should be printing out the results of. There's also a slightly better API you could be using in the NSString class.
Change your code to something like this:
NSError *error = NULL;
NSStringEncoding actualEncoding;
// variable names in Objective-C should usually start with lower case letters, so change
// URL in your code to "url", or even something more descriptive, like "urlOfOurString"
NSString *string = [[NSString alloc] initWithContentsOfURL:urlOfOurString usedEncoding:&actualEncoding error:&error];
if(string)
{
NSLog( #"hey, I actually got a result of %#", string);
if(actualEncoding != NSUTF8StringEncoding)
{
// I also suspect the string you're trying to load really isn't UTF8
NSLog( #"and look at that, the actual encoding wasn't NSUTF8StringEncoding");
}
} else {
NSLog( #"error when trying to fetch from URL %# - %#", [urlOfOurString absoluteString], [error localizedDescription]);
}
I'm now using STHTTPRequest instead. I recommend this library very much, easy to use yet powerful.
Is there any replacement for Windows's CreateFont(..) function in OSX?
I've tried to use NSFontDescriptor and its matchingFontDescriptorsWithMandatoryKeys: method, but this method doesn't find the "closest" font, it finds the matched characteristics and also it can return nil.
Is there any way to find the closest font by specified characteristics (like a CreateFont) in OSX?
UPDATED
Something strange happens with NSFontDescriptor..
I have two pieces of code:
on Cocoa:
NSDictionary* fontTraits = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:NSFontSansSerifClass], NSFontSymbolicTrait,
[NSNumber numberWithFloat:0.4], NSFontWidthTrait,
nil];
NSDictionary* fontAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
fontTraits, NSFontTraitsAttribute,
nil];
NSFontDescriptor* fontDescriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:fontAttributes];
NSArray* matchedDescriptors = [fontDescriptor matchingFontDescriptorsWithMandatoryKeys:nil];
And using CoreText API:
CFMutableDictionaryRef fontTraits = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
float weight = 0.4;
CFNumberRef fontWeight = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloat32Type, &weight);
CFDictionaryAddValue(fontTraits, kCTFontWeightTrait, fontWeight);
int symbolicTraits = kCTFontSansSerifClass;
CFNumberRef fontSymbolicTraits = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &symbolicTraits);
CFDictionaryAddValue(fontTraits, kCTFontSymbolicTrait, fontSymbolicTraits);
CFMutableDictionaryRef fontAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(fontAttributes, kCTFontTraitsAttribute, fontTraits);
CTFontDescriptorRef fontDescriptor = CTFontDescriptorCreateWithAttributes(fontAttributes);
CFArrayRef matchedDescriptors = CTFontDescriptorCreateMatchingFontDescriptors(fontDescriptor, 0);
I've created the same font descriptors in both cases, but in first case matchedDescriptors is nil and with CoreText API there are some fonts in matchedDescriptors. Is it a bug?
But in general, if I pass nil to XXXMatchingFontDescriptorsXXX as mandatory attribute, should it return at least one descriptor?
I would please file a Radar if you haven't. I just got bit by this same difference in behavior myself.
A surprising thing while debugging, I found that [fontDescriptor matchingFontDescriptorWithMandatoryKeys:] is actually defined, though not documented, and functions as expected for a single descriptor that is. Meaning, it works just like CTFontDescriptorCreateMatchingFontDescriptor().
While [fontDescriptor matchingFontDescriptorsWithMandatoryKeys:] definitely appears broken to me.
I found this problem when I was using [UIFont fontWithDescriptor:size:], and it was matching things just fine, and as expected. Then I switched to [fontDescriptor matchingFontDescriptorsWithMandatoryKeys:nil], and it returned nil for the same descriptor.
Something felt off, so I compared with CoreText APIs as you did, and came to the conclusion that I am sharing with you here.
I know you are looking at the list versions of these methods, I figured I would share that I went with this method in a UIFontDescriptor category:
- (nullable instancetype)my_matchingFontDescriptorWithMandatoryKeys:(nullable NSSet<UIFontDescriptorAttributeName> *)mandatoryKeys {
return (__bridge_transfer UIFontDescriptor *)CTFontDescriptorCreateMatchingFontDescriptor((__bridge CTFontDescriptorRef)self, (__bridge CFSetRef)mandatoryKeys);
}
I am a newbie so I apologise if I am missing something obvious.
I am trying to write an app in Xcode 4 to produce stats for my local sports team.
This is the relevant detail of the problem area of my programme:
NSError *error;
NSArray *games = [context executeFetchRequest:fetchRequest error:&error];
if (games == nil) {
NSLog(#"There was an error!");
}
int noOfBatOuts = games.count;
int noOfNotOuts=0;
for (NSManagedObject *oneMatch in games) {
if ([oneMatch valueForKey:#"batOut"]==#"NO") {
noOfBatOuts = noOfBatOuts - 1;
noOfNotOuts = noOfNotOuts + 1;
NSLog(#"Not Out!");
}
NSLog(#"How out %#",[oneMatch valueForKey:#"batOut"]);
}
notOuts.text=[NSString stringWithFormat:#"%d",(noOfNotOuts)];
NSLog(#"No of Not Outs is %#",notOuts.text);
When I run with data that has a not out string - NO, - the NSLog(#"Not Out!") is never called and the final NSLog(#"No of Not Outs...) reports zero. However I know that the data is there and it is identified in the middle NSLog(#"How Out....).
I am starting to tear my hair out in frustration and not having the knowledge yet to know the answer. Can anybody help please?
I would assume that batOut is a Boolean rather than string type, in which case you should be checking for truth rather than string equality.
If batOut really is a string, then you still can't compare strings this way. You need to use isEqual: or isEqualToString:. For example:
if ([[oneMatch valueForKey:#"batOut"] isEqual:#"NO"]) {
Normally you'd use isEqualToString: for string comparisons, but -valueForKey: is an id so isEqual: is safer.
The == operator checks that two pointers have the same value. Two strings can have the same contents but not be stored in the same memory.
You can't compare strings with ==. Use NSString's isEqualToString:
I often use Transformable for Core Data attributes, so I can change them later.
However, it seems like, if I want to use NSPredicate to find a NSManagedObject, using "uniqueKey == %#", or "uniqueKey MATCHES[cd] %#", it's not working as it should.
It always misses matching objects, until I change the attributes of the uniqueKey of the matching object to have specific class like NSString, or NSNumber.
Can someone explain the limitation of using NSPredicate with Transformable attributes?
Note: I'm not sure when/if this has changed since 5/2011 (from Scott Ahten's accepted answer), but you can absolutely search with NSPredicate on transformable attributes. Scott correctly explained why your assumptions were broken, but if Can someone explain the limitation of using NSPredicate with Transformable attributes? was your question, he implied that it is not possible, and that is incorrect.
Since the is the first google hit for "Core Data transformable value search nspredicate" (what I searched for trying to find inspiration), I wanted to add my working answer.
How to use NSPredicate with transformable properties
Short, heady answer: you need to be smart about your data transformers. You need to transfrom the value to NSData that contains what I'll call "primitive identifying information", i.e. the smallest, most identifying set of bytes that can be used to reconstruct your object. Long answer, ...
Foremost, consider:
Did you actual mean to use a transformable attribute? If any supported data type -- even binary data -- will suffice, use it.
Do you understand what transformable attributes actually are? How they pack and unpack data to and from the store? Review Non-Standard Persistent Attributes in Apple's documentation.
After reading the above, ask: does custom code that hides a supported type "backing attribute" work for you? Possibly use that technique.
Now, past those considerations, transformable attributes are rather slick. Frankly, writing an NSValueTransformer "FooToData" for Foo instances to NSData seemed cleaner than writing a lot of adhoc custom code. I haven't found a case where Core Data doesn't know it needs to transform the data using the registered NSValueTransformer.
To proceed simply address these concerns:
Did you tell Core Data what transformer to use? Open the Core Data model in table view, click the entity, click the attribute, load the Data Model Inspector pane. Under "Attribute Type: Transformable", set "Name" to your transformer.
Use a default transformer (again, see the previous Apple docs) or write your own transformer -- transformedValue: must return NSData.
NSKeyedUnarchiveFromDataTransformerName is the default transformer and may not suffice, or may draw in somewhat-transient instance data that can make two similar objects be different when they are equal.
The transformed value should contain only -- what I'll call -- "primitive identifying information". The store is going to be comparing bytes, so every byte counts.
You may also register your transformer globally. I have to do this since I actually reuse them elsewhere in the app -- e.g. NSString *name = #"FooTrans"; [NSValueTransformer setValueTransformer:[NSClassFromString(name) new] forName:name];
You probably don't want to use transforms heavily queried data operations - e.g. a large import where the primary key information uses transformers - yikes!
And then in the end, I simply use this to test for equality for high-level object attributes on models with NSPredicates -- e.g. "%K == %#" -- and it works fine. I haven't tried some of the various matching terms, but I wouldn't be surprised if they worked sometimes, and others not.
Here's an example of an NSURL to NSData transformer. Why not just store the string? Yeah, that's fine -- that's a good example of custom code masking the stored attribute. This example illustrates that an extra byte is added to the stringified URL to record if it was a file URL or not -- allowing us to know what constructors to use when the object is unpacked.
// URLToDataTransformer.h - interface
extern NSString *const kURLToDataTransformerName;
#interface URLToDataTransformer : NSValueTransformer
#end
...
// URLToDataTransformer.m - implementation
#import "URLToDataTransformer.h"
NSString *const kURLToDataTransformerName = #"URLToDataTransformer";
#implementation URLToDataTransformer
+ (Class)transformedValueClass { return [NSData class]; }
+ (BOOL)allowsReverseTransformation { return YES; }
- (id)transformedValue:(id)value
{
if (![value isKindOfClass:[NSURL class]])
{
// Log error ...
return nil;
}
NSMutableData *data;
char fileType = 0;
if ([value isFileURL])
{
fileType = 1;
data = [NSMutableData dataWithBytes:&fileType length:1];
[data appendData:[[(NSURL *)value path] dataUsingEncoding:NSUTF8StringEncoding]];
}
else
{
fileType = -1;
data = [NSMutableData dataWithBytes:&fileType length:1];
[data appendData:[[(NSURL *)value absoluteString] dataUsingEncoding:NSUTF8StringEncoding]];
}
return data;
}
- (id)reverseTransformedValue:(id)value
{
if (![value isKindOfClass:[NSData class]])
{
// Log error ...
return nil;
}
NSURL *url = nil;
NSData *data = (NSData *)value;
char fileType = 0;
NSRange range = NSMakeRange(1, [data length]-1);
[data getBytes:&fileType length:1];
if (1 == fileType)
{
NSData *actualData = [data subdataWithRange:range];
NSString *str = [[NSString alloc] initWithData:actualData encoding:NSUTF8StringEncoding];
url = [NSURL fileURLWithPath:str];
}
else if (-1 == fileType)
{
NSData *actualData = [data subdataWithRange:range];
NSString *str = [[NSString alloc] initWithData:actualData encoding:NSUTF8StringEncoding];
url = [NSURL URLWithString:str];
}
else
{
// Log error ...
return nil;
}
return url;
}
#end
Transformable attributes are usually persisted as archived binary data. As such, you are attempting to compare an instance of NSData with an instance of NSString or NSNumber.
Since these classes interpret the same data in different ways, they are not considered a match.
you can try this way
NSExpression *exprPath = [NSExpression expressionForKeyPath:#"transformable_field"];
NSExpression *exprKeyword = [NSExpression expressionForConstantValue:nsdataValue];
NSPredicate *predicate = [NSComparisonPredicate predicateWithLeftExpression:exprPath rightExpression:exprKeyword modifier:NSDirectPredicateModifier type:NSEqualToPredicateOperatorType options:0];