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
14 changes: 14 additions & 0 deletions android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
.cxx/

# Remember to never publicly share your keystore.
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks
46 changes: 46 additions & 0 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
plugins {
id("com.android.application")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
}

android {
namespace = "com.example.flutter_template"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion

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

defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.flutter_template"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
// minSdk = 23 required by flutter_secure_storage 9.x (see docs/setup_reference.md).
minSdk = 23
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}

buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
}
}
}

kotlin {
compilerOptions {
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
}
}

flutter {
source = "../.."
}
7 changes: 7 additions & 0 deletions android/app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
45 changes: 45 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="flutter_template"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.

In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ public static void registerWith(@NonNull FlutterEngine flutterEngine) {
} catch (Exception e) {
Log.e(TAG, "Error registering plugin flutter_secure_storage, com.it_nomads.fluttersecurestorage.FlutterSecureStoragePlugin", e);
}
try {
flutterEngine.getPlugins().add(new com.github.dart_lang.jni.JniPlugin());
} catch (Exception e) {
Log.e(TAG, "Error registering plugin jni, com.github.dart_lang.jni.JniPlugin", e);
}
try {
flutterEngine.getPlugins().add(new dev.fluttercommunity.plus.packageinfo.PackageInfoPlugin());
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.example.flutter_template

import io.flutter.embedding.android.FlutterActivity

class MainActivity : FlutterActivity()
12 changes: 12 additions & 0 deletions android/app/src/main/res/drawable-v21/launch_background.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />

<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
12 changes: 12 additions & 0 deletions android/app/src/main/res/drawable/launch_background.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />

<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
Binary file added android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions android/app/src/main/res/values-night/styles.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.

This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
18 changes: 18 additions & 0 deletions android/app/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.

This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
7 changes: 7 additions & 0 deletions android/app/src/profile/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
24 changes: 24 additions & 0 deletions android/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
allprojects {
repositories {
google()
mavenCentral()
}
}

val newBuildDir: Directory =
rootProject.layout.buildDirectory
.dir("../../build")
.get()
rootProject.layout.buildDirectory.value(newBuildDir)

subprojects {
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
project.layout.buildDirectory.value(newSubprojectBuildDir)
}
subprojects {
project.evaluationDependsOn(":app")
}

tasks.register<Delete>("clean") {
delete(rootProject.layout.buildDirectory)
}
6 changes: 6 additions & 0 deletions android/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
# This newDsl flag was added by the Flutter template
android.newDsl=false
# This builtInKotlin flag was added by the Flutter template
android.builtInKotlin=false
5 changes: 5 additions & 0 deletions android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip
6 changes: 6 additions & 0 deletions android/key.properties.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
# Copy this file to key.properties and fill in your values
# NEVER commit key.properties to git!

# NOTE: The generated android/app/build.gradle.kts currently signs the release
# build with the debug keystore (Flutter's default). It does NOT yet read this
# file. Real release signing via key.properties is tracked in the follow-up
# issue #18 "Release signing: key.properties + keystore for make build-android".
# Keep this example as the reference format for when that is wired in.

storePassword=YOUR_KEYSTORE_PASSWORD
keyPassword=YOUR_KEY_PASSWORD
keyAlias=release
Expand Down
26 changes: 26 additions & 0 deletions android/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
pluginManagement {
val flutterSdkPath =
run {
val properties = java.util.Properties()
file("local.properties").inputStream().use { properties.load(it) }
val flutterSdkPath = properties.getProperty("flutter.sdk")
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
flutterSdkPath
}

includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")

repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}

plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "9.0.1" apply false
id("org.jetbrains.kotlin.android") version "2.3.20" apply false
}

include(":app")
10 changes: 5 additions & 5 deletions docs/plans/android_scaffolding.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ No race conditions identified — all operations are synchronous and single-thre

## No-Gos (Out of Scope)

- [SEPARATE-SLUG] Release signing setup (creating a real `key.properties` + keystore and verifying `make build-android` / `flutter build apk --release`) — out of scope because it requires a real keystore and secrets that must not be committed. The acceptance criteria only require the debug build. **The release build (`make build-android`) is NOT verified by this fix**; it is deferred to a concrete follow-up issue, "Release signing: key.properties + keystore for make build-android" (owner: yudame), linked to #13 (resolves CONCERN 2).
- [SEPARATE-SLUG] Release signing setup (creating a real `key.properties` + keystore and verifying `make build-android` / `flutter build apk --release`) — out of scope because it requires a real keystore and secrets that must not be committed. The acceptance criteria only require the debug build. **The release build (`make build-android`) is NOT verified by this fix**; it is deferred to a concrete follow-up issue, "Release signing: key.properties + keystore for make build-android" (owner: yudame, #18), linked to #13 (resolves CONCERN 2).
- [EXTERNAL] Installing/verifying the Android SDK, JDK, or licenses on a developer machine — a human/environment action, not a repo change.

## Update System
Expand Down Expand Up @@ -184,7 +184,7 @@ No documentation site changes required.
- [ ] `minSdk = 23` is set in `android/app/build.gradle.kts` (for `flutter_secure_storage`).
- [ ] The existing 2 tracked files (`GeneratedPluginRegistrant.java`, `key.properties.example`) are preserved.
- [ ] `git status` shows only new `android/` files added and `key.properties.example` unchanged. `GeneratedPluginRegistrant.java` may appear as `M` (content-identical or content-drifted regeneration is acceptable) — only a deletion of `key.properties.example` or an unexpected new top-level file fails the gate (resolves CONCERN 1).
- [ ] Release build (`make build-android` / `flutter build apk --release`) is NOT verified by this fix; it is explicitly deferred to the release-signing follow-up issue (resolves CONCERN 2). The debug build is the gate.
- [ ] Release build (`make build-android` / `flutter build apk --release`) is NOT verified by this fix; it is explicitly deferred to the release-signing follow-up issue #18 (resolves CONCERN 2). The debug build is the gate.

## Team Orchestration

Expand Down Expand Up @@ -287,14 +287,14 @@ When this plan is executed, the lead agent orchestrates work using Task tools. T
## Open Questions

1. ~~**Toolchain pins source**~~ **RESOLVED (decision a)** — The issue's Solution Sketch cites pins (AGP 9.0.1, Gradle 9.1.0, JDK 17, Android SDK 36) that are not documented anywhere in the repo. Running `flutter create` and committing the generated Gradle files inherently hard-pins whatever the author's Flutter 3.44.8 emits, so the question was decided implicitly by Task 1. To make the committed toolchain explicit rather than emergent, Task 3 records the concrete generated AGP / Gradle wrapper / compileSdk / minSdk versions in the completion note (resolves CONCERN 3). No hard-pin override of the generated toolchain.
2. ~~**Release signing follow-up**~~ **RESOLVED (deferred)** — Deferred as a concrete follow-up issue, "Release signing: key.properties + keystore for make build-android" (owner: yudame), linked to #13. This fix verifies only the debug build; `make build-android` / `flutter build apk --release` is explicitly out of scope and NOT verified here (resolves CONCERN 2).
2. ~~**Release signing follow-up**~~ **RESOLVED (deferred)** — Deferred as a concrete follow-up issue, "Release signing: key.properties + keystore for make build-android" (owner: yudame, #18), linked to #13. This fix verifies only the debug build; `make build-android` / `flutter build apk --release` is explicitly out of scope and NOT verified here (resolves CONCERN 2).

## Implementation Notes (Revision Pass)

Embedded resolutions for the do-plan-critique findings (commit 6e444db, verdict READY TO BUILD with concerns). Each concern's resolution is applied in the plan text and linked where relevant:

- **CONCERN 1 (Risk & Robustness)**: Success criterion 6 and the Verification "Existing files preserved" row now explicitly permit `GeneratedPluginRegistrant.java` appearing as `M` (content-identical or content-drifted regeneration is acceptable), with only a `D ` deletion of `key.properties.example` or an unexpected new top-level file failing the gate. Task 1 carries the same note. The gate is no longer self-contradictory.
- **CONCERN 2 (Scope & Value)**: The plan is now explicit that `make build-android` / `flutter build apk --release` is NOT verified by this fix — the debug build is the gate. Deferred to a concrete follow-up issue, "Release signing: key.properties + keystore for make build-android" (owner: yudame, linked to #13), noted in No-Gos, Success Criteria, and resolved Open Question 2.
- **CONCERN 2 (Scope & Value)**: The plan is now explicit that `make build-android` / `flutter build apk --release` is NOT verified by this fix — the debug build is the gate. Deferred to a concrete follow-up issue, "Release signing: key.properties + keystore for make build-android" (owner: yudame, #18), noted in No-Gos, Success Criteria, and resolved Open Question 2.
- **CONCERN 3 (Toolchain)**: Open Question 1 is resolved as decision (a) — accept the toolchain `flutter create` emits. Task 3 now captures and records the concrete generated AGP / Gradle wrapper / compileSdk / minSdk versions in the completion note, making the committed toolchain explicit rather than emergent.
- **NIT (Scope)**: Verification and Success Criteria now state the applicationId is `com.example.flutter_template` — the "matches pubspec" criterion is a substring match (contains `flutter_template`), not literal equality, and the `com.example` prefix is accepted for a template.

Expand All @@ -305,6 +305,6 @@ Embedded resolutions for the do-plan-critique findings (commit 6e444db, verdict
Round 2 re-critique confirms the four round-1 resolutions are embedded in the plan text and close their concerns; no new findings. Verdict: **READY TO BUILD (no concerns)**.

- **CONCERN 1 (GeneratedPluginRegistrant.java `M` tolerance)** — CLOSED. Success Criteria (line 186), Task 1 (line 229), and Verification (line 273) all explicitly permit `GeneratedPluginRegistrant.java` to appear as `M`; only a `D ` deletion of `key.properties.example` or an unexpected new top-level file fails the gate. The gate is no longer self-contradictory.
- **CONCERN 2 (release-build out-of-scope + follow-up)** — CLOSED. No-Gos (line 157), Success Criteria (line 187), and resolved Open Question 2 (line 290) all state the release build (`make build-android` / `flutter build apk --release`) is NOT verified by this fix and is deferred to the concrete follow-up issue "Release signing: key.properties + keystore for make build-android" (owner: yudame, linked to #13).
- **CONCERN 2 (release-build out-of-scope + follow-up)** — CLOSED. No-Gos (line 157), Success Criteria (line 187), and resolved Open Question 2 (line 290) all state the release build (`make build-android` / `flutter build apk --release`) is NOT verified by this fix and is deferred to the concrete follow-up issue "Release signing: key.properties + keystore for make build-android" (owner: yudame, #18).
- **CONCERN 3 (toolchain decision (a))** — CLOSED. Open Question 1 (line 289) resolves to decision (a); Task 3 (line 251) captures the concrete generated AGP / Gradle wrapper / compileSdk / minSdk versions in the completion note, making the committed toolchain explicit rather than emergent.
- **NIT (applicationId substring match)** — CLOSED. Success Criteria (line 183), Verification (line 272), and Task 3 (line 250) state the applicationId is `com.example.flutter_template`, accepted as a substring match (contains `flutter_template`), not literal equality.
16 changes: 12 additions & 4 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.5"
jni:
dependency: transitive
description:
name: jni
sha256: d2c361082d554d4593c3012e26f6b188f902acd291330f13d6427641a92b3da1
url: "https://pub.dev"
source: hosted
version: "0.14.2"
js:
dependency: transitive
description:
Expand Down Expand Up @@ -761,18 +769,18 @@ packages:
dependency: transitive
description:
name: sentry
sha256: "599701ca0693a74da361bc780b0752e1abc98226cf5095f6b069648116c896bb"
sha256: c2ecd8abe82e63cdcb6947f71320612ced56e10ba94db7529d85cc02be47cb3b
url: "https://pub.dev"
source: hosted
version: "8.14.2"
version: "9.27.0"
sentry_flutter:
dependency: "direct main"
description:
name: sentry_flutter
sha256: "5ba2cf40646a77d113b37a07bd69f61bb3ec8a73cbabe5537b05a7c89d2656f8"
sha256: ec89cc6ba939ca19155ea83900d9740a36544f50b3b6baf265518e3348fb0f50
url: "https://pub.dev"
source: hosted
version: "8.14.2"
version: "9.27.0"
shared_preferences:
dependency: "direct main"
description:
Expand Down
Loading
Loading