Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6eceab7
feat: add pigeon and messages.dart
marcossevilla Nov 4, 2025
753302b
refactor: use host api instead of method channel
marcossevilla Nov 4, 2025
f085015
refactor(android): use host api
marcossevilla Nov 5, 2025
eb90aa5
refactor(ios): use host api
marcossevilla Nov 5, 2025
285d923
refactor(linux): use host api
marcossevilla Nov 5, 2025
e730b9e
refactor(macos): use host api
marcossevilla Nov 5, 2025
189e41f
refactor(windows): use host api
marcossevilla Nov 5, 2025
fb2d2c2
refactor(android): implement host api in plugin
marcossevilla Nov 6, 2025
ba630c3
refactor(ios): implement host api in plugin
marcossevilla Nov 6, 2025
8c7aa8b
refactor(macos): implement host api in plugin
marcossevilla Nov 6, 2025
fd200d1
refactor(linux): implement host api in plugin
marcossevilla Nov 6, 2025
89c8724
refactor(hooks): update plugin's hook tests
marcossevilla Nov 7, 2025
a127ceb
Merge branch 'main' into feat/flutter_plugin/pigeon
marcossevilla Mar 27, 2026
da6f8ae
fix: linux and windows pigeon migration
marcossevilla Mar 27, 2026
28220f6
chore: remove build files
marcossevilla Mar 27, 2026
8150a59
chore: ignore generated files
marcossevilla Mar 27, 2026
da52155
Merge branch 'main' into feat/flutter_plugin/pigeon
marcossevilla Mar 27, 2026
f759288
fix: correct iOS doc macro reference from _android to _ios
marcossevilla Mar 30, 2026
5620eeb
fix: conflicts
marcossevilla Mar 30, 2026
dc1bdfb
Merge branch 'main' into feat/flutter_plugin/pigeon
marcossevilla Mar 31, 2026
c5ecb59
Merge branch 'main' into feat/flutter_plugin/pigeon
marcossevilla Apr 8, 2026
d106e23
ci: add missing params
marcossevilla Apr 8, 2026
a413a92
Merge branch 'feat/flutter_plugin/pigeon' of github.com:VeryGoodOpenS…
marcossevilla Apr 8, 2026
125af9f
Merge branch 'main' into feat/flutter_plugin/pigeon
marcossevilla Apr 14, 2026
9a6ef7d
fix: skip running pigeon on web platform
marcossevilla Apr 14, 2026
d701f05
fix: dart format
marcossevilla Apr 14, 2026
0b96001
fix: dart format
marcossevilla Apr 14, 2026
c650b7d
chore: update DartCli format
marcossevilla Apr 14, 2026
21d99b1
feat: add path to DartCli.format
marcossevilla Apr 14, 2026
06dd686
Merge branch 'main' into feat/flutter_plugin/pigeon
marcossevilla Apr 14, 2026
8f15ece
fix: dart analyze
marcossevilla Apr 14, 2026
cd7e39e
Merge branch 'feat/flutter_plugin/pigeon' of github.com:VeryGoodOpenS…
marcossevilla Apr 14, 2026
1d093ff
Merge branch 'main' into feat/flutter_plugin/pigeon
marcossevilla Apr 14, 2026
d24ea87
fix: tests
marcossevilla Apr 15, 2026
e68c780
Merge branch 'feat/flutter_plugin/pigeon' of github.com:VeryGoodOpenS…
marcossevilla Apr 15, 2026
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
1 change: 1 addition & 0 deletions .github/.cspell/words_dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ dependabot # Automated dependency updates built into GitHub.
deserializes # The process of reconstructing a data structure or object from a series of bytes or a string in order to instantiate the object for consumption.
docusaurs # An optimized site generator in React.
genhtml # Tool to generate an HTML view from LCOV coverage data files.
gobject # Base system for the GTK library used in Linux.
gradlew # Wrapper tool that uses Gradle.
lcov # Graphical tool for displaying coverage reports.
localizable # Capable of being localized.
Expand Down
42 changes: 20 additions & 22 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,30 @@ We use [`release-please-action`][release-please-action-link] to automate version
### How it works:

- 📌 **On Every Commit to main:**
- Commits are analyzed using [Conventional Commits][conventional_commits_link].
- If a version bump is needed, a **release PR** is automatically created or updated by [`release-please-action`][release-please-action-link].
- The **release PR** includes:
- An updated `CHANGELOG.md`
- A version bump in `brick.yaml`

##### 💡 Notes

- Release PR's are created **per template**.
- The GitHub Action workflow that automates the release process is configured in `.github/workflows/release_please.yaml`
- release-please settings are defined in `.release-please-config.json` and `.release-please-manifest.json`
- The release PR can be manually edited before merging.
- The release PR should be merged **ONLY** when a new release is needed.
- Commits are analyzed using [Conventional Commits][conventional_commits_link].
- If a version bump is needed, a **release PR** is automatically created or updated by [`release-please-action`][release-please-action-link].
- The **release PR** includes:
- An updated `CHANGELOG.md`
- A version bump in `brick.yaml`

##### 💡 Notes
- Release PR's are created **per template**.
- The GitHub Action workflow that automates the release process is configured in `.github/workflows/release_please.yaml`
- release-please settings are defined in `.release-please-config.json` and `.release-please-manifest.json`
- The release PR can be manually edited before merging.
- The release PR should be merged **ONLY** when a new release is needed.

<br />

- ✅ **When the Release PR Is Merged:**
- A new Git tag is created.
- A GitHub Release is published with the changelog.
- A new version of the brick is automatically published in [brickhub.dev][brickhub_link].
- A new Git tag is created.
- A GitHub Release is published with the changelog.
- A new version of the brick is automatically published in [brickhub.dev][brickhub_link].

#### 💡 Notes

- GitHub Releases are created **per template**.
- The publishing process is automatically triggered when a version tag is created.
- The automated publishing workflows to [brickhub.dev][brickhub_link] are defined in `.github/workflows/publish_<template-name>.yaml`
#### 💡 Notes
- GitHub Releases are created **per template**.
- The publishing process is automatically triggered when a version tag is created.
- The automated publishing workflows to [brickhub.dev][brickhub_link] are defined in `.github/workflows/publish_<template-name>.yaml`

<br />

Expand All @@ -40,4 +38,4 @@ This document provides a good summary of how it works and how we use it, but we
[brickhub_publishing_link]: https://docs.brickhub.dev/mason-publish
[sem_ver_link]: https://semver.org/
[release-please-action-link]: https://github.com/googleapis/release-please-action
[conventional_commits_link]: https://www.conventionalcommits.org/en/v1.0.0
[conventional_commits_link]: https://www.conventionalcommits.org/en/v1.0.0
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ Collection of open source templates created and maintained by the [Very Good Ven

### Deprecated Templates

| Template | Description |
| -------------------------------------------- | ------------------------------------------------------------------ |
| [very_good_wear_app](very_good_wear_app/) | A Very Good WearOS Flutter app. **Deprecated** -- no longer maintained. |
| Template | Description |
| ----------------------------------------- | ----------------------------------------------------------------------- |
| [very_good_wear_app](very_good_wear_app/) | A Very Good WearOS Flutter app. **Deprecated** -- no longer maintained. |

<!-- Very Good Ventures -->

Expand Down Expand Up @@ -94,5 +94,3 @@ Collection of open source templates created and maintained by the [Very Good Ven
[very_good_flutter_plugin_workflow_link]: https://github.com/VeryGoodOpenSource/very_good_templates/actions/workflows/very_good_flutter_plugin.yaml?query=branch%3Amain
[very_good_flutter_plugin_code_link]: https://github.com/VeryGoodOpenSource/very_good_templates/tree/main/very_good_flutter_plugin
[very_good_flutter_plugin_docs_link]: https://cli.vgv.dev/docs/templates/federated_plugin


1 change: 1 addition & 0 deletions very_good_dart_package/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
.dart_tool/
.packages
pubspec.lock
build/

# Files and directories created by mason
.mason/
Expand Down
9 changes: 4 additions & 5 deletions very_good_flutter_plugin/__brick__/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ A Very Good Flutter Federated Plugin created by the [Very Good Ventures Team][ve

Generated by the [Very Good CLI][very_good_cli_link]. 🤖

## Integration tests 🧪

### Integration tests 🧪

Very Good Flutter Plugin uses [fluttium][fluttium_link] for integration tests. Those tests are located
in the front facing package `{{project_name.snakeCase()}}` example.
Very Good Flutter Plugin uses [fluttium][fluttium_link] for integration tests. Those tests are located
in the front facing package `{{project_name.snakeCase()}}` example.

**❗ In order to run the integration tests, you need to have the `fluttium_cli` installed. [See how][fluttium_install].**

Expand All @@ -40,4 +39,4 @@ fluttium test flows/test_platform_name.yaml
[very_good_ventures_link_dark]: https://verygood.ventures/?utm_source=github&utm_medium=banner&utm_campaign=core#gh-dark-mode-only
[very_good_ventures_link_light]: https://verygood.ventures/?utm_source=github&utm_medium=banner&utm_campaign=core#gh-light-mode-only
[fluttium_link]: https://fluttium.dev/
[fluttium_install]: https://fluttium.dev/docs/getting-started/installing-cli
[fluttium_install]: https://fluttium.dev/docs/getting-started/installing-cli
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
include: package:very_good_analysis/analysis_options.yaml
analyzer:
exclude:
- "**/*.g.dart"
Original file line number Diff line number Diff line change
@@ -1,30 +1,22 @@
package {{org_name.dotCase()}}

import androidx.annotation.NonNull

import {{project_name.pascalCase()}}Api
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result

class {{project_name.pascalCase()}}Plugin : FlutterPlugin, MethodCallHandler {
private lateinit var channel: MethodChannel
class {{project_name.pascalCase()}}Plugin : FlutterPlugin, {{project_name.pascalCase()}}Api {
companion object {
private const val TAG = "{{project_name.pascalCase()}}Plugin"
}

override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "{{project_name.snakeCase()}}_android")
channel.setMethodCallHandler(this)
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
{{project_name.pascalCase()}}Api.setUp(binding.binaryMessenger, this)
}

override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getPlatformName") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else {
result.notImplemented()
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
{{project_name.pascalCase()}}Api.setUp(binding.binaryMessenger, null)
}

override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
override fun getPlatformName(callback: (Result<String?>) -> Unit) {
callback(Result.success("Android ${android.os.Build.VERSION.RELEASE}"))
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:{{project_name.snakeCase()}}_android/src/messages.g.dart';
import 'package:{{project_name.snakeCase()}}_platform_interface/{{project_name.snakeCase()}}_platform_interface.dart';

/// {@template {{project_name.snakeCase()}}_android}
/// The Android implementation of [{{project_name.pascalCase()}}Platform].
class {{project_name.pascalCase()}}Android
extends {{project_name.pascalCase()}}Platform {
/// The method channel used to interact with the native platform.
@visibleForTesting
final methodChannel = const MethodChannel(
'{{project_name.snakeCase()}}_android',
);
/// {@endtemplate}
class {{project_name.pascalCase()}}Android extends {{project_name.pascalCase()}}Platform {
/// {@macro {{project_name.snakeCase()}}_android}
{{project_name.pascalCase()}}Android({
@visibleForTesting {{project_name.pascalCase()}}Api? api,
}) : api = api ?? {{project_name.pascalCase()}}Api();

/// The API used to interact with the native platform.
final {{project_name.pascalCase()}}Api api;

/// Registers this class as the default instance of
/// [{{project_name.pascalCase()}}Platform].
Expand All @@ -20,6 +23,6 @@ class {{project_name.pascalCase()}}Android

@override
Future<String?> getPlatformName() {
return methodChannel.invokeMethod<String>('getPlatformName');
return api.getPlatformName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Copyright (c) {{currentYear}}, {{org_name.titleCase()}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// {{project_name.pascalCase()}}Api must be abstract.
// ignore_for_file: one_member_abstracts

import 'package:pigeon/pigeon.dart';

@ConfigurePigeon(
PigeonOptions(
dartOut: 'lib/src/messages.g.dart',
dartPackageName: '{{project_name.snakeCase()}}',
kotlinOut: 'android/src/main/kotlin/{{org_name.pathCase()}}/Messages.g.kt',
kotlinOptions: KotlinOptions(),
copyrightHeader: 'pigeons/copyright.txt',
),
)
@HostApi()
abstract class {{project_name.pascalCase()}}Api {
@async
String? getPlatformName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
mocktail: ^1.0.4
pigeon: ^26.0.2
plugin_platform_interface: ^2.1.8
very_good_analysis: ^10.2.0
Original file line number Diff line number Diff line change
@@ -1,32 +1,23 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:{{project_name.snakeCase()}}_android/src/messages.g.dart';
import 'package:{{project_name.snakeCase()}}_android/{{project_name.snakeCase()}}_android.dart';
import 'package:{{project_name.snakeCase()}}_platform_interface/{{project_name.snakeCase()}}_platform_interface.dart';

class _Mock{{project_name.pascalCase()}}Api extends Mock
implements {{project_name.pascalCase()}}Api {}

void main() {
TestWidgetsFlutterBinding.ensureInitialized();

group('{{project_name.pascalCase()}}Android', () {
group({{project_name.pascalCase()}}Android, () {
Comment thread
marcossevilla marked this conversation as resolved.
const kPlatformName = 'Android';
late {{project_name.pascalCase()}}Android {{project_name.camelCase()}};
late List<MethodCall> log;

setUp(() async {
{{project_name.camelCase()}} = {{project_name.pascalCase()}}Android();

log = <MethodCall>[];
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler({{project_name.camelCase()}}.methodChannel, (
methodCall,
) async {
log.add(methodCall);
switch (methodCall.method) {
case 'getPlatformName':
return kPlatformName;
default:
return null;
}
});
late {{project_name.pascalCase()}}Api api;

setUp(() {
api = _Mock{{project_name.pascalCase()}}Api();
{{project_name.camelCase()}} = {{project_name.pascalCase()}}Android(api: api);
});

test('can be registered', () {
Expand All @@ -38,12 +29,14 @@ void main() {
});

test('getPlatformName returns correct name', () async {
final name = await {{project_name.camelCase()}}.getPlatformName();
expect(
log,
<Matcher>[isMethodCall('getPlatformName', arguments: null)],
when(api.getPlatformName).thenAnswer((_) async => kPlatformName);

await expectLater(
{{project_name.camelCase()}}.getPlatformName(),
completion(equals(kPlatformName)),
);
expect(name, equals(kPlatformName));

verify(api.getPlatformName).called(1);
});
});
}
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
include: package:very_good_analysis/analysis_options.yaml
analyzer:
exclude:
- "**/*.g.dart"
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import Flutter
import UIKit

public class {{project_name.pascalCase()}}Plugin: NSObject, FlutterPlugin {
public class {{project_name.pascalCase()}}Plugin: NSObject, FlutterPlugin, {{project_name.pascalCase()}}Api {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "{{project_name.snakeCase()}}_ios", binaryMessenger: registrar.messenger())
let binaryMessenger = registrar.messenger()
let instance = {{project_name.pascalCase()}}Plugin()
registrar.addMethodCallDelegate(instance, channel: channel)
{{project_name.pascalCase()}}ApiSetup.setUp(binaryMessenger: binaryMessenger, api: instance)
registrar.publish(instance)
}

public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
result("iOS")
func getPlatformName(completion: @escaping (Result<String?, Error>) -> Void) {
completion(.success("iOS"))
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:{{project_name.snakeCase()}}_ios/src/messages.g.dart';
import 'package:{{project_name.snakeCase()}}_platform_interface/{{project_name.snakeCase()}}_platform_interface.dart';

/// {@template {{project_name.snakeCase()}}_ios}
/// The iOS implementation of [{{project_name.pascalCase()}}Platform].
class {{project_name.pascalCase()}}IOS
extends {{project_name.pascalCase()}}Platform {
/// The method channel used to interact with the native platform.
@visibleForTesting
final methodChannel = const MethodChannel(
'{{project_name.snakeCase()}}_ios',
);
/// {@endtemplate}
class {{project_name.pascalCase()}}IOS extends {{project_name.pascalCase()}}Platform {
/// {@macro {{project_name.snakeCase()}}_ios}
{{project_name.pascalCase()}}IOS({
@visibleForTesting {{project_name.pascalCase()}}Api? api,
}) : api = api ?? {{project_name.pascalCase()}}Api();

/// The API used to interact with the native platform.
final {{project_name.pascalCase()}}Api api;

/// Registers this class as the default instance of
/// [{{project_name.pascalCase()}}Platform].
Expand All @@ -20,6 +23,6 @@ class {{project_name.pascalCase()}}IOS

@override
Future<String?> getPlatformName() {
return methodChannel.invokeMethod<String>('getPlatformName');
return api.getPlatformName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Copyright (c) {{currentYear}}, {{org_name.sentenceCase()}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// {{project_name.pascalCase()}}Api must be abstract.
// ignore_for_file: one_member_abstracts

import 'package:pigeon/pigeon.dart';

@ConfigurePigeon(
PigeonOptions(
dartOut: 'lib/src/messages.g.dart',
dartPackageName: '{{project_name.snakeCase()}}',
swiftOut: 'ios/{{project_name.snakeCase()}}_ios/Sources/{{project_name.snakeCase()}}_ios/Messages.g.swift',
swiftOptions: SwiftOptions(),
copyrightHeader: 'pigeons/copyright.txt',
),
)
@HostApi()
abstract class {{project_name.pascalCase()}}Api {
@async
String? getPlatformName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
mocktail: ^1.0.4
pigeon: ^26.0.2
plugin_platform_interface: ^2.1.8
very_good_analysis: ^10.2.0
Loading