Skip to content
Closed
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
65 changes: 65 additions & 0 deletions .github/workflows/build_and_local_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Build and local test

on:
push:
branches: [ "base", "multimodule" ]
pull_request:
branches: [ "base", "multimodule" ]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v6
- name: set up JDK 17
uses: actions/setup-java@v5
with:
java-version: 17
distribution: 'zulu'
cache: gradle

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Build debug
run: ./gradlew assembleDebug --stacktrace

- name: Run local tests
run: ./gradlew testDebug --stacktrace

- name: Upload build outputs (APKs)
uses: actions/upload-artifact@v5
with:
name: build-outputs
path: ./app/build/outputs

- name: Upload build reports
if: always()
uses: actions/upload-artifact@v5
with:
name: build-reports
path: ./app/build/reports

- name: Clean before running customizer
run: git clean -fx .

- name: Run customizer script
run: bash customizer.sh com.android.blah MyNewModel MyNewApplication

- name: "Check that customizer ran correctly"
uses: andstor/file-existence-action@v3
with:
files: "app/src/main/java/com/android/blah/MyNewApplication.kt"
fail: false

- name: "Check that customizer removed all unnecessary files"
id: customizer_rm
uses: andstor/file-existence-action@v3
with:
files: ".git/config"
fail: false
- name: "Fail if unnecessary files were not deleted"
if: steps.customizer_rm.outputs.files_exists == 'true'
run: exit 1
47 changes: 47 additions & 0 deletions .github/workflows/instrumented_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Instrumented tests

on:
push:
branches: [ "base", "multimodule" ]
pull_request:
branches: [ "base", "multimodule" ]

jobs:
androidTest:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
matrix:
api-level: [23, 26, 29]

steps:
- name: Enable KVM group perms
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
ls /dev/kvm

- name: Checkout
uses: actions/checkout@v6

- name: Set up JDK 17
uses: actions/setup-java@v5
with:
java-version: 17
distribution: 'zulu'

- name: Run instrumentation tests
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api-level }}
arch: x86
disable-animations: true
script: ./gradlew connectedCheck --stacktrace

- name: Upload test reports
if: always()
uses: actions/upload-artifact@v5
with:
name: test-reports-${{ matrix.api-level }}
path: ./app/build/reports/androidTests
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
/.idea
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
31 changes: 31 additions & 0 deletions .google/packaging.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright (C) 2020 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# GOOGLE SAMPLE PACKAGING DATA
#
# This file is used by Google as part of our samples packaging process.
# End users may safely ignore this file. It has no relevance to other systems.
---
status: PUBLISHED
technologies: [Android]
categories:
- AndroidTesting
- AndroidArchitecture
- AndroidArchitectureUILayer
- AndroidArchitectureDataLayer
languages: [Kotlin]
solutions: [Mobile]
github: android/architecture-templates
level: INTERMEDIATE
license: apache2
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Architecture starter template (multi-module)
==================

This template is compatible with the latest **stable** version of Android Studio.

![Screenshot](https://github.com/android/architecture-templates/raw/main/screenshots.png)

## Features

* Room Database
* Hilt
* ViewModel, read+write
* UI in Compose, list + write (Material3)
* Navigation
* Repository and data source
* Kotlin Coroutines and Flow
* Unit tests
* UI tests using fake data with Hilt

## Modules
The following module types are used:

- `core` modules contain objects that are used by one or more feature modules.
- `feature-mymodel` contains the `mymodel` feature.
- `feature-mymodel-navigation` contains the navigation keys for the `mymodel` feature. This allows other feature modules to navigate to `mymodel`'s screens without creating a dependency on `feature-mymodel`. An alternative approach is to use an [api / implementation split](https://developer.android.com/topic/modularization/patterns#dependency_injection).

Check the [modularization guidance](https://developer.android.com/topic/modularization) for more information.

## Usage

1. Clone this branch

```
git clone https://github.com/android/architecture-templates.git --branch multimodule
```


2. Run the customizer script:

```
./customizer.sh your.package.name DataItemType [MyApplication]
```

Where `your.package.name` is your app ID (should be lowercase) and `DataItemType` is used for the
name of the screen, exposed state and data base entity (should be PascalCase). You can add an optional application name.

# License

Now in Android is distributed under the terms of the Apache License (Version 2.0). See the
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The phrase "Now in Android is distributed..." appears to be a remnant from another project. It would be clearer to update this to be specific to the current project, for example, "This code is distributed...".

Suggested change
Now in Android is distributed under the terms of the Apache License (Version 2.0). See the
This code is distributed under the terms of the Apache License (Version 2.0). See the

[license](LICENSE) for more information.
1 change: 1 addition & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
113 changes: 113 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.jetbrains.kotlin.gradle.dsl.JvmTarget

@Suppress("DSL_SCOPE_VIOLATION") // Remove when fixed https://youtrack.jetbrains.com/issue/KTIJ-19369
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.hilt.gradle)
alias(libs.plugins.ksp)
alias(libs.plugins.compose.compiler)
}

android {
namespace = "android.template"
compileSdk = 36

defaultConfig {
applicationId = "android.template"
minSdk = 23
targetSdk = 36
versionCode = 1
versionName = "1.0"

vectorDrawables {
useSupportLibrary = true
}

// Enable room auto-migrations
ksp {
arg("room.schemaLocation", "$projectDir/schemas")
}
Comment on lines +42 to +45
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The room.schemaLocation is already configured in the core-database module, which is the appropriate location since it's where the Room database is defined. This declaration in the app module is redundant and could lead to confusion. Removing it would improve the clarity of the build configuration.

}

buildTypes {
getByName("release") {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

buildFeatures {
compose = true
aidl = false
buildConfig = false
renderScript = false
shaders = false
}

packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}

// Migrate from kotlinOptions to compilerOptions
kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
}
}

dependencies {
implementation(project(":core-ui"))
implementation(project(":feature-mymodel"))
implementation(project(":feature-mymodel-navigation"))

// Core Android dependencies
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)

// Hilt Dependency Injection
implementation(libs.hilt.android)
ksp(libs.hilt.compiler)

// Arch Components
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.lifecycle.viewmodel.compose)

// Compose
val composeBom = platform(libs.androidx.compose.bom)
implementation(composeBom)
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.compose.material3)

// Tooling
debugImplementation(libs.androidx.compose.ui.tooling)

// Navigation
implementation(libs.androidx.navigation3.ui)
implementation(libs.androidx.lifecycle.viewmodel.navigation3)
}
21 changes: 21 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
45 changes: 45 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication"
android:name=".MyApplication"
tools:targetApi="31">
<activity
android:name=".ui.MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustResize"
android:theme="@style/Theme.MyApplication">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Loading
Loading