Xcode 9.3 Swift嵌套自定义框架单元测试和iTunesConnect上传

时间:2018-06-07 16:25:36

标签: ios swift xcode frameworks

我厌倦了几天后弄乱构建设置......

我有一个应用程序,让我们称之为MyiPhoneApp,它使用大约10个私有/自定义框架(Cocoa Touch动态框架)。 MyiPhoneApp还使用Cocoapods来获取某些依赖项(不相关?)。我的私人框架本身就是在使用它们(彼此依赖)。

所以我的设置是(为了便于阅读而简化):

FRAMEWORKS(私人/自定义Cocoa Touch动态):

Models

目标: ViewModelsViewModelsTests
取决于私有框架:无

ViewModels

目标ViewModelsViewModelsTests
取决于私有框架Models

Views

目标ViewsViews
取决于私有框架ModelsViewModels

APPS

MyiPhoneApp

目标MyiPhoneAppMyiPhoneAppTestsMyiPhoneAppUITests
MyiPhoneApp依赖于私有框架ModelsViewModelsViews

Catch 22运行Unit Tests&上传到iTunesConnect

对于所有目标ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES,我可以在每个私有框架中运行所有单元测试。 然后我从iTunes Connect收到拒绝错误:

  

[04:06:20]:[转运错误输出]:错误ITMS-90206:"无效   束。捆绑在' MyiPhoneApp.app/Frameworks/Models.framework'   包含不允许的文件'框架'。" [04:06:20]:[转运错误   输出]:错误ITMS-90206:"无效的捆绑包。捆绑在   ' MyiPhoneApp.app/Frameworks/ViewModels.framework'包含不允许   文件'框架'。" [04:06:20]:[Transporter Error Output]:ERROR   ITMS-90206:"无效的捆绑包。捆绑在   ' MyiPhoneApp.app/Frameworks/Views.framework'包含不允许的文件   '框架'"

这似乎类似于: (SO Q958)[Validation Error: Invalid Bundle. The bundle at ... contains disallowed file 'Frameworks'

来自Q958的

The answer with over 240 upvotes,建议: 为框架和测试目标设置ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO(和框架'测试目标..?)和YES为应用程序。这也在this Github comment

中提出

尝试(ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO框架及其测试目标时)我无法运行测试。

当我尝试运行ModelTests时(记住Framwork Models不依赖于任何其他框架)测试失败/死于:

  

dyld:未加载库:@ rpath / libswiftCore.dylib引用自:   /Users/sajjon/Library/Developer/Xcode/DerivedData/Models-ahgxztzgogwcfheblqbzabdqxhtm/Build/Products/Debug-iphonesimulator/Models.framework/Models   原因:未找到图像

什么是正确的设置?

我尝试过Xcode 9.3和Xcode 9.4。我的框架和我的应用程序使用此xcconfig文件:

我的系统

Macbook Pro 15" 2016年末 macOS High Sierra v 10.13.5(17F77)

Cocoapods 1.5.3(捆绑商)

Bundler版本1.16.1
bundle exec pod --version => 1.5.3

我的Podfile

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '11.2'
inhibit_all_warnings!
use_frameworks!

workspace 'MyWorkspace.xcworkspace'

### PODS (sorted by name) ###

def nimble
  pod 'Nimble',  '~> 7.1'
end

def rxswift           
  pod 'RxSwift', '~> 4.1'
end

def viewcomposer      
  pod 'ViewComposer', :git => 'https://github.com/Sajjon/ViewComposer.git'
end

def quick
  pod 'Quick',  '~> 1.3'
end

# Rest of pods removed for this StackOverFlow question for readability #

# Global Pod used by ___ALL___ targets
swiftlint

#@@ Apps (sorted by name) @@#

target 'MyiPhoneApp' do
  project 'Apps/MyiPhoneApp/MyiPhoneApp'


  # lots of pods removed for this SO question for readability
  rxswift
  tinyconstraints
  viewcomposer

  abstract_target 'Tests' do
    nimble
    quick

    target "MyiPhoneAppTests"
    target "MyiPhoneAppUITests"
  end
end


### PRIVATE FRAMEWORKS ###

abstract_target 'Framework-Models' do
  project 'Common/Models/Models'

  target 'Models' do
    # lots of pods removed for this SO question for readability
    rxswift
    swiftybeaver
  end

  target 'ModelsTests' do
    nimble
    quick
  end
end

abstract_target 'Framework-ViewModels' do
  project 'Common/ViewModels/ViewModels'

  target 'ViewModels' do
    # lots of pods removed for this SO question for readability
    rxswift
    viewcomposer
  end

  target 'ViewModelsTests' do
    nimble
    quick
  end
end

abstract_target 'Framework-Views' do
  project 'Common/Views/Views'

  target 'Views' do
    # lots of pods removed for this SO question for readability
    rxswift
    tinyconstraints
    viewcomposer
  end

  target 'ViewsTests' do
    nimble
    quick
  end
end

我的xcconfig文件设置

正如您在上面的Podfile中看到的,我的私有框架使用了pod。但我想使用xcconfig文件在我的框架之间共享构建设置(我只写了三个ViewModelsViewsModels,但实际上我有大约10个。)。

因此,我调查了Xcode默认为Apps创建的xcconfig文件,Cocoa Touch动态框架以及这些文件的设置在测试目标和非测试目标之间以及调试和发布之间的区别。

由此我创建了这些xcconfig文件

base_shared.xcconfig

包括配置:描述:由所有目标使用(App(主要,测试,UITest),框架(主要,测试))。

base_debug.xcconfig

包括配置:描述:由所有调试目标(App(主要,测试,UITest),框架(主要,测试))使用。

base_release.xcconfig

包括配置:描述:由所有版本目标(App(主要,测试,UITest),框架(主要,测试))使用。

base_apps.xcconfig

包含配置: base_shared
说明:由应用目标(主要,测试,UITest)使用

base_framework.xcconfig

包含配置: base_shared
说明:由框架使用(主要,测试)。

base_tests.xcconfig

包含配置: base_shared
描述:由所有测试目标(App,Framework)使用。

base_uitests.xcconfig

包含配置: base_shared
说明:由所有UITest目标(应用)使用。

然后,对于每个和app框架,我在Common xcconfig中包含了正确的xcconfigs组合。所以例如对于框架Models,我创建了6个配置文件:Models-Common.xcconfigModels-Debug.xcconfigModels-Release.xcconfig," ModelsTests-Common.xcconfig",ModelsTests-Debug.xcconfigModelsTests-Release.xcconfig

虽然这导致了许多xcconfig文件,每个框架有6个,但它们都很小。我可以在所有10个以上的框架之间共享所有构建设置。这是一种权衡。

我的xcconfig文件的内容

base_shared.xcconfig

// BuildSettings shared between both DEBUG and RELEASE and also identical for both FRAMEWORKS (Cocoa Touch Framework) and APPS (iOS)

// Vanilla Xcode 9.3 settings
ALWAYS_SEARCH_USER_PATHS = NO
CLANG_ANALYZER_NONNULL = YES
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE
CLANG_CXX_LANGUAGE_STANDARD = gnu++14
CLANG_CXX_LIBRARY = libc++
CLANG_ENABLE_MODULES = YES
CLANG_ENABLE_OBJC_ARC = YES
CLANG_ENABLE_OBJC_WEAK = YES
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES
CLANG_WARN_BOOL_CONVERSION = YES
CLANG_WARN_COMMA = YES
CLANG_WARN_CONSTANT_CONVERSION = YES
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR
CLANG_WARN_DOCUMENTATION_COMMENTS = YES
CLANG_WARN_EMPTY_BODY = YES
CLANG_WARN_ENUM_CONVERSION = YES
CLANG_WARN_INFINITE_RECURSION = YES
CLANG_WARN_INT_CONVERSION = YES
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES
CLANG_WARN_STRICT_PROTOTYPES = YES
CLANG_WARN_SUSPICIOUS_MOVE = YES
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
CLANG_WARN_UNREACHABLE_CODE = YES
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
COPY_PHASE_STRIP = NO
ENABLE_STRICT_OBJC_MSGSEND = YES
GCC_C_LANGUAGE_STANDARD = gnu11
GCC_NO_COMMON_BLOCKS = YES
SDKROOT = iphoneos
GCC_WARN_64_TO_32_BIT_CONVERSION = YES
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR
GCC_WARN_UNDECLARED_SELECTOR = YES
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE
GCC_WARN_UNUSED_FUNCTION = YES
GCC_WARN_UNUSED_VARIABLE = YES
IPHONEOS_DEPLOYMENT_TARGET = 11.2

// Custom set
CODE_SIGN_STYLE = Manual
SWIFT_VERSION = 4.1
DEVELOPMENT_TEAM = MYTEAMIDGOESHERE
ENABLE_BITCODE = NO
CODE_SIGN_ENTITLEMENTS =
CODE_SIGN_IDENTITY =

base_debug.xcconfig

_DEBUG = DEBUG
GCC_PREPROCESSOR_DEFINITIONS = $(_DEBUG)
DEBUG_INFORMATION_FORMAT = dwarf
ENABLE_TESTABILITY = YES
GCC_DYNAMIC_NO_PIC = NO
GCC_OPTIMIZATION_LEVEL = 0
MTL_ENABLE_DEBUG_INFO = YES
ONLY_ACTIVE_ARCH = YES
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG
SWIFT_OPTIMIZATION_LEVEL = -Onone
SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) $(_DEBUG)

base_release.xcconfig

DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
ENABLE_NS_ASSERTIONS = NO
MTL_ENABLE_DEBUG_INFO = NO
SWIFT_COMPILATION_MODE = wholemodule
SWIFT_OPTIMIZATION_LEVEL = -O
VALIDATE_PRODUCT = YES

base_apps.xcconfig

#include "base_shared.xcconfig"
// Apps have no specific BuildSettings that the FRAMEWORKS does not have as well. But in the future they might have, thus we have this file.

// These settings were in the TravelCompanion xcconfig
SWIFT_ACTIVE_COMPILATION_CONDITIONS[sdk=iphonesimulator*] = $(inherited) IOS_SIMULATOR
MTL_ENABLE_DEBUG_INFO = NO
SWIFT_OPTIMIZATION_LEVEL = -O
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
ENABLE_NS_ASSERTIONS = NO
VALIDATE_PRODUCT = YES
SUPPORTED_PLATFORMS = iphonesimulator iphoneos
VALID_ARCHS = arm64 armv7 armv7s
CLANG_MODULES_AUTOLINK = YES
GCC_OPTIMIZATION_LEVEL = s
CLANG_ENABLE_CODE_COVERAGE = NO
TARGETED_DEVICE_FAMILY = 1
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES
VERSIONING_SYSTEM = apple_generic

// Custom
// The flag `ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES` should be set to `YES` for apps and `NO` for frameworks
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES

base_framework.xcconfig

#include "base_shared.xcconfig"

// BuildSettings specific for FRAMEWORKS (Cocoa Touch Framework)

// Vanilla BuildSettings
CURRENT_PROJECT_VERSION = 1
VERSIONING_SYSTEM = apple-generic
VERSION_INFO_PREFIX =

// Custom Set
PRODUCT_NAME = $(TARGET_NAME:c99extidentifier)
INSTALL_PATH = $(LOCAL_LIBRARY_DIR)/Frameworks
DYLIB_COMPATIBILITY_VERSION = 1
DYLIB_CURRENT_VERSION = 1
DEFINES_MODULE = YES
SKIP_INSTALL = YES


// The flag `ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES` should be set to `YES` for apps and `NO` for frameworks
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO

LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks

base_tests.xcconfig

#include "base_shared.xcconfig"

ONLY_ACTIVE_ARCH = YES

//Only used by APPS but it does not mess up build settings for test targets for FRAMEWORKS in Xcode 9.3 so will keep it here for now
BUNDLE_LOADER = $(TEST_HOST)

base_uitests.xcconfig

#include "base_shared.xcconfig"
TEST_TARGET_NAME = $(PRODUCT_NAME)

Models-Common.xcconfig

#include "../../../../Configurations/base_framework.xcconfig"

INFOPLIST_FILE = Source/SupportingFiles/Models-Info.plist
PRODUCT_BUNDLE_IDENTIFIER = com.sajjon.Models

Models-Debug.xcconfig

#include "Models-Common.xcconfig"
#include "../../../../Configurations/base_debug.xcconfig"
#include "../../Pods/Target Support Files/Pods-Framework-Models-Models/Pods-Framework-Models-Models.debug.xcconfig"

Models-Release.xcconfig

#include "Models-Common.xcconfig"
#include "../../../../Configurations/base_release.xcconfig"
#include "../../Pods/Target Support Files/Pods-Framework-Models-Models/Pods-Framework-Models-Models.release.xcconfig"

ModelsTests-Common.xcconfig

#include "../../../../Configurations/base_framework.xcconfig"
#include "../../../../Configurations/base_tests.xcconfig"
INFOPLIST_FILE = Tests/SupportingFiles/ModelsTests-Info.plist

ModelsTests-Debug.xcconfig

#include "ModelsTests-Common.xcconfig"
#include "../../../../Configurations/base_debug.xcconfig"
#include "../../Pods/Target Support Files/Pods-Framework-Models-ModelsTests/Pods-Framework-Models-ModelsTests.debug.xcconfig"

ModelsTests-Release.xcconfig

#include "ModelsTests-Common.xcconfig"
#include "../../../../Configurations/base_release.xcconfig"
#include "../../Pods/Target Support Files/Pods-Framework-Models-ModelsTests/Pods-Framework-Models-ModelsTests.release.xcconfig"

MyiPhoneApp-Commong.xcconfig

#include "../../../../Configurations/base_apps.xcconfig"

_APP_NAME_PROD = My iPhone App
_BUNDLE_IDENTIFIER_PROD = com.sajjon.myiphoneaop
INFOPLIST_FILE = Source/SupportingFiles/MyiPhoneApp-Info.plist

DEVELOPMENT_TEAM = MYTEAMGOESHERE

PRODUCT_NAME = $(_APP_NAME_PROD)
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage

CODE_SIGN_ENTITLEMENTS = Source/SupportingFiles/$(_APP_NAME_PROD).entitlements
SWIFT_OBJC_BRIDGING_HEADER = Source/SupportingFiles/MyiPhoneApp-Bridging-Header.h

PRODUCT_MODULE_NAME = TravelCompanion

// Overridden in Debug.xcconfig
CODE_SIGN_IDENTITY = iPhone Distribution

// Overridden in Release.xcconfig
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon-Alpha

ENABLE_TESTABILITY = YES

MyiPhoneApp-Debug.xcconfig

#include "MyiPhoneApp-Common.xcconfig"
#include "../../../../Configurations/base_debug.xcconfig"
#include "../../Pods/Target Support Files/Pods-MyiPhoneApp/Pods-MyiPhoneApp.debug.xcconfig"

_DEBUG = DEBUG
_CODE_SIGN_ID_DEBUG = iPhone Developer
_BUNDLE_IDENTIFIER_DEBUG = $(_BUNDLE_IDENTIFIER_PROD).dev
_PP_DEBUG = match Development $(_BUNDLE_IDENTIFIER_DEBUG)

CODE_SIGN_IDENTITY = $(_CODE_SIGN_ID_DEBUG)

PROVISIONING_PROFILE_SPECIFIER = $(_PP_DEBUG)
PRODUCT_BUNDLE_IDENTIFIER = $(_BUNDLE_IDENTIFIER_DEBUG)
APP_DISPLAY_NAME = MyiPhoneApp
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon-Debug
SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) $(_DEBUG)
GCC_PREPROCESSOR_DEFINITIONS = $(_DEBUG)
GCC_OPTIMIZATION_LEVEL = 0
GCC_OPTIMIZATION_LEVEL = 0
MTL_ENABLE_DEBUG_INFO = YES
SWIFT_OPTIMIZATION_LEVEL = -Onone
GCC_DYNAMIC_NO_PIC = NO
ONLY_ACTIVE_ARCH = YES
ENABLE_NS_ASSERTIONS = YES
ENABLE_NS_ASSERTIONS[sdk=iphoneos*] = YES
VALIDATE_PRODUCT = NO

MyiPhoneApp-Release.xcconfig

#include "MyiPhoneApp-Common.xcconfig"
#include "../../../../Configurations/base_release.xcconfig"
#include "../../Pods/Target Support Files/Pods-MyiPhoneApp/Pods-MyiPhoneApp.release.xcconfig"

_PP_PROD = match AppStore $(_BUNDLE_IDENTIFIER_PROD)

PROVISIONING_PROFILE_SPECIFIER = $(_PP_PROD)
PRODUCT_BUNDLE_IDENTIFIER = $(_BUNDLE_IDENTIFIER_PROD)
APP_DISPLAY_NAME = $(_APP_NAME_PROD)
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon-Production
SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) APP_STORE_BUILD
SWIFT_OPTIMIZATION_LEVEL = -Owholemodule

1 个答案:

答案 0 :(得分:1)

我们的项目中有很多自定义框架,我们遇到了类似的问题。我们为每个框架提供了两个构建配置,即DEBUG和RELEASE。我们只为我们用来运行测试的DEBUG构建启用了ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES。