Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 82 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,82 @@
# android-test-apps
# android-test-apps

## Setup

### Prerequisites
- Android Studio
- JDK 17+
- Firebase CLI (`brew install firebase-cli`)

### local.properties

This file is git-ignored and must be created manually at the project root. It holds all secrets and local paths:

```properties
sdk.dir=/path/to/your/Android/sdk

# Movable Ink
MOVABLE_INK_SDK_API_KEY=your_value

# Salesforce Marketing Cloud
MC_ACCESS_TOKEN=your_value
MC_APP_ID=your_value
FCM_SENDER_ID=your_value
MARKETING_CLOUD_URL=your_value

# Release signing
STORE_FILE=movableink-release.jks
STORE_PASSWORD=your_password
KEY_ALIAS=movableink
KEY_PASSWORD=your_password
```

---

## Firebase App Distribution Release

### First-time setup

**1. Generate a keystore** (only needed once):
```bash
keytool -genkeypair -v \
-keystore app/movableink-release.jks \
-alias movableink \
-keyalg RSA \
-keysize 2048 \
-validity 10000 \
-storepass YOUR_PASSWORD \
-keypass YOUR_PASSWORD \
-dname "CN=Movable Ink, OU=Engineering, O=Movable Ink, L=New York, ST=NY, C=US"
```

Add the credentials to `local.properties` as shown above. Never commit the `.jks` file or `local.properties`.

**2. Get a Firebase CI token** (only needed once):
```bash
firebase login:ci
```

Sign in with your Google account in the browser. Copy the token printed in the terminal and export it:
```bash
export FIREBASE_TOKEN=your_token_here
```

You can add this to your shell profile (`~/.zshrc` or `~/.bashrc`) to avoid setting it each time.

---

### Releasing a build

**1. Update the release notes** at `app/release-notes.txt` with what's changed.

**2. Update `versionCode`** in `gradle.properties` (increment by 1 each release):
```properties
versionCode=5
```

**3. Build and upload** from the project root:
```bash
./gradlew assembleRelease appDistributionUploadRelease
```

The APK will be built, signed, and uploaded to Firebase App Distribution automatically. Testers with access via the distribution link will be notified.
33 changes: 25 additions & 8 deletions app/android.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,28 @@ android {
composeOptions {
kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get()
}

signingConfigs {
release {
storeFile file(localProperties['STORE_FILE'])
storePassword localProperties['STORE_PASSWORD']
keyAlias localProperties['KEY_ALIAS']
keyPassword localProperties['KEY_PASSWORD']
}
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
firebaseAppDistribution {
artifactType = "APK"
releaseNotesFile = "app/release-notes.txt"
groups = "Mobile"
}
}
debug{
debug {
minifyEnabled false
}
}
Expand All @@ -24,11 +40,12 @@ android {
versionName findProperty("versionName")
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
manifestPlaceholders ["MOVABLE_INK_SDK_API_KEY"] = localProperties['MOVABLE_INK_SDK_API_KEY']
resValue "string", "accessToken", localProperties['MC_ACCESS_TOKEN']
resValue "string", "mc_appId", localProperties['MC_APP_ID']
resValue "string", "mc_mid", localProperties['MC_MID']
resValue "string", "fcm_sender_id", localProperties['FCM_SENDER_ID']
resValue "string", "marketing_cloud_url", localProperties['MARKETING_CLOUD_URL']
vectorDrawables.useSupportLibrary = true




}
buildFeatures {
compose true
Expand All @@ -42,7 +59,7 @@ android {
}
}
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
}
}
15 changes: 8 additions & 7 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
id("com.android.application")
kotlin("android")
id("org.jetbrains.kotlin.plugin.compose")
id("com.google.gms.google-services")
id("com.google.firebase.appdistribution")
}

apply(from = "android.gradle")

tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.jvmTarget = "1.8"
compilerOptions.jvmTarget.set(JvmTarget.JVM_17)
}
@Suppress("DSL_SCOPE_VIOLATION")
dependencies {
implementation(platform(libs.firebase.bom))
implementation(libs.firebase.auth)
implementation(libs.firebase.analytics)
implementation(libs.firebase.core)
implementation(libs.firebase.analytics)
implementation(libs.firebase.messaging)

implementation(libs.kotlin.stdlib.jdk7)
Expand All @@ -34,13 +35,13 @@ dependencies {

implementation(libs.activity.compose)
implementation(libs.navigation.compose)

// implementation(libs.play.services)
// Browser
implementation(libs.androidx.browser)

// AppsFlyer
implementation(libs.appsflyer)
implementation(libs.installreferrer)
// SFMC
implementation(libs.salesforce.mc.sdk)
// implementation(libs.marketingcloudsdk.v810)

// Movable Ink
implementation(libs.movableink)
Expand Down
1 change: 1 addition & 0 deletions app/release-notes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SFMC Integration
28 changes: 9 additions & 19 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
<queries>
<package android:name="com.google.android.gms" />
</queries>
Comment on lines +8 to +11

Copilot AI Mar 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FullScreenWebViewActivity is started from WebViewUtility, but it isn’t declared in the manifest. Add an <activity> entry for it (and ensure exported/launchMode settings are correct for your use case), otherwise ActivityNotFoundException will occur at runtime.

Copilot uses AI. Check for mistakes.

<application
android:name=".App"
Expand All @@ -30,87 +34,73 @@
android:theme="@style/Theme.ShoppingCart">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:scheme="http"
android:host="movableink.onelink.me" />
</intent-filter>


</activity>

<activity
android:name=".salesforce.FullScreenWebViewActivity"
android:exported="false" />

<activity
android:name=".DeepLinkActivity"
android:exported="true"
android:launchMode="singleInstancePerTask"
android:theme="@style/Theme.ShoppingCart">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:scheme="https"
android:host="www.movable-ink-7158.com"
android:pathPrefix="/p/cpm" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:scheme="https"
android:host="www.movable-ink-7158.com"
android:pathPrefix="/p/rpm" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:scheme="https"
android:host="www.movable-ink-7158.com"
android:pathPrefix="/p/gom" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:scheme="miapp"
android:pathPrefix="/product" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:scheme="miapp"
android:host="movableink-inkredible-retail.herokuapp.com"
android:pathPattern="/product/\\d+" />
</intent-filter>
</activity>


<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
Expand All @@ -121,4 +111,4 @@

</application>

</manifest>
</manifest>
Loading
Loading