I am changing the name of my app based on the device it is running on through configuration files, i.e. I put in an _iPhone, _iPad or _Universal in the display name accordingly.
To do this I am using xcconfig files as follows:
TARGETED_DEVICE_FAMILY = 1,2
APP_NAME1 = Something_iPhone
APP_NAME2 = Something_iPad
APP_NAME1,2 = Something_Universal //1,2 The "," causes a problem here.
The problem is that the comma character is causing a problem:
*Build setting 'APP_NAME1,2' does not have a valid base name.*
Any ideas?
No apps will be approved for app store with using the trade marked names such as iPhone or iPad try using something else. I have had that even in the binary and not in the display and they rejected it in review. If you want to create a set of codes for universal porpose the take a look at this code snippet. I use this a lot in my universal apps.
`if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
NSLog(#"iPad Idiom");
else
#else
NSLog(#"iPhone Idiom");
#endif
Adrian
Related
I've got this source (xcode 3.2.5):
NSLog(#"IPHONE = %d, SIMULATOR = %d, MAC = %d", TARGET_OS_IPHONE, TARGET_IPHONE_SIMULATOR, TARGET_OS_MAC);
And I get this result:
2012-03-30 13:50:06.777 MyApp[36810:207] IPHONE = 1, SIMULATOR = 1, MAC = 1
No wonder my #if statements are confused!
What gives? Any ideas?
FWIW: On (tethered) iPod Touch I get this: IPHONE = 1, SIMULATOR = 0, MAC = 1
Added: Well, I figured out that my original problem with #if was due to misspelling TARGET_OS_IPHONE as TARGET_OS_PHONE in several places. (Good ol' copy/paste!)
Would still like to find a definitive description of how Apple's defines are supposed to be set.
Use TARGET_OS_IPHONE (only!) for differentiating between iOS and OSX.
#if TARGET_OS_IPHONE
// iOS
#else
// Mac OS X
#endif
TARGET_OS_MAC will be 1 on both OSX and iOS; it predates iOS, and iOS is considered a variant of OSX as far as TargetConditionals.h is concerned.
I might be wrong here, but my assumption was that TARGET_OS_MAC specifies that you are building for Mac OS X (as opposed to, say, win32). iOS is actually a version of Mac OS X (although it is not branded / marketed as such).
To see how they are all defined, choose a build target and command-click their definition in xcode.
In the header file, the macros are defined as such:
TARGET_OS_MAC - Generate code will run under Mac OS
TARGET_OS_WIN32 - Generate code will run under 32-bit Windows
TARGET_OS_UNIX - Generate code will run under some non Mac OS X unix
TARGET_OS_EMBEDDED - Generate code will run under an embedded OS variant
of TARGET_OS_MAC
TARGET_OS_IPHONE - Generate code will run under iPhone OS which
is a variant of TARGET_OS_MAC.
So, it can be expected that TARGET_OS_MAC is defined for iOS, as well as TARGET_OS_IPHONE for example.
I'm looking at using openUDID inside my app for registration purposes.
However its still using the UDID number apple issues and so I was just reading though the .m file and came across this:
// One day, this may no longer be allowed in iOS. When that is, just comment this line out.
//
#if TARGET_OS_IPHONE
if([UIDevice instancesRespondToSelector:#selector(uniqueIdentifier)]){
_openUDID = [[UIDevice currentDevice] uniqueIdentifier];
}
#endif
// Take this opportunity to give the simulator a proper UDID (i.e. nullify UDID and create an OpenUDID)
//
#if TARGET_IPHONE_SIMULATOR
_openUDID = nil;
#endif
// Next we try to use an alternative method which uses the host name, process ID, and a time stamp
// We then hash it with md5 to get 32 bytes, and then add 4 extra random bytes
// Collision is possible of course, but unlikely and suitable for most industry needs (e.g.. aggregate tracking)
//
However I'm not sure exactly what line to comment out so that it used the alternative method which uses the host name, process ID, and a time stamp
You would comment out the 3 lines of code in the TARGET_OS_IPHONE block
You can "comment" out the line with uniqueIdentifier in it by prefixing that line using double slash comment.... or you can change the #if TARGET_OS_IPHONE line to #if 0, which means that block of code will never get called at all.
And then the alternative code will get used instead.
The way the code is currently written, it seems pretty safe to me to just leave it as is. Once Apple does completely do away with the uniqueIdentifier method, the instancesRespondToSelector call will properly fail and the alternative code will get used automatically.
Is there a way to determine programmatically if the currently running app was built and signed for development only or whether it was built for distribution? And can one determine if was build for app store or ad hoc distribution?
Is it e.g. possibly to access the code signature and get the information from there? Or are there certain files present in one of variants that don't exist in the other ones? Is part of the bundle info? Or can it be derived from the executable file?
Any hints are appreciated.
It seems that the embedded.mobileprovision file is in ASN.1 format.
The easiest way to check is to look at embedded.mobileprovision ([[NSBundle mainBundle] pathForResource:#"embedded.mobileprovision" ofType:nil]):
It's a bit of a pain to parse since it's a signed plist (PKCS#7 signed data, according to openssl asn1parse -inform der), but a bad hack is to just look for <plist and </plist>.
Development contains UDIDs and <key>get-task-allow</key><true/>
Ad Hoc distribution contains UDIDs (and get-task-allow=false)
App Store distribution contains no UDIDs.
The other thing you can check is the entitlements embedded in the executable (otool -l lists it as LC_CODE_SIGNATURE). Parsing this is even more tedious (you need to parse the Mach-O header and load commands, and for "universal" binaries which are now the default, you'll need to check the currently-loaded architecture or all architectures).
Development builds contain <key>get-task-allow</key><true/>
Ad Hoc and App Store builds contain <key>get-task-allow</key><false/>
I don't think the entitlements distinguish between Ad Hoc and App Store builds.
Apart from those and the certificate it's signed with, there's no difference between Development/Ad Hoc/App Store apps (there are a few other things in the entitlements/provisioning profile, but nothing more reliable that I can think of).
Security considerations
Neither of these are that difficult to circumvent. For the first method, the app could just "swizzle" -[NSBundle pathForResource:ofType:]. The second method is a bit more difficult depending on what API you use to read the file.
openssl asn1parse -inform DEM -in *Mobile_Provision_File* -strparse 54 is the easiest way to access the data that I've found.
EDIT:
security cms -D -i *Mobile_Provision_File* is actually easier. The openssl command leaves some garbage in the output.
I've extracted an embedded.mobileprovision file and pasted into an online ASN.1 viewer (e.g. http://www.geocities.co.jp/SiliconValley-SanJose/3377/asn1JS.html), and that's what a got:
SEQUENCE {
OBJECTIDENTIFIER 1.2.840.113549.1.7.2 (signedData)
[0] {
SEQUENCE {
INTEGER 1
SET {
SEQUENCE {
OBJECTIDENTIFIER 1.3.14.3.2.26
NULL
}
}
SEQUENCE {
OBJECTIDENTIFIER 1.2.840.113549.1.7.1 (data)
[0] {
OCTETSTRING 3c3f786d6c20766 ... 6c6973743e0a
}
}
[0] {
SEQUENCE {
SEQUENCE {
[0] {
INTEGER 2
}
... [much more]
With this and some ASN.1 knowledge, your explanation makes perfect sense.
The interesting part is the octet string starting 3c3f786d6c. That's the XML part in Apple's property list format that contains all the answers about the distribution type (developer, ad-hoc, App Store).
#if (DEBUG)
#define SERVER #"aaaa.com/dev"
#else
#define SERVER #"aaa.com/pro"
#endif
that's the way i distinguish the debug and release mode ,
but i have no idea for adhoc or production unless use the provision profile name
I create a gist to detect Ad Hoc build
See : https://gist.github.com/iShawnWang/d904934efded271d83b36288562df410
AdHoc detect with following 2 conditions :
1.embedded.mobileprovision contains field ProvisionedDevices (Debug and Ad Hoc Build contains this field ,Release not)
2.it is not DEBUG Build , we can use #ifdef DEBUG to decide it
NS_INLINE BOOL isAdHoc(){
BOOL isAdHoc = NO;
BOOL isDebug;
#ifdef DEBUG
isDebug=YES;
#else
isDebug=NO;
#endif
NSData *data=[NSData dataWithContentsOfURL:[[NSBundle mainBundle]URLForResource:#"embedded" withExtension:#"mobileprovision"]];
NSString *str=[[NSString alloc]initWithData:data encoding:NSISOLatin1StringEncoding];
NSRange rangeOfDevicesUDIDs = [str rangeOfString:#"ProvisionedDevices"];
isAdHoc = rangeOfDevicesUDIDs.location!=NSNotFound && !isDebug;
return isAdHoc;
}
I'm having trouble compiling the current release.
I was able to download a copy of the source distribution today using:
hg clone https://core-plot.googlecode.com/hg/ core-plot
I opened the "core-plot/framework".
I then double clicked on CorePlot-CocoaTouch.xcodeproj to launch Xcode.
When I build the project I get the following error:
-(void)bind:(NSString *)binding toObject:(id)observable withKeyPath:(NSString *)keyPath options:(NSDictionary *)options
{
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
[NSException raise:CPException format:BindingsNotSupportedString];
Format not a string literal and no formal arguments
#else
[super bind:binding toObject:observable withKeyPath:keyPath options:options];
#endif
}
I am running on a new MacBook with OS 10.6, and IPhone Simulator 4.0.
Any help will be greatly appreciated.
Charles
A more appropriate place to ask this question would be the Core Plot mailing list, because I'm one of the few developers for the project that regularly visits here.
That said, the issue here is that we're using a string constant for a format string, which Xcode now seems to be warning about (rightly so, as this can lead to problems). To work around this for now, you can replace the line in CPLayer.m
static NSString * const BindingsNotSupportedString = #"Bindings are not supported on the iPhone in Core Plot";
with
#define BindingsNotSupportedString #"Bindings are not supported on the iPhone in Core Plot"
Search in your project for BindingsNotSupportedString, seems like it's not in the current file and therefore needs to be included. Or just try to change this to an acceptable format.
I'm trying to have 2 version of my iPhone application within the same XCode project.
The codebase it's almost the same and where I need to have different behaviours I've decided to use preprocessor's conditionals and the ${TARGET_NAME} tag.
I've set the OTHER_CFLAGS to contain "-DTARGET_NAME=${TARGET_NAME}".
Then in my code I tried to do
#if TARGET_NAME == myApp
NSLog(#"pro");
#elif TARGET_NAME == myAppLite
NSLog(#"lite");
#endif
Unfortunately I always get "lite" printed out since TARGET_NAME == myApp it's always true: since TARGET_NAME is defined. I cannot for the life of me figure out how to evaluate this string comparison.
Any idea?
thanks in advance
You can't compare strings like that in an #if block. Instead, add the defines to each specific target. For instance, on the full version's target, open the Info panel and go to the build tab and add something like FULL_VERSION to the GCC_PREPROCESSOR_DEFINITIONS build setting. Then, for the lite target, enter something like LITE_VERSION. In your code, you can do:
#ifdef FULL_VERSION
NSLog(#"Full");
#else
NSLog(#"Lite");
#endif
Actually you can get the target's name to compare it, but this will not skip unnecessary code from other targets at compile time, to do this:
First go to menu Product -> Scheme -> Edit Scheme... (or CMD + <)
Then in the arguments section, add inside environment variables something like:
In your code you can get the target's name as:
NSString *targetName = [[NSProcessInfo processInfo] environment][#"TARGET_NAME"];
NSLog(#"target = %#", targetName); // Will print the target's name
You can compare that string now in runtime.
But following your example: if you want that all the Pro version code to be omitted at compile time. You should do what #jason-coco says. And go to preprocessor macros in build settings, and add $(TARGET_NAME) there:
The code inside the #define will be compiled and executed if my target is "MLBGoldPA"
#if defined MLBGoldPA
NSLog(#"Compiling MLBGoldPA");
#endif
to get your conditional evaluation working, you have to do something like:
#define myApp 1
#define myAppLite 2
beforehand, like in your _Prefix.pch file.