This is likely not limited to iOS Universal Frameworks but all xxx.framework files. However I can't seem to find documentation on how to get the current version and build of a framework within the client application. Within an app you'd use something like:
NSString *name = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleDisplayName"];
NSString *build = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"];
That would give you the current information stored in the Info.plist for the app. But how to we find that information for a framework. And in my case, specifically an embedded framework.
Here's a solution that does work with Universal Frameworks. Just replace SomeFrameworkClass with a class from the desired framework.
if let sdkVersion = Bundle(for: SomeFrameworkClass.self).infoDictionary?["CFBundleShortVersionString"] {
// sdkVersion is available here
}
I have found that Apple's new Cocoa Touch frameworks supported in Xcode 6, offer an easy answer to this problem. In the default header file created for you, something like Framework.h, you'll see two constants declared for you. These are defined later presumably at runtime by internal framework logic. But I have confirmed they're pulled from the plist for the framework.
//! Project version number for LocalSearch.
FOUNDATION_EXPORT double FrameworkVersionNumber;
//! Project version string for LocalSearch.
FOUNDATION_EXPORT const unsigned char FrameworkVersionString[];
Let's say Foo is a class from the given framework, you can use something like :
NSDictionary *infoDictionary = [[NSBundle bundleForClass: [Foo class]] infoDictionary];
NSString *name = [infoDictionary valueForKey:(__bridge NSString*)kCFBundleNameKey];
NSString *version = [infoDictionary valueForKey:(__bridge NSString*)kCFBundleVersionKey];
NSLog(#"%# version %#", name, version);
In Swift :
// `Foo` is a type defined in the framework
if let infos = Bundle(for: Foo.self).infoDictionary,
let name = infos[kCFBundleNameKey as String],
let version = infos[kCFBundleVersionKey as String] {
print("Using \(name) version \(version)")
if let shortVersion = infos["CFBundleShortVersionString"] as? String {
print("Short version : " + shortVersion)
}
}
Note : For some reason, "CFBundleShortVersionString" is not defined in a constant, cf Is there a constant defined for CFBundleShortVersionString in iOS/MacOS framework
This is for who may want to have a function on your framework that returns or print on the console it's version with build number. Just make sure you are using the class you are sharing on your Framework.h when declaring the *infoDictionary. In my example I'm using a class named cloud
+(NSString *)frameWorkVersion {
NSDictionary *infoDictionary = [[NSBundle bundleForClass: [cloud class]] infoDictionary];
NSString *version = [infoDictionary objectForKey:#"CFBundleShortVersionString"];
NSString *build = [infoDictionary objectForKey:(NSString *)kCFBundleVersionKey];
NSString *fVersion = [NSString stringWithFormat:#"%#.%#",version,build];
NSLog(#"Framework Version %#",fVersion);
return fVersion; }
Related
I'm writing an iOS SDK using Objective-C programming language. I would like to know if there is a field in Xcode where i can set version number for SDK
Is there a way in objective-C to set version and build number the way we do it for iOS apps (EX: Version: 2.5.1 Build: 2.5.1.12) ?
Also need a way to detect this version number so i can expose an API something like
- (NSString *)getSDKVersion {
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString *majorVersion = [infoDictionary objectForKey:#"CFBundleShortVersionString"];
NSString *minorVersion = [infoDictionary objectForKey:#"CFBundleVersion"];
return [NSString stringWithFormat:#"SDK Version %# (%#)", majorVersion, minorVersion];
}
-(NSString*)getSDKBuildVersion;
Which returns the SDK version and build number.
Using:
Xcode - 7.0 (Beta 3 version)
Thanks in advance.
You can set version and build number clicking in the Project(left side) -> General tab(right side) -> Identity section. You will find the fields: Bundle Identifier, Version and Build.
For get the values programmatically:
NSDictionary *infoDictionary = [[NSBundle mainBundle]infoDictionary];
NSString *version = [infoDictionary objectForKey:#"CFBundleShortVersionString"];
NSString *build = [infoDictionary objectForKey:kCFBundleVersionKey];
I have created a custom plist named as test.plist in Supporting Files folder. In that i stored App product name and App version number.
Now, how could i get product name from test.plist for PRODUCT NAME in Build Settings in Target.
I can get values from user defined build settings. But i don't want that.
Note: I need to store product name in test.plist only. And others can access the value from this file.
Thanks in Advance..
you can read the values from the plist in main bundle, put below code in viewDidLoad , method, Please note that all files in main bundle are read only if you want to write any data to plist then you have to copy it to app's document directory
NSString *bundle = [[NSBundle mainBundle] pathForResource:#”test” ofType:#”plist”];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:bundle];
NSString *productName = [dict objectForKey:#"ProductName"];
NSString * appVersion = [dict objectForKey:#"AppVersion"];
Another way is to read app properties
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleDisplayName"];
NSString appVersion = [NSString stringWithFormat:#"Version %# (%#)", [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"], kRevisionNumber];
Hope it helps!
I am trying to get my version number of my app using:
NSString * version = [[NSBundle mainBundle] objectForInfoDictionaryKey: #"CFBundleShortVersionString"];
but it crashes with this error:
[NSString stringWithUTF8String:]: NULL cString
What am I doing wrong?
Check your info.plist to make sure short version (CFBundleShortVersionString) or (Bundle versions string, short) is set.
Your code is fine. But you can also call it this way:
NSString * version = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"];
I followed this Tutorial to use resources in my ios static library.
Now, I can use images, xib files, plist files... into my static library but I can't use localized resources..
In my bundle resources I can see all (for example) images into correct folders (es: english image into en.lproj folder)
But .. when I load the image, I see always the english image also when my language device is different from english.
I have same problem about localized strings: always I see only english localized strings.
* EDIT **
I could not find a better solution for this problem ..
I was in a hurry to fix this so I duvuto apply this method to solve the problem with the localized images:
+ (NSString*) getLocalizedPathImageWithImageName:(NSString*) aImageName
{
NSString *currentDeviceLanguage = [[NSLocale preferredLanguages] objectAtIndex:0];
NSString *resourceBundlePath = [[NSBundle mainBundle] pathForResource:BUNDLE_RESOURCESNAME ofType:#"bundle"];
NSString *completeLocalizedImageName = [aImageName stringByAppendingFormat:#"_%#",currentDeviceLanguage];
NSString *imagePath = [[NSBundle bundleWithPath:resourceBundlePath] pathForResource:completeLocalizedImageName ofType:USERBUTTON_PNG_FILEEXTENSION];
if (imagePath == nil) {
completeLocalizedImageName = [aImageName stringByAppendingFormat:#"_%#",DEFAULT_LANGUAGE];
imagePath = [[NSBundle bundleWithPath:resourceBundlePath] pathForResource:completeLocalizedImageName ofType:USERBUTTON_PNG_FILEEXTENSION];
}
return imagePath;
}
a better solution is welcome
I am implementing a application based on web services. In that I need to add a string as property in .plist and I need to get the value from the .plist whenever I need in the code.
Here is a code sample:
NSString *path = [[NSBundle mainBundle] pathForResource: #"YourPLIST" ofType: #"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile: path];
id obj = [dict objectForKey: #"YourKey"];
NSBundle* mainBundle = [NSBundle mainBundle];
// Reads the value of the custom key I added to the Info.plist
NSString *value = [mainBundle objectForInfoDictionaryKey:#"key"];
//Log the value
NSLog(#"Value = %#", value);
// Get the value for the "Bundle version" from the Info.plist
[mainBundle objectForInfoDictionaryKey:#"CFBundleVersion"];
// Get the bundle identifier
[mainBundle bundleIdentifier];
NSURL *url = [[NSBundle mainBundle] URLForResource:#"YOURPLIST" withExtension:#"plist"];
NSArray *playDictionariesArray = [[NSArray alloc ] initWithContentsOfURL:url];
NSLog(#"Here is the Dict %#",playDictionariesArray);
or you can use following also
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Sample.plist"];
Get from plist is very simple.
NSString *path = [[NSBundle mainBundle] pathForResource:#"SaveTags" ofType:#"plist"];
if (path) {
NSDictionary *root = [NSDictionary dictionaryWithContentsOfFile:path];
}
If you want to add something to a plist, maybe you can find the answer here:
How to write data in plist?
But if you only want save some message in you app, NSUserDefaults is the better way.
You can not do this. Any Bundle wether it is iOS or Mac OS is readonly, you can only read to it and you can't create files, write or do anything with the files in a bundle. This is part of the Security features of apple. You can use the NSDocumentsDirectory to writr and read your stuff you need for your app
Swift
I know this was asked 12+ years ago. But this was the first SO question to come up via google. So to save time for everyone, here is how to do this in swift:
struct Config {
// option 1
static var apiRootURL: String {
guard let value = (Bundle.main.object(forInfoDictionaryKey: "BASE_URL") as? String), !value.isEmpty else {
fatalError("Base URL not found in PLIST")
}
return value
}
// option 2
static var databaseName: String {
guard let value = (Bundle.main.infoDictionary?["DB_NAME"] as? String), !value.isEmpty else {
fatalError("DB NAME not found in PLIST")
}
return value
}
}
Notice the 2 functions use slightly diffrent methods to access the plist. But in effect they are almost the same.
In theory there might not be a plist. Hence infoDictionary is optional. But in this case the first method will also return an unexpected value, resulting in an error.
One actual difference as noted by Apple:
Refering to Bundle.main.object(forInfoDictionaryKey: "BASE_URL")
Use of this method is preferred over other access methods because it returns the localized value of a key when one is available.