Internal Engineering Document
SDK v1.0.1 · Internal
Bahrain · Android Platform · Developer Guide

stcPay Android SDK
Internal Setup &
Verification Guide

For stcPay Bahrain Android Team

Created by Mian Sarim Hameed

Document type
Internal Team Guide
Audience
stcPay Android Developers & Team Lead
SDK version
1.0.1
Branch
feature/stcpay-android-sdk
01
Introduction

Document Purpose

This guide covers everything a stcPay Android team member needs to:

  1. Set up the feature/stcpay-android-sdk branch locally on a fresh machine
  2. Publish all stcPay modules to Maven Local
  3. Create a clean test super app from scratch
  4. Verify the SDK integration works correctly on both UAT and PROD environments
Audience This guide is written for the stcPay internal team. It assumes familiarity with Android development and access to both stcpay-customer-android and stcpay-ui-kit-android repositories. This is NOT for the super app integration team.
02
Navigation

Contents

03
Before you begin

Architecture Overview

What is the stcPay SDK?

The feature/stcpay-android-sdk branch packages the entire stcpay-customer-android app experience as a distributable Android library: com.stcpay:stcpay-sdk:1.0.1. A super app team can integrate the complete stcPay Bahrain experience by adding a single Gradle dependency and calling StcPaySDK.launch(context).

Repositories involved

RepositoryBranchPurpose
stcpay-customer-android feature/stcpay-android-sdk Main SDK source — contains :stcpay-sdk module and all 30+ feature modules
stcpay-ui-kit-android feature/stcpay-android-sdk UI component library — integrated as a Gradle composite build inside stcpay-customer-android. Branch exists for consistency only; no separate publishing is needed.

How publishing works

All 30+ stcpay-customer-android repo modules are published to Maven Local (~/.m2/repository/com/stcpay/) as individual Maven artifacts under the group com.stcpay, version 1.0.1. A super app then resolves everything from Maven Local (or a private Maven server in the future).

Three artifacts cannot be auto-published because they are flat-dir local AARs with no Gradle module source. These must be manually installed to Maven Local once on each developer machine:

stcpay-ui-kit-android (com.stcpay:stcpay-ui-kit:1.0.0) is handled automatically because it is included as a Gradle composite build — Gradle substitutes the Maven coordinate with the local source project during publish.

Java version requirement

Critical — Read Before Running Any Command The project uses a Gradle version that is incompatible with Java 25 (the current macOS system default). You MUST use JBR 21 (JetBrains Runtime 21) for all Gradle commands. All commands in this guide use JAVA_HOME explicitly — do not omit it.

JBR 21 is bundled with Android Studio. Typical path on macOS:

bash
/Users/<username>/Library/Java/JavaVirtualMachines/jbr-21.0.x/Contents/Home

Find yours with:

bash
$ /usr/libexec/java_home -V

Look for a line containing JetBrains and 21.x. Use that path for every JAVA_HOME= in this guide.

04
Checklist

Prerequisites

Verify all of the following before running any commands:

05
Step 1

Pull Both Repositories

bash
# Pull the stcpay-customer-android SDK branch
$ cd /path/to/stcpay-customer-android
$ git fetch origin
$ git checkout feature/stcpay-android-sdk
$ git pull origin feature/stcpay-android-sdk

# Pull the stcpay-ui-kit-android branch (for branch name consistency)
$ cd /path/to/stcpay-ui-kit-android
$ git fetch origin
$ git checkout feature/stcpay-android-sdk
$ git pull origin feature/stcpay-android-sdk
Note on stcpay-ui-kit-android Branch The stcpay-ui-kit-android branch feature/stcpay-android-sdk is branched from develop and contains no SDK-specific changes. It exists only so both repos share the same branch name. No separate build or publish step is needed for stcpay-ui-kit-android.
06
Step 2

Configure local.properties

In the root of the stcpay-customer-android project, open local.properties (create it if it does not exist) and add:

properties
# Absolute path to the stcpay-ui-kit-android project root
# Replace with the actual path on your machine
stcpay-ui-kit-androidProjectPath=/Users/<username>/path/to/stcpay-ui-kit-android

# Android SDK path (if not already present)
sdk.dir=/Users/<username>/Library/Android/sdk
Composite Build Wiring This tells Gradle to include stcpay-ui-kit-android as a composite build. When publishToMavenLocal runs, Gradle will automatically substitute com.stcpay:stcpay-ui-kit:1.0.0 with the local stcpay-ui-kit-android project source and publish it alongside all other modules. No separate step is needed.
07
Step 3 — One-time per machine

Manually Install Local AARs

These two artifacts are flat-dir local AARs (no Gradle module source) and must be installed once per developer machine. They will not be re-installed on each publish.

7.1  Install secureutility

bash
$ mvn install:install-file \
    -Dfile=/path/to/stcpay-customer-android/util/libs/secureutility-1.0.1.aar \
    -DgroupId=com.stcpay \
    -DartifactId=secureutility \
    -Dversion=1.0.1 \
    -Dpackaging=aar \
    -DgeneratePom=true

Verify:

bash
$ ls ~/.m2/repository/com/stcpay/secureutility/1.0.1/
# Expected: secureutility-1.0.1.aar  secureutility-1.0.1.pom

7.2  Install benefit_pay_sdk

bash
$ mvn install:install-file \
    -Dfile=/path/to/stcpay-customer-android/benefit_pay_sdk/libs/benefitinappsdk-1.0.23.aar \
    -DgroupId=com.stcpay \
    -DartifactId=benefit_pay_sdk \
    -Dversion=1.0.0 \
    -Dpackaging=aar \
    -DgeneratePom=true

Verify:

bash
$ ls ~/.m2/repository/com/stcpay/benefit_pay_sdk/1.0.0/
# Expected: benefit_pay_sdk-1.0.0.aar  benefit_pay_sdk-1.0.0.pom
One-time only These two steps are one-time per machine. You do not repeat them when re-publishing the SDK after source changes.
08
Step 4

Publish All Modules to Maven Local

8.1  Full publish (first time or after any module source change)

This compiles and publishes all 30+ stcpay-customer-android repo modules plus stcpay-ui-kit-android. It takes approximately ~20 minutes.

bash
$ cd /path/to/stcpay-customer-android

$ JAVA_HOME=/Users/<username>/Library/Java/JavaVirtualMachines/jbr-21.0.x/Contents/Home \
  ./gradlew publishToMavenLocal --parallel
Do not omit JAVA_HOME Using the system Java (25) will cause build failures. Always prefix with JAVA_HOME=… as shown.

8.2  SDK-only publish (after changes to stcpay-sdk source only)

If you only changed files inside stcpay-sdk/src/ or stcpay-sdk/build.gradle.kts, run a faster targeted publish (~5–10 min):

bash
$ cd /path/to/stcpay-customer-android

$ JAVA_HOME=/Users/<username>/Library/Java/JavaVirtualMachines/jbr-21.0.x/Contents/Home \
  ./gradlew :stcpay-sdk:publishToMavenLocal

8.3  Verify the publish

bash
$ ls ~/.m2/repository/com/stcpay/
# Expected: a folder for every stcpay-customer-android module

$ ls ~/.m2/repository/com/stcpay/stcpay-sdk/1.0.1/
# Expected 6 variant AARs + .module + .pom:
# stcpay-sdk-1.0.1-gmsUat.aar
# stcpay-sdk-1.0.1-gmsPreProd.aar
# stcpay-sdk-1.0.1-gmsProd.aar
# stcpay-sdk-1.0.1-hmsUat.aar
# stcpay-sdk-1.0.1-hmsPreProd.aar
# stcpay-sdk-1.0.1-hmsProd.aar
# stcpay-sdk-1.0.1.module
# stcpay-sdk-1.0.1.pom

$ ls ~/.m2/repository/com/stcpay/stcpay-ui-kit/1.0.0/
# Expected: stcpay-ui-kit-1.0.0*.aar (composite build auto-published)

8.4  When to re-publish

Change madeCommand to run
Any file under stcpay-sdk/src/ or stcpay-sdk/build.gradle.kts./gradlew :stcpay-sdk:publishToMavenLocal
Any feature module, util, common, navigator, etc../gradlew publishToMavenLocal --parallel
Any file in stcpay-ui-kit-android./gradlew publishToMavenLocal --parallel (composite build republishes it)
Always Clean Rebuild After Re-publish After every re-publish, you MUST do a clean rebuild of the test super app. Gradle caches resolved AARs by version — a clean build forces it to pick up the newly published AAR from Maven Local instead of the stale cache.
09
Step 5

Create the Test Super App

Create a new Android project in Android Studio with these settings:

TemplateEmpty Activity
Package namecom.yourcompany.stcpaysuperapp (or any name)
LanguageKotlin
Minimum SDKAPI 24

Then apply the following configuration to each file:

9.1  settings.gradle.kts

Replace the existing dependencyResolutionManagement block entirely:

kotlin
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        mavenLocal()          // resolves com.stcpay:* from ~/.m2
        google()
        mavenCentral()
        maven { url = uri("https://jitpack.io") }   // dotlottie-android transitive dep
        exclusiveContent {
            forRepository { maven { url = uri("https://repo.mobile.jumio.ai") } }
            filter {
                includeGroup("com.jumio.android")
                includeGroup("com.iproov.sdk")
            }
        }
    }
}
Testing a published build? Use GitHub Packages instead If you only want to consume and test the SDK (not build it from source), resolve from the private GitHub Packages registry instead of mavenLocal() — you can skip §05–§08 entirely. See §15 for the full repository block and credentials.

9.2  build.gradle.kts (project-level)

kotlin
plugins {
    id("com.android.application") version "9.0.1" apply false
    id("org.jetbrains.kotlin.android") version "2.0.21" apply false
    id("com.google.dagger.hilt.android") version "2.56.2" apply false
    // Required: generates a Crashlytics build UUID at compile time.
    // The SDK bundles firebase-crashlytics which checks for this UUID at runtime.
    // Without this plugin the app crashes on launch with "Crashlytics build ID is missing".
    id("com.google.firebase.crashlytics") version "3.0.2" apply false
}

9.3  gradle/libs.versions.toml — add these entries

toml
[versions]
composeBom = "2025.12.01"

[libraries]
# Must use compose-bom-alpha:2025.12.01 to match the Compose version
# the SDK was compiled against. Using a different BOM causes runtime crashes.
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom-alpha", version.ref = "composeBom" }

9.4  app/build.gradle.kts — full file

kotlin
import com.android.build.api.attributes.BuildTypeAttr
import org.gradle.api.attributes.AttributeCompatibilityRule
import org.gradle.api.attributes.AttributeDisambiguationRule
import org.gradle.api.attributes.CompatibilityCheckDetails
import org.gradle.api.attributes.MultipleCandidatesDetails
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

// ── Android Studio / IntelliJ variant resolution fix ──────────────────────
// The stcPay SDK uses custom build types (uat / preProd / prod) instead of
// debug/release. AGP's matchingFallbacks covers most configs, but Android
// Studio's internal ijDownloadArtifact bypasses AGP — these rules cover it.
abstract class StcPayBuildTypeCompatibility : AttributeCompatibilityRule<BuildTypeAttr> {
    override fun execute(details: CompatibilityCheckDetails<BuildTypeAttr>) {
        val consumer = details.consumerValue?.name ?: return
        val producer = details.producerValue?.name ?: return
        when {
            consumer == "release" && producer in setOf("prod", "preProd", "uat") -> details.compatible()
            consumer == "debug"   && producer in setOf("uat", "preProd", "prod") -> details.compatible()
        }
    }
}
abstract class StcPayBuildTypeDisambiguation : AttributeDisambiguationRule<BuildTypeAttr> {
    override fun execute(details: MultipleCandidatesDetails<BuildTypeAttr>) {
        val consumer = details.consumerValue?.name ?: return
        val preferred = when (consumer) { "release" -> "prod"; "debug" -> "uat"; else -> return }
        details.candidateValues.firstOrNull { it.name == preferred }?.let { details.closestMatch(it) }
    }
}
// ─────────────────────────────────────────────────────────────────────────

plugins {
    alias(libs.plugins.kotlin.compose)
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
    id("com.google.dagger.hilt.android")
    id("org.jetbrains.kotlin.kapt")
    id("com.google.firebase.crashlytics")
}

android {
    namespace = "com.yourcompany.stcpaysuperapp"
    compileSdk = 36

    defaultConfig {
        applicationId = "com.yourcompany.stcpaysuperapp"
        minSdk = 24
        targetSdk = 36
        versionCode = 1
        versionName = "1.0"
        // Required: SDK has a 'contentType' product flavor dimension (gms/hms).
        // Host app has no such dimension — tell Gradle which to pick.
        missingDimensionStrategy("contentType", "gms")
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
            signingConfig = signingConfigs.getByName("debug")
            // SDK has no "release" type — map to prod
            matchingFallbacks += listOf("prod", "preProd", "uat")
        }
        debug {
            // SDK has no "debug" type — map to uat
            matchingFallbacks += listOf("uat", "preProd", "prod")
        }
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
        isCoreLibraryDesugaringEnabled = true
    }
    buildFeatures { compose = true }

    firebaseCrashlytics {
        mappingFileUploadEnabled = false
        nativeSymbolUploadEnabled = false
    }
}

kotlin { compilerOptions { jvmTarget.set(JvmTarget.JVM_11) } }

dependencies {
    attributesSchema {
        attribute(BuildTypeAttr.ATTRIBUTE) {
            compatibilityRules.add(StcPayBuildTypeCompatibility::class.java)
            disambiguationRules.add(StcPayBuildTypeDisambiguation::class.java)
        }
    }

    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.lifecycle.runtime.ktx)
    implementation(libs.androidx.activity.compose)

    // Compose BOM — must be compose-bom-alpha:2025.12.01
    implementation(platform(libs.androidx.compose.bom))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.ui:ui-graphics")
    implementation("androidx.compose.ui:ui-tooling-preview")
    implementation("androidx.compose.material3:material3")
    debugImplementation("androidx.compose.ui:ui-tooling")

    // Required: backports java.time to devices below API 26
    coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")

    // Required: SDK uses Hilt throughout
    implementation("com.google.dagger:hilt-android:2.56.2")
    kapt("com.google.dagger:hilt-android-compiler:2.56.2")

    // stcPay SDK — single dependency. The following are auto re-exported:
    //   coil-compose, coil-network-okhttp, material-icons-extended, hilt-work
    implementation("com.stcpay:stcpay-sdk:1.0.1")
}

9.5  Application class — MyApplication.kt

kotlin
package com.yourcompany.stcpaysuperapp

import com.stcpay.sdk.StcPayApplication
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class MyApplication : StcPayApplication()
Why extend StcPayApplication? StcPayApplication is an open class provided by the SDK. Extending it automatically handles Firebase initialisation, analytics, WorkManager, and all other internal SDK dependencies in onCreate().

9.6  AndroidManifest.xml

xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.StcPaySuperApp"
        tools:replace="android:allowBackup">
        <!-- tools:replace required: Jumio declares allowBackup="false" -->

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:theme="@style/Theme.StcPaySuperApp">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- Required: disables WorkManager default initializer.
             StcPayApplication provides custom config via Hilt @EntryPoint.
             Default initializer running first causes a crash. -->
        <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            tools:node="merge">
            <meta-data
                android:name="androidx.work.WorkManagerInitializer"
                android:value="androidx.startup"
                tools:node="remove" />
        </provider>

    </application>
</manifest>

9.7  Main Activity — launch button

kotlin
package com.yourcompany.stcpaysuperapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.stcpay.sdk.StcPaySDK
import com.stcpay.sdk.StcPayConfig
import com.stcpay.sdk.StcPayEnvironment
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Column(
                modifier = Modifier.fillMaxSize().padding(32.dp),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Button(onClick = {
                    StcPaySDK.configure(StcPayConfig(environment = StcPayEnvironment.UAT))
                    StcPaySDK.launch(this@MainActivity)
                }) { Text("Launch stcPay (UAT)") }
                Spacer(Modifier.height(16.dp))
                Button(onClick = {
                    StcPaySDK.configure(StcPayConfig(environment = StcPayEnvironment.PROD))
                    StcPaySDK.launch(this@MainActivity)
                }) { Text("Launch stcPay (PROD)") }
            }
        }
    }
}
10
Step 6

Build and Verify on UAT

10.1  Build the debug variant

In Android Studio: Run → Run 'app' (or ⇧F10). The debug build type maps to the SDK's gmsUat variant.

10.2  Expected Logcat output after launch

Filter Logcat by package com.yourcompany.stcpaysuperapp. Within 2–3 seconds of app start:

logcat
SdkOrchestrator   D  Security SDK initialised
SdkOrchestrator   D  Timber tree planted
SdkAdjustInit     D  Adjust initialised: <token>
SdkIntercomInit   D  Intercom initialised
SdkOneSignalInit  D  OneSignal initialised: <app-id>
Note These logs only appear in non-production builds (UAT and PreProd). They will be absent in PROD builds — that is expected behaviour.

10.3  Functional verification — UAT

  1. Tap "Launch stcPay (UAT)" button
  2. SdkActivity opens — the full stcPay Bahrain UI loads
  3. Navigate to the Login screen — enter UAT credentials and verify login completes
  4. Navigate through key screens: Home, Wallet, Profile — verify no crashes
  5. Press back — verify return to the host app's MainActivity
UAT Success Criteria Login completes, all key screens render without crash, back navigation returns to host. No SSL certificate errors in Logcat. Network calls go to the UAT base URL, not production.
11
Step 7

Build and Verify on PROD

11.1  Build the release variant

In Android Studio: Build → Generate Signed Bundle/APK → APK → use debug signing for testing. Or from the terminal:

bash
$ cd /path/to/super-app

$ JAVA_HOME=/Users/<username>/Library/Java/JavaVirtualMachines/jbr-21.0.x/Contents/Home \
  ./gradlew assembleRelease

11.2  Functional verification — PROD

  1. Install the release APK on a physical device:
    bash
    $ adb install app/build/outputs/apk/release/app-release.apk
  2. Tap "Launch stcPay (PROD)" button
  3. Verify the full stcPay UI loads — no crashes, no blank screens
  4. Navigate to Login — verify PROD API endpoints are used
  5. Confirm Logcat shows no SdkOrchestrator debug logs (Timber disabled in prod)
Do Not Use Real Credentials Do not enter real credentials on a test device. Use test accounts if available for PROD environment testing.
12
Ongoing workflow

Re-publishing After Source Changes

bash
# 1. Publish — use full or SDK-only depending on what changed
$ cd /path/to/stcpay-customer-android
$ JAVA_HOME=… ./gradlew :stcpay-sdk:publishToMavenLocal      # SDK-only changes
# OR
$ JAVA_HOME=… ./gradlew publishToMavenLocal --parallel       # Any module changes

# 2. Clean rebuild super app — REQUIRED to bust Gradle AAR cache
$ cd /path/to/super-app
$ JAVA_HOME=… ./gradlew clean assembleDebug
The #1 Cause of "My Changes Aren't Showing Up" Skipping the clean rebuild means Gradle serves the old bytecode from cache even after re-publishing. Always run ./gradlew clean assembleDebug in the super app after every re-publish.
13
Troubleshooting

Common Errors & Fixes

ErrorRoot causeFix
IllegalStateException: The Crashlytics build ID is missing com.google.firebase.crashlytics Gradle plugin not applied Add to project-level and app-level build.gradle.kts as shown in §8.2
IllegalStateException: Default FirebaseApp is not initialized Stale AAR in Gradle cache from old SDK version Run ./gradlew clean assembleDebug in the super app
IllegalStateException: You need to use a Theme.AppCompat theme Old SDK version where SdkActivity had no theme declared Ensure SDK version is 1.0.1. Clean rebuild.
Manifest merger failed: allowBackup conflict Jumio declares allowBackup="false" Add tools:replace="android:allowBackup" to <application> tag
Unable to find a matching variant of com.stcpay:stcpay-sdk:1.0.1 missingDimensionStrategy or matchingFallbacks missing Add both as shown in §8.4
Execution failed for task ':app:ijDownloadArtifact...' Android Studio's ijDownloadArtifact bypasses AGP variant resolution Add StcPayBuildTypeCompatibility and StcPayBuildTypeDisambiguation attribute rules shown in §8.4
NoClassDefFoundError: Failed resolution of: Lsome/library/ClassName SDK uses that library as implementation (not exported to consumers) Add the missing library to app/build.gradle.kts using same version as in stcpay-customer-android/gradle/libs.versions.toml. Notify SDK lead to promote to api().
FATAL EXCEPTION: BAD_DECRYPT / OPENSSL_internal AES key mismatch between debug (uat) and release (prod) on same device + same package Fixed in SDK via PreferencesUtil.decryptOrClear(). Ensure SDK version is 1.0.1.
SDK Logcat tags not visible after re-publish Gradle cache serving the old AAR Run ./gradlew clean assembleDebug in the super app
Could not resolve com.stcpay:secureutility:1.0.1 or benefit_pay_sdk:1.0.0 Manual AARs not installed to Maven Local Run the mvn install:install-file commands from §07
Could not GET '…maven.pkg.github.com…' Received status code 401 (GitHub Packages) PAT missing/invalid, or not present in ~/.gradle/gradle.properties Add a token with read:packages as shown in §15.2–§15.3. Confirm you have access to the stcpaybh/stcpay-customer-android repo.
Received status code 422: Unprocessable Entity (publishing to GitHub Packages) Maven coordinate contains uppercase letters — GitHub Packages requires lowercase Maintainers only: the publish convention plugin lowercases every artifactId. Ensure you publish from the SDK branch where this fix is present.
14
Final verification

Quick Checklist

Setup Phase
  • Both repos pulled on feature/stcpay-android-sdk
  • stcpay-ui-kit-androidProjectPath set in stcpay-customer-android/local.properties
  • Maven CLI available — mvn --version returns a version
  • JBR 21 located and path noted
Maven Local Phase
  • secureutility-1.0.1 installed — ls ~/.m2/repository/com/stcpay/secureutility/1.0.1/ shows files
  • benefit_pay_sdk-1.0.0 installed — ls ~/.m2/repository/com/stcpay/benefit_pay_sdk/1.0.0/ shows files
  • ./gradlew publishToMavenLocal --parallel completed without errors
  • stcpay-sdk/1.0.1/ directory contains 6 variant AARs
Super App Phase
  • mavenLocal(), jitpack.io, Jumio repo added to settings.gradle.kts
  • Firebase Crashlytics plugin in project-level build.gradle.kts
  • missingDimensionStrategy("contentType", "gms") in defaultConfig
  • matchingFallbacks on both release and debug build types
  • StcPayBuildTypeCompatibility + StcPayBuildTypeDisambiguation attribute rules added
  • isCoreLibraryDesugaringEnabled = true + coreLibraryDesugaring dep added
  • firebaseCrashlytics { mappingFileUploadEnabled = false } block added
  • Compose BOM is compose-bom-alpha:2025.12.01
  • Hilt deps added + kapt
  • implementation("com.stcpay:stcpay-sdk:1.0.1") added
  • Application class extends StcPayApplication + @HiltAndroidApp
  • tools:replace="android:allowBackup" in manifest <application> tag
  • WorkManager InitializationProvider entry removed from manifest
Verification Phase
  • App builds (debug) without errors
  • UAT button opens stcPay UI — login works, no crashes
  • Expected Logcat tags visible: SdkOrchestrator, SdkAdjustInit, SdkIntercomInit, SdkOneSignalInit
  • App builds (release) without errors
  • PROD button opens stcPay UI — login works, no crashes
  • No Logcat SDK tags in PROD build — Timber disabled in prod (expected)
15
Remote alternative — instead of Maven Local

Consume from GitHub Packages

The SDK is also published to a private GitHub Packages Maven registry. If you only want to consume and test a published build — not modify the SDK source — use this path instead of Maven Local. You can skip the entire local-publish pipeline (§05–§08): no cloning, no manual AAR install, no publishToMavenLocal.

Which path should I use? Maven Local (§05–§08) — you are developing or changing the SDK source and need to test your own builds.  ·  GitHub Packages (this section) — you just want to integrate and test an already-published version.
Maven Local stepNeeded for GitHub Packages?
§05 Pull both repositories❌ Not needed
§06 Configure local.properties❌ Not needed
§07 Manually install local AARs❌ Not needed — already on the registry
§08 Publish to Maven Local❌ Not needed — already published
§09 Create the test super app✅ Yes — with the repo block in §15.5
§10 / §11 Build & verify (UAT / PROD)✅ Yes — identical

15.1  Prerequisites

Far lighter than the Maven Local path — you are only consuming a published artifact, not building the SDK:

Not required (unlike Maven Local) No Maven CLI · no stcpay-customer-android or stcpay-ui-kit-android clone · no local.properties · no manual AAR install · no publishToMavenLocal. You never compile the SDK from source.

15.2  Registry & version

Registry URLhttps://maven.pkg.github.com/stcpaybh/stcpay-customer-android
Groupcom.stcpay
Current published version1.0.1
Version note The current published version is 1.0.1. Use it in your dependency. All com.stcpay coordinates are lowercase — GitHub Packages rejects uppercase Maven coordinates, so each published artifactId is the lowercased form of its Gradle module name (e.g. securityNDKsecurityndk).

15.3  Create a GitHub token (one-time)

Create a Personal Access Token (classic) at github.com/settings/tokens with these scopes:

You must be a member of stcpaybh with access to the stcpay-customer-android repository.

15.4  Add credentials to ~/.gradle/gradle.properties

Use the global Gradle properties file (in your home directory) — it is never committed, so it is the safe place for tokens:

properties
# ~/.gradle/gradle.properties — global, never committed to git
stcPayMavenUser=<your-github-username>
stcPayMavenPassword=<your-PAT-with-read:packages>
Never commit your token Keep the PAT in ~/.gradle/gradle.properties (global) or a CI secret — never in the project's committed gradle.properties or settings.gradle.kts.

15.5  settings.gradle.kts — GitHub Packages instead of mavenLocal()

This is the only structural difference from §9.1: the mavenLocal() line is replaced by the StcPayPrivateMaven repository. The content { includeGroup("com.stcpay") } filter ensures Gradle only queries the registry for stcPay artifacts — all other dependencies still come from Google / Maven Central / JitPack.

kotlin
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        // ⬇ Replaces mavenLocal() — resolves com.stcpay:* from GitHub Packages
        maven {
            name = "StcPayPrivateMaven"
            url = uri("https://maven.pkg.github.com/stcpaybh/stcpay-customer-android")
            credentials {
                username = providers.gradleProperty("stcPayMavenUser").orNull
                    ?: System.getenv("STCPAY_MAVEN_USER") ?: ""
                password = providers.gradleProperty("stcPayMavenPassword").orNull
                    ?: System.getenv("STCPAY_MAVEN_PASSWORD") ?: ""
            }
            content { includeGroup("com.stcpay") }
        }
        google()
        mavenCentral()
        maven { url = uri("https://jitpack.io") }   // dotlottie-android transitive dep
        exclusiveContent {
            forRepository { maven { url = uri("https://repo.mobile.jumio.ai") } }
            filter {
                includeGroup("com.jumio.android")
                includeGroup("com.iproov.sdk")
            }
        }
    }
}

15.6  app/build.gradle.kts — dependency

Identical to §9.4, but point at the remote version:

kotlin
implementation("com.stcpay:stcpay-sdk:1.0.1")

Every other file in §09 — the project-level build.gradle.kts, libs.versions.toml, the StcPayApplication subclass, AndroidManifest.xml, and MainActivity — is exactly the same as the Maven Local path. Build and verify using §10 (UAT) and §11 (PROD) unchanged.

No clean-rebuild caveat Unlike Maven Local, published versions are immutable — every change ships under a new version number. The stale-AAR-cache problem from §12 does not apply here; to pick up a new build, just bump the version in your dependency.

15.7  Build & verify the integration

Build the debug variant in Android Studio (Run → Run 'app'). To prove resolution comes from the registry — not a stale local cache — force a clean re-resolve from the terminal:

bash
$ cd /path/to/super-app
$ ./gradlew clean :app:assembleDebug --refresh-dependencies

A successful build downloads every com.stcpay:* artifact from maven.pkg.github.com into the Gradle cache. Then run the same functional checks as the Maven Local path — they are identical:

401 / 403 on download If Gradle reports Could not GET … 401, your token is missing, expired, or lacks read:packages — re-check §15.3–§15.4. A 403 usually means your account lacks access to the stcpaybh repository. See also §13.

15.8  Quick checklist — GitHub Packages path

15.9  Maintainers — how a version is published (reference)

For context, a maintainer pushes a release to the registry from stcpay-customer-android (credentials read from the same ~/.gradle/gradle.properties, with a token that also has write:packages):

bash
$ cd /path/to/stcpay-customer-android

# Publishes all com.stcpay modules to the GitHub Packages registry
$ JAVA_HOME=/Users/<username>/Library/Java/JavaVirtualMachines/jbr-21.0.x/Contents/Home \
  ./gradlew publishAllPublicationsToStcPayPrivateMavenRepository
Vendor AARs are already on the registry secureutility:1.0.1, stcpay-ui-kit:1.0.0, and benefit_pay_sdk:1.0.0 are published once and resolved automatically — consumers do not install them manually (unlike §07 for Maven Local).