mirror of
https://github.com/flutter/samples.git
synced 2025-11-09 22:38:42 +00:00
Tidying up add-to-app samples (#160)
This commit is contained in:
@@ -10,6 +10,10 @@ a standalone Flutter module called `flutter_module`.
|
||||
## Goals for this sample
|
||||
|
||||
* Show developers how to add Flutter to their existing applications.
|
||||
* Show the following options:
|
||||
- Whether to build the Flutter module from source each time the app builds or
|
||||
rely on a separately pre-built module.
|
||||
- Whether plugins are needed by the Flutter module used in the app.
|
||||
|
||||
## The important bits
|
||||
|
||||
@@ -20,13 +24,12 @@ There are two Flutter modules included in the codebase:
|
||||
* `flutter_module` displays the dimensions of the screen, a button that
|
||||
increments a simple counter, and an optional exit button.
|
||||
* `flutter_module_using_plugin` does everything `flutter_module` does, and adds
|
||||
another button that will save the counter's value to a file using the
|
||||
[`path_provider`](https://pub.dev/packages/path_povider) Flutter plugin.
|
||||
another button that will open the Flutter documentation in a browser using the
|
||||
[`url_launcher`](https://pub.dev/packages/url_launcher) Flutter plugin.
|
||||
|
||||
Before running any of the Android or iOS apps included in this sample project,
|
||||
you first need to resolve the Flutter modules' depencies. Do so by running this
|
||||
command from within the `flutter_module` and `flutter_module_using_plugin`
|
||||
directories:
|
||||
Before using them, you need to resolve the Flutter modules' dependencies. Do so
|
||||
by running this command from within the `flutter_module` and
|
||||
`flutter_module_using_plugin` directories:
|
||||
|
||||
```bash
|
||||
flutter packages get
|
||||
@@ -38,14 +41,15 @@ In addition to the Flutter modules, this repo also includes a number of
|
||||
Android and iOS applications that demonstrate different ways of importing
|
||||
them.
|
||||
|
||||
The Android apps are ready to run once you've completed the
|
||||
`flutter packages get` commands listed above. The iOS apps use CocoaPods,
|
||||
so you need to run this command to install the dependencies listed in their
|
||||
Podfiles prior to running them the first time.
|
||||
With the exception of `android_using_prebuilt_module`, the Android apps are
|
||||
ready to run once you've completed the `flutter packages get` commands listed
|
||||
above. The iOS apps use CocoaPods, though, so you need to run this command to
|
||||
install the dependencies listed in their Podfiles prior to running them the
|
||||
first time.
|
||||
|
||||
This should be done in the individual project directories themselves. For
|
||||
example, prior to running `ios_fullscreen` for the first time, you need to run
|
||||
these commands:
|
||||
example, prior to running `ios_fullscreen` or `ios_using_plugin` for the first
|
||||
time, you need to run these commands:
|
||||
|
||||
```bash
|
||||
cd ios_fullscreen
|
||||
@@ -71,6 +75,55 @@ These apps showcase a relatively straightforward integration of
|
||||
If you are new to Flutter's add-to-app APIs, these projects are a great place
|
||||
to begin learning how to use them.
|
||||
|
||||
### `android_using_plugin` and `ios_plugin`
|
||||
|
||||
These apps are similar to `android_fullscreen` and `ios_fullscreen`, with the
|
||||
following differences:
|
||||
|
||||
* Rather than importing `flutter_module`, they import
|
||||
`flutter_module_using_plugin`.
|
||||
* They include the native code (Kotlin or Swift) required to initialize plugins
|
||||
at Flutter engine creation time.
|
||||
* Their Flutter view includes an additional button that opens the Flutter docs
|
||||
in the mobile device's browser.
|
||||
|
||||
If you're interested in learning what additional steps an app needs to take in
|
||||
order to use a Flutter module that relies on plugins, these projects can help.
|
||||
|
||||
### `android_using_prebuilt_module`
|
||||
|
||||
This app is essentially identical to `android_fullscreen` with one key
|
||||
difference:
|
||||
|
||||
* The Flutter module is *not* built automatically when the app builds. Instead,
|
||||
it's built separately into an `aar`. The Android app is configured to import
|
||||
that `aar` along with its other gradle dependencies.
|
||||
|
||||
This can be useful for teams that don't want to require every developer working
|
||||
on the app to have the Flutter toolchain installed on their local machines.
|
||||
|
||||
Prior to building `android_using_prebuilt_module` for the first time, the
|
||||
Flutter module should be built into an `aar`. The build can be done in a debug
|
||||
or release configuration. To build a debug `aar`, run this command from the
|
||||
`flutter_module` directory:
|
||||
|
||||
```
|
||||
flutter build aar --debug
|
||||
```
|
||||
|
||||
To build a release version of the `aar`, simply omit the debug flag:
|
||||
|
||||
```
|
||||
flutter build aar
|
||||
```
|
||||
|
||||
The Android app is configured to import the appropriate `aar` based on its own
|
||||
build configuration, so if you build a debug version of the app, it will look
|
||||
for the debug `aar`, and likewise for a release build.
|
||||
|
||||
If the `flutter_module` project is updated, the `aar` must be rebuilt via one of
|
||||
the commands above in order for those changes to appear in the app.
|
||||
|
||||
## Questions/issues
|
||||
|
||||
If you have a general question about incorporating Flutter into an existing
|
||||
|
||||
@@ -11,7 +11,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private var counterLabel: TextView? = null
|
||||
private lateinit var counterLabel: TextView
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -32,6 +32,6 @@ class MainActivity : AppCompatActivity() {
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
val app = application as MyApplication
|
||||
counterLabel?.text = "Current count: ${app.count}"
|
||||
counterLabel.text = "Current count: ${app.count}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ const val ENGINE_ID = "1"
|
||||
class MyApplication : Application() {
|
||||
var count = 0
|
||||
|
||||
private var channel: MethodChannel? = null
|
||||
private lateinit var channel: MethodChannel
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
@@ -31,7 +31,7 @@ class MyApplication : Application() {
|
||||
|
||||
channel = MethodChannel(flutterEngine.dartExecutor, "dev.flutter.example/counter")
|
||||
|
||||
channel?.setMethodCallHandler { call, _ ->
|
||||
channel.setMethodCallHandler { call, _ ->
|
||||
when (call.method) {
|
||||
"incrementCounter" -> {
|
||||
count++
|
||||
@@ -45,6 +45,6 @@ class MyApplication : Application() {
|
||||
}
|
||||
|
||||
private fun reportCounter() {
|
||||
channel?.invokeMethod("reportCounter", count)
|
||||
channel.invokeMethod("reportCounter", count)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
||||
classpath 'com.android.tools.build:gradle:3.5.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
||||
@@ -11,7 +11,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private var counterLabel: TextView? = null
|
||||
private lateinit var counterLabel: TextView
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -32,6 +32,6 @@ class MainActivity : AppCompatActivity() {
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
val app = application as MyApplication
|
||||
counterLabel?.text = "Current count: ${app.count}"
|
||||
counterLabel.text = "Current count: ${app.count}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ const val ENGINE_ID = "1"
|
||||
class MyApplication : Application() {
|
||||
var count = 0
|
||||
|
||||
private var channel: MethodChannel? = null
|
||||
private lateinit var channel: MethodChannel
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
@@ -31,7 +31,7 @@ class MyApplication : Application() {
|
||||
|
||||
channel = MethodChannel(flutterEngine.dartExecutor, "dev.flutter.example/counter")
|
||||
|
||||
channel?.setMethodCallHandler { call, _ ->
|
||||
channel.setMethodCallHandler { call, _ ->
|
||||
when (call.method) {
|
||||
"incrementCounter" -> {
|
||||
count++
|
||||
@@ -45,6 +45,6 @@ class MyApplication : Application() {
|
||||
}
|
||||
|
||||
private fun reportCounter() {
|
||||
channel?.invokeMethod("reportCounter", count)
|
||||
channel.invokeMethod("reportCounter", count)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,10 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
/// The entrypoint for the flutter module.
|
||||
void main() {
|
||||
// This call ensures the Flutter binding has been set up before creating the
|
||||
// MethodChannel-based model.
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
final model = CounterModel();
|
||||
@@ -19,6 +22,13 @@ void main() {
|
||||
);
|
||||
}
|
||||
|
||||
/// A simple model that uses a [MethodChannel] as the source of truth for the
|
||||
/// state of the counter.
|
||||
///
|
||||
/// Rather than storing app state data within the Flutter module itself (where
|
||||
/// the native portions of the app can't access it), this module passes messages
|
||||
/// back to the containing app whenever it needs to increment or retrieve the
|
||||
/// value of the counter.
|
||||
class CounterModel extends ChangeNotifier {
|
||||
CounterModel() {
|
||||
_channel.setMethodCallHandler(_handleMessage);
|
||||
@@ -43,6 +53,10 @@ class CounterModel extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
/// The "app" displayed by this module.
|
||||
///
|
||||
/// It offers two routes, one suitable for displaying as a full screen and
|
||||
/// another designed to be part of a larger UI.class MyApp extends StatelessWidget {
|
||||
class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -56,6 +70,8 @@ class MyApp extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps [Contents] in a Material [Scaffold] so it looks correct when displayed
|
||||
/// full-screen.
|
||||
class FullScreenView extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -68,6 +84,11 @@ class FullScreenView extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// The actual content displayed by the module.
|
||||
///
|
||||
/// This widget displays info about the state of a counter and how much room (in
|
||||
/// logical pixels) it's been given. It also offers buttons to increment the
|
||||
/// counter and (optionally) close the Flutter view.
|
||||
class Contents extends StatelessWidget {
|
||||
final bool showExit;
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ packages:
|
||||
name: provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.1.0+1"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -192,4 +192,4 @@ packages:
|
||||
source: hosted
|
||||
version: "3.5.0"
|
||||
sdks:
|
||||
dart: ">=2.5.0 <3.0.0"
|
||||
dart: ">=2.6.0-dev <3.0.0"
|
||||
|
||||
@@ -4,7 +4,7 @@ description: An example Flutter module.
|
||||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.5.0 <3.0.0"
|
||||
sdk: ">=2.6.0-dev <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
buildscript {}
|
||||
@@ -7,7 +7,10 @@ import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:url_launcher/url_launcher.dart' as launcher;
|
||||
|
||||
/// The entrypoint for the flutter module.
|
||||
void main() {
|
||||
// This call ensures the Flutter binding has been set up before creating the
|
||||
// MethodChannel-based model.
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
final model = CounterModel();
|
||||
@@ -20,6 +23,13 @@ void main() {
|
||||
);
|
||||
}
|
||||
|
||||
/// A simple model that uses a [MethodChannel] as the source of truth for the
|
||||
/// state of the counter.
|
||||
///
|
||||
/// Rather than storing app state data within the Flutter module itself (where
|
||||
/// the native portions of the app can't access it), this module passes messages
|
||||
/// back to the containing app whenever it needs to increment or retrieve the
|
||||
/// value of the counter.
|
||||
class CounterModel extends ChangeNotifier {
|
||||
CounterModel() {
|
||||
_channel.setMethodCallHandler(_handleMessage);
|
||||
@@ -44,6 +54,10 @@ class CounterModel extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
/// The "app" displayed by this module.
|
||||
///
|
||||
/// It offers two routes, one suitable for displaying as a full screen and
|
||||
/// another designed to be part of a larger UI.
|
||||
class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -57,6 +71,8 @@ class MyApp extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps [Contents] in a Material [Scaffold] so it looks correct when displayed
|
||||
/// full-screen.
|
||||
class FullScreenView extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -69,6 +85,12 @@ class FullScreenView extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// The actual content displayed by the module.
|
||||
///
|
||||
/// This widget displays info about the state of a counter and how much room (in
|
||||
/// logical pixels) it's been given. It also offers buttons to increment the
|
||||
/// counter, opening the Flutter documentation via the url_launcher plugin, and
|
||||
/// (optionally) close the Flutter view.
|
||||
class Contents extends StatelessWidget {
|
||||
final bool showExit;
|
||||
|
||||
@@ -126,6 +148,8 @@ class Contents extends StatelessWidget {
|
||||
),
|
||||
RaisedButton(
|
||||
onPressed: () async {
|
||||
// Use the url_launcher plugin to open the Flutter docs in
|
||||
// a browser.
|
||||
final url = 'https://flutter.dev/docs';
|
||||
if (await launcher.canLaunch(url)) {
|
||||
launcher.launch(url);
|
||||
|
||||
@@ -115,7 +115,7 @@ packages:
|
||||
name: provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.1.0+1"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -183,7 +183,14 @@ packages:
|
||||
name: url_launcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.2.0"
|
||||
version: "5.2.5"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -199,5 +206,5 @@ packages:
|
||||
source: hosted
|
||||
version: "3.5.0"
|
||||
sdks:
|
||||
dart: ">=2.5.0 <3.0.0"
|
||||
flutter: ">=1.5.0 <2.0.0"
|
||||
dart: ">=2.6.0-dev <3.0.0"
|
||||
flutter: ">=1.9.1+hotfix.4 <2.0.0"
|
||||
|
||||
@@ -4,13 +4,13 @@ description: An example Flutter module that uses a plugin.
|
||||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.5.0 <3.0.0"
|
||||
sdk: ">=2.6.0-dev <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
provider: ^3.1.0
|
||||
url_launcher: ^5.1.6
|
||||
url_launcher: ^5.2.5
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
@@ -494,6 +494,7 @@
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
@@ -555,6 +556,7 @@
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objectVersion = 51;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -152,7 +152,6 @@
|
||||
BF8095192EC0A98CBABFC968 /* Pods-IOSUsingPluginUITests.debug.xcconfig */,
|
||||
256E81164BC118D2D32C497F /* Pods-IOSUsingPluginUITests.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -495,6 +494,7 @@
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
@@ -556,6 +556,7 @@
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
|
||||
@@ -16,7 +16,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
// Instantiate Flutter engine
|
||||
self.flutterEngine = FlutterEngine(name: "io.flutter", project: nil)
|
||||
self.flutterEngine?.run(withEntrypoint: nil)
|
||||
GeneratedPluginRegistrant.register(with: self.flutterEngine)
|
||||
GeneratedPluginRegistrant.register(with: self.flutterEngine!)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ SPEC CHECKSUMS:
|
||||
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
|
||||
flutter_module_using_plugin: ab21df6109f463a98496d1b37ad061e4fd4e3664
|
||||
FlutterPluginRegistrant: 5f023d9f4a14f5b49cc6bb950327099916b47859
|
||||
url_launcher: 0067ddb8f10d36786672aa0722a21717dba3a298
|
||||
url_launcher: a1c0cc845906122c4784c542523d8cacbded5626
|
||||
|
||||
PODFILE CHECKSUM: f4d84c8c6c48bfdf0126e770a3e88f6f1ef3ffe8
|
||||
PODFILE CHECKSUM: 357b6c94e1edb8289fba0dbdd79daa105ab9d88c
|
||||
|
||||
COCOAPODS: 1.7.5
|
||||
|
||||
Reference in New Issue
Block a user