简体   繁体   中英

Get Cocoa Touch Framework project version string in Swift

Cocoa Touch Frameworks provide support for versioning, which can be found in Build Settings under the Versioning section.

To access this value at runtime, we can use the FrameworkVersionNumber and FrameworkVersionString[] variables which are auto-generated for us as part of the build process.

When working with a Swift project, these can be found auto-generated at the top of the Objective-C compatibility header:

//! Project version number for Framework.
FOUNDATION_EXPORT double FrameworkVersionNumber;

//! Project version string for Framework.
FOUNDATION_EXPORT const unsigned char FrameworkVersionString[];

However, whilst FrameworkVersionNumber is accessible from Swift, FrameworkVersionString[] is not. In fact looking at the contents of the framework module, I can see that only the first variable is exposed to Swift:

//! Project version number for Framework.
var FrameworkVersionNumber: Double

The problem with this is that since FrameworkVersionNumber is a Double , any version numbers like 3.2.1 simply get changed to 3.200000...

Does anyone know whether this is a flaw in my project setup, a bug in Xcode, or whether there is a way of getting the framework version in Swift as a String or array, so that I can provide more granular versioning than major.minor ?

I have actually found a potential workaround for this issue, it's not so clean but it does work:

By default, when Xcode creates a framework it sets the Version to 1.0 and the Build to $(CURRENT_PROJECT_VERSION) which is great, because this value is actually being copied from the Current Project Version field in Build Settings > Versioning.

So what you can do to get this value at runtime is as follows:

let bundle = NSBundle(identifier: "com.yourframework.Framework")! // Get a reference to the bundle from your framework (not the bundle of the app itself!)
let build = bundle.infoDictionary![kCFBundleVersionKey] as! String // Get the build from the framework's bundle as a String

This does work but it feels quite circuitous for something that used to (I believe) be readily accessible from a variable in Objective-C.

for swift 4.2 it works:

if let bundle = Bundle(identifier: "com.ingconti.SampleFramework") {
       if let build = bundle.infoDictionary?["CFBundleShortVersionString"] {
           print(build)
       }
}

These variables are populated in an automatically generated .c file when building from the project's CURRENT_PROJECT_VERSION . It looks like this:

 extern const unsigned char FrameworkVersionString[];
 extern const double FrameworkVersionNumber;

 const unsigned char FrameworkVersionString[] __attribute__ ((used)) = "@(#)PROGRAM:Mark2SDK  PROJECT:Framework-1" "\n";
 const double FrameworkVersionNumber __attribute__ ((used)) = (double)1.;

The C array doesn't make it to Swift for some reason. Modifying the array definition to a pointer causes an EXC_BAD_ACCESS crash. What you can do though is create a pointer to the array and use that. In Framework.h :

//! Project version string for Framework.
FOUNDATION_EXPORT const unsigned char FrameworkVersionString[];
// add this
extern const unsigned char * FrameworkVersionStringPtr;

Then, either by creating Framework.c or in another c or m file, add this:

#import "Framework.h"

const unsigned char * FrameworkVersionStringPtr = FrameworkVersionString;

You can then use the string pointer in Swift to get the version:

func version() -> String? {
    let ver = String(cString: Mark2SDKVersionStringPtr)
    guard let range = ver.range(of: "-") else {
        return nil
    }
    return String(ver[range.upperBound...])
}
print(version())
// 1.0.1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM