From 7512d06e9163b7f5259690b25e95ef830c061ab9 Mon Sep 17 00:00:00 2001 From: Leo Natan Date: Mon, 25 Jun 2018 18:40:16 +0300 Subject: [PATCH 1/2] Fix Xcode 10 build Move universal framework creation into shell script rather than a build phase in Xcode --- detox/ios/Detox.xcodeproj/project.pbxproj | 60 -------------- .../xcschemes/DetoxFramework.xcscheme | 80 ------------------- detox/scripts/build_framework.ios.sh | 4 +- detox/scripts/build_universal_framework.sh | 52 ++++++++++++ 4 files changed, 54 insertions(+), 142 deletions(-) delete mode 100644 detox/ios/Detox.xcodeproj/xcshareddata/xcschemes/DetoxFramework.xcscheme create mode 100755 detox/scripts/build_universal_framework.sh diff --git a/detox/ios/Detox.xcodeproj/project.pbxproj b/detox/ios/Detox.xcodeproj/project.pbxproj index 8a95b48eae..310ab1bcf5 100644 --- a/detox/ios/Detox.xcodeproj/project.pbxproj +++ b/detox/ios/Detox.xcodeproj/project.pbxproj @@ -6,20 +6,6 @@ objectVersion = 46; objects = { -/* Begin PBXAggregateTarget section */ - 3941F4F21DC6200700F23DAC /* DetoxFramework */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 3941F4F31DC6200700F23DAC /* Build configuration list for PBXAggregateTarget "DetoxFramework" */; - buildPhases = ( - 3941F4F61DC6203000F23DAC /* ShellScript */, - ); - dependencies = ( - ); - name = DetoxFramework; - productName = DetoxFramework; - }; -/* End PBXAggregateTarget section */ - /* Begin PBXBuildFile section */ 390D1C691E3A14EF007F5F46 /* UNNotificationResponse+PrivateHeaders.h in Headers */ = {isa = PBXBuildFile; fileRef = 390D1C671E3A14EF007F5F46 /* UNNotificationResponse+PrivateHeaders.h */; settings = {ATTRIBUTES = (Private, ); }; }; 390D1C9C1E3A45F1007F5F46 /* UNNotification+PrivateHeaders.h in Headers */ = {isa = PBXBuildFile; fileRef = 390D1C9A1E3A45F1007F5F46 /* UNNotification+PrivateHeaders.h */; }; @@ -545,10 +531,6 @@ LastSwiftMigration = 0900; ProvisioningStyle = Automatic; }; - 3941F4F21DC6200700F23DAC = { - CreatedOnToolsVersion = 8.1; - ProvisioningStyle = Automatic; - }; 394767961DBF985400D72256 = { CreatedOnToolsVersion = 8.1; LastSwiftMigration = 0900; @@ -583,7 +565,6 @@ projectRoot = ""; targets = ( 394767961DBF985400D72256 /* Detox */, - 3941F4F21DC6200700F23DAC /* DetoxFramework */, 3928EFA41E47404900C19B6E /* DetoxUserNotificationTests */, ); }; @@ -669,22 +650,6 @@ }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 3941F4F61DC6203000F23DAC /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/bash; - shellScript = "set -e\n\nfunction remove_arch() {\n lipo -create \"${1}\" \"${2}\" -output \"${3}\"\n}\n\nUNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal\n\n# Make sure the output directory exists\n\nmkdir -p \"${UNIVERSAL_OUTPUTFOLDER}\"\n\n# Step 1. Build Device and Simulator versions\n\nxcodebuild -target \"${PROJECT_NAME}\" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -arch arm64 -sdk iphoneos BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" clean build VALID_ARCHS=arm64\nxcodebuild -target \"${PROJECT_NAME}\" -configuration ${CONFIGURATION} -arch x86_64 -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" clean build VALID_ARCHS=x86_64\n\n# Step 2. Copy the framework structure (from iphoneos build) to the universal folder\n\ncp -R \"${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework\" \"${UNIVERSAL_OUTPUTFOLDER}/\"\n\n# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory\nSIMULATOR_SWIFT_MODULES_DIR=\"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/.\"\nif [ -d \"${SIMULATOR_SWIFT_MODULES_DIR}\" ]; then\ncp -R \"${SIMULATOR_SWIFT_MODULES_DIR}\" \"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule\"\nfi\n\n# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory\n\nremove_arch \"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}\" \"${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}\" \"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}\"\n\n# Step 5. Create universal binaries for embedded frameworks\n\nfor SUB_FRAMEWORK in $( ls \"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Frameworks\" ); do\nif [ -d \"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Frameworks/$SUB_FRAMEWORK\" ]; then\necho \"Processing ${SUB_FRAMEWORK} as a dir\"\nBINARY_NAME=\"${SUB_FRAMEWORK%.*}\"\n\nremove_arch \"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}\" \"${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}\" \"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}\"\n\nelse\necho \"Processing ${SUB_FRAMEWORK} as a file\"\n\nremove_arch \"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Frameworks/${SUB_FRAMEWORK}\" \"${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/Frameworks/${SUB_FRAMEWORK}\" \"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Frameworks/${SUB_FRAMEWORK}\"\n\nfi\ndone"; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 3928EFA11E47404900C19B6E /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -780,22 +745,6 @@ }; name = Release; }; - 3941F4F41DC6200700F23DAC /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 390D1C981E3A2893007F5F46 /* Detox.xcconfig */; - buildSettings = { - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 3941F4F51DC6200700F23DAC /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 390D1C981E3A2893007F5F46 /* Detox.xcconfig */; - buildSettings = { - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; 3947679D1DBF985400D72256 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 390D1C981E3A2893007F5F46 /* Detox.xcconfig */; @@ -986,15 +935,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 3941F4F31DC6200700F23DAC /* Build configuration list for PBXAggregateTarget "DetoxFramework" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3941F4F41DC6200700F23DAC /* Debug */, - 3941F4F51DC6200700F23DAC /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 394767911DBF985400D72256 /* Build configuration list for PBXProject "Detox" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/detox/ios/Detox.xcodeproj/xcshareddata/xcschemes/DetoxFramework.xcscheme b/detox/ios/Detox.xcodeproj/xcshareddata/xcschemes/DetoxFramework.xcscheme deleted file mode 100644 index 4018b01e85..0000000000 --- a/detox/ios/Detox.xcodeproj/xcshareddata/xcschemes/DetoxFramework.xcscheme +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/detox/scripts/build_framework.ios.sh b/detox/scripts/build_framework.ios.sh index 5f3b099b1a..425de70391 100755 --- a/detox/scripts/build_framework.ios.sh +++ b/detox/scripts/build_framework.ios.sh @@ -1,4 +1,4 @@ -#!/bin/bash -e +#!/bin/bash -e -x detoxRootPath="$(dirname $(dirname ${0}))" detoxVersion=`node -p "require('${detoxRootPath}/package.json').version"` @@ -32,7 +32,7 @@ function buildFramework () { detoxSourcePath="${1}" echo "Building Detox.framework from ${detoxSourcePath}..." mkdir -p "${detoxFrameworkDirPath}" - xcodebuild build -project "${detoxSourcePath}"/Detox.xcodeproj -scheme DetoxFramework -configuration Release -derivedDataPath "${detoxFrameworkDirPath}"/DetoxBuild BUILD_DIR="${detoxFrameworkDirPath}"/DetoxBuild/Build/Products &> "${detoxFrameworkDirPath}"/detox_ios.log + "${detoxRootPath}"/scripts/build_universal_framework.sh "${detoxSourcePath}"/Detox.xcodeproj "${detoxFrameworkDirPath}"/DetoxBuild &> "${detoxFrameworkDirPath}"/detox_ios.log mv "${detoxFrameworkDirPath}"/DetoxBuild/Build/Products/Release-universal/Detox.framework "${detoxFrameworkDirPath}" rm -fr "${detoxFrameworkDirPath}"/DetoxBuild } diff --git a/detox/scripts/build_universal_framework.sh b/detox/scripts/build_universal_framework.sh new file mode 100755 index 0000000000..5ad2950506 --- /dev/null +++ b/detox/scripts/build_universal_framework.sh @@ -0,0 +1,52 @@ +PROJECT=$1 +DERIVED_DATA=$2 +CONFIGURATION=Release +PROJECT_NAME=Detox + +set -e + +function remove_arch() { + lipo -create "${1}" "${2}" -output "${3}" +} + +UNIVERSAL_OUTPUTFOLDER=${DERIVED_DATA}/Build/Products/${CONFIGURATION}-universal + +# Make sure the output directory exists + +mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" + +# Step 1. Build Device and Simulator versions + +xcodebuild -project "${PROJECT}" -scheme Detox ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -arch arm64 -sdk iphoneos clean build VALID_ARCHS=arm64 -derivedDataPath "${DERIVED_DATA}" +xcodebuild -project "${PROJECT}" -scheme Detox -configuration ${CONFIGURATION} -arch x86_64 -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO clean build VALID_ARCHS=x86_64 -derivedDataPath "${DERIVED_DATA}" + +# Step 2. Copy the framework structure (from iphoneos build) to the universal folder + +cp -R "${DERIVED_DATA}/Build/Products/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/" + +# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory +SIMULATOR_SWIFT_MODULES_DIR="${DERIVED_DATA}/Build/Products/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." +if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then +cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule" +fi + +# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory + +remove_arch "${DERIVED_DATA}/Build/Products/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${DERIVED_DATA}/Build/Products/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" + +# Step 5. Create universal binaries for embedded frameworks + +for SUB_FRAMEWORK in $( ls "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Frameworks" ); do +if [ -d "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Frameworks/$SUB_FRAMEWORK" ]; then +echo "Processing ${SUB_FRAMEWORK} as a dir" +BINARY_NAME="${SUB_FRAMEWORK%.*}" + +remove_arch "${DERIVED_DATA}/Build/Products/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" "${DERIVED_DATA}/Build/Products/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" + +else +echo "Processing ${SUB_FRAMEWORK} as a file" + +remove_arch "${DERIVED_DATA}/Build/Products/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Frameworks/${SUB_FRAMEWORK}" "${DERIVED_DATA}/Build/Products/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/Frameworks/${SUB_FRAMEWORK}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Frameworks/${SUB_FRAMEWORK}" + +fi +done From 30d5160195d7a1fc483755902f43ff4bb8b54449 Mon Sep 17 00:00:00 2001 From: Leo Natan Date: Sun, 1 Jul 2018 12:09:37 +0300 Subject: [PATCH 2/2] Improve dispatch queue idling resource handling --- detox/ios/Detox.xcodeproj/project.pbxproj | 2 -- detox/ios/Detox/ReactNativeSupport.m | 36 ++++++++++++++++------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/detox/ios/Detox.xcodeproj/project.pbxproj b/detox/ios/Detox.xcodeproj/project.pbxproj index 310ab1bcf5..b0b998c821 100644 --- a/detox/ios/Detox.xcodeproj/project.pbxproj +++ b/detox/ios/Detox.xcodeproj/project.pbxproj @@ -228,7 +228,6 @@ 39A34C701E30F10D00BEBB59 /* DetoxAppDelegateProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DetoxAppDelegateProxy.m; sourceTree = ""; }; 39AB2D30205ABBD90029CD1F /* DetoxUserActivityDispatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetoxUserActivityDispatcher.swift; sourceTree = ""; }; 39CEFCDA1E34E91B00A09124 /* DetoxUserNotificationDispatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetoxUserNotificationDispatcher.swift; sourceTree = ""; }; - 39D91D2E202B4128008DD636 /* test */ = {isa = PBXFileReference; lastKnownFileType = folder; name = test; path = ../test; sourceTree = ""; }; 39F642201FDD5EB000468FED /* DTXLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DTXLogging.h; path = DTXLoggingInfra/DTXLogging.h; sourceTree = SOURCE_ROOT; }; 39F642271FDD5EB000468FED /* DTXLogging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DTXLogging.m; path = DTXLoggingInfra/DTXLogging.m; sourceTree = SOURCE_ROOT; }; 39F6422A1FDD5EEC00468FED /* Detox.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Detox.pch; sourceTree = ""; }; @@ -312,7 +311,6 @@ 39408DEE1FE6368100C20BD5 /* JS */ = { isa = PBXGroup; children = ( - 39D91D2E202B4128008DD636 /* test */, 3975C78220272ED500C59ED8 /* src */, ); name = JS; diff --git a/detox/ios/Detox/ReactNativeSupport.m b/detox/ios/Detox/ReactNativeSupport.m index 3a7b2326ee..ea145a530c 100644 --- a/detox/ios/Detox/ReactNativeSupport.m +++ b/detox/ios/Detox/ReactNativeSupport.m @@ -64,6 +64,7 @@ void swz_addToRunLoop(id self, SEL _cmd, NSRunLoop* runloop) } static NSMutableArray* __observedQueues; +static NSMutableArray* __currentDispatchQueueIdlingResources; static dispatch_queue_t (*wx_original_dispatch_queue_create)(const char *_Nullable label, dispatch_queue_attr_t _Nullable attr); @@ -126,6 +127,7 @@ void setupForTests() } __observedQueues = [NSMutableArray new]; + __currentDispatchQueueIdlingResources = [NSMutableArray new]; //Add an idling resource for each module queue. Method m = class_getInstanceMethod(cls, NSSelectorFromString(@"setUpMethodQueue")); @@ -135,17 +137,20 @@ void setupForTests() dispatch_queue_t queue = object_getIvar(_self, class_getInstanceVariable(cls, "_methodQueue")); - if(queue != nil && [queue isKindOfClass:[NSNull class]] == NO && queue != dispatch_get_main_queue() && [__observedQueues containsObject:queue] == NO) - { - NSString* queueName = [[NSString alloc] initWithUTF8String:dispatch_queue_get_label(queue) ?: ""]; - - [__observedQueues addObject:queue]; - - dtx_log_info(@"Adding idling resource for queue: %@", queue); - - - [[GREYUIThreadExecutor sharedInstance] registerIdlingResource:[GREYDispatchQueueIdlingResource resourceWithDispatchQueue:queue name:queueName ?: @"SomeReactQueue"]]; - } + dispatch_sync(__currentIdlingResourceSerialQueue, ^{ + if(queue != nil && [queue isKindOfClass:[NSNull class]] == NO && queue != dispatch_get_main_queue() && [__observedQueues containsObject:queue] == NO) + { + NSString* queueName = [[NSString alloc] initWithUTF8String:dispatch_queue_get_label(queue) ?: ""]; + + [__observedQueues addObject:queue]; + + dtx_log_info(@"Adding idling resource for queue: %@", queue); + + GREYDispatchQueueIdlingResource* ir = [GREYDispatchQueueIdlingResource resourceWithDispatchQueue:queue name:queueName ?: @"SomeReactQueue"]; + [__currentDispatchQueueIdlingResources addObject:ir]; + [[GREYUIThreadExecutor sharedInstance] registerIdlingResource:ir]; + } + }); })); //Cannot just extern this function - we are not linked with RN, so linker will fail. Instead, look for symbol in runtime. @@ -183,6 +188,15 @@ + (void)reloadApp return; } + dispatch_sync(__currentIdlingResourceSerialQueue, ^{ + [__currentDispatchQueueIdlingResources enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + [[GREYUIThreadExecutor sharedInstance] deregisterIdlingResource:obj]; + }]; + + [__currentDispatchQueueIdlingResources removeAllObjects]; + [__observedQueues removeAllObjects]; + }); + id bridge = [NSClassFromString(@"RCTBridge") valueForKey:@"currentBridge"]; SEL reqRelSel = NSSelectorFromString(@"requestReload");