【问题标题】:Get the main app bundle from within extension从扩展中获取主应用程序包
【发布时间】:2014-11-29 02:36:54
【问题描述】:

是否可以从应用扩展中获取包含应用的NSBundle?我想获取主应用程序的显示名称,而不是扩展程序的显示名称。

【问题讨论】:

    标签: ios swift nsbundle ios-app-extension


    【解决方案1】:

    根据@phatblat 的回答,这是一个不太可能因文件结构更改而中断的解决方案。

    extension Bundle {
        /// Return the main bundle when in the app or an app extension.
        static var app: Bundle {
            var components = main.bundleURL.path.split(separator: "/")
            var bundle: Bundle?
    
            if let index = components.lastIndex(where: { $0.hasSuffix(".app") }) {
                components.removeLast((components.count - 1) - index)
                bundle = Bundle(path: components.joined(separator: "/"))
            }
    
            return bundle ?? main
        }
    }
    

    【讨论】:

      【解决方案2】:

      +mainBundle 方法返回包含“当前应用程序可执行文件”的包,当从扩展程序中调用时,它是应用程序的子文件夹。

      此解决方案涉及从包的 URL 中剥离两个目录级别,当它以“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"];
      

      斯威夫特 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")
      

      斯威夫特 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")
      

      如果 iOS 扩展的 pathExtension 或目录结构发生变化,这将中断。

      【讨论】:

      • 谢谢!您是否能够通过这种方式获得 AppStore 应用的批准?
      • 是的,这里没有使用私有 API。我们在 watchOS 1 扩展中使用它来从主 iOS 应用程序包中加载 UIManagedDocument 的托管对象模型。
      • 啊太棒了。感谢您的洞察力。
      • 有人可以转换成 Swift 吗?我在跟上有点麻烦。谢谢!
      • @FelixSFD 我喜欢你的按语言和版本划分的方式。就个人而言,我尽可能避免强制解包选项,尤其是在其他人的示例代码中。在 Swift 3 代码中这样做的一个好处是您可以使用 try? 来减少对 do/catch 语句的需求。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-21
      • 1970-01-01
      • 1970-01-01
      • 2014-11-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多