【问题标题】:Using Cocoapods in an app extension using a framework在使用框架的应用程序扩展中使用 Cocoapods
【发布时间】:2017-06-26 03:07:10
【问题描述】:

我有一个用 Swift 编写的应用程序(我们称之为 MyApp),目标如下:

  • MyApp:主要目标
  • MyAppKit :目标为在应用程序及其扩展程序之间共享的代码构建框架,主要是 API 后端和数据库处理
  • MyAppWidget :使用 MyAppKit 框架的今日视图小部件(或现在所称的任何名称)。

MyAppKit 框架链接到每个使用它的目标,即MyAppMyAppWidget。进入 Cocoapods :我曾经有以下 Podfile 结构:

platform :ios, '8.0'
use_frameworks!

target 'MyApp' do
    # Mostly UI or convenience pods
    pod 'Eureka', '~> 2.0.0-beta'
    pod 'PKHUD', '~> 4.0'
    pod '1PasswordExtension', '~> 1.8'
end

target 'MyAppKit' do
    # Backend pods for networking, storage, etc.
    pod 'Alamofire', '~> 4.0'
    pod 'Fuzi', '~> 1.0'
    pod 'KeychainAccess', '~> 3.0'
    pod 'RealmSwift', '~> 2.0'
    pod 'Result', '~> 3.0'
end

target 'MyAppWidget' do
    # Added here event though the target only imports MyAppKit but it worked
    pod 'RealmSwift', '~> 2.0'
end

这里的目的是仅将 MyAppKit 框架暴露给其他部分,而不是其所有 pod(例如,我不希望能够在主应用程序中使用 import Alamofire)。但是,从 Cocoapods 1.2.0 RC 开始,pod install 失败并出现以下错误:[!] The 'Pods-MyApp' target has frameworks with conflicting names: realm and realmswift.。它曾经可以工作,因为 pod 是为扩展声明的,但仅嵌入在主机应用程序中(有关更多信息,请参阅this issue)。所以我从小部件的目标中删除了 pod,只留下一个空白的 target 'MyAppWidget' 行。

使用此配置,pod install 运行良好,但在 MyAppWidget 目标的链接阶段编译失败:ld: framework not found Realm for architecture x86_64。这可以通过将Realm.frameworkRealmSwift.framework 显式添加到“Link Binary With Libraries”部分以及目标的Pods-MyAppWidget.[debug/release].xcconfig 中的以下构建设置来解决:

FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Realm" "$PODS_CONFIGURATION_BUILD_DIR/RealmSwift"`

但是,每当我运行 pod install 时,构建设置自然会恢复,我必须再次添加构建设置。

我看到以下解决方案:

  • 添加一个post_install 钩子,每次都添加这些设置,但它看起来确实很“hacky”,经过几次错误的尝试后,我发现没有 API 参考,也不知道如何将这些设置添加到 MyAppWidget 目标通过脚本。
  • 将 Podfile 更改为以下结构(甚至将其包装在抽象目标中):

    [...]
    target 'MyAppKit' do
        # Backend pods for networking, storage, etc.
        pod 'Alamofire', '~> 4.0'
        pod 'Fuzi', '~> 1.0'
        pod 'KeychainAccess', '~> 3.0'
        pod 'RealmSwift', '~> 2.0'
        pod 'Result', '~> 3.0'
    
        target 'MyAppWidget' do
            inherit! :search_paths # Because else we get the "conflicting names" error
        end
    end
    

    这对我来说似乎是合乎逻辑的,“小部件应该知道在链接期间查看的位置,但本身不需要 pod”但这并没有添加上述构建设置(我可能误解了:search_paths继承)(编辑:它确实有效,但不适用于抽象目标)。我想到这个想法是因为在旧版本的 CocoaPods 中,solution 显然是要添加 link_with,现在已弃用。

  • 也在 MyApp 目标中公开 Realm,但这与我在主代码中无法访问“后端”代码的目标相冲突(这可能是纯粹的审美?)。

所以,我的问题是:将 pod 集成到主应用程序和扩展程序之间共享的框架中,同时仍然能够编译,而无需调整和手动添加内容的最佳方法是什么?

提前干杯和感谢!


编辑

Prientus' comment 之后,我探索了抽象和继承的可能性。我现在发现的潜在问题实际上是多方面的:

  • 它曾经在 Cocoapods 1.2.0 之前工作,因为在小部件目标下声明的 pod 嵌入在主机应用程序中,但仍链接到小部件。不,它只是拒绝在“主与扩展”关系中为不同目标使用同名的 pod
  • 使用抽象目标是不够的,因为目标不能只继承抽象目标的搜索路径 (inherit! :search_paths)。
  • 搜索路径可以从像MyAppKit这样的真实目标继承,但这会将所有这些pod暴露给MyApp的代码(我想避免),并且仍然存在链接Realm框架的问题(因为实际上这个小部件使用了最微小的 getter,因此需要它)。

使用最后一个选项并手动链接 Realm.framework 是可行的,但就我的意图和过去的工作方式而言不是最理想的。根据variousissuesonCocoapods 的 GitHub,其中一些问题似乎是一个错误。我添加了my own issue,有消息会更新。

【问题讨论】:

  • 您提到在您的解决方案中使用抽象类,但我想知道您是否真的尝试过。你在这里提出了一个很好的问题,我自己也遇到过。
  • 另外,我会尝试使用继承!方法,但在父对象之外声明目标。我注意到这里的语法:guides.cocoapods.org/syntax/podfile.html#target 并认为它可能有用。

标签: ios swift cocoapods


【解决方案1】:

我不认识你。但对我来说,让扩展和宿主应用程序包含框架定义的所有 pod 是完全合法和合理的。这就是我的意思:

def shared_pods
    pod 'Alamofire'
end

target 'Framework' do
    shared_pods
end

target 'Host' do
    shared_pods
    // Some other pods
end

target 'Extension' do
    shared_pods
end

我知道你很担心,但如果你仔细想想,你使用的所有那些 3rd 方框架,它们都有依赖关系。您不必担心它们,因为 Cocoapods 会为您照顾它们。如果你想利用它,那么你需要在列表中放置一个本地 pod 条目。

target 'Host' do
    pod Framework, :path => '../Framework'
end

但是你必须维护podspec文件。

【讨论】:

  • 在无所事事的研究和测试之后,我找到了解决问题的方法(在下面发布以供参考)。它主要涉及到无论您如何配置 Podfile,所有 pod 都可以在任何地方导入(我猜是因为链接的共享框架),因此我最初关心的不是问题。应该注意的是,您的解决方案不会导致“目标具有名称冲突的框架”,因为您最终会在扩展中引用 pod。
  • 我正在尝试这个但不起作用请帮助我。我对这一点提出疑问stackoverflow.com/questions/53607730/…
【解决方案2】:

那么,是什么给了:

  • 我担心“在目标之间分离 pod”是荒谬的,因为您仍然可以在任何地方导入它们。
  • “您必须手动链接”问题已通过简单的 import RealmSwift 语句修复。

因此,固定且工作的 Podfile 是:

platform :ios, '8.0'
use_frameworks!

target 'MyApp' do
    pod 'Eureka', '~> 2.0.0-beta'
    pod 'PKHUD', '~> 4.0'
    pod '1PasswordExtension', '~> 1.8'
end

target 'MyAppKit' do
    pod 'Fuzi', '~> 1.0'
    pod 'RealmSwift', '~> 2.0'
    pod 'Alamofire', '~> 4.0'
    pod 'KeychainAccess', '~> 3.0'
    pod 'Result', '~> 3.0'

    target 'MyAppWidget' do
        inherit! :search_paths
    end
end

就是这样。我会说旧的行为更明显,不需要阅读“podfile 目标继承”。不过我确实学到了很多。干杯!

【讨论】:

  • 我按照你说的做了,并使用了inherit! :search_paths,它只在构建到设备时才有效。当我尝试归档应用程序时,对于我尝试在扩展程序中使用的每个 pod,它都会失败“没有这样的模块”
  • @YichenBman 我刚刚归档了我的应用程序,没有任何错误。也许你可以给我看你的 Podfile 或者在这里打开一个新问题。作为一般规则,请确保 CocoaPods 和 Xcode 是最新的。
  • 非常感谢,您为我节省了数小时的辛勤工作,但是存档不起作用。当我导入它时它无法识别模块...
  • @Eduard 不确定我理解。所以你可以在正常情况下构建良好,但它只是存档失败?您能否向我提供您的 Podfile 或显示问题的示例项目?
  • 我使用的是私有框架,Podfile 和你的一样,在我构建时它运行良好,但是当我将配置设置为测试而不是调试或尝试存档时它会失败 ¯_(ツ)_/¯.
【解决方案3】:

这是一个 swift-3.0 项目的配置文件示例。

platform :ios, '8.0'

def import_public_pods

  pod 'SwiftyJSON'

end


target 'Demo' do
  use_frameworks!

  # Pods for Demo
  import_public_pods 
  pod 'Fabric'
  pod 'Crashlytics'

  target 'DemoTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'DemoUITests' do
    inherit! :search_paths
    # Pods for testing
  end

end


target 'DemoKit' do
  use_frameworks!

  # Pods for DemoKit
  import_public_pods
  pod 'RealmSwift'

  target 'DemoKitTests' do
    inherit! :search_paths
    # Pods for testing
  end

end

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多