在Swift中获取应用名称


69

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

谷歌搜索给了我这个:

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

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

NSBundle.mainBundle().infoDictionary.objectForKey("CFBundleName")

Answers:


127

这应该工作:

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

infoDictionary被声明为a,var infoDictionary: [NSObject : AnyObject]!因此您必须将其拆开,将其作为Swift字典访问(而不是使用objectForKey),然后AnyObject将其转换为。

更新Swift 3(Xcode 8 beta 2)

在可能的情况下,也总是最好使用常量:

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

3
我是唯一一个认为颇具讽刺意味的Full Decent建议使用强制施法的人吗?
fpg1503

1
CFBundleName可能并不总是显示给用户的应用程序的名称。请参阅下面的答案,如何获取主屏幕上图标下方显示的应用名称。
玛丽安·塞尔尼

@VadimBulavin和MariánČerný给出的答案更好,而且强制转换也不是惯用的
Departamento B

35

我相信这种解决方案会更优雅。更重要的是,使用object(forInfoDictionaryKey:)由苹果公司鼓励

“与其他访问方法相比,首选使用此方法,因为它在有密钥时会返回密钥的本地化值。”

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

访问包显示名称:

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

1
它必须是CFBundleName
ixany

1
@ixany,这是苹果问答的引号,证明了它CFBundleDisplayName是正确的值:“ iPhone主屏幕上的应用程序名称来自CFBundleDisplayName(或“ Bundle显示名称”,即Xcode中的人类可读字符串)”
Vadim Bulavin

2
应该是CFBundleDisplayName。但是,如果无法使用,则应退回到CFBundleName。请参阅下面的答案。
玛丽安·塞尔尼

28

我创建了一个简单的扩展名,以获取显示在主屏幕上图标下的应用程序名称。

默认情况下,仅CFBundleName设置应用程序。但是,某些应用程序设置了CFBundleDisplayName (捆绑包的用户可见名称)来更改应用程序图标下的标题。通常会添加空格,例如,包名称“ ExampleApp”可以将包显示名称设置为“ Example App”。

extension Bundle {
    // Name of the app - title under the icon.
    var displayName: String? {
            return object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ??
                object(forInfoDictionaryKey: "CFBundleName") as? String
    }
}

用法:

let appName = Bundle.main.displayName

2
这应该是首选答案。它不仅处理这两种情况,而且无需强制包装,这是永远不会出现在示例代码中的瘟疫。
SafeFastExpressive

12

斯威夫特4

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


1
线程1:致命错误:展开一个可选值时意外发现nil
Omar N Shamali

12

Swift 4.2中的答案相同

extension Bundle {
    static func appName() -> String {
        guard let dictionary = Bundle.main.infoDictionary else {
            return ""
        }
        if let version : String = dictionary["CFBundleName"] as? String {
            return version
        } else {
            return ""
        }
    }
}

您可以像下面一样使用它

let appName = Bundle.appName()

希望这可以帮助 :)


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中的更多内容


4

//返回应用名称

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
}

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

它是可选的,因此将其放入let或guard语句中。


3
  1. 刚返回的所有答案CFBundleName通常都不会返回用户期望的名称,就像包中有CFBundleDisplayName,则Finder,系统框架和大多数其他应用程序会显示此键。

  2. 大多数答案仅直接访问信息字典,但是信息字典可以通过字符串文件进行本地化,并且在直接访问它们时,也将忽略此本地化,因此可能会返回错误的名称,因为Finder将显示本地化的名称。

  3. 虽然CFBundleDisplayNameInfo.plist文件中是可选的CFBundleName,但实际上不是可选的,但是如果您忘记添加它,则系统中不会出现任何中断,因此您的信息字典已损坏,但是大多数用户可能永远不会注意到,在这种情况下,大多数答案的代码可能根本不返回任何有意义的东西。

这是我的解决方案(快速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()方法始终在信息字典的本地化版本上运行,因此,如果存在本地化,将自动使用它。

  3. 如果字典中CFBundleDisplayName也不CFBundleName存在,则代码将退回到仅使用磁盘文件包中的文件名而没有扩展名(因此“ My Cool App.app”将为“ My Cool App”),这是一个后备版本,因此此功能将永不返回nil


3

这个在Swift 4.2中对我有用

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

2

这应该更像您要寻找的内容:

let infoDictionary: NSDictionary = NSBundle.mainBundle().infoDictionary as NSDictionary!
let appName: NSString = infoDictionary.objectForKey("CFBundleName") as NSString

NSLog("Name \(appName)")

仍然有更好的方法可以执行此操作,但是在我非常有限的测试中,它至少可以正确返回应用程序名称...


2

尝试这个:

extension Bundle {
    var displayName: String {
        let name = object(forInfoDictionaryKey: "CFBundleDisplayName") as? String
        return name ?? object(forInfoDictionaryKey: kCFBundleNameKey as String) as! String
    }
}

1
let bundleInfoDict: NSDictionary = NSBundle.mainBundle().infoDictionary!
let appName = bundleInfoDict["CFBundleName"] as String

1

这对我来说很完美

let appName = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleDisplayName") as! String

1

这就是在Xcode 11.0和Swift 5中对我有用的东西

 let bundleID = Bundle.main.bundleIdentifier
 let bundleInfoDict: NSDictionary = Bundle.main.infoDictionary! as NSDictionary
 let appName = bundleInfoDict["CFBundleName"] as! String
 print(bundleID!)
 print(appName)

0

对于Swift 5,iOS 13 *

如前所述,它是可选的,因此将其放在保护语句中。我使用一个结构来做到这一点:

struct Model {
    struct ProgVariablen{
        static var appBundleName:String {
            get {guard Bundle.main.infoDictionary != nil else {return ""}
                return Bundle.main.infoDictionary!["CFBundleName"] as! String
            }//end get
        }//end computed property
        static var appBundleShortVersion:String {
            get {guard Bundle.main.infoDictionary != nil else {return ""}
                return Bundle.main.infoDictionary ["CFBundleShortVersionString"] as! String
            }//end get
        }//end computed property
        static var appBundleBuild:String {
            get {guard Bundle.main.infoDictionary != nil else {return ""}
                return Bundle.main.infoDictionary["CFBundleVersion"] as! String
        }//end get
    }//end computed property

    //initialsieren der Variablen
    init(
         appBundleName:String,
         appBundleShortVersion:String,
         appBundleBuild:String,
         )
    {
        // do here nothing for 'let'
        // do here nothing for 'computed properties'
        // your other ‘var’ are here like:
        // ProgVariablen.var1 = var1
    }//end init
    }//end struct ProgVariablen
}//end struct Model

用法:

print("Model.ProgVariablen.appBundleName: '\(Model.ProgVariablen.appBundleName)'")

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.