我写了一个自定义的 private CocoaPod。我正在尝试在我的iOS应用程序中使用它,效果很好。但是,当我将其添加到iMessage应用或共享扩展程序时,它会失败,并在尝试使用'shared' is unavailable: Use view controller based solutions where appropriate instead.时给我一个错误UIApplication.shared

我首先想到的解决方法是添加一个Swift Flag IN_EXTENSION或类似的东西。然后将代码包装在#if块中。

问题是CocoaPod源的目标是在某种类型的框架中。来源不直接属于应用程序或扩展程序。因此,添加该标志并没有真正的帮助。

以下是我的Podfile的示例。

source 'https://github.com/CocoaPods/Specs.git'
source 'git@github.com:CUSTOMORG/Private-CocoaPods-Spec.git'
platform :ios, '9.0'
use_frameworks!
inhibit_all_warnings!

target 'MyApp' do
  pod 'MyCustomSwiftPackage', '1.0.0'
end

target 'MyApp Share Extension' do
  pod 'MyCustomSwiftPackage', '1.0.0'
end

如果我将pod 'MyCustomSwiftPackage', '1.0.0'下的MyApp Share Extension行注释掉,则可以正常工作。但是,如果我不加注释,它将失败。

我的共享扩展名中确实需要此软件包。

我考虑过要编写一个单独的Pod,该Pod只处理UIApplication.shared逻辑,然后将该Pod添加到MyApp中。但这似乎是一种真正的痛苦。尤其是因为我不知道一种在依赖相同源文件的项目中部署2个CocoaPods的方法。

如果那是唯一的解决方案,那么使用Git子模块并直接在应用程序中拥有源代码似乎更好,因此我可以将其直接作为那些目标的一部分,然后#if应该可以工作。问题是如果我使用Git子模块,将无法处理CocoaPod的依赖关系。所以我真的必须以某种方式使用CocoaPods。

我希望有一个简单的解决方案,它不会像那些解决方案那样笨拙。那么,有没有更好的方法来解决这个问题并修复该错误,而不必诉诸重写大量的代码,那不是一个 super hacky解决方案吗?

在评论中提到使用NSSelectorFromStringUIApplication.respondsUIApplication.perform。问题在于,如果Apple更改了API,即使对于应用程序的先前版本,代码也会中断,因为它是在没有API将来证明的情况下动态调用的。尽管该解决方案听起来很简单,但似乎是一个错误的决定。

answer below看起来非常有前途。遗憾的是,在注释中概述了一些更改后,它仍然无法正常运行,主应用程序同时具有Core子规范和AppExtension子规范。

最佳答案

假设您是 MyLibrary 的所有者:

Pod::Spec.new do |s|
  s.name             = "MyLibrary"
  # Omitting metadata stuff and deployment targets

  s.source_files = 'MyLibrary/*.{m,h}'
end

您使用了不可用的API,因此该代码有条件地基于名为 MYLIBRARY_APP_EXTENSIONS 的预处理程序宏编译了某些部分。我们声明一个名为Core的子规范,其中包含所有代码,但标志关闭。如果用户未指定子规范,则将其指定为默认子规范。然后,我们将声明一个名为AppExtension的附加子规范,其中包括所有代码,但会设置预处理器宏:
Pod::Spec.new do |s|
  s.name             = "MyLibrary"
  # Omitting metadata stuff and deployment targets
  s.default_subspec = 'Core'

  s.subspec 'Core' do |core|
    core.source_files = 'MyLibrary/*.{m,h}'
  end

  s.subspec 'AppExtension' do |ext|
    ext.source_files = 'MyLibrary/*.{m,h}'
    # For app extensions, disabling code paths using unavailable API
    ext.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'MYLIBRARY_APP_EXTENSIONS=1' }
  end
end

然后,在应用程序Podfile中,您将链接至主应用程序目标中的Core以及扩展中的AppExtension,如下所示:
abstract_target 'App' do
  # Shared pods between App and extension, compiled with same preprocessor macros
  pod 'AFNetworking'

  target 'MyApp' do
    pod 'MyLibrary/Core'
  end

  target 'MyExtension' do
    pod 'MyLibrary/AppExtension'
  end
end

而已!

10-07 19:41
查看更多