diff --git a/examples/hello_android/README.md b/examples/hello_android/README.md
new file mode 100644
index 00000000000..c7d64c4fac2
--- /dev/null
+++ b/examples/hello_android/README.md
@@ -0,0 +1,16 @@
+# Example of building a Flutter app for Android using Gradle
+
+This project demonstrates how to embed Flutter within an Android application
+and build the Android and Flutter components with Gradle.
+
+To build this project:
+
+* Create a `local.properties` file with these entries:
+ * `sdk.dir=[path to the Android SDK]`
+ * `flutter.sdk=[path to the Flutter SDK]`
+ * `flutter.jar=[path to the flutter.jar file in your build of the Flutter engine]`
+
+Then run:
+
+* `gradle wrapper`
+* `./gradlew build`
diff --git a/examples/hello_android/app/build.gradle b/examples/hello_android/app/build.gradle
new file mode 100644
index 00000000000..8ece56f40bf
--- /dev/null
+++ b/examples/hello_android/app/build.gradle
@@ -0,0 +1,15 @@
+apply plugin: 'com.android.application'
+apply plugin: 'flutter'
+
+android {
+ compileSdkVersion 22
+ buildToolsVersion '22.0.1'
+
+ lintOptions {
+ disable 'InvalidPackage'
+ }
+}
+
+flutter {
+ source 'src/flutter'
+}
diff --git a/examples/hello_android/app/src/flutter/lib/main.dart b/examples/hello_android/app/src/flutter/lib/main.dart
new file mode 100644
index 00000000000..151b1da2b81
--- /dev/null
+++ b/examples/hello_android/app/src/flutter/lib/main.dart
@@ -0,0 +1,7 @@
+// Copyright 2016 The Chromium Authors. 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/widgets.dart';
+
+void main() => runApp(new Center(child: new Text('Hello from Flutter!')));
diff --git a/examples/hello_android/app/src/flutter/pubspec.yaml b/examples/hello_android/app/src/flutter/pubspec.yaml
new file mode 100644
index 00000000000..56699090ba1
--- /dev/null
+++ b/examples/hello_android/app/src/flutter/pubspec.yaml
@@ -0,0 +1,4 @@
+name: gradle
+dependencies:
+ flutter:
+ path: ../../../../../packages/flutter
diff --git a/examples/hello_android/app/src/main/AndroidManifest.xml b/examples/hello_android/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000000..a272e1429ac
--- /dev/null
+++ b/examples/hello_android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/hello_android/app/src/main/java/com/example/flutter/FlutterActivity.java b/examples/hello_android/app/src/main/java/com/example/flutter/FlutterActivity.java
new file mode 100644
index 00000000000..7323d6feb29
--- /dev/null
+++ b/examples/hello_android/app/src/main/java/com/example/flutter/FlutterActivity.java
@@ -0,0 +1,39 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package com.example.flutter;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import org.chromium.base.PathUtils;
+import org.domokit.sky.shell.SkyApplication;
+import org.domokit.sky.shell.SkyMain;
+import org.domokit.sky.shell.PlatformViewAndroid;
+
+import java.io.File;
+
+public class FlutterActivity extends Activity {
+ private PlatformViewAndroid flutterView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ SkyMain.ensureInitialized(getApplicationContext(), null);
+ setContentView(R.layout.flutter_layout);
+
+ flutterView = (PlatformViewAndroid) findViewById(R.id.flutter_view);
+ File appBundle = new File(PathUtils.getDataDirectory(this), SkyApplication.APP_BUNDLE);
+ flutterView.runFromBundle(appBundle.getPath(), null);
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (flutterView != null) {
+ flutterView.destroy();
+ }
+ super.onDestroy();
+ }
+}
diff --git a/examples/hello_android/app/src/main/res/layout/flutter_layout.xml b/examples/hello_android/app/src/main/res/layout/flutter_layout.xml
new file mode 100644
index 00000000000..bc8c11d2394
--- /dev/null
+++ b/examples/hello_android/app/src/main/res/layout/flutter_layout.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/examples/hello_android/app/src/main/res/values/strings.xml b/examples/hello_android/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000000..670cfaef817
--- /dev/null
+++ b/examples/hello_android/app/src/main/res/values/strings.xml
@@ -0,0 +1,5 @@
+
+
+ Flutter App
+ Flutter Application
+
diff --git a/examples/hello_android/build.gradle b/examples/hello_android/build.gradle
new file mode 100644
index 00000000000..ba2176743a5
--- /dev/null
+++ b/examples/hello_android/build.gradle
@@ -0,0 +1,17 @@
+buildscript {
+ repositories {
+ jcenter()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.5.0'
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
+
+task wrapper(type: Wrapper) {
+ gradleVersion = '2.8'
+}
diff --git a/examples/hello_android/buildSrc/build.gradle b/examples/hello_android/buildSrc/build.gradle
new file mode 100644
index 00000000000..b62a213c72f
--- /dev/null
+++ b/examples/hello_android/buildSrc/build.gradle
@@ -0,0 +1,7 @@
+repositories {
+ jcenter()
+}
+
+dependencies {
+ compile "com.android.tools.build:gradle:1.5.0"
+}
diff --git a/examples/hello_android/buildSrc/src/main/groovy/FlutterPlugin.groovy b/examples/hello_android/buildSrc/src/main/groovy/FlutterPlugin.groovy
new file mode 100644
index 00000000000..bdd0c2ec2a5
--- /dev/null
+++ b/examples/hello_android/buildSrc/src/main/groovy/FlutterPlugin.groovy
@@ -0,0 +1,107 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.domokit.sky.gradle
+
+import com.android.builder.model.AndroidProject
+import org.gradle.api.DefaultTask
+import org.gradle.api.GradleException
+import org.gradle.api.Project
+import org.gradle.api.Plugin
+import org.gradle.api.Task
+import org.gradle.api.file.FileCollection
+import org.gradle.api.tasks.Copy
+import org.gradle.api.tasks.InputDirectory
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.TaskAction
+
+class FlutterPlugin implements Plugin {
+ private File sdkDir
+
+ @Override
+ void apply(Project project) {
+ Properties properties = new Properties()
+ properties.load(project.rootProject.file("local.properties").newDataInputStream())
+
+ String enginePath = properties.getProperty("flutter.jar")
+ if (enginePath == null) {
+ throw new GradleException("flutter.jar must be defined in local.properties")
+ }
+ FileCollection flutterEngine = project.files(enginePath)
+ if (!flutterEngine.singleFile.isFile()) {
+ throw new GradleException("flutter.jar must point to a Flutter engine JAR")
+ }
+
+ String sdkPath = properties.getProperty("flutter.sdk")
+ if (sdkPath == null) {
+ throw new GradleException("flutter.sdk must be defined in local.properties")
+ }
+ sdkDir = project.file(sdkPath)
+ if (!sdkDir.isDirectory()) {
+ throw new GradleException("flutter.sdk must point to the Flutter SDK directory")
+ }
+
+ project.extensions.create("flutter", FlutterExtension)
+ project.dependencies.add("compile", flutterEngine)
+ project.afterEvaluate this.&addFlutterTask
+ }
+
+ private void addFlutterTask(Project project) {
+ if (project.flutter.source == null) {
+ throw new GradleException("Must provide Flutter source directory")
+ }
+
+ FlutterTask flutterTask = project.tasks.create("flutterBuild", FlutterTask) {
+ sdkDir this.sdkDir
+ sourceDir project.file(project.flutter.source)
+ intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter")
+ }
+
+ project.android.applicationVariants.all { variant ->
+ Task copyFlxTask = project.tasks.create(name: "copyFlx${variant.name.capitalize()}", type: Copy) {
+ dependsOn flutterTask
+ dependsOn variant.mergeAssets
+ from flutterTask.flxPath
+ into variant.mergeAssets.outputDir
+ }
+ variant.outputs[0].processResources.dependsOn(copyFlxTask)
+ }
+ }
+}
+
+class FlutterExtension {
+ String source
+}
+
+class FlutterTask extends DefaultTask {
+ File sdkDir
+
+ @InputDirectory
+ File sourceDir
+
+ @OutputDirectory
+ File intermediateDir
+
+ String getFlxPath() {
+ return "${intermediateDir}/app.flx"
+ }
+
+ @TaskAction
+ void build() {
+ if (!sourceDir.isDirectory()) {
+ throw new GradleException("Invalid Flutter source directory: ${sourceDir}")
+ }
+
+ intermediateDir.mkdirs()
+ project.exec {
+ executable "${sdkDir}/bin/flutter"
+ workingDir sourceDir
+ args "build"
+ args "-o", flxPath
+ args "--snapshot", "${intermediateDir}/snapshot_blob.bin"
+ args "--depfile", "${intermediateDir}/snapshot_blob.bin.d"
+ args "--working-dir", "${intermediateDir}/flx"
+ }
+ }
+}
diff --git a/examples/hello_android/buildSrc/src/main/resources/META-INF/gradle-plugins/flutter.properties b/examples/hello_android/buildSrc/src/main/resources/META-INF/gradle-plugins/flutter.properties
new file mode 100644
index 00000000000..f8219bee105
--- /dev/null
+++ b/examples/hello_android/buildSrc/src/main/resources/META-INF/gradle-plugins/flutter.properties
@@ -0,0 +1 @@
+implementation-class=org.domokit.sky.gradle.FlutterPlugin
diff --git a/examples/hello_android/settings.gradle b/examples/hello_android/settings.gradle
new file mode 100644
index 00000000000..e7b4def49cb
--- /dev/null
+++ b/examples/hello_android/settings.gradle
@@ -0,0 +1 @@
+include ':app'