【问题标题】:How to detect if code is running in Main App or App Extension Target?如何检测代码是否在主应用程序或应用程序扩展目标中运行?
【发布时间】:2014-09-22 18:09:00
【问题描述】:

如果您在应用扩展中运行,有谁知道您如何从代码中检测到?

我有一个应用程序在应用程序和扩展程序之间共享类。应用程序代码使用[UIApplication sharedApplication],但这在扩展中不可用,所以它不会编译说:

“sharedApplication”不可用:iOS(应用扩展)不可用

所以我需要一种方法来检测我是否在扩展程序中,如果是这样的话,我需要使用 sharedApplication 的替代方法。

【问题讨论】:

  • 检查这个线程 stackoverflow.com/a/29076070/366025>。还有一个没有预处理器宏的 MACRO 解决方案

标签: ios uiapplicationdelegate ios-app-extension


【解决方案1】:

您可以使用预处理器宏:

在项目设置中,使用顶部栏中的下拉菜单选择您的扩展目标:

然后:

  1. 点击Build Settings
  2. Apple LLVM 6.0 - Preprocessing 下查找(或搜索)Preprocessor Macros
  3. 在调试和发布部分添加 TARGET_IS_EXTENSION 或您选择的任何其他名称。

然后在你的代码中:

#ifndef TARGET_IS_EXTENSION // if it's not defined
    // Do your calls to UIApplication
#endif

【讨论】:

  • 谢谢,这种方法有效,但实际上是相反的,我需要检测才能想到它。如果不是扩展,请使用 UIApplication。无论如何,我在应用程序目标构建设置中使用一个标志来解决它,将其标识为应用程序而不是扩展程序。
  • @MarkBridges 抱歉。我在给未来读者的回答中解决了这个问题。
  • 此解决方案不适用于框架中的代码。我们目前检查应用程序包的名称以查看代码是否在扩展中运行,但我希望找到更好的方法。
  • 您能否描述您的代码我也面临同样的问题,我需要添加什么标志或代码,然后应用程序将根据应用程序或扩展程序选择。请记住,我创建了共享框架,这些代码应根据捆绑 ID 执行。
  • 我的代码流似乎根本没有进入 ifdef。知道为什么吗?
【解决方案2】:

正如Apple's documentation 所说:

当您基于 Xcode 模板构建扩展时,您会得到一个以 .appex 结尾的扩展包。

所以,我们可以使用下面的代码:

if ([[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]) {
    // this is an app extension
}

// Swift version
if Bundle.main.bundlePath.hasSuffix(".appex") {
    // this is an app extension
}

【讨论】:

  • 这应该是选择的答案,它比依赖于预处理器宏要好得多。
  • 同意,这样更干净。
  • 不是很干净,它是间接的,如果该扩展发生变化,将来可能会发生变化,加上条件编译将允许您排除无法在扩展中编译的资源或方法。
【解决方案3】:

预处理器宏将主要工作,但不能在共享库(例如 cocoapods 或共享框架)中工作。

或者,您可以使用以下代码。

@implementation ExtensionHelpers

+(BOOL) isAppExtension
{
    return [[[NSBundle mainBundle] executablePath] containsString:@".appex/"];
}

@end

这项工作通过检查捆绑可执行路径来完成,因为只有 App Extension 具有扩展名“.appex”。

【讨论】:

  • 我在编译共享库时仍然遇到编译错误,因为它的“仅需要应用程序扩展安全 API”的标志设置为“是”。如何在仍然使用上面编写的代码的同时避免编译错误?
  • 我不建议在生产中使用 -[NSString containsString:] 有两个原因: 1. 它没有发布 API,即官方帮助页面没有提到它(这可能是一个错误,但无论如何); 2. iOS7会崩溃。使用 -[NSString rangeOfString:] 代替。
  • @AlexanderVasenin 2:它记录在 NSString.h 中,并明确标记为在 iOS 8+ 上可用。
【解决方案4】:

斯威夫特 5

let bundleUrl: URL = Bundle.main.bundleURL
let bundlePathExtension: String = bundleUrl.pathExtension
let isAppex: Bool = bundlePathExtension == "appex"

// `true` when invoked inside the `Extension process`
// `false` when invoked inside the `Main process`

【讨论】:

  • 这太完美了!谢谢:)
【解决方案5】:

您可以在扩展目标上添加预处理器宏,然后在您的类中检查 #ifdef

【讨论】:

    【解决方案6】:

    圣诞老人提出的解决方案对我不起作用。

    有效的是:

    1. 选择扩展目标
    2. 构建设置
    3. 搜索“自定义标志”
    4. 添加新标志(例如:“EXTENSION”)以进行调试和发布

    现在是代码:

    #if EXTENSION
    // IF is extension (SIRI) we do stuff
    #else
    // ELSE is main app do more stuff
    #endif
    

    【讨论】:

      【解决方案7】:

      对于我的共享库,我创建了一个单独的目标,该目标的应用扩展标志设置为“是”,并在该特定目标的构建设置中使用了预处理器宏。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-02-20
        • 1970-01-01
        • 2021-06-01
        • 2012-08-18
        • 1970-01-01
        • 1970-01-01
        • 2017-03-08
        相关资源
        最近更新 更多