From f01778a51c42ffe574c42d0255831dcc06becd59 Mon Sep 17 00:00:00 2001 From: "personaclick-courier[bot]" <205635110+personaclick-courier[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 12:33:37 +0000 Subject: [PATCH] feat: release --- .github/workflows/build_apk.yaml.bak | 70 ++++++ .github/workflows/publish.yaml.bak | 24 ++ .github/workflows/sync.yaml | 28 +++ .vim/coc-settings.json | 3 + LICENSE | 28 +++ README.md | 29 ++- app/.gitignore | 1 + .../demo_android/app/DemoApplication.kt | 2 +- app/src/main/res/drawable/ic_app.xml | 9 - app/src/main/res/drawable/ic_logo.xml | 36 --- buildConfig/.gitignore | 1 + buildConfig/bin/main/AppBuildConfig.kt | 237 ++++++++++++++++++ core/.gitignore | 1 + .../core/settings/RecommendationSettings.kt | 6 +- feature/.gitignore | 1 + feature/src/main/res/layout/fragment_home.xml | 2 +- navigation/.gitignore | 1 + ui/.gitignore | 1 + 18 files changed, 429 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/build_apk.yaml.bak create mode 100644 .github/workflows/publish.yaml.bak create mode 100644 .github/workflows/sync.yaml create mode 100644 .vim/coc-settings.json create mode 100644 LICENSE create mode 100644 app/.gitignore delete mode 100644 app/src/main/res/drawable/ic_app.xml delete mode 100644 app/src/main/res/drawable/ic_logo.xml create mode 100644 buildConfig/.gitignore create mode 100644 buildConfig/bin/main/AppBuildConfig.kt create mode 100644 core/.gitignore create mode 100644 feature/.gitignore create mode 100644 navigation/.gitignore create mode 100644 ui/.gitignore diff --git a/.github/workflows/build_apk.yaml.bak b/.github/workflows/build_apk.yaml.bak new file mode 100644 index 0000000..83c464c --- /dev/null +++ b/.github/workflows/build_apk.yaml.bak @@ -0,0 +1,70 @@ +name: Build APK + +on: + workflow_run: + workflows: + - "Publish to Play Store and Bump Version" + types: + - completed + +jobs: + build_release_apk: + runs-on: ubuntu-latest + steps: + - uses: actions/create-github-app-token@v1 + id: app-token + with: + app-id: ${{ vars.PUBLIVERSIONER_ID }} + private-key: ${{ secrets.PUBLIVERSIONER_SECRET }} + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Get current version from source + env: + FILE_PATH: "version.properties" + id: version_source + run: | + current_version=$(awk -F"=" '/VERSION_NAME/ {print $2}' "$FILE_PATH") + echo "version=$current_version" >> $GITHUB_OUTPUT + + - name: Decode and create google-services.json + run: | + mkdir -p app/src/prod/release + echo "$GOOGLE_SERVICES_JSON" | base64 -d > app/src/prod/release/google-services.json + env: + GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_FILE_AS_BASE64 }} + + - name: Decode Keystore + run: | + echo "$KEYSTORE_AS_BASE64" | base64 --decode > app/keystore.jks + env: + KEYSTORE_AS_BASE64: ${{ secrets.GOOGLE_PLAY_SIGNING_KEY_FILE_AS_BASE64 }} + + - name: Set up JDK 20 + uses: actions/setup-java@v4 + with: + java-version: "20" + distribution: "zulu" + + - name: Build Release APK + run: ./gradlew assembleProdRelease + env: + SIGNING_STORE_FILE: ${{ github.workspace }}/app/keystore.jks + SIGNING_STORE_PASSWORD: ${{ secrets.RELEASE_STORE_PASSWORD }} + SIGNING_KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }} + SIGNING_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }} + + - name: Prepare release directory + run: | + mkdir -p release + cp app/build/outputs/apk/prod/release/app-prod-release.apk release/ + + - name: Create release + env: + TAG: ${{ steps.version_source.outputs.version }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + gh release create "v$TAG" ./release/app-prod-release.apk \ + --title=$TAG \ + --generate-notes diff --git a/.github/workflows/publish.yaml.bak b/.github/workflows/publish.yaml.bak new file mode 100644 index 0000000..697a83a --- /dev/null +++ b/.github/workflows/publish.yaml.bak @@ -0,0 +1,24 @@ +name: Publish to Play Store and Bump Version + +on: + pull_request: + types: + - closed + workflow_dispatch: + +jobs: + publish_and_version_bump: + uses: rees46/workflow/.github/workflows/reusable-android-google-play-publish.yaml@master + with: + githubAppId: ${{ vars.PUBLIVERSIONER_ID }} + packageName: "rees46.demo_shop" + aabReleasePath: "app/build/outputs/bundle/prodRelease/app-prod-release.aab" + propertiesFilePath: "version.properties" + secrets: + GITHUB_APP_PRIVATE_KEY: ${{ secrets.PUBLIVERSIONER_SECRET }} + GOOGLE_SERVICES_FILE_AS_BASE64: ${{ secrets.GOOGLE_SERVICES_FILE_AS_BASE64 }} + GOOGLE_PLAY_SIGNING_KEY_FILE_AS_BASE64: ${{ secrets.GOOGLE_PLAY_SIGNING_KEY_FILE_AS_BASE64 }} + RELEASE_STORE_PASSWORD: ${{ secrets.RELEASE_STORE_PASSWORD }} + RELEASE_KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }} + RELEASE_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }} + PLAY_ACCOUNT_AS_BASE64: ${{ secrets.PLAY_ACCOUNT_AS_BASE64 }} diff --git a/.github/workflows/sync.yaml b/.github/workflows/sync.yaml new file mode 100644 index 0000000..d7ca662 --- /dev/null +++ b/.github/workflows/sync.yaml @@ -0,0 +1,28 @@ +name: Sync repositories + +on: + pull_request: + # TODO uncomment + # workflow_run: + # workflows: + # - "Publish to Play Store and Bump Version" + # types: + # - completed + # workflow_dispatch: + +jobs: + run: + # TODO uncomment + # uses: personaClick/workflow/.github/workflows/reusable-android-synchronization.yaml@master + uses: personaClick/workflow/.github/workflows/reusable-android-synchronization.yaml@refactor/reusable-android-synchronization + permissions: write-all + with: + appId: ${{ vars.PERSONACLICK_COURIER_ID }} + targetRepository: personaclick/demo-android + sourceDirname: personaClick + targetDirname: personaClick + syncIgnore: ".git,.idea,version.properties,app/src/main/res/drawable/ic_app.xml,app/src/main/res/drawable/ic_logo.xml" + replacementExtentions: "*.kts,*.kt,*.md,*.xml,*.toml,*.yml,*.yaml" + replacementContents: "42a4cd11ebab3b0454778d18d4f3d5|42a4cd11ebab3b0454778d18d4f3d5,5a57812604806d58d3d98f8e9480cb97|5a57812604806d58d3d98f8e9480cb97,e4fd6e3a19610f7aea5534e96eec69d6|e4fd6e3a19610f7aea5534e96eec69d6,5a57812604806d58d3d98f8e9480cb97|aabc899d3db3d71c4032832e4291c16a,09d291f54de95e9e5bde43b343b0b0d7|09d291f54de95e9e5bde43b343b0b0d7,https://api.personaclick.com/|https://api.personaclick.com/,com.personaclick:personaclick-sdk|com.personaclick:personaclick-sdk,api.personaclick.com|api.personaclick.com,personaclick.com|personaclick.com,personaClick|personaClick,PersonaClick|PersonaClick,PersonaClick|PersonaClick" + secrets: + privateKey: ${{ secrets.PERSONACLICK_COURIER_SECRET }} diff --git a/.vim/coc-settings.json b/.vim/coc-settings.json new file mode 100644 index 0000000..be97557 --- /dev/null +++ b/.vim/coc-settings.json @@ -0,0 +1,3 @@ +{ + "java.compile.nullAnalysis.mode": "disabled" +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c2fba6b --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2024, REES46 + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index 6b67f91..3b7d686 100644 --- a/README.md +++ b/README.md @@ -1 +1,28 @@ -# trigger-repository +# PersonaClick Demo Android + +## Description + +PersonaClick Demo Android - application to demonstrate working with SDK. + +## Configure + +Versions: +- PersonaClick SDK 2.0.20 +- Java 20 +- Kotlin 2.0.0 +- Gradle 8.8 +- Android Gradle Plugin 8.5.2 + +Copy `google-services.json` file from [Firebase console](https://console.firebase.google.com/u/0/) to app module. + +## Documentation + +For detailed information on methods used from the SDK, please refer to the documentation available at the following link: + +[Official API references](https://reference.api.personaclick.com/#introduction) + +## Screenshots + +![home (1)](https://github.com/user-attachments/assets/2d16d6f6-d821-442e-b850-1b6ed1b8dbf4) +![2](https://github.com/user-attachments/assets/b7994bb1-5aa0-4178-a257-bab0f740145b) +![cart](https://github.com/user-attachments/assets/37a21ca8-904b-4819-859f-93643968634a) diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/src/main/java/personaClick/demo_android/app/DemoApplication.kt b/app/src/main/java/personaClick/demo_android/app/DemoApplication.kt index f0f31cb..03e7a9a 100644 --- a/app/src/main/java/personaClick/demo_android/app/DemoApplication.kt +++ b/app/src/main/java/personaClick/demo_android/app/DemoApplication.kt @@ -54,6 +54,6 @@ class DemoApplication : Application() { } companion object { - private const val SHOP_ID = "357382bf66ac0ce2f1722677c59511" + private const val SHOP_ID = "42a4cd11ebab3b0454778d18d4f3d5" } } diff --git a/app/src/main/res/drawable/ic_app.xml b/app/src/main/res/drawable/ic_app.xml deleted file mode 100644 index cc21897..0000000 --- a/app/src/main/res/drawable/ic_app.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_logo.xml b/app/src/main/res/drawable/ic_logo.xml deleted file mode 100644 index 2dbf407..0000000 --- a/app/src/main/res/drawable/ic_logo.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - diff --git a/buildConfig/.gitignore b/buildConfig/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/buildConfig/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/buildConfig/bin/main/AppBuildConfig.kt b/buildConfig/bin/main/AppBuildConfig.kt new file mode 100644 index 0000000..835ba56 --- /dev/null +++ b/buildConfig/bin/main/AppBuildConfig.kt @@ -0,0 +1,237 @@ +@file:Suppress("DEPRECATION") + +import com.android.build.gradle.AppExtension +import com.android.build.gradle.LibraryExtension +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.util.Properties +import org.gradle.api.JavaVersion +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +class AppBuildConfig : Plugin { + + override fun apply(project: Project) { + project.plugins.withId(ANDROID_APPLICATION_LIB) { + configureAppExtension(project.extensions.getByType(AppExtension::class.java), project) + } + + project.plugins.withId(ANDROID_LIB) { + configureLibraryExtension(project.extensions.getByType(LibraryExtension::class.java)) + } + + configureKotlinCompile(project) + } + + private fun configureAppExtension(androidExtension: AppExtension, project: Project) { + val versionPropsFile = File(project.rootProject.projectDir, "version.properties") + val versionProps = Properties() + if (versionPropsFile.exists()) { + versionProps.load(FileInputStream(versionPropsFile)) + } + + val currentVersionCode = versionProps[VERSION_CODE]?.toString()?.toInt() ?: 1 + val currentVersionName = versionProps[VERSION_NAME]?.toString() ?: "1.0.0" + + androidExtension.apply { + compileSdkVersion(TARGET_SDK) + defaultConfig { + applicationId = APPLICATION_ID + minSdk = MIN_SDK + targetSdk = TARGET_SDK + versionCode = currentVersionCode + versionName = currentVersionName + viewBinding { + enable = true + } + } + flavorDimensions(DIMENSION_FLAVORS) + configureProductFlavors() + configureSigningConfigs(project) + configureBuildTypes() + configurePackagingOptions() + configureJavaAndKotlinOptions() + + project.tasks.register(PUBLISH_TO_ITERNAL_TESTING) { + dependsOn(RELEASE_BUNDLE) + finalizedBy(PUBLISH_RELEASE_BUNDLE) + } + + project.tasks.register(INCREMENT_VERSION) { + doLast { + incrementVersion(versionProps, versionPropsFile) + } + } + } + } + + private fun incrementVersion(versionProps: Properties, versionPropsFile: File) { + val currentVersionCode = versionProps[VERSION_CODE]?.toString()?.toInt() ?: 1 + val newVersionCode = currentVersionCode + 1 + + val currentVersionName = versionProps[VERSION_NAME]?.toString() ?: "1.0.0" + val versionNameParts = currentVersionName.split(".").toMutableList() + + if (versionNameParts.size == 3) { + val patchVersion = versionNameParts[2].toIntOrNull() ?: 0 + versionNameParts[2] = (patchVersion + 1).toString() + } + + val newVersionName = versionNameParts.joinToString(".") + + versionProps[VERSION_CODE] = newVersionCode.toString() + versionProps[VERSION_NAME] = newVersionName + versionProps.store(FileOutputStream(versionPropsFile), null) + + println("Version updated to: versionCode=$newVersionCode, versionName=$newVersionName") + } + + private fun AppExtension.configureProductFlavors() { + productFlavors { + create(DEV_FLAVOR) { + dimension = DIMENSION_FLAVORS + } + create(STAGE_FLAVOR) { + dimension = DIMENSION_FLAVORS + applicationIdSuffix = APPLICATION_STAGE_SUFFIX + } + create(PROD_FLAVOR) { + dimension = DIMENSION_FLAVORS + } + } + } + + private fun AppExtension.configureSigningConfigs(project: Project) { + val localProperties = Properties() + val localPropertiesFile = project.rootProject.file(LOCAL_PROPERTIES_FILE) + if (localPropertiesFile.exists()) { + localProperties.load(FileInputStream(localPropertiesFile)) + } + + signingConfigs { + create(RELEASE_CONFIG) { + storeFile = File( + localProperties.getProperty(RELEASE_STORE_FILE) ?: System.getenv("SIGNING_STORE_FILE") + ) + storePassword = localProperties.getProperty(RELEASE_STORE_PASSWORD) ?: System.getenv("SIGNING_STORE_PASSWORD") + keyAlias = localProperties.getProperty(RELEASE_KEY_ALIAS) ?: System.getenv("SIGNING_KEY_ALIAS") + keyPassword = localProperties.getProperty(RELEASE_KEY_PASSWORD) ?: System.getenv("SIGNING_KEY_PASSWORD") + } + create(DEBUG_CONFIG) { + } + } + } + + private fun AppExtension.configureBuildTypes() { + buildTypes { + getByName(RELEASE_TYPE) { + signingConfig = signingConfigs.getByName(RELEASE_CONFIG) + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile(PROGUARD_ANDROID_TXT), + PROGUARD_RULES + ) + } + getByName(DEBUG_TYPE) { + isDebuggable = true + } + } + } + + private fun AppExtension.configurePackagingOptions() { + packagingOptions { + exclude("META-INF/*.kotlin_module") + exclude("META-INF/AL2.0") + exclude("META-INF/LGPL2.1") + } + } + + private fun configureLibraryExtension(androidExtension: LibraryExtension) { + androidExtension.apply { + compileSdk = TARGET_SDK + configureDefaultConfig() + configureBuildTypes() + configureJavaAndKotlinOptions() + } + } + + private fun LibraryExtension.configureDefaultConfig() { + defaultConfig { + minSdk = MIN_SDK + targetSdk = TARGET_SDK + } + } + + private fun LibraryExtension.configureBuildTypes() { + buildTypes { + getByName(RELEASE_TYPE) { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile(PROGUARD_ANDROID_TXT), + PROGUARD_RULES + ) + } + } + } + + private fun configureKotlinCompile(project: Project) { + project.tasks.withType(KotlinCompile::class.java).configureEach { + kotlinOptions { + jvmTarget = JVM_TARGET + } + } + } + + private fun AppExtension.configureJavaAndKotlinOptions() { + compileOptions { + sourceCompatibility = JavaVersion.VERSION_20 + targetCompatibility = JavaVersion.VERSION_20 + } + } + + private fun LibraryExtension.configureJavaAndKotlinOptions() { + compileOptions { + sourceCompatibility = JavaVersion.VERSION_20 + targetCompatibility = JavaVersion.VERSION_20 + } + } + + companion object { + private const val PUBLISH_TO_ITERNAL_TESTING = "publishProdReleaseToPlay" + private const val PUBLISH_RELEASE_BUNDLE = "publishProdReleaseBundle" + private const val LOCAL_PROPERTIES_FILE = "local.properties" + private const val INCREMENT_VERSION = "incrementVersion" + private const val RELEASE_BUNDLE = "bundleProdRelease" + + private const val VERSION_NAME = "VERSION_NAME" + private const val VERSION_CODE = "VERSION_CODE" + + private const val RELEASE_STORE_PASSWORD = "RELEASE_STORE_PASSWORD" + private const val RELEASE_KEY_PASSWORD = "RELEASE_KEY_PASSWORD" + private const val RELEASE_STORE_FILE = "RELEASE_STORE_FILE" + private const val RELEASE_KEY_ALIAS = "RELEASE_KEY_ALIAS" + + private const val ANDROID_APPLICATION_LIB = "com.android.application" + private const val APPLICATION_ID = "personaClick.demo_android" + private const val ANDROID_LIB = "com.android.library" + private const val JVM_TARGET = "20" + private const val TARGET_SDK = 34 + private const val MIN_SDK = 24 + + private const val RELEASE_CONFIG = "releaseConfig" + private const val DEBUG_CONFIG = "debugConfig" + private const val RELEASE_TYPE = "release" + private const val DEBUG_TYPE = "debug" + + private const val STAGE_FLAVOR = "stage" + private const val PROD_FLAVOR = "prod" + private const val DEV_FLAVOR = "dev" + private const val APPLICATION_STAGE_SUFFIX = ".test" + private const val DIMENSION_FLAVORS = "demoShop" + + private const val PROGUARD_ANDROID_TXT = "proguard-android-optimize.txt" + private const val PROGUARD_RULES = "proguard-rules.pro" + } +} \ No newline at end of file diff --git a/core/.gitignore b/core/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/core/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/core/src/main/java/personaClick/demo_android/core/settings/RecommendationSettings.kt b/core/src/main/java/personaClick/demo_android/core/settings/RecommendationSettings.kt index d6898cf..b21c649 100644 --- a/core/src/main/java/personaClick/demo_android/core/settings/RecommendationSettings.kt +++ b/core/src/main/java/personaClick/demo_android/core/settings/RecommendationSettings.kt @@ -1,7 +1,7 @@ package personaClick.demo_android.core.settings object RecommendationSettings { - const val SIMPLE_RECOMMENDED_CODE = "a043dbc2f852ffe18861a2cdfc364ef2" - const val CART_RECOMMENDED_CODE = "2dbebc39bee259b118bcc0ac3fa74a42" - const val ALSO_LIKE_RECOMMENDED_CODE = "a043dbc2f852ffe18861a2cdfc364ef2" + const val SIMPLE_RECOMMENDED_CODE = "5a57812604806d58d3d98f8e9480cb97" + const val CART_RECOMMENDED_CODE = "e4fd6e3a19610f7aea5534e96eec69d6" + const val ALSO_LIKE_RECOMMENDED_CODE = "5a57812604806d58d3d98f8e9480cb97" } diff --git a/feature/.gitignore b/feature/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/feature/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/feature/src/main/res/layout/fragment_home.xml b/feature/src/main/res/layout/fragment_home.xml index 3002099..16c472d 100644 --- a/feature/src/main/res/layout/fragment_home.xml +++ b/feature/src/main/res/layout/fragment_home.xml @@ -32,7 +32,7 @@ android:id="@+id/story" android:layout_width="match_parent" android:layout_height="wrap_content" - app:code="fcaa8d3168ab7d7346e4b4f1a1c92214" + app:code="09d291f54de95e9e5bde43b343b0b0d7" app:layout_constraintTop_toTopOf="parent" />