diff --git a/.github/workflows/ios-browserstack.yml b/.github/workflows/ios-browserstack.yml new file mode 100644 index 000000000..08862378b --- /dev/null +++ b/.github/workflows/ios-browserstack.yml @@ -0,0 +1,81 @@ +name: Build and test iOS Sample App on Browserstack +on: pull_request + +jobs: + run-ios-browserstack: + runs-on: macos-latest + + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.2.2" + bundler-cache: true + - run: brew install xcodesorg/made/xcodes + - name: Install the Apple certificate and provisioning profile + env: + BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} + P12_PASSWORD: ${{ secrets.P12_PASSWORD }} + BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }} + BUILD_PROVISION_EXTENSION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_EXTENSION_PROFILE_BASE64 }} + BUILD_PROVISION_WILDCARD_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_WILDCARD_PROFILE_BASE64 }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + EXPORT_OPTIONS_PLIST: ${{ secrets.EXPORT_OPTIONS_PLIST }} + run: | + # create variables + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + PP_1_PATH=$RUNNER_TEMP/build_pp_1.mobileprovision + PP_2_PATH=$RUNNER_TEMP/build_pp_2.mobileprovision + PP_3_PATH=$RUNNER_TEMP/build_pp_3.mobileprovision + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + + # import certificate and provisioning profile from secrets + echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH + echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_1_PATH + echo -n "$BUILD_PROVISION_EXTENSION_PROFILE_BASE64" | base64 --decode -o $PP_2_PATH + echo -n "$BUILD_PROVISION_WILDCARD_PROFILE_BASE64" | base64 --decode -o $PP_3_PATH + + # create temporary keychain + security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + security set-keychain-settings -lut 21600 $KEYCHAIN_PATH + security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + + # import certificate to keychain + security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + security list-keychain -d user -s $KEYCHAIN_PATH + + # apply provisioning profile + mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles + cp $PP_1_PATH ~/Library/MobileDevice/Provisioning\ Profiles + cp $PP_2_PATH ~/Library/MobileDevice/Provisioning\ Profiles + cp $PP_3_PATH ~/Library/MobileDevice/Provisioning\ Profiles + + # create plist + EXPORT_OPTS_PATH=$RUNNER_TEMP/ExportOptions.plist + echo -n "$EXPORT_OPTIONS_PLIST" | base64 --decode -o $EXPORT_OPTS_PATH + + - name: fastlane build swift-sample-app + run: bundle exec fastlane build_for_browserstack plist:$RUNNER_TEMP/ExportOptions.plist + + - name: upload swift-sample-app .ipa to browserstack + id: upload_ipa + run: | + app_url=$(curl -u "${{ secrets.BROWSERSTACK_USERNAME }}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \ + -X POST "https://api-cloud.browserstack.com/app-automate/xcuitest/v2/app" \ + -F "file=@${{ github.workspace }}/build-swift-sample-app/swift-sample-app.ipa" \ + -F "custom_id=swift-sample-app" | jq -r '.app_url'); echo "app_url=$app_url" >> $GITHUB_OUTPUT + + - name: upload test suite .zip to browserstack + id: upload_test + run: | + test_suite_url=$(curl -u "${{ secrets.BROWSERSTACK_USERNAME}}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \ + -X POST "https://api-cloud.browserstack.com/app-automate/xcuitest/v2/test-suite" \ + -F "file=@${{ github.workspace }}/build-swift-sample-app/swift-sample-app-ui-test.zip" \ + -F "custom_id=swift-sample-app-ui-test" | jq -r '.test_suite_url'); echo "test_suite_url=$test_suite_url" >> $GITHUB_OUTPUT + + - name: execute test suite on browserstack + run: | + curl -u "${{ secrets.BROWSERSTACK_USERNAME }}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \ + -X POST "https://api-cloud.browserstack.com/app-automate/xcuitest/v2/build" \ + -d '{"devices": ["iPad Air 4-14", "iPhone XS-13", "iPhone 14 Pro Max-16"], "app": "${{ steps.upload_ipa.outputs.app_url }}", "testSuite": "${{ steps.upload_test.outputs.test_suite_url }}"}' \ + -H "Content-Type: application/json" diff --git a/Gemfile b/Gemfile new file mode 100644 index 000000000..3831d7eda --- /dev/null +++ b/Gemfile @@ -0,0 +1,4 @@ +source "https://rubygems.org" + +gem "fastlane" +gem "xcode-install" \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 000000000..6088701f1 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,220 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.6) + rexml + addressable (2.8.5) + public_suffix (>= 2.0.2, < 6.0) + artifactory (3.0.15) + atomos (0.1.3) + aws-eventstream (1.3.0) + aws-partitions (1.863.0) + aws-sdk-core (3.190.0) + aws-eventstream (~> 1, >= 1.3.0) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.8) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.74.0) + aws-sdk-core (~> 3, >= 3.188.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.141.0) + aws-sdk-core (~> 3, >= 3.189.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.8) + aws-sigv4 (1.8.0) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + claide (1.1.0) + colored (1.2) + colored2 (3.1.2) + commander (4.6.0) + highline (~> 2.0.0) + declarative (0.0.20) + digest-crc (0.6.5) + rake (>= 12.0.0, < 14.0.0) + domain_name (0.6.20231109) + dotenv (2.8.1) + emoji_regex (3.2.3) + excon (0.105.0) + faraday (1.10.3) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.7) + faraday (>= 0.8.0) + http-cookie (~> 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.0.4) + multipart-post (~> 2) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + faraday_middleware (1.2.0) + faraday (~> 1.0) + fastimage (2.2.7) + fastlane (2.217.0) + CFPropertyList (>= 2.3, < 4.0.0) + addressable (>= 2.8, < 3.0.0) + artifactory (~> 3.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.3, < 2.0.0) + bundler (>= 1.12.0, < 3.0.0) + colored + commander (~> 4.6) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + excon (>= 0.71.0, < 1.0.0) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.0) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-storage (~> 1.31) + highline (~> 2.0) + http-cookie (~> 1.0.5) + json (< 3.0.0) + jwt (>= 2.1.0, < 3) + mini_magick (>= 4.9.4, < 5.0.0) + multipart-post (>= 2.0.0, < 3.0.0) + naturally (~> 2.2) + optparse (~> 0.1.1) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 2.0.0, < 3.0.0) + security (= 0.1.3) + simctl (~> 1.6.3) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (~> 3) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.3.0) + xcpretty-travis-formatter (>= 0.0.3) + gh_inspector (1.1.3) + google-apis-androidpublisher_v3 (0.53.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-core (0.11.2) + addressable (~> 2.5, >= 2.5.1) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.a) + rexml + webrick + google-apis-iamcredentials_v1 (0.17.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-playcustomapp_v1 (0.13.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-storage_v1 (0.29.0) + google-apis-core (>= 0.11.0, < 2.a) + google-cloud-core (1.6.1) + google-cloud-env (>= 1.0, < 3.a) + google-cloud-errors (~> 1.0) + google-cloud-env (2.0.1) + faraday (>= 1.0, < 3.a) + google-cloud-errors (1.3.1) + google-cloud-storage (1.45.0) + addressable (~> 2.8) + digest-crc (~> 0.4) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.29.0) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) + mini_mime (~> 1.0) + googleauth (1.8.1) + faraday (>= 0.17.3, < 3.a) + jwt (>= 1.4, < 3.0) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.5) + domain_name (~> 0.5) + httpclient (2.8.3) + jmespath (1.6.2) + json (2.7.1) + jwt (2.7.1) + mini_magick (4.12.0) + mini_mime (1.1.5) + multi_json (1.15.0) + multipart-post (2.3.0) + nanaimo (0.3.0) + naturally (2.2.1) + optparse (0.1.1) + os (1.1.4) + plist (3.7.0) + public_suffix (5.0.4) + rake (13.1.0) + representable (3.2.0) + declarative (< 0.1.0) + trailblazer-option (>= 0.1.1, < 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rexml (3.2.6) + rouge (2.0.7) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) + security (0.1.3) + signet (0.18.0) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simctl (1.6.10) + CFPropertyList + naturally + terminal-notifier (2.0.0) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + trailblazer-option (0.1.2) + tty-cursor (0.7.1) + tty-screen (0.8.1) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unicode-display_width (2.5.0) + webrick (1.8.1) + word_wrap (1.0.0) + xcode-install (2.8.1) + claide (>= 0.9.1) + fastlane (>= 2.1.0, < 3.0.0) + xcodeproj (1.23.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (~> 3.2.4) + xcpretty (0.3.0) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.1) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + arm64-darwin-21 + ruby + x86_64-darwin-20 + x86_64-linux + +DEPENDENCIES + fastlane + xcode-install + +BUNDLED WITH + 2.4.22 diff --git a/fastlane/Fastfile b/fastlane/Fastfile new file mode 100644 index 000000000..03bcbaab8 --- /dev/null +++ b/fastlane/Fastfile @@ -0,0 +1,54 @@ +default_platform(:ios) + +platform :ios do + desc "build swift-sample-app .ipa and ui-test.zip for browserstack" + lane :build_for_browserstack do |options| + xcodes(version: "14.2", select_for_current_build_only: true) + ensure_xcode_version(version: "14.2") + build_swift_sample_app(plist:options[:plist]) + build_ui_tests + end + + desc "build swift-sample-app .ipa" + lane :build_swift_sample_app do |options| + build_app( + project: "sample-apps/swift-sample-app/swift-sample-app.xcodeproj", + configuration: "Debug", + scheme: "swift-sample-app", + silent: true, + clean: true, + sdk: "iphoneos", + destination: "generic/platform=iOS", + output_directory: "./build-swift-sample-app", + output_name: "swift-sample-app.ipa", + export_method: "development", + export_options: { + provisioningProfiles: { + "iterable.swift-sample-app" => "ios-dev-swift-sample-app", + "iterable.swift-sample-app.swift-sample-app-notification-extension" => "ios-dev-swift-sample-app-notification-extension", + } + } + ) + end + + desc "build swift-sample-app UI tests" + lane :build_ui_tests do + scan( + project: "sample-apps/swift-sample-app/swift-sample-app.xcodeproj", + configuration: "Debug", + scheme: "swift-sample-app", + sdk: "iphoneos", + destination: "generic/platform=iOS", + skip_build: false, + derived_data_path: "./build-swift-sample-app", + build_for_testing: true, + clean: true, + xcargs: "-allowProvisioningUpdates" + ) + + zip( + path: "./build-swift-sample-app/Build/Products/Debug-iphoneos/SwiftSampleAppUITest-Runner.app", + output_path: "./build-swift-sample-app/swift-sample-app-ui-test.zip" + ) + end +end diff --git a/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/project.pbxproj b/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/project.pbxproj index 17659f0ab..750bb1e71 100644 --- a/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/project.pbxproj +++ b/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/project.pbxproj @@ -19,8 +19,10 @@ ACA3A14020E2F6B100FEF74F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ACA3A13F20E2F6B100FEF74F /* Assets.xcassets */; }; ACA3A14320E2F6B100FEF74F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ACA3A14120E2F6B100FEF74F /* LaunchScreen.storyboard */; }; ACA3A15120E2F83E00FEF74F /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ACA3A15020E2F83E00FEF74F /* NotificationService.swift */; }; - ACA3A15520E2F83E00FEF74F /* swift-sample-app-notification-extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = ACA3A14E20E2F83D00FEF74F /* swift-sample-app-notification-extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + ACA3A15520E2F83E00FEF74F /* swift-sample-app-notification-extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = ACA3A14E20E2F83D00FEF74F /* swift-sample-app-notification-extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; ACE7624B20FEB2C20040A002 /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ACE7624A20FEB2C20040A002 /* LoginViewController.swift */; }; + C3353E992B1E65390031F9FE /* SwiftSampleAppUITest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3353E982B1E65390031F9FE /* SwiftSampleAppUITest.swift */; }; + C3353EA22B1E6C1F0031F9FE /* XCUITestBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3353EA12B1E6C1F0031F9FE /* XCUITestBase.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -31,18 +33,25 @@ remoteGlobalIDString = ACA3A14D20E2F83D00FEF74F; remoteInfo = "swift-sample-app-notification-extension"; }; + C3353E9C2B1E65390031F9FE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = ACA3A12D20E2F6AF00FEF74F /* Project object */; + proxyType = 1; + remoteGlobalIDString = ACA3A13420E2F6AF00FEF74F; + remoteInfo = "swift-sample-app"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ - ACA3A15920E2F83E00FEF74F /* Embed App Extensions */ = { + ACA3A15920E2F83E00FEF74F /* Embed Foundation Extensions */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 13; files = ( - ACA3A15520E2F83E00FEF74F /* swift-sample-app-notification-extension.appex in Embed App Extensions */, + ACA3A15520E2F83E00FEF74F /* swift-sample-app-notification-extension.appex in Embed Foundation Extensions */, ); - name = "Embed App Extensions"; + name = "Embed Foundation Extensions"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ @@ -65,6 +74,9 @@ ACA3A16420E2FC7500FEF74F /* swift-sample-app.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "swift-sample-app.entitlements"; sourceTree = ""; }; ACE7624A20FEB2C20040A002 /* LoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = ""; }; ACFA148520E3033700AF4A5A /* CoffeeType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoffeeType.swift; sourceTree = ""; }; + C3353E962B1E65390031F9FE /* SwiftSampleAppUITest.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftSampleAppUITest.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + C3353E982B1E65390031F9FE /* SwiftSampleAppUITest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftSampleAppUITest.swift; sourceTree = ""; }; + C3353EA12B1E6C1F0031F9FE /* XCUITestBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCUITestBase.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -84,6 +96,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + C3353E932B1E65390031F9FE /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -121,6 +140,7 @@ children = ( ACA3A13520E2F6AF00FEF74F /* swift-sample-app.app */, ACA3A14E20E2F83D00FEF74F /* swift-sample-app-notification-extension.appex */, + C3353E962B1E65390031F9FE /* SwiftSampleAppUITest.xctest */, ); name = Products; sourceTree = ""; @@ -128,6 +148,7 @@ ACA3A13720E2F6AF00FEF74F /* swift-sample-app */ = { isa = PBXGroup; children = ( + C3353E972B1E65390031F9FE /* swift-sample-app-ui-test */, AC5ECD9D20E303F50081E1DA /* ViewControllers */, AC5ECD9B20E3038B0081E1DA /* Deep Link Handling */, ACFA148620E3034800AF4A5A /* Assets */, @@ -182,6 +203,15 @@ name = Storyboards; sourceTree = ""; }; + C3353E972B1E65390031F9FE /* swift-sample-app-ui-test */ = { + isa = PBXGroup; + children = ( + C3353E982B1E65390031F9FE /* SwiftSampleAppUITest.swift */, + C3353EA12B1E6C1F0031F9FE /* XCUITestBase.swift */, + ); + path = "swift-sample-app-ui-test"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -192,7 +222,7 @@ ACA3A13120E2F6AF00FEF74F /* Sources */, ACA3A13220E2F6AF00FEF74F /* Frameworks */, ACA3A13320E2F6AF00FEF74F /* Resources */, - ACA3A15920E2F83E00FEF74F /* Embed App Extensions */, + ACA3A15920E2F83E00FEF74F /* Embed Foundation Extensions */, ); buildRules = ( ); @@ -227,14 +257,32 @@ productReference = ACA3A14E20E2F83D00FEF74F /* swift-sample-app-notification-extension.appex */; productType = "com.apple.product-type.app-extension"; }; + C3353E952B1E65390031F9FE /* SwiftSampleAppUITest */ = { + isa = PBXNativeTarget; + buildConfigurationList = C3353EA02B1E65390031F9FE /* Build configuration list for PBXNativeTarget "SwiftSampleAppUITest" */; + buildPhases = ( + C3353E922B1E65390031F9FE /* Sources */, + C3353E932B1E65390031F9FE /* Frameworks */, + C3353E942B1E65390031F9FE /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + C3353E9D2B1E65390031F9FE /* PBXTargetDependency */, + ); + name = SwiftSampleAppUITest; + productName = SwiftSampleAppUITest; + productReference = C3353E962B1E65390031F9FE /* SwiftSampleAppUITest.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ ACA3A12D20E2F6AF00FEF74F /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0940; - LastUpgradeCheck = 1200; + LastSwiftUpdateCheck = 1420; + LastUpgradeCheck = 1420; ORGANIZATIONNAME = Iterable; TargetAttributes = { ACA3A13420E2F6AF00FEF74F = { @@ -253,6 +301,10 @@ CreatedOnToolsVersion = 9.4; LastSwiftMigration = 1030; }; + C3353E952B1E65390031F9FE = { + CreatedOnToolsVersion = 14.2; + TestTargetID = ACA3A13420E2F6AF00FEF74F; + }; }; }; buildConfigurationList = ACA3A13020E2F6AF00FEF74F /* Build configuration list for PBXProject "swift-sample-app" */; @@ -270,6 +322,7 @@ targets = ( ACA3A13420E2F6AF00FEF74F /* swift-sample-app */, ACA3A14D20E2F83D00FEF74F /* swift-sample-app-notification-extension */, + C3353E952B1E65390031F9FE /* SwiftSampleAppUITest */, ); }; /* End PBXProject section */ @@ -292,6 +345,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + C3353E942B1E65390031F9FE /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -317,6 +377,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + C3353E922B1E65390031F9FE /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C3353E992B1E65390031F9FE /* SwiftSampleAppUITest.swift in Sources */, + C3353EA22B1E6C1F0031F9FE /* XCUITestBase.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -325,6 +394,11 @@ target = ACA3A14D20E2F83D00FEF74F /* swift-sample-app-notification-extension */; targetProxy = ACA3A15320E2F83E00FEF74F /* PBXContainerItemProxy */; }; + C3353E9D2B1E65390031F9FE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = ACA3A13420E2F6AF00FEF74F /* swift-sample-app */; + targetProxy = C3353E9C2B1E65390031F9FE /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -380,7 +454,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_IDENTITY = "Apple Development: Justin Yu (23ZWSJHXW7)"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -468,8 +542,11 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "swift-sample-app/swift-sample-app.entitlements"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = BP98Z28R86; + CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = BP98Z28R86; INFOPLIST_FILE = "swift-sample-app/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -477,6 +554,8 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "iterable.swift-sample-app"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "ios-dev-swift-sample-app"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -487,8 +566,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "swift-sample-app/swift-sample-app.entitlements"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = BP98Z28R86; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = BP98Z28R86; INFOPLIST_FILE = "swift-sample-app/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -496,6 +577,8 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "iterable.swift-sample-app"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "ios-dev-swift-sample-app"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -504,8 +587,11 @@ ACA3A15720E2F83E00FEF74F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = BP98Z28R86; + CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = BP98Z28R86; INFOPLIST_FILE = "swift-sample-app-notification-extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -514,6 +600,8 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "iterable.swift-sample-app.swift-sample-app-notification-extension"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "ios-dev-swift-sample-app-notification-extension"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -523,8 +611,10 @@ ACA3A15820E2F83E00FEF74F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = BP98Z28R86; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = BP98Z28R86; INFOPLIST_FILE = "swift-sample-app-notification-extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -533,12 +623,61 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "iterable.swift-sample-app.swift-sample-app-notification-extension"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "ios-dev-swift-sample-app-notification-extension"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; + C3353E9E2B1E65390031F9FE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = BP98Z28R86; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "iterable.swift-sample-app.SwiftSampleAppUITest"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "ios-dev-swift-sample-app-wildcard"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = "swift-sample-app"; + }; + name = Debug; + }; + C3353E9F2B1E65390031F9FE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = BP98Z28R86; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "iterable.swift-sample-app.SwiftSampleAppUITest"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = "swift-sample-app"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -569,6 +708,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + C3353EA02B1E65390031F9FE /* Build configuration list for PBXNativeTarget "SwiftSampleAppUITest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C3353E9E2B1E65390031F9FE /* Debug */, + C3353E9F2B1E65390031F9FE /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ diff --git a/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/xcshareddata/xcschemes/SwiftSampleAppUITest.xcscheme b/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/xcshareddata/xcschemes/SwiftSampleAppUITest.xcscheme new file mode 100644 index 000000000..39e2b5e25 --- /dev/null +++ b/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/xcshareddata/xcschemes/SwiftSampleAppUITest.xcscheme @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/xcshareddata/xcschemes/swift-sample-app-notification-extension.xcscheme b/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/xcshareddata/xcschemes/swift-sample-app-notification-extension.xcscheme index 13f5a5822..48a0602d2 100644 --- a/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/xcshareddata/xcschemes/swift-sample-app-notification-extension.xcscheme +++ b/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/xcshareddata/xcschemes/swift-sample-app-notification-extension.xcscheme @@ -1,6 +1,6 @@ + + + + diff --git a/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/xcshareddata/xcschemes/swift-sample-app.xcscheme b/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/xcshareddata/xcschemes/swift-sample-app.xcscheme index 3f4321f4a..9d2871c93 100644 --- a/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/xcshareddata/xcschemes/swift-sample-app.xcscheme +++ b/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/xcshareddata/xcschemes/swift-sample-app.xcscheme @@ -1,6 +1,6 @@ + + + + Bool { // ITBL: Setup Notification diff --git a/sample-apps/swift-sample-app/swift-sample-app/swift-sample-app-ui-test/SwiftSampleAppUITest.swift b/sample-apps/swift-sample-app/swift-sample-app/swift-sample-app-ui-test/SwiftSampleAppUITest.swift new file mode 100644 index 000000000..974ae4492 --- /dev/null +++ b/sample-apps/swift-sample-app/swift-sample-app/swift-sample-app-ui-test/SwiftSampleAppUITest.swift @@ -0,0 +1,17 @@ +// +// SwiftSampleAppUITest.swift +// SwiftSampleAppUITest +// +// Created by Justin Yu on 12/4/23. +// Copyright © 2023 Iterable. All rights reserved. +// + +import XCTest + +class SwiftSampleAppUITest: XCUITestBase { + func testElementsVisible() { + if app.staticTexts["Coffees"].waitForExistence(timeout:30) { + XCTAssertTrue(app.staticTexts["Coffees"].exists) + } + } +} diff --git a/sample-apps/swift-sample-app/swift-sample-app/swift-sample-app-ui-test/XCUITestBase.swift b/sample-apps/swift-sample-app/swift-sample-app/swift-sample-app-ui-test/XCUITestBase.swift new file mode 100644 index 000000000..1f1facfc6 --- /dev/null +++ b/sample-apps/swift-sample-app/swift-sample-app/swift-sample-app-ui-test/XCUITestBase.swift @@ -0,0 +1,24 @@ +// +// XCUITestBase.swift +// SwiftSampleAppUITest +// +// Created by Justin Yu on 12/4/23. +// Copyright © 2023 Iterable. All rights reserved. +// + +import XCTest + +class XCUITestBase: XCTestCase { + var app = XCUIApplication() + + override func setUp() { + super.setUp() + continueAfterFailure = false + app.launch() + } + + override func tearDown() { + app.terminate() + super.tearDown() + } +}