diff --git a/Scripts/embed-runner-icon.sh b/Scripts/embed-runner-icon.sh new file mode 100755 index 000000000..b71ba0ab5 --- /dev/null +++ b/Scripts/embed-runner-icon.sh @@ -0,0 +1,87 @@ +#!/bin/bash +# Embed the WDA app icon into the wrapping XCTRunner host app so the +# installed WebDriverAgent shows the Appium logo on the iOS home screen +# instead of a blank icon. +# +# Apple's USES_XCTRUNNER auto-generates a Runner.app around UI-testing +# .xctest bundles but does not inherit icons from the test bundle's +# asset catalog. actool produces AppIcon*.png + Assets.car inside +# PlugIns/.xctest/ where iOS never looks. This script lifts +# them up to the Runner.app root and patches Info.plist accordingly. +# +# Limitations: +# - Touches XCTRunner internals; may need updates across Xcode versions. +# - iOS only; tvOS uses different "Brand Assets" and is not handled. +# - Cloud device farms that re-sign WDA must preserve these changes. + +set -euo pipefail + +RUNNER_APP="${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}-Runner.app" +XCTEST="${RUNNER_APP}/PlugIns/${PRODUCT_NAME}.xctest" + +if [ ! -d "$RUNNER_APP" ]; then + echo "warning: ${PRODUCT_NAME}-Runner.app not found at $RUNNER_APP; skipping icon embed" + exit 0 +fi + +if [ ! -d "$XCTEST" ]; then + echo "warning: ${PRODUCT_NAME}.xctest not found inside Runner.app; skipping icon embed" + exit 0 +fi + +shopt -s nullglob +ICONS=("$XCTEST"/AppIcon*.png) +if [ ${#ICONS[@]} -eq 0 ]; then + echo "warning: no compiled AppIcon*.png found inside $XCTEST; skipping icon embed" + exit 0 +fi + +cp -f "${ICONS[@]}" "$RUNNER_APP/" +if [ -f "$XCTEST/Assets.car" ]; then + cp -f "$XCTEST/Assets.car" "$RUNNER_APP/" +fi + +PLIST="$RUNNER_APP/Info.plist" +/usr/libexec/PlistBuddy -c "Delete :CFBundleIcons" "$PLIST" 2>/dev/null || true +/usr/libexec/PlistBuddy -c "Delete :CFBundleIcons~ipad" "$PLIST" 2>/dev/null || true + +/usr/libexec/PlistBuddy -c "Add :CFBundleIcons dict" "$PLIST" +/usr/libexec/PlistBuddy -c "Add :CFBundleIcons:CFBundlePrimaryIcon dict" "$PLIST" +/usr/libexec/PlistBuddy -c "Add :CFBundleIcons:CFBundlePrimaryIcon:CFBundleIconName string AppIcon" "$PLIST" +/usr/libexec/PlistBuddy -c "Add :CFBundleIcons:CFBundlePrimaryIcon:CFBundleIconFiles array" "$PLIST" +/usr/libexec/PlistBuddy -c "Add :CFBundleIcons:CFBundlePrimaryIcon:CFBundleIconFiles:0 string AppIcon60x60" "$PLIST" + +/usr/libexec/PlistBuddy -c "Add :CFBundleIcons~ipad dict" "$PLIST" +/usr/libexec/PlistBuddy -c "Add :CFBundleIcons~ipad:CFBundlePrimaryIcon dict" "$PLIST" +/usr/libexec/PlistBuddy -c "Add :CFBundleIcons~ipad:CFBundlePrimaryIcon:CFBundleIconName string AppIcon" "$PLIST" +/usr/libexec/PlistBuddy -c "Add :CFBundleIcons~ipad:CFBundlePrimaryIcon:CFBundleIconFiles array" "$PLIST" +/usr/libexec/PlistBuddy -c "Add :CFBundleIcons~ipad:CFBundlePrimaryIcon:CFBundleIconFiles:0 string AppIcon60x60" "$PLIST" +/usr/libexec/PlistBuddy -c "Add :CFBundleIcons~ipad:CFBundlePrimaryIcon:CFBundleIconFiles:1 string AppIcon76x76" "$PLIST" + +# Re-codesign since we modified the bundle after Xcode signed it. +# In a scheme post-action context Xcode's CODE_SIGN_* env vars are not exposed, +# so discover the existing signing identity from the already-signed bundle. +if [ -d "$RUNNER_APP/_CodeSignature" ]; then + # Capture the signature info once. Piping codesign straight into + # `awk ... exit` makes awk close the pipe early, killing codesign with + # SIGPIPE -- which `set -o pipefail` turns into a fatal error. That trips + # only when an Authority line exists, i.e. on every real-device build. + SIGN_INFO=$(codesign -dvv "$RUNNER_APP" 2>&1 || true) + EXISTING_IDENT="${EXPANDED_CODE_SIGN_IDENTITY:-}" + if [ -z "$EXISTING_IDENT" ]; then + EXISTING_IDENT=$(awk -F'=' '/^Authority/ {print $2; exit}' <<< "$SIGN_INFO") + fi + # Simulator builds are ad-hoc signed: there is no Authority line, but the + # bundle can still be re-signed ad-hoc with an identity of "-". + if [ -z "$EXISTING_IDENT" ] && grep -q '^Signature=adhoc' <<< "$SIGN_INFO"; then + EXISTING_IDENT="-" + fi + if [ -n "$EXISTING_IDENT" ]; then + codesign --force --sign "$EXISTING_IDENT" \ + --preserve-metadata=identifier,entitlements "$RUNNER_APP" + else + echo "warning: bundle is signed but no identity discovered; signature will be invalid" + fi +fi + +echo "embedded icon into $RUNNER_APP" diff --git a/WebDriverAgent.xcodeproj/project.pbxproj b/WebDriverAgent.xcodeproj/project.pbxproj index 2d353269e..82f506bb8 100644 --- a/WebDriverAgent.xcodeproj/project.pbxproj +++ b/WebDriverAgent.xcodeproj/project.pbxproj @@ -826,6 +826,7 @@ F59CD6D52EF16E5E00F91287 /* XCUIElement+FBCustomActions.m in Sources */ = {isa = PBXBuildFile; fileRef = F59CD6D32EF16E5E00F91287 /* XCUIElement+FBCustomActions.m */; }; F59CD6D62EF16E5E00F91287 /* XCUIElement+FBCustomActions.h in Headers */ = {isa = PBXBuildFile; fileRef = F59CD6D22EF16E5E00F91287 /* XCUIElement+FBCustomActions.h */; }; F59CD6D72EF16E5E00F91287 /* XCUIElement+FBCustomActions.m in Sources */ = {isa = PBXBuildFile; fileRef = F59CD6D32EF16E5E00F91287 /* XCUIElement+FBCustomActions.m */; }; + A1B2C3D4E5F600000000001B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A1B2C3D4E5F600000000001A /* Assets.xcassets */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -1368,6 +1369,7 @@ EE9AB7921CAEDF0C008C271F /* FBRuntimeUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBRuntimeUtils.m; sourceTree = ""; }; EE9AB7FC1CAEE048008C271F /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = WebDriverAgentRunner/Info.plist; sourceTree = SOURCE_ROOT; }; EE9AB7FD1CAEE048008C271F /* UITestingUITests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UITestingUITests.m; path = WebDriverAgentRunner/UITestingUITests.m; sourceTree = SOURCE_ROOT; }; + A1B2C3D4E5F600000000001A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = WebDriverAgentRunner/Assets.xcassets; sourceTree = SOURCE_ROOT; }; EE9AB8031CAEE182008C271F /* build.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = build.sh; sourceTree = ""; }; EE9B75D41CF7956C00275851 /* IntegrationApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IntegrationApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; EE9B75EC1CF7956C00275851 /* IntegrationTests_1.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IntegrationTests_1.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2294,6 +2296,7 @@ children = ( EE9AB7FC1CAEE048008C271F /* Info.plist */, EE9AB7FD1CAEE048008C271F /* UITestingUITests.m */, + A1B2C3D4E5F600000000001A /* Assets.xcassets */, ); name = WebDriverAgentRunner; path = XCTUITestRunner; @@ -3110,6 +3113,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + A1B2C3D4E5F600000000001B /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4346,6 +4350,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = EEE5CABF1C80361500CBBDD9 /* IOSSettings.xcconfig */; buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_STATIC_ANALYZER_MODE = deep; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_TESTING_SEARCH_PATHS = YES; @@ -4399,6 +4404,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = EEE5CABF1C80361500CBBDD9 /* IOSSettings.xcconfig */; buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_STATIC_ANALYZER_MODE = deep; ENABLE_TESTING_SEARCH_PATHS = YES; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; diff --git a/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner.xcscheme b/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner.xcscheme index da77fd577..157829787 100644 --- a/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner.xcscheme +++ b/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner.xcscheme @@ -5,6 +5,24 @@ + + + + + + + + + +