Search code examples
iosswiftnsbundleios-app-extension

Get the main app bundle from within extension


Is it possible to get the containing app's NSBundle from within an app extension? I would like to get the main app's display name, not the extension's display name.


Solution

  • The +mainBundle method returns the bundle containing the "current application executable", which is a subfolder of your app when called from within an extension.

    This solution involves peeling off two directory levels from the URL of the bundle, when it ends in "appex".

    Objective-C

    NSBundle *bundle = [NSBundle mainBundle];
    if ([[bundle.bundleURL pathExtension] isEqualToString:@"appex"]) {
        // Peel off two directory levels - MY_APP.app/PlugIns/MY_APP_EXTENSION.appex
        bundle = [NSBundle bundleWithURL:[[bundle.bundleURL URLByDeletingLastPathComponent] URLByDeletingLastPathComponent]];
    }
    
    NSString *appDisplayName = [bundle objectForInfoDictionaryKey:@"CFBundleDisplayName"];
    

    Swift 2.2

    var bundle = NSBundle.mainBundle()
    if bundle.bundleURL.pathExtension == "appex" {
        // Peel off two directory levels - MY_APP.app/PlugIns/MY_APP_EXTENSION.appex
        bundle = NSBundle(URL: bundle.bundleURL.URLByDeletingLastPathComponent!.URLByDeletingLastPathComponent!)!
    }
    
    let appDisplayName = bundle.objectForInfoDictionaryKey("CFBundleDisplayName")
    

    Swift 3

    var bundle = Bundle.main
    if bundle.bundleURL.pathExtension == "appex" {
        // Peel off two directory levels - MY_APP.app/PlugIns/MY_APP_EXTENSION.appex
        let url = bundle.bundleURL.deletingLastPathComponent().deletingLastPathComponent()
        if let otherBundle = Bundle(url: url) {
            bundle = otherBundle
        }
    }
    
    let appDisplayName = bundle.object(forInfoDictionaryKey: "CFBundleDisplayName")
    

    This will break if the pathExtension or the directory structure for an iOS extension ever changes.