Skip to content

Commit 41ae39a

Browse files
authored
flutter_tools: Update app template. (#2)
1 parent 66efcfa commit 41ae39a

21 files changed

Lines changed: 83 additions & 1080 deletions

File tree

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package {{androidIdentifier}}
2+
3+
import io.flutter.FlutterInjector
4+
import io.flutter.embedding.engine.FlutterEngine
5+
import io.flutter.embedding.engine.FlutterEngineCache
6+
import io.flutter.embedding.engine.dart.DartExecutor
7+
8+
class Application : android.app.Application() {
9+
10+
companion object {
11+
// Use a constant key so Activities/Services can fetch the engine later.
12+
const val ENGINE_ID = "headless_engine"
13+
}
14+
15+
private var engine: FlutterEngine? = null
16+
17+
override fun onCreate() {
18+
super.onCreate()
19+
20+
// Ensure Flutter is initialized (loads engine resources, etc.)
21+
// Usually automatic, but doing it explicitly makes startup behavior predictable.
22+
FlutterInjector.instance().flutterLoader().startInitialization(this)
23+
FlutterInjector.instance().flutterLoader().ensureInitializationComplete(this, null)
24+
25+
// Create a FlutterEngine not tied to any Activity.
26+
val flutterEngine = FlutterEngine(this)
27+
28+
// Start executing Dart code. This runs the "main()" of your Flutter app by default.
29+
val entrypoint = DartExecutor.DartEntrypoint.createDefault()
30+
flutterEngine.dartExecutor.executeDartEntrypoint(entrypoint)
31+
32+
// Optionally: register MethodChannels / EventChannels here, once the engine exists.
33+
// Example: setupChannels(flutterEngine)
34+
35+
// Cache it so other components can reuse it without recreating.
36+
FlutterEngineCache.getInstance().put(ENGINE_ID, flutterEngine)
37+
38+
engine = flutterEngine
39+
}
40+
41+
override fun onTerminate() {
42+
// onTerminate is not reliable in production, but safe to keep for emulators/tests.
43+
engine?.destroy()
44+
engine = null
45+
super.onTerminate()
46+
}
47+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package {{androidIdentifier}}
22

3-
import io.flutter.embedding.android.FlutterActivity
3+
import android.app.Activity
44

5-
class MainActivity : FlutterActivity()
5+
class MainActivity : Activity()

packages/flutter_tools/templates/app/android.tmpl/app/src/main/AndroidManifest.xml.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
22
<application
33
android:label="{{projectName}}"
4-
android:name="${applicationName}"
4+
android:name=".Application"
55
android:icon="@mipmap/ic_launcher">
66
<activity
77
android:name=".MainActivity"

packages/flutter_tools/templates/app/ios.tmpl/Runner/AppDelegate.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ import Flutter
22
import UIKit
33

44
@main
5-
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
5+
@objc class AppDelegate: FlutterAppDelegate {
6+
var engine: FlutterEngine?
7+
68
override func application(
79
_ application: UIApplication,
810
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
911
) -> Bool {
12+
engine = FlutterEngine(name: "project", project: nil)
13+
GeneratedPluginRegistrant.register(with: engine!)
14+
engine?.run(withEntrypoint:nil)
1015
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
1116
}
12-
13-
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
14-
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
15-
}
1617
}
Lines changed: 0 additions & 273 deletions
Original file line numberDiff line numberDiff line change
@@ -1,275 +1,2 @@
1-
import 'package:flutter/material.dart';
2-
{{#withEmptyMain}}
3-
41
void main() {
5-
runApp(const MainApp());
62
}
7-
8-
class MainApp extends StatelessWidget {
9-
const MainApp({super.key});
10-
11-
@override
12-
Widget build(BuildContext context) {
13-
return const MaterialApp(
14-
home: Scaffold(
15-
body: Center(
16-
child: Text('Hello World!'),
17-
),
18-
),
19-
);
20-
}
21-
}
22-
{{/withEmptyMain}}
23-
{{^withEmptyMain}}
24-
{{#withPlatformChannelPluginHook}}
25-
import 'dart:async';
26-
27-
import 'package:flutter/services.dart';
28-
import 'package:{{pluginProjectName}}/{{pluginProjectName}}.dart';
29-
{{/withPlatformChannelPluginHook}}
30-
{{#withFfi}}
31-
import 'dart:async';
32-
33-
import 'package:{{pluginProjectName}}/{{pluginProjectName}}.dart' as {{pluginProjectName}};
34-
{{/withFfi}}
35-
36-
void main() {
37-
runApp(const MyApp());
38-
}
39-
40-
{{^withPluginHook}}
41-
class MyApp extends StatelessWidget {
42-
const MyApp({super.key});
43-
44-
// This widget is the root of your application.
45-
@override
46-
Widget build(BuildContext context) {
47-
return MaterialApp(
48-
title: 'Flutter Demo',
49-
theme: ThemeData(
50-
// This is the theme of your application.
51-
//
52-
// TRY THIS: Try running your application with "flutter run". You'll see
53-
// the application has a purple toolbar. Then, without quitting the app,
54-
// try changing the seedColor in the colorScheme below to Colors.green
55-
// and then invoke "hot reload" (save your changes or press the "hot
56-
// reload" button in a Flutter-supported IDE, or press "r" if you used
57-
// the command line to start the app).
58-
//
59-
// Notice that the counter didn't reset back to zero; the application
60-
// state is not lost during the reload. To reset the state, use hot
61-
// restart instead.
62-
//
63-
// This works for code too, not just values: Most code changes can be
64-
// tested with just a hot reload.
65-
colorScheme: .fromSeed(seedColor: Colors.deepPurple),
66-
),
67-
home: const MyHomePage(title: 'Flutter Demo Home Page'),
68-
);
69-
}
70-
}
71-
72-
class MyHomePage extends StatefulWidget {
73-
const MyHomePage({super.key, required this.title});
74-
75-
// This widget is the home page of your application. It is stateful, meaning
76-
// that it has a State object (defined below) that contains fields that affect
77-
// how it looks.
78-
79-
// This class is the configuration for the state. It holds the values (in this
80-
// case the title) provided by the parent (in this case the App widget) and
81-
// used by the build method of the State. Fields in a Widget subclass are
82-
// always marked "final".
83-
84-
final String title;
85-
86-
@override
87-
State<MyHomePage> createState() => _MyHomePageState();
88-
}
89-
90-
class _MyHomePageState extends State<MyHomePage> {
91-
int _counter = 0;
92-
93-
void _incrementCounter() {
94-
setState(() {
95-
// This call to setState tells the Flutter framework that something has
96-
// changed in this State, which causes it to rerun the build method below
97-
// so that the display can reflect the updated values. If we changed
98-
// _counter without calling setState(), then the build method would not be
99-
// called again, and so nothing would appear to happen.
100-
_counter++;
101-
});
102-
}
103-
104-
@override
105-
Widget build(BuildContext context) {
106-
// This method is rerun every time setState is called, for instance as done
107-
// by the _incrementCounter method above.
108-
//
109-
// The Flutter framework has been optimized to make rerunning build methods
110-
// fast, so that you can just rebuild anything that needs updating rather
111-
// than having to individually change instances of widgets.
112-
return Scaffold(
113-
appBar: AppBar(
114-
// TRY THIS: Try changing the color here to a specific color (to
115-
// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
116-
// change color while the other colors stay the same.
117-
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
118-
// Here we take the value from the MyHomePage object that was created by
119-
// the App.build method, and use it to set our appbar title.
120-
title: Text(widget.title),
121-
),
122-
body: Center(
123-
// Center is a layout widget. It takes a single child and positions it
124-
// in the middle of the parent.
125-
child: Column(
126-
// Column is also a layout widget. It takes a list of children and
127-
// arranges them vertically. By default, it sizes itself to fit its
128-
// children horizontally, and tries to be as tall as its parent.
129-
//
130-
// Column has various properties to control how it sizes itself and
131-
// how it positions its children. Here we use mainAxisAlignment to
132-
// center the children vertically; the main axis here is the vertical
133-
// axis because Columns are vertical (the cross axis would be
134-
// horizontal).
135-
//
136-
// TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
137-
// action in the IDE, or press "p" in the console), to see the
138-
// wireframe for each widget.
139-
mainAxisAlignment: .center,
140-
children: [
141-
const Text('You have pushed the button this many times:'),
142-
Text(
143-
'$_counter',
144-
style: Theme.of(context).textTheme.headlineMedium,
145-
),
146-
],
147-
),
148-
),
149-
floatingActionButton: FloatingActionButton(
150-
onPressed: _incrementCounter,
151-
tooltip: 'Increment',
152-
child: const Icon(Icons.add),
153-
),
154-
);
155-
}
156-
}
157-
{{/withPluginHook}}
158-
{{#withPlatformChannelPluginHook}}
159-
class MyApp extends StatefulWidget {
160-
const MyApp({super.key});
161-
162-
@override
163-
State<MyApp> createState() => _MyAppState();
164-
}
165-
166-
class _MyAppState extends State<MyApp> {
167-
String _platformVersion = 'Unknown';
168-
final _{{pluginClassLowerCamelCase}} = {{pluginDartClass}}();
169-
170-
@override
171-
void initState() {
172-
super.initState();
173-
initPlatformState();
174-
}
175-
176-
// Platform messages are asynchronous, so we initialize in an async method.
177-
Future<void> initPlatformState() async {
178-
String platformVersion;
179-
// Platform messages may fail, so we use a try/catch PlatformException.
180-
// We also handle the message potentially returning null.
181-
try {
182-
platformVersion =
183-
await _{{pluginClassLowerCamelCase}}.getPlatformVersion() ?? 'Unknown platform version';
184-
} on PlatformException {
185-
platformVersion = 'Failed to get platform version.';
186-
}
187-
188-
// If the widget was removed from the tree while the asynchronous platform
189-
// message was in flight, we want to discard the reply rather than calling
190-
// setState to update our non-existent appearance.
191-
if (!mounted) return;
192-
193-
setState(() {
194-
_platformVersion = platformVersion;
195-
});
196-
}
197-
198-
@override
199-
Widget build(BuildContext context) {
200-
return MaterialApp(
201-
home: Scaffold(
202-
appBar: AppBar(title: const Text('Plugin example app')),
203-
body: Center(child: Text('Running on: $_platformVersion\n')),
204-
),
205-
);
206-
}
207-
}
208-
{{/withPlatformChannelPluginHook}}
209-
{{#withFfi}}
210-
class MyApp extends StatefulWidget {
211-
const MyApp({super.key});
212-
213-
@override
214-
State<MyApp> createState() => _MyAppState();
215-
}
216-
217-
class _MyAppState extends State<MyApp> {
218-
late int sumResult;
219-
late Future<int> sumAsyncResult;
220-
221-
@override
222-
void initState() {
223-
super.initState();
224-
sumResult = {{pluginProjectName}}.sum(1, 2);
225-
sumAsyncResult = {{pluginProjectName}}.sumAsync(3, 4);
226-
}
227-
228-
@override
229-
Widget build(BuildContext context) {
230-
const textStyle = TextStyle(fontSize: 25);
231-
const spacerSmall = SizedBox(height: 10);
232-
return MaterialApp(
233-
home: Scaffold(
234-
appBar: AppBar(title: const Text('Native Packages')),
235-
body: SingleChildScrollView(
236-
child: Container(
237-
padding: const .all(10),
238-
child: Column(
239-
children: [
240-
const Text(
241-
'This calls a native function through FFI that is shipped as source in the package. '
242-
'The native code is built as part of the Flutter Runner build.',
243-
style: textStyle,
244-
textAlign: .center,
245-
),
246-
spacerSmall,
247-
Text(
248-
'sum(1, 2) = $sumResult',
249-
style: textStyle,
250-
textAlign: .center,
251-
),
252-
spacerSmall,
253-
FutureBuilder<int>(
254-
future: sumAsyncResult,
255-
builder: (BuildContext context, AsyncSnapshot<int> value) {
256-
final displayValue = (value.hasData)
257-
? value.data
258-
: 'loading';
259-
return Text(
260-
'await sumAsync(3, 4) = $displayValue',
261-
style: textStyle,
262-
textAlign: .center,
263-
);
264-
},
265-
),
266-
],
267-
),
268-
),
269-
),
270-
),
271-
);
272-
}
273-
}
274-
{{/withFfi}}
275-
{{/withEmptyMain}}

0 commit comments

Comments
 (0)