From 7c6e85a3c5f14c4daf83119075ba1834d308c18a Mon Sep 17 00:00:00 2001 From: jnelle Date: Sat, 22 Jun 2024 17:42:19 +0200 Subject: [PATCH] ci: add iOS build Signed-off-by: jnelle chore: change app name Signed-off-by: jnelle ci: add mobile provision cert Signed-off-by: jnelle ci: fix release workflow file ci: add missing ipa output Signed-off-by: jnelle chore: add export options Signed-off-by: jnelle chore: update exportoptions Signed-off-by: jnelle ci(iOS): change export method Signed-off-by: jnelle ci: improve iOS builds Update release.yml ci: improve iOS builds Update release.yml --- .github/workflows/android.yml | 66 ------------- .github/workflows/release.yml | 120 ++++++++++++++++++++++++ iosApp/Configuration/Config.xcconfig | 4 +- iosApp/exportOptionsRelease.plist | 20 ++++ iosApp/iosApp.xcodeproj/project.pbxproj | 12 ++- 5 files changed, 151 insertions(+), 71 deletions(-) delete mode 100644 .github/workflows/android.yml create mode 100644 .github/workflows/release.yml create mode 100644 iosApp/exportOptionsRelease.plist diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml deleted file mode 100644 index fe3c12a..0000000 --- a/.github/workflows/android.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: CI/CD - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - runs-on: macos-14 - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - - name: Get Next Version - id: semver - uses: ietf-tools/semver-action@v1 - with: - token: ${{ github.token }} - branch: master - patchList: "refactor, fix, style, chore" - - name: set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: 21 - distribution: 'zulu' - - uses: actions/cache@v4 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - restore-keys: ${{ runner.os }}-gradle- - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 - - name: Retrieve the keystore and decode it to a file - env: - ANDROID_RELEASE_KEYSTORE_FILE: ${{ secrets.ANDROID_RELEASE_KEYSTORE_FILE }} - run: | - mkdir release - echo $ANDROID_RELEASE_KEYSTORE_FILE | base64 --decode > release/release.keystore - - - name: Write local.properties - env: - ANDROID_RELEASE_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_RELEASE_KEYSTORE_PASSWORD }} - ANDROID_RELEASE_KEY_ALIAS: ${{ secrets.ANDROID_RELEASE_KEY_ALIAS }} - ANDROID_RELEASE_KEY_PASSWORD: ${{ secrets.ANDROID_RELEASE_KEY_PASSWORD }} - run: | - echo androidReleaseStoreFile=/release/release.keystore >> local.properties - echo androidReleaseStorePassword=$ANDROID_RELEASE_KEYSTORE_PASSWORD >> local.properties - echo androidReleaseKeyAlias=$ANDROID_RELEASE_KEY_ALIAS >> local.properties - echo androidReleaseKeyPassword=$ANDROID_RELEASE_KEY_PASSWORD >> local.properties - - - name: Build release apk - run: ./gradlew :composeApp:assembleRelease - - name: Create Release - uses: ncipollo/release-action@v1.12.0 - with: - allowUpdates: true - draft: false - makeLatest: true - name: ${{ steps.semver.outputs.next }} - body: Changelog Contents - token: ${{ github.token }} - artifacts: "composeApp/build/outputs/apk/release/composeApp-release.apk" - generateReleaseNotes: true - tag: ${{ steps.semver.outputs.next }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..ccd9f76 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,120 @@ +name: CI/CD + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: macos-14 + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + - name: Get Next Version + id: semver + uses: ietf-tools/semver-action@v1 + with: + token: ${{ github.token }} + branch: master + patchList: "refactor, fix, style, chore" + - name: set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: 21 + distribution: 'zulu' + - uses: actions/cache@v4 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: ${{ runner.os }}-gradle- + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + - name: Android Retrieve the keystore and decode it to a file + env: + ANDROID_RELEASE_KEYSTORE_FILE: ${{ secrets.ANDROID_RELEASE_KEYSTORE_FILE }} + run: | + mkdir release + echo $ANDROID_RELEASE_KEYSTORE_FILE | base64 --decode > release/release.keystore + + - name: Android Write local.properties + env: + ANDROID_RELEASE_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_RELEASE_KEYSTORE_PASSWORD }} + ANDROID_RELEASE_KEY_ALIAS: ${{ secrets.ANDROID_RELEASE_KEY_ALIAS }} + ANDROID_RELEASE_KEY_PASSWORD: ${{ secrets.ANDROID_RELEASE_KEY_PASSWORD }} + run: | + echo androidReleaseStoreFile=/release/release.keystore >> local.properties + echo androidReleaseStorePassword=$ANDROID_RELEASE_KEYSTORE_PASSWORD >> local.properties + echo androidReleaseKeyAlias=$ANDROID_RELEASE_KEY_ALIAS >> local.properties + echo androidReleaseKeyPassword=$ANDROID_RELEASE_KEY_PASSWORD >> local.properties + + - name: Android Build release apk + run: ./gradlew :composeApp:assembleRelease + + - name: iOS Update Archive Version + run: | + /usr/libexec/Plistbuddy -c "Set CFBundleVersion ${{ steps.semver.outputs.next }}" "iosApp/iosApp/Info.plist" + /usr/libexec/Plistbuddy -c "Set CFBundleShortVersionString ${{ steps.semver.outputs.next }}" "iosApp/iosApp/Info.plist" + - name: Install the Apple certificate and provisioning profile + env: + BUILD_CERTIFICATE_BASE64: ${{ secrets.P12_BASE64_KEY }} + P12_PASSWORD: ${{ secrets.P12_KEY_PASSWORD }} + BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.MOBILE_PROVISIONING_B64 }} + KEYCHAIN_PASSWORD: ${{ secrets.P12_KEY_PASSWORD }} + run: | + # create variables + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + PP_PATH=$RUNNER_TEMP/build_pp.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_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_PATH ~/Library/MobileDevice/Provisioning\ Profiles + + - name: build archive + run: | + xcodebuild -scheme "iosApp" \ + -workspace Untitled.xcworkspace \ + -allowProvisioningUpdates \ + -archivePath $RUNNER_TEMP/iosApp.xcarchive \ + -sdk iphoneos \ + -configuration Release \ + -destination generic/platform=iOS \ + clean archive + + - name: export ipa + env: + EXPORT_OPTIONS_PLIST: ${{ secrets.EXPORT_OPTIONS_PLIST }} + run: | + EXPORT_OPTS_PATH=iosApp/exportOptionsRelease.plist + xcodebuild -exportArchive -archivePath $RUNNER_TEMP/iosApp.xcarchive -exportOptionsPlist $EXPORT_OPTS_PATH -exportPath build/ + + + - name: Create Release + uses: ncipollo/release-action@v1.12.0 + with: + allowUpdates: true + draft: false + makeLatest: true + name: ${{ steps.semver.outputs.next }} + body: Changelog Contents + token: ${{ github.token }} + artifacts: "composeApp/build/outputs/apk/release/composeApp-release.apk,build/MGPlayer.ipa" + generateReleaseNotes: true + tag: ${{ steps.semver.outputs.next }} + diff --git a/iosApp/Configuration/Config.xcconfig b/iosApp/Configuration/Config.xcconfig index eb5894d..a4f68cd 100644 --- a/iosApp/Configuration/Config.xcconfig +++ b/iosApp/Configuration/Config.xcconfig @@ -1,3 +1,3 @@ TEAM_ID= -BUNDLE_ID=com.mgtv.MassengeschmackTV -APP_NAME=MassengeschmackTV \ No newline at end of file +BUNDLE_ID=com.mg.player +APP_NAME=MGPlayer diff --git a/iosApp/exportOptionsRelease.plist b/iosApp/exportOptionsRelease.plist new file mode 100644 index 0000000..7dd5374 --- /dev/null +++ b/iosApp/exportOptionsRelease.plist @@ -0,0 +1,20 @@ + + + + + compileBitcode + + destination + export + method + release-testing + signingStyle + automatic + stripSwiftSymbols + + teamID + ANY487J8ZV + thinning + <none> + + diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj index 95f0f7e..9c18e1f 100644 --- a/iosApp/iosApp.xcodeproj/project.pbxproj +++ b/iosApp/iosApp.xcodeproj/project.pbxproj @@ -19,7 +19,7 @@ 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = ""; }; 583BF3302C0BA88E00640500 /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; - 7555FF7B242A565900829871 /* MassengeschmackTV.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MassengeschmackTV.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 7555FF7B242A565900829871 /* MGPlayer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MGPlayer.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7555FF82242A565900829871 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; AB3632DC29227652001CCB65 /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = ""; }; @@ -64,7 +64,7 @@ 7555FF7C242A565900829871 /* Products */ = { isa = PBXGroup; children = ( - 7555FF7B242A565900829871 /* MassengeschmackTV.app */, + 7555FF7B242A565900829871 /* MGPlayer.app */, ); name = Products; sourceTree = ""; @@ -110,7 +110,7 @@ packageProductDependencies = ( ); productName = iosApp; - productReference = 7555FF7B242A565900829871 /* MassengeschmackTV.app */; + productReference = 7555FF7B242A565900829871 /* MGPlayer.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -327,6 +327,8 @@ "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", ); INFOPLIST_FILE = iosApp/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = MGPlayer; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.news"; IPHONEOS_DEPLOYMENT_TARGET = 15.3; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -338,6 +340,7 @@ composeApp, ); PRODUCT_BUNDLE_IDENTIFIER = "${BUNDLE_ID}${TEAM_ID}"; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.mg.player; PRODUCT_NAME = "${APP_NAME}"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; @@ -359,6 +362,8 @@ "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", ); INFOPLIST_FILE = iosApp/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = MGPlayer; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.news"; IPHONEOS_DEPLOYMENT_TARGET = 15.3; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -370,6 +375,7 @@ composeApp, ); PRODUCT_BUNDLE_IDENTIFIER = "${BUNDLE_ID}${TEAM_ID}"; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.mg.player; PRODUCT_NAME = "${APP_NAME}"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0;