在Swift中获取应用程序名称

94

我该如何在Swift中获取应用程序的名称?

谷歌搜索给了我这个:

[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];

我将其转换为Swift;错误 - 方法不存在:

NSBundle.mainBundle().infoDictionary.objectForKey("CFBundleName")
19个回答

155

这应该可以工作:

NSBundle.mainBundle().infoDictionary!["CFBundleName"] as! String

infoDictionary声明为var infoDictionary: [NSObject : AnyObject]!,因此您需要解包它,将其视为Swift字典(而不是使用objectForKey),由于结果是一个AnyObject,因此需要进行类型转换。

更新 Swift 3 (Xcode 8 beta 2)

在可能的情况下,始终最好使用常量(和可选项):

Bundle.main.infoDictionary?[kCFBundleNameKey as String] as? String

5
只有我认为Full Decent推荐强制性投票有些具有讽刺意味吗? - fpg1503
3
CFBundleName并不总是用户看到的应用程序名称。请查看下面我的回答,了解如何获取显示在主屏幕图标下方的应用程序名称。 - Marián Černý
@VadimBulavin和MariánČerný给出的答案更好,而且强制转换不是惯用语。 - Lucas van Dongen

62

我认为这个解决方案更加优雅。此外,使用object(forInfoDictionaryKey:)方法得到的结果是被苹果公司所推荐的:

"使用该方法比其他访问方法更好,因为当存在本地化的键值对时,它会返回本地化的值。"

extension Bundle {
    var displayName: String? {
        return object(forInfoDictionaryKey: "CFBundleDisplayName") as? String
    }
}

访问捆绑包显示名称:

if let displayName = Bundle.main.displayName {
    print(displayName)
}

1
@ixany,这是来自苹果的问答中证明CFBundleDisplayName是正确值的引用:“iPhone主屏幕上的应用程序名称来自CFBundleDisplayName(或“Bundle display name”,即Xcode中的可读字符串)”。 - Vadim Bulavin
4
应该使用CFBundleDisplayName。但是如果没有可用的,就应该退而求其次使用CFBundleName。请参阅下面我的答案。 - Marián Černý

56
我创建了一个简单的扩展,用于获取在主屏幕上图标下方显示的应用程序名称。
默认情况下,应用程序只设置了CFBundleName。然而,一些应用程序将CFBundleDisplayName(包的用户可见名称)设置为更改应用程序图标下方的标题。通常情况下,会添加空格,例如,包名称"ExampleApp"可以将包显示名称设置为"Example App"。
extension Bundle {
    /// Application name shown under the application icon.
    var applicationName: String? {
        object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ??
            object(forInfoDictionaryKey: "CFBundleName") as? String
    }
}

使用方法:

let appName = Bundle.main.applicationName

4
这应该是首选答案。它不仅处理了两种情况,而且没有强制包装,这是示例代码中不应该有的瘟疫。 - SafeFastExpressive
绝对是首选答案! - undefined

23

同样的答案在 Swift 4.2 中

extension Bundle {
    class var applicationName: String {

        if let displayName: String = Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String {
            return displayName
        } else if let name: String = Bundle.main.infoDictionary?["CFBundleName"] as? String {
            return name
        }
        return "No Name Found"
    }
}

你可以像下面这样使用它

Bundle.applicationName

或者,另一种方法是避免使用静态或类方法或属性,而是添加到实例级别。

extension Bundle {
    var applicationName: String {

        if let displayName: String = self.infoDictionary?["CFBundleDisplayName"] as? String {
            return displayName
        } else if let name: String = self.infoDictionary?["CFBundleName"] as? String {
            return name
        }
        return "No Name Found"
    }
}

以及所有类似的内容

Bundle.main.applicationName

希望这可以帮到您 :)


13

Swift 4

let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as! String

在Swift 4中,可以使用上述代码获取应用程序的名称。其中“CFBundleDisplayName”是一个键,用于从Info.plist文件中检索应用程序名称。将此代码添加到您的项目中,以便在需要时获取应用程序名称。

1
线程1:致命错误:在解包可选值时意外地发现了nil - Omar N Shamali

6

// 返回应用程序的名称

public static var appDisplayName: String? {
    if let bundleDisplayName = Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String {
        return bundleDisplayName
    } else if let bundleName = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String {
        return bundleName
    }
    return nil
}

6
  1. 如果应用程序包含CFBundleDisplayName这个键,Finder、系统框架和大多数其他应用程序都将显示它,因此只返回CFBundleName会导致用户看到不正确的名称。

  2. 大多数直接访问信息字典的答案会忽略本地化字符串文件,因此也可能返回错误的名称。在这种情况下,Finder将显示本地化名称。

  3. 虽然Info.plist文件中CFBundleDisplayName是可选的,但实际上CFBundleName并不是必须添加的。如果您忘记添加它,仍然不会对系统造成任何影响。但是,大多数用户可能永远不会注意到,此时大多数答案可能根本无法返回有意义的内容。

以下是我的解决方案(Swift 3):

private
func stripFileExtension ( _ filename: String ) -> String {
    var components = filename.components(separatedBy: ".")
    guard components.count > 1 else { return filename }
    components.removeLast()
    return components.joined(separator: ".")
}

func nameOfApp ( ) -> String {
    let bundle = Bundle.main
    if let name =  bundle.object(forInfoDictionaryKey: "CFBundleDisplayName")
        ?? bundle.object(forInfoDictionaryKey: kCFBundleNameKey as String),
        let stringName = name as? String
        { return stringName }

    let bundleURL = bundle.bundleURL
    let filename = bundleURL.lastPathComponent
    return stripFileExtension(filename)
}

这种解决方案有什么优点?

  1. 它会首先检查CFBundleDisplayName,仅在未找到时回退到CFBundleName

  2. object()方法总是在本地化版本的info字典上操作,因此如果存在本地化,则会自动使用。

  3. 如果字典中既没有CFBundleDisplayName也没有CFBundleName,则代码会回退到仅使用磁盘上的包文件名而不带扩展名(因此"My Cool App.app"将成为"My Cool App"),这是一个后备选项,以便此函数永远不会返回nil


6

简单方法:

let appName = NSBundle.mainBundle().infoDictionary?[kCFBundleNameKey as String] as? String

方便的方式:

extension NSBundle {
    class func mainInfoDictionary(key: CFString) -> String? {
        return self.mainBundle().infoDictionary?[key as String] as? String
    }
}
print(NSBundle.mainInfoDictionary(kCFBundleNameKey))

kCFBundleNameKey - 标准的 Info.plist 关键字,更多信息请参见 CFBundle


6
let appDisplayName = Bundle.main.infoDictionary?["CFBundleName"] as? String

这是可选项,因此请将其放入if let或guard语句中。


4

这个在Swift 4.2中对我有效。

guard let dictionary = Bundle.main.infoDictionary else { return "" }
if let version: String = dictionary["CFBundleDisplayName"] as? String {
   return version
} else {
   return ""
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接