42

We know that Xcode maintains environment variable of ${TARGET_NAME} but how to access this variable in objective-C code ?

What I have tried ?
I have added "TARGET_NAME=${TARGET_NAME}" this in Preprocessor macros section of Build Settings. But now I am not sure how to use this variable "TARGET_NAME" as a string in objective-C code.

In my case product name and target name are different so, no chance to use that.

I tried to access using

#ifdef TARGET_NAME
 NSLog(@"TargetIdentifier %@",TARGET_NAME);
#endif

This code is giving error like "Use of undeclared identifier 'myapptargetname'"

Iducool
  • 3,543
  • 2
  • 24
  • 45

7 Answers7

69

You can add "TargetName" key to your Info.plist file:

enter image description here

Then you can access it (swift code):

var plistFileName = NSBundle.mainBundle().infoDictionary?["TargetName"] as String
Sergey Demchenko
  • 2,924
  • 1
  • 24
  • 26
  • 1
    I had already achieved solution but didn't get time to updated here. Thanks for posting solution so, other can get help – Iducool Mar 29 '15 at 13:53
  • 1
    How do we access it on Objective C? And where should I type this code out? @Iducool I've spent so much time on finding this target name and I still cant find it :( – munmunbb Oct 09 '15 at 21:45
  • 1
    @WendyMunmunWang NSString *plistFileName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"TargetName"]; – Sergey Demchenko Oct 09 '15 at 23:12
  • 3
    @VasilValchev It works on xcode 7 as well. Please note that this key is not presented in Info.plist by default, you have to add it manually by yourself. – Sergey Demchenko Mar 14 '16 at 22:42
  • Not working now, must be updated to `let plistFileName = Bundle.main.infoDictionary?["TargetName"] as? String ?? ""` – mikep Feb 10 '21 at 13:11
30
NSLog(@"Target name: %@",[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]);

Hope to help you!

Edited: "CFBundleName" thanks Max and Daniel Bo for your commend

Jonny Vu
  • 1,420
  • 2
  • 13
  • 32
22

Swift 4, Xcode 9+

Bundle name:

Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String ?? ""

Bundle display name:

Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ?? ""

Swift 3, Xcode 8+

let targetName = Bundle.main.infoDictionary?["CFBundleName"] as? String ?? ""
Lawliet
  • 3,438
  • 2
  • 17
  • 28
  • 6
    doesnt print target name, it prints the display name :) – MBH Nov 01 '17 at 08:41
  • Not `CFBundleName`, nor `CFBundleDisplayName` return target name, most likely they will be set in Info.plist to return product name. – ivanzoid Jul 15 '20 at 06:38
3

Swift 5:

var plistFileName = Bundle.main.infoDictionary?["CFBundleName"]
Grenoblois
  • 503
  • 1
  • 5
  • 19
0

I must credit the original answer by vk.edward.li, as this answer only merely expands on it.

All the build setting macros can easily be used in source code as preprocessor macros too. The problem is that they're not set in advance; you have to specify which ones you get access to, yourself.

enter image description here

I've already added three extra preprocessor macros. Simply click the +, and add this: TARGET_NAME=\""$TARGET_NAME"\", and you've granted yourself access to one more build setting macro.

Project settings ––> Build Settings ––> Apple Clang - Preprocessing[Preprocessor Macros]. Note that if you try to insert them for both compilation modes at once, the DEBUG=1 macro will get deleted, but it can as easily be added right back afterwards.

It's also worth noting that the macro values should be set differently for different languages: Objective-C and C++/Swift, etc. This is due to the NSString prefix used in Objective-C, so for that language, it should be MACRO=@\""$MACRO"\" instead of MACRO=\""$MACRO"\".

0

If you have lots of targets this method will be move convenient than the one suggested by @Sergey Demchenko, as you'll do it once and there will be no need to do any changes in Info.plist if you add new target.

  1. Go to Project Build Settings (not Target's Build Settings), and add the following Preprocessor Macro(s):
TARGET_NAME="$(TARGET_NAME)"

enter image description here

  1. Now, we need to get value of this macro in our code. Swift doesn't support string macros, so we'll need to go back to good old Objective-C.

Add the following files:

AppTargetName.h:

#import <Foundation/Foundation.h>

NSString * _Nullable AppTargetName(void);

AppTargetName.m, with some C preprocessor magic (thanks to):

#import "AppTargetName.h"

#ifndef TARGET_NAME
    #define TARGET_NAME ""
#endif

#define STRINGIZE(x) #x
#define STRINGIZE2(x) STRINGIZE(x)
#define TARGET_NAME_STRING @ STRINGIZE2(TARGET_NAME)

NSString * _Nullable AppTargetName() {
    if (TARGET_NAME_STRING.length == 0) {
        return nil;
    } else {
        return TARGET_NAME_STRING;
    }
}
  1. Add #import "AppTargetName.h" to Obj-c Bridging header (and add/configure it if you don't have one).

  2. And now in Swift, you may call AppTargetName() and get your target name, without need to modify Info.plist if you add new target!

if let targetName = AppTargetName() {
    print("Target Name = \(targetName)")
}

ivanzoid
  • 5,952
  • 2
  • 34
  • 43
-1

In Xcode 7.3.1

if let targetName = NSBundle.mainBundle().infoDictionary?["CFBundleName"] as? String{
    print(targetName)
}
Atef
  • 2,872
  • 1
  • 36
  • 32