17

我在 Objective-C 中使用__DATE__and__TIME__来获取我的应用程序的构建日期和时间。我找不到在 Swift 中获取这些信息的方法。可能吗?

4

5 回答 5

33

您可以在不恢复到 Objective-C 的情况下获取构建日期和时间。构建应用程序时,放置在包中的 Info.plist 文件始终是从项目中的文件创建的。因此,该文件的创建日期与构建日期和时间相匹配。您始终可以读取应用程序包中的文件并获取它们的属性。因此,您可以通过访问其 Info.plist 文件属性来获取 Swift 中的构建日期:

 var buildDate:NSDate 
 {
     if let infoPath = NSBundle.mainBundle().pathForResource("Info.plist", ofType: nil),
        let infoAttr = try? NSFileManager.defaultManager().attributesOfItemAtPath(infoPath),
        let infoDate = infoAttr["NSFileCreationDate"] as? NSDate
     { return infoDate }
     return NSDate()
 }

注意:当我最初遇到此问题时,这是让我使用桥接头的帖子。从那以后我发现了这个“Swiftier”解决方案,所以我想我会分享它以供将来参考。

[编辑] 添加了 compileDate 变量以获取最新的编译日期,即使没有进行完整构建。这仅在开发过程中有意义,因为您将不得不进行完整构建才能在应用商店上发布应用程序,但它可能仍然有一些用处。它的工作方式相同,但使用包含实际代码的捆绑文件而不是 Info.plist 文件。

var compileDate:Date
{
    let bundleName = Bundle.main.infoDictionary!["CFBundleName"] as? String ?? "Info.plist"
    if let infoPath = Bundle.main.path(forResource: bundleName, ofType: nil),
       let infoAttr = try? FileManager.default.attributesOfItem(atPath: infoPath),
       let infoDate = infoAttr[FileAttributeKey.creationDate] as? Date
    { return infoDate }
    return Date()
}
于 2016-07-17T12:58:54.553 回答
12

您可以使用#line#column#function


原答案:

在你的项目中创建一个新的 Objective-C 文件,当 Xcode 询问时,对创建桥接头说是。

在这个新的 Objective-C 文件中,添加以下.h文件:

NSString *compileDate();
NSString *compileTime();

并在.m实现这些功能:

NSString *compileDate() {
    return [NSString stringWithUTF8String:__DATE__];
}

NSString *compileTime() {
    return [NSString stringWithUTF8String:__TIME__];
}

现在转到桥接头并导入.h我们创建的。

现在回到你的任何 Swift 文件:

println(compileDate() + ", " + compileTime())
于 2014-11-08T02:13:59.953 回答
9

Swift 5 版本的 Alain T 的回答:

var buildDate: Date {
    if let infoPath = Bundle.main.path(forResource: "Info", ofType: "plist"),
        let infoAttr = try? FileManager.default.attributesOfItem(atPath: infoPath),
        let infoDate = infoAttr[.modificationDate] as? Date {
        return infoDate
    }
    return Date()
}
于 2019-12-30T23:36:11.050 回答
1

与以前的答案略有不同,而是检查可执行文件的创建日期。这似乎也适用于 macOS(使用 Catalyst 应用程序测试)。

/// Returns the build date of the app.
public static var buildDate: Date
{
    if let executablePath = Bundle.main.executablePath,
        let attributes = try? FileManager.default.attributesOfItem(atPath: executablePath),
        let date = attributes[.creationDate] as? Date
    {
        return date
    }
    return Date()
}
于 2021-01-01T11:44:29.527 回答
1

这里所有较​​旧的答案都不好,因为它们没有提供稳定可靠的方法来获取实际构建日期。例如,在应用程序中获取文件的文件日期并不好,因为文件日期可能会更改而不会使应用程序的代码签名无效。

Xcode将正式的构建日期添加到应用程序的 Info.plist 中——这是您应该使用的日期。

例如,使用这段代码(抱歉,它在 ObjC 中,但将其转录为 Swift 应该不会那么难):

+ (NSDate *)buildDate {
    static NSDate *result = nil;
    if (result == nil) { 
        NSDictionary *infoDictionary = NSBundle.mainBundle.infoDictionary;
        NSString *s = [infoDictionary valueForKey:@"BuildDateString"];
        NSISO8601DateFormatter *formatter = [[NSISO8601DateFormatter alloc] init];
        NSDate *d = [formatter dateFromString:s];
        result = d;
    }
    return result;
}

这是您必须从项目的构建阶段运行的脚本,以便将其添加BuildDateString到您的Info.plist

#!/bin/sh
infoplist="$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH"
builddate=`date +%Y-%m-%dT%H:%M:%S%z`
if [[ -n "$builddate" ]]; then
    # if BuildDateString doesn't exist, add it
    /usr/libexec/PlistBuddy -c "Add :BuildDateString string $builddate" "${infoplist}"
    # and if BuildDateString already existed, update it
    /usr/libexec/PlistBuddy -c "Set :BuildDateString $builddate" "${infoplist}"
fi
于 2021-07-07T15:06:45.347 回答