snapshot of https://github.com/flutter/samples.git (main, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Main Branch CI / Test Flutter beta on ubuntu-latest (push) Has been skipped
Main Branch CI / Test Flutter stable on ubuntu-latest (push) Has been skipped
Main Branch CI / Test Flutter beta on macos-latest (push) Has been cancelled
Main Branch CI / Test Flutter stable on macos-latest (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-16 01:43:26 +05:00
commit 9ed6a80afa
2886 changed files with 140184 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:platform_channels/src/add_pet_details.dart';
import 'package:platform_channels/src/event_channel_demo.dart';
import 'package:platform_channels/src/method_channel_demo.dart';
import 'package:platform_channels/src/pet_list_screen.dart';
import 'package:platform_channels/src/platform_image_demo.dart';
void main() {
runApp(const PlatformChannelSample());
}
class PlatformChannelSample extends StatelessWidget {
const PlatformChannelSample({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'Platform Channel Sample',
theme: ThemeData(
snackBarTheme: SnackBarThemeData(
backgroundColor: Colors.blue[500],
),
),
routerConfig: router(),
);
}
}
GoRouter router([String? initialLocation]) {
return GoRouter(
initialLocation: initialLocation ?? '/',
routes: [
GoRoute(
path: '/',
builder: (context, state) => const HomePage(),
routes: [
GoRoute(
path: 'methodChannelDemo',
builder: (context, state) => const MethodChannelDemo(),
),
GoRoute(
path: 'eventChannelDemo',
builder: (context, state) => const EventChannelDemo(),
),
GoRoute(
path: 'platformImageDemo',
builder: (context, state) => const PlatformImageDemo(),
),
GoRoute(
path: 'petListScreen',
builder: (context, state) => const PetListScreen(),
routes: [
GoRoute(
path: 'addPetDetails',
builder: (context, state) => const AddPetDetails(),
),
],
),
],
),
],
);
}
class DemoInfo {
final String demoTitle;
final String demoRoute;
DemoInfo(this.demoTitle, this.demoRoute);
}
List<DemoInfo> demoList = [
DemoInfo('MethodChannel Demo', '/methodChannelDemo'),
DemoInfo('EventChannel Demo', '/eventChannelDemo'),
DemoInfo('Platform Image Demo', '/platformImageDemo'),
DemoInfo('BasicMessageChannel Demo', '/petListScreen'),
];
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Platform Channel Sample')),
body: ListView(
children: demoList.map((demoInfo) => DemoTile(demoInfo)).toList(),
),
);
}
}
/// This widget is responsible for displaying the [ListTile] on [HomePage].
class DemoTile extends StatelessWidget {
final DemoInfo demoInfo;
const DemoTile(this.demoInfo, {super.key});
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(demoInfo.demoTitle),
onTap: () {
context.go(demoInfo.demoRoute);
},
);
}
}

View File

@@ -0,0 +1,37 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/services.dart';
/// This class includes the implementation for [EventChannel] to listen to value
/// changes from the Accelerometer sensor from native side. It has a [readings]
/// getter to provide a stream of [AccelerometerReadings].
class Accelerometer {
static const _eventChannel = EventChannel('eventChannelDemo');
/// Method responsible for providing a stream of [AccelerometerReadings] to listen
/// to value changes from the Accelerometer sensor.
static Stream<AccelerometerReadings> get readings {
return _eventChannel.receiveBroadcastStream().map(
(dynamic event) => AccelerometerReadings(
event[0] as double,
event[1] as double,
event[2] as double,
),
);
}
}
class AccelerometerReadings {
/// Acceleration force along the x-axis.
final double x;
/// Acceleration force along the y-axis.
final double y;
/// Acceleration force along the z-axis.
final double z;
AccelerometerReadings(this.x, this.y, this.z);
}

View File

@@ -0,0 +1,81 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:platform_channels/src/pet_list_message_channel.dart';
/// Demonstrates how to use [BasicMessageChannel] to send a message to platform.
///
/// The widget uses [TextField] and [RadioListTile] to take the [PetDetails.breed] and
/// [PetDetails.petType] from the user respectively.
class AddPetDetails extends StatefulWidget {
const AddPetDetails({super.key});
@override
State<AddPetDetails> createState() => _AddPetDetailsState();
}
class _AddPetDetailsState extends State<AddPetDetails> {
final breedTextController = TextEditingController();
String petType = 'Dog';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Add Pet Details'),
actions: [
IconButton(
icon: const Icon(Icons.add),
onPressed: () {
PetListMessageChannel.addPetDetails(
PetDetails(
petType: petType,
breed: breedTextController.text,
),
);
context.pop();
},
),
],
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: RadioGroup(
groupValue: petType,
onChanged: (value) {
setState(() {
petType = value!;
});
},
child: Column(
children: [
const SizedBox(height: 8),
TextField(
controller: breedTextController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
filled: true,
hintText: 'Breed of pet',
labelText: 'Breed',
),
),
const SizedBox(height: 8),
RadioListTile<String>(
title: const Text('Dog'),
value: 'Dog',
),
RadioListTile<String>(
title: const Text('Cat'),
value: 'Cat',
),
],
),
),
),
);
}
}

View File

@@ -0,0 +1,33 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/services.dart';
/// This class includes implementation of two platform methods [increment],
/// and [decrement] which are used to increment and decrement value
/// of count respectively.
class Counter {
/// Creates a [MethodChannel] with the specified name to invoke platform method.
/// In order to communicate across platforms, the name of MethodChannel
/// should be same on native and dart side.
static MethodChannel methodChannel = const MethodChannel(
'methodChannelDemo',
);
/// This method is responsible to increment and return the value of count.
static Future<int> increment({required int counterValue}) async {
final result = await methodChannel.invokeMethod<int>('increment', {
'count': counterValue,
});
return result!;
}
/// This method is responsible to decrement and return the value of count.
static Future<int> decrement({required int counterValue}) async {
final result = await methodChannel.invokeMethod<int>('decrement', {
'count': counterValue,
});
return result!;
}
}

View File

@@ -0,0 +1,56 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:platform_channels/src/accelerometer_event_channel.dart';
/// Demonstrates how to use [EventChannel] to listen continuous values
/// of Accelerometer Sensor from platform.
///
/// The widget uses a [StreamBuilder] to rebuild it's descendant whenever it
/// listens a new value from the [Accelerometer.readings] stream. It has three
/// [Text] widgets to display the value of [AccelerometerReadings.x],
/// [AccelerometerReadings.y], and [AccelerometerReadings.z] respectively.
class EventChannelDemo extends StatelessWidget {
const EventChannelDemo({super.key});
@override
Widget build(BuildContext context) {
final textStyle = Theme.of(context).textTheme.headlineSmall;
return Scaffold(
appBar: AppBar(title: const Text('EventChannel Demo')),
body: Center(
child: StreamBuilder<AccelerometerReadings>(
stream: Accelerometer.readings,
builder: (context, snapshot) {
return switch (snapshot) {
AsyncSnapshot(hasError: true) => Text(
(snapshot.error as PlatformException).message!,
),
AsyncSnapshot(hasData: true) => Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'x axis: ${snapshot.data!.x.toStringAsFixed(3)}',
style: textStyle,
),
Text(
'y axis: ${snapshot.data!.y.toStringAsFixed(3)}',
style: textStyle,
),
Text(
'z axis: ${snapshot.data!.z.toStringAsFixed(3)}',
style: textStyle,
),
],
),
_ => Text('No Data Available', style: textStyle),
};
},
),
),
);
}
}

View File

@@ -0,0 +1,28 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/services.dart';
/// This class manages a [BasicMessageChannel] that can return an image loaded
/// from a native asset. The [BasicMessageChannel] uses [StandardMessageCodec]
/// since it supports [Uint8List], which is used to transport the image data.
class PlatformImageFetcher {
static const _basicMessageChannel = BasicMessageChannel<dynamic>(
'platformImageDemo',
StandardMessageCodec(),
);
/// Method responsible for providing the platform image.
static Future<Uint8List> getImage() async {
final reply = await _basicMessageChannel.send('getImage') as Uint8List?;
if (reply == null) {
throw PlatformException(
code: 'Error',
message: 'Failed to load Platform Image',
details: null,
);
}
return reply;
}
}

View File

@@ -0,0 +1,90 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:platform_channels/src/counter_method_channel.dart';
/// The widget demonstrates how to use [MethodChannel] to invoke platform methods.
/// It has two [FilledButton]s to increment and decrement the value of
/// [count], and a [Text] widget to display its value.
class MethodChannelDemo extends StatefulWidget {
const MethodChannelDemo({super.key});
@override
State<MethodChannelDemo> createState() => _MethodChannelDemoState();
}
class _MethodChannelDemoState extends State<MethodChannelDemo> {
int count = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('MethodChannel Demo')),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Value of count is $count',
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// Whenever users press the FilledButton, it invokes
// Counter.increment method to increment the value of count.
FilledButton.icon(
onPressed: () async {
try {
final value = await Counter.increment(
counterValue: count,
);
setState(() => count = value);
} catch (error) {
if (!context.mounted) return;
showErrorMessage(
context,
(error as PlatformException).message!,
);
}
},
icon: const Icon(Icons.add),
label: const Text('Increment'),
),
// Whenever users press the FilledButton, it invokes
// Counter.decrement method to decrement the value of count.
FilledButton.icon(
onPressed: () async {
try {
final value = await Counter.decrement(
counterValue: count,
);
setState(() => count = value);
} catch (error) {
if (!context.mounted) return;
showErrorMessage(
context,
(error as PlatformException).message!,
);
}
},
icon: const Icon(Icons.remove),
label: const Text('Decrement'),
),
],
),
],
),
);
}
void showErrorMessage(BuildContext context, String errorMessage) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(errorMessage)));
}
}

View File

@@ -0,0 +1,86 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:flutter/services.dart';
/// This class includes two methods [addPetDetails] and [removePet] which are used
/// to add a new pet and remove a pet from the the list respectively.
class PetListMessageChannel {
static const _jsonMessageCodecChannel = BasicMessageChannel<dynamic>(
'jsonMessageCodecDemo',
JSONMessageCodec(),
);
static const _binaryCodecChannel = BasicMessageChannel(
'binaryCodecDemo',
BinaryCodec(),
);
/// Method to add a new pet to the list.
///
/// Demonstrates how to use [BasicMessageChannel] and [JSONMessageCodec] to
/// send more structured data to platform like a [Map] in this case.
static void addPetDetails(PetDetails petDetails) {
_jsonMessageCodecChannel.send(petDetails.toJson());
}
/// Method to remove a pet from the list.
///
/// Demonstrates how to use [BasicMessageChannel] and [BinaryCodec] to
/// send [ByteData] to platform. If the reply received is null, then
/// we will throw a [PlatformException].
static Future<void> removePet(int index) async {
final uInt8List = utf8.encoder.convert(index.toString());
final reply = await _binaryCodecChannel.send(
uInt8List.buffer.asByteData(),
);
if (reply == null) {
throw PlatformException(
code: 'INVALID INDEX',
message: 'Failed to delete pet details',
details: null,
);
}
}
}
/// A model class that provides [petList] which is received from platform.
class PetListModel {
PetListModel({required this.petList});
final List<PetDetails> petList;
/// Method that maps the incoming string of json object to List of [PetDetails].
factory PetListModel.fromJson(String jsonString) {
final jsonData = json.decode(jsonString) as Map<String, dynamic>;
return PetListModel(
petList: List.from(
(jsonData['petList'] as List).map<PetDetails>(
(dynamic petDetailsMap) =>
PetDetails.fromMap(petDetailsMap as Map<String, dynamic>),
),
),
);
}
}
/// A simple model that provides pet details like [petType] and [breed] of pet.
class PetDetails {
PetDetails({required this.petType, required this.breed});
final String petType;
final String breed;
factory PetDetails.fromMap(Map<String, dynamic> map) => PetDetails(
petType: map['petType'] as String,
breed: map['breed'] as String,
);
Map<String, String> toJson() => <String, String>{
'petType': petType,
'breed': breed,
};
}

View File

@@ -0,0 +1,103 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
import 'package:platform_channels/src/pet_list_message_channel.dart';
/// Demonstrates how to use [BasicMessageChannel] to send & receive the platform
/// Message.
class PetListScreen extends StatefulWidget {
const PetListScreen({super.key});
@override
State<PetListScreen> createState() => _PetListScreenState();
}
class _PetListScreenState extends State<PetListScreen> {
PetListModel petListModel = PetListModel(petList: []);
final scaffoldKey = GlobalKey<ScaffoldState>();
@override
void didChangeDependencies() {
super.didChangeDependencies();
// Receives a string of json object from the platform and converts it
// to PetModel.
final scaffoldMessenger = ScaffoldMessenger.of(context);
const BasicMessageChannel<String?>(
'stringCodecDemo',
StringCodec(),
).setMessageHandler((message) async {
if (message == null) {
scaffoldMessenger.showSnackBar(
const SnackBar(
content: Text('An error occurred while adding pet details.'),
),
);
} else {
setState(() {
petListModel = PetListModel.fromJson(message);
});
}
return null;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: AppBar(title: const Text('Pet List')),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
context.go('/petListScreen/addPetDetails');
},
),
body: petListModel.petList.isEmpty
? const Center(child: Text('Enter Pet Details'))
: BuildPetList(petListModel.petList),
);
}
}
/// Shows list of [PetDetails].
class BuildPetList extends StatelessWidget {
final List<PetDetails> petList;
const BuildPetList(this.petList, {super.key});
@override
Widget build(BuildContext context) {
return ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: petList.length,
itemBuilder: (context, index) {
return ListTile(
title: Text('Pet breed: ${petList[index].breed}'),
subtitle: Text('Pet type: ${petList[index].petType}'),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () async {
final scaffoldMessenger = ScaffoldMessenger.of(context);
try {
await PetListMessageChannel.removePet(index);
scaffoldMessenger.showSnackBar(
const SnackBar(content: Text('Removed successfully!')),
);
} catch (error) {
scaffoldMessenger.showSnackBar(
SnackBar(
content: Text((error as PlatformException).message!),
),
);
}
},
),
);
},
);
}
}

View File

@@ -0,0 +1,74 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:platform_channels/src/image_basic_message_channel.dart';
/// Demonstrates how to use [BasicMessageChannel] to get an image from platform.
///
/// The widget uses [Image.memory] to display the image obtained from the
/// platform.
class PlatformImageDemo extends StatefulWidget {
const PlatformImageDemo({super.key});
@override
State<PlatformImageDemo> createState() => _PlatformImageDemoState();
}
class _PlatformImageDemoState extends State<PlatformImageDemo> {
Future<Uint8List>? imageData;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Platform Image Demo')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Flexible(
child: FractionallySizedBox(
widthFactor: 1,
heightFactor: 0.6,
child: FutureBuilder<Uint8List>(
future: imageData,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.none) {
return const Placeholder();
} else if (snapshot.hasError) {
return Center(
child: Text(
(snapshot.error as PlatformException).message!,
),
);
} else if (snapshot.connectionState ==
ConnectionState.done) {
return Image.memory(
snapshot.data!,
fit: BoxFit.fill,
);
}
return const CircularProgressIndicator();
},
),
),
),
const SizedBox(height: 16),
FilledButton(
onPressed: imageData != null
? null
: () {
setState(() {
imageData = PlatformImageFetcher.getImage();
});
},
child: const Text('Get Image'),
),
],
),
),
);
}
}