Tidying up add-to-app samples (#160)

pull/161/head
Andrew Brogdon 6 years ago committed by GitHub
parent e184a46ce6
commit 8155d8a777
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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:

@ -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

Loading…
Cancel
Save