Refactoring the Android_views tests app to prepare for adding the iOS platform view tests (#36200)

This PR created a main page for platform view tests in the android views testing app. The main page none contains a list of the links to the pages being tested. It puts the android view motion events tests to a sub page.
The PR also added iOS related files to get ready for adding the iOS platform views tests.
diff --git a/dev/integration_tests/android_views/ios/Flutter/AppFrameworkInfo.plist b/dev/integration_tests/android_views/ios/Flutter/AppFrameworkInfo.plist
new file mode 100644
index 0000000..6b4c0f7
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Flutter/AppFrameworkInfo.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>$(DEVELOPMENT_LANGUAGE)</string>
+  <key>CFBundleExecutable</key>
+  <string>App</string>
+  <key>CFBundleIdentifier</key>
+  <string>io.flutter.flutter.app</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>App</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>1.0</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>1.0</string>
+  <key>MinimumOSVersion</key>
+  <string>8.0</string>
+</dict>
+</plist>
diff --git a/dev/integration_tests/android_views/ios/Flutter/Debug.xcconfig b/dev/integration_tests/android_views/ios/Flutter/Debug.xcconfig
new file mode 100644
index 0000000..e8efba1
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Flutter/Debug.xcconfig
@@ -0,0 +1,2 @@
+#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
+#include "Generated.xcconfig"
diff --git a/dev/integration_tests/android_views/ios/Flutter/Release.xcconfig b/dev/integration_tests/android_views/ios/Flutter/Release.xcconfig
new file mode 100644
index 0000000..399e934
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Flutter/Release.xcconfig
@@ -0,0 +1,2 @@
+#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
+#include "Generated.xcconfig"
diff --git a/dev/integration_tests/android_views/ios/Runner.xcodeproj/project.pbxproj b/dev/integration_tests/android_views/ios/Runner.xcodeproj/project.pbxproj
index c4840cd..b5f300b 100644
--- a/dev/integration_tests/android_views/ios/Runner.xcodeproj/project.pbxproj
+++ b/dev/integration_tests/android_views/ios/Runner.xcodeproj/project.pbxproj
@@ -14,12 +14,12 @@
 		9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
 		9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
-		9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; };
 		978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
 		97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
 		97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
 		97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
 		97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+		E82AC4A900C312A21923945D /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F587E366BE7AF2672B05525E /* libPods-Runner.a */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -45,6 +45,7 @@
 		7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
 		7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
 		7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+		7C09407F283942748BDF3120 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
 		9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
 		9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
 		9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
@@ -54,6 +55,9 @@
 		97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 		97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
 		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		B11AF3E99D4F5D486C420DF0 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
+		B2650B490C790D76CEA2113C /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
+		F587E366BE7AF2672B05525E /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -63,12 +67,21 @@
 			files = (
 				9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
 				3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
+				E82AC4A900C312A21923945D /* libPods-Runner.a in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
+		2F33CA3A53A8A6BEE1876983 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				F587E366BE7AF2672B05525E /* libPods-Runner.a */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
 		9740EEB11CF90186004384FC /* Flutter */ = {
 			isa = PBXGroup;
 			children = (
@@ -88,6 +101,8 @@
 				9740EEB11CF90186004384FC /* Flutter */,
 				97C146F01CF9000F007C117D /* Runner */,
 				97C146EF1CF9000F007C117D /* Products */,
+				A6C97EFD3D2B49B718A36762 /* Pods */,
+				2F33CA3A53A8A6BEE1876983 /* Frameworks */,
 			);
 			sourceTree = "<group>";
 		};
@@ -123,6 +138,17 @@
 			name = "Supporting Files";
 			sourceTree = "<group>";
 		};
+		A6C97EFD3D2B49B718A36762 /* Pods */ = {
+			isa = PBXGroup;
+			children = (
+				B2650B490C790D76CEA2113C /* Pods-Runner.debug.xcconfig */,
+				B11AF3E99D4F5D486C420DF0 /* Pods-Runner.release.xcconfig */,
+				7C09407F283942748BDF3120 /* Pods-Runner.profile.xcconfig */,
+			);
+			name = Pods;
+			path = Pods;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
@@ -130,12 +156,14 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
 			buildPhases = (
+				65B7702AA4EEA53E0B44B116 /* [CP] Check Pods Manifest.lock */,
 				9740EEB61CF901F6004384FC /* Run Script */,
 				97C146EA1CF9000F007C117D /* Sources */,
 				97C146EB1CF9000F007C117D /* Frameworks */,
 				97C146EC1CF9000F007C117D /* Resources */,
 				9705A1C41CF9048500538489 /* Embed Frameworks */,
 				3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+				9DDC76A7660D91401ED287A5 /* [CP] Embed Pods Frameworks */,
 			);
 			buildRules = (
 			);
@@ -152,7 +180,7 @@
 		97C146E61CF9000F007C117D /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0910;
+				LastUpgradeCheck = 1020;
 				ORGANIZATIONNAME = "The Chromium Authors";
 				TargetAttributes = {
 					97C146ED1CF9000F007C117D = {
@@ -184,7 +212,6 @@
 			buildActionMask = 2147483647;
 			files = (
 				97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
-				9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */,
 				3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
 				9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
 				97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
@@ -209,6 +236,28 @@
 			shellPath = /bin/sh;
 			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
 		};
+		65B7702AA4EEA53E0B44B116 /* [CP] Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+			);
+			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
+			);
+			name = "[CP] Check Pods Manifest.lock";
+			outputFileListPaths = (
+			);
+			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+			showEnvVarsInLog = 0;
+		};
 		9740EEB61CF901F6004384FC /* Run Script */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
@@ -223,6 +272,25 @@
 			shellPath = /bin/sh;
 			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
 		};
+		9DDC76A7660D91401ED287A5 /* [CP] Embed Pods Frameworks */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Embed Pods Frameworks";
+			outputFileListPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
@@ -258,7 +326,7 @@
 /* End PBXVariantGroup section */
 
 /* Begin XCBuildConfiguration section */
-		24D9CED621828E3300CB8465 /* Profile */ = {
+		249021D3217E4FDB00AE95B9 /* Profile */ = {
 			isa = XCBuildConfiguration;
 			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
 			buildSettings = {
@@ -272,12 +340,14 @@
 				CLANG_WARN_BOOL_CONVERSION = YES;
 				CLANG_WARN_COMMA = YES;
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
 				CLANG_WARN_EMPTY_BODY = YES;
 				CLANG_WARN_ENUM_CONVERSION = YES;
 				CLANG_WARN_INFINITE_RECURSION = YES;
 				CLANG_WARN_INT_CONVERSION = YES;
 				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
 				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
 				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@@ -306,7 +376,7 @@
 			};
 			name = Profile;
 		};
-		24D9CED721828E3300CB8465 /* Profile */ = {
+		249021D4217E4FDB00AE95B9 /* Profile */ = {
 			isa = XCBuildConfiguration;
 			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
 			buildSettings = {
@@ -343,12 +413,14 @@
 				CLANG_WARN_BOOL_CONVERSION = YES;
 				CLANG_WARN_COMMA = YES;
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
 				CLANG_WARN_EMPTY_BODY = YES;
 				CLANG_WARN_ENUM_CONVERSION = YES;
 				CLANG_WARN_INFINITE_RECURSION = YES;
 				CLANG_WARN_INT_CONVERSION = YES;
 				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
 				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
 				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@@ -397,12 +469,14 @@
 				CLANG_WARN_BOOL_CONVERSION = YES;
 				CLANG_WARN_COMMA = YES;
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
 				CLANG_WARN_EMPTY_BODY = YES;
 				CLANG_WARN_ENUM_CONVERSION = YES;
 				CLANG_WARN_INFINITE_RECURSION = YES;
 				CLANG_WARN_INT_CONVERSION = YES;
 				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
 				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
 				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@@ -485,7 +559,7 @@
 			buildConfigurations = (
 				97C147031CF9000F007C117D /* Debug */,
 				97C147041CF9000F007C117D /* Release */,
-				24D9CED621828E3300CB8465 /* Profile */,
+				249021D3217E4FDB00AE95B9 /* Profile */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
@@ -495,7 +569,7 @@
 			buildConfigurations = (
 				97C147061CF9000F007C117D /* Debug */,
 				97C147071CF9000F007C117D /* Release */,
-				24D9CED721828E3300CB8465 /* Profile */,
+				249021D4217E4FDB00AE95B9 /* Profile */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
diff --git a/dev/integration_tests/android_views/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/dev/integration_tests/android_views/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
deleted file mode 100644
index 18d9810..0000000
--- a/dev/integration_tests/android_views/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>IDEDidComputeMac32BitWarning</key>
-	<true/>
-</dict>
-</plist>
diff --git a/dev/integration_tests/android_views/ios/Runner.xcodeproj/xcshareddata/IDEWorkspaceChecks.plist b/dev/integration_tests/android_views/ios/Runner.xcodeproj/xcshareddata/IDEWorkspaceChecks.plist
deleted file mode 100644
index 18d9810..0000000
--- a/dev/integration_tests/android_views/ios/Runner.xcodeproj/xcshareddata/IDEWorkspaceChecks.plist
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>IDEDidComputeMac32BitWarning</key>
-	<true/>
-</dict>
-</plist>
diff --git a/dev/integration_tests/android_views/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/dev/integration_tests/android_views/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index 1263ac8..a28140c 100644
--- a/dev/integration_tests/android_views/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/dev/integration_tests/android_views/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "0910"
+   LastUpgradeVersion = "1020"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
@@ -26,7 +26,6 @@
       buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      language = ""
       shouldUseLaunchSchemeArgsEnv = "YES">
       <Testables>
       </Testables>
@@ -46,7 +45,6 @@
       buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      language = ""
       launchStyle = "0"
       useCustomWorkingDirectory = "NO"
       ignoresPersistentStateOnLaunch = "NO"
@@ -67,7 +65,7 @@
       </AdditionalOptions>
    </LaunchAction>
    <ProfileAction
-      buildConfiguration = "Release"
+      buildConfiguration = "Profile"
       shouldUseLaunchSchemeArgsEnv = "YES"
       savedToolIdentifier = ""
       useCustomWorkingDirectory = "NO"
diff --git a/dev/integration_tests/android_views/ios/Runner.xcworkspace/contents.xcworkspacedata b/dev/integration_tests/android_views/ios/Runner.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..21a3cc1
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "group:Runner.xcodeproj">
+   </FileRef>
+   <FileRef
+      location = "group:Pods/Pods.xcodeproj">
+   </FileRef>
+</Workspace>
diff --git a/dev/integration_tests/android_views/ios/Runner/AppDelegate.h b/dev/integration_tests/android_views/ios/Runner/AppDelegate.h
new file mode 100644
index 0000000..d129e6e
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/AppDelegate.h
@@ -0,0 +1,10 @@
+// Copyright 2018 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 <Flutter/Flutter.h>
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : FlutterAppDelegate
+
+@end
diff --git a/dev/integration_tests/android_views/ios/Runner/AppDelegate.m b/dev/integration_tests/android_views/ios/Runner/AppDelegate.m
new file mode 100644
index 0000000..e5b5ebe
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/AppDelegate.m
@@ -0,0 +1,17 @@
+// Copyright 2018 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.
+
+#include "AppDelegate.h"
+#include "GeneratedPluginRegistrant.h"
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application
+    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+  [GeneratedPluginRegistrant registerWithRegistry:self];
+  // Override point for customization after application launch.
+  return [super application:application didFinishLaunchingWithOptions:launchOptions];
+}
+
+@end
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..d36b1fa
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,122 @@
+{
+  "images" : [
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-20x20@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-20x20@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-40x40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-40x40@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-60x60@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-60x60@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-20x20@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-20x20@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-29x29@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-29x29@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-40x40@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-40x40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-76x76@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-76x76@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "83.5x83.5",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-83.5x83.5@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "1024x1024",
+      "idiom" : "ios-marketing",
+      "filename" : "Icon-App-1024x1024@1x.png",
+      "scale" : "1x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
new file mode 100644
index 0000000..dc9ada4
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
new file mode 100644
index 0000000..28c6bf0
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
new file mode 100644
index 0000000..2ccbfd9
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
new file mode 100644
index 0000000..f091b6b
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
new file mode 100644
index 0000000..4cde121
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
new file mode 100644
index 0000000..d0ef06e
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
new file mode 100644
index 0000000..dcdc230
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
new file mode 100644
index 0000000..2ccbfd9
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
new file mode 100644
index 0000000..c8f9ed8
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
new file mode 100644
index 0000000..a6d6b86
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
new file mode 100644
index 0000000..a6d6b86
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
new file mode 100644
index 0000000..75b2d16
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
new file mode 100644
index 0000000..c4df70d
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
new file mode 100644
index 0000000..6a84f41
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
new file mode 100644
index 0000000..d0e1f58
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
new file mode 100644
index 0000000..0bedcf2
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "LaunchImage.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "LaunchImage@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "LaunchImage@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
new file mode 100644
index 0000000..9da19ea
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
new file mode 100644
index 0000000..9da19ea
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
new file mode 100644
index 0000000..9da19ea
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
Binary files differ
diff --git a/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
new file mode 100644
index 0000000..89c2725
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
@@ -0,0 +1,5 @@
+# Launch Screen Assets
+
+You can customize the launch screen with your own desired assets by replacing the image files in this directory.
+
+You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
diff --git a/dev/integration_tests/android_views/ios/Runner/Base.lproj/LaunchScreen.storyboard b/dev/integration_tests/android_views/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..f2e259c
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="EHf-IW-A2E">
+            <objects>
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
+                        <viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
+                            </imageView>
+                        </subviews>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
+                            <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
+                        </constraints>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="53" y="375"/>
+        </scene>
+    </scenes>
+    <resources>
+        <image name="LaunchImage" width="168" height="185"/>
+    </resources>
+</document>
diff --git a/dev/integration_tests/android_views/ios/Runner/Base.lproj/Main.storyboard b/dev/integration_tests/android_views/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..f3c2851
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
+    </dependencies>
+    <scenes>
+        <!--Flutter View Controller-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+        </scene>
+    </scenes>
+</document>
diff --git a/dev/integration_tests/android_views/ios/Runner/Info.plist b/dev/integration_tests/android_views/ios/Runner/Info.plist
new file mode 100644
index 0000000..d9d4bdc
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/Info.plist
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>android_views</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>$(FLUTTER_BUILD_NAME)</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>$(FLUTTER_BUILD_NUMBER)</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>UILaunchStoryboardName</key>
+	<string>LaunchScreen</string>
+	<key>UIMainStoryboardFile</key>
+	<string>Main</string>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UIViewControllerBasedStatusBarAppearance</key>
+	<false/>
+</dict>
+</plist>
diff --git a/dev/integration_tests/android_views/ios/Runner/main.m b/dev/integration_tests/android_views/ios/Runner/main.m
new file mode 100644
index 0000000..dff6597
--- /dev/null
+++ b/dev/integration_tests/android_views/ios/Runner/main.m
@@ -0,0 +1,9 @@
+#import <Flutter/Flutter.h>
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char* argv[]) {
+  @autoreleasepool {
+    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+  }
+}
diff --git a/dev/integration_tests/android_views/lib/main.dart b/dev/integration_tests/android_views/lib/main.dart
index 74b1ea5..9697a6a 100644
--- a/dev/integration_tests/android_views/lib/main.dart
+++ b/dev/integration_tests/android_views/lib/main.dart
@@ -1,298 +1,36 @@
-// Copyright 2018 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 'dart:async';
-import 'dart:io';
-import 'dart:typed_data';
-
 import 'package:flutter/material.dart';
-import 'package:flutter/services.dart';
 import 'package:flutter_driver/driver_extension.dart';
-import 'package:path_provider/path_provider.dart';
+import 'motion_events_page.dart';
+import 'page.dart';
 
-import 'motion_event_diff.dart';
-
-MethodChannel channel = const MethodChannel('android_views_integration');
-
-const String kEventsFileName = 'touchEvents';
-
-/// Wraps a flutter driver [DataHandler] with one that waits until a delegate is set.
-///
-/// This allows the driver test to call [FlutterDriver.requestData] before the handler was
-/// set by the app in which case the requestData call will only complete once the app is ready
-/// for it.
-class FutureDataHandler {
-  final Completer<DataHandler> handlerCompleter = Completer<DataHandler>();
-
-  Future<String> handleMessage(String message) async {
-    final DataHandler handler = await handlerCompleter.future;
-    return handler(message);
-  }
-}
-
-FutureDataHandler driverDataHandler = FutureDataHandler();
+final List<Page> _allPages = <Page>[
+  const MotionEventsPage(),
+];
 
 void main() {
   enableFlutterDriverExtension(handler: driverDataHandler.handleMessage);
-  runApp(MyApp());
+  runApp(MaterialApp(home: Home()));
 }
 
-class MyApp extends StatelessWidget {
+class Home extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
-    return MaterialApp(
-      title: 'Android Views Integration Test',
-      home: Scaffold(
-        body: PlatformViewPage(),
-      ),
-    );
-  }
-}
-
-class PlatformViewPage extends StatefulWidget {
-  @override
-  State createState() => PlatformViewState();
-}
-
-class PlatformViewState extends State<PlatformViewPage> {
-  static const int kEventsBufferSize = 1000;
-
-  MethodChannel viewChannel;
-
-  /// The list of motion events that were passed to the FlutterView.
-  List<Map<String, dynamic>> flutterViewEvents = <Map<String, dynamic>>[];
-
-  /// The list of motion events that were passed to the embedded view.
-  List<Map<String, dynamic>> embeddedViewEvents = <Map<String, dynamic>>[];
-
-  @override
-  Widget build(BuildContext context) {
-    return Column(
-      children: <Widget>[
-        SizedBox(
-          height: 300.0,
-          child: AndroidView(
-              viewType: 'simple_view',
-              onPlatformViewCreated: onPlatformViewCreated),
+    return Scaffold(
+      body: ListView.builder(
+        itemCount: _allPages.length,
+        itemBuilder: (_, int index) => ListTile(
+          title: Text(_allPages[index].title),
+          key: _allPages[index].tileKey,
+          onTap: () => _pushPage(context, _allPages[index]),
         ),
-        Expanded(
-          child: ListView.builder(
-            itemBuilder: buildEventTile,
-            itemCount: flutterViewEvents.length,
-          ),
-        ),
-        Row(
-          children: <Widget>[
-            RaisedButton(
-              child: const Text('RECORD'),
-              onPressed: listenToFlutterViewEvents,
-            ),
-            RaisedButton(
-              child: const Text('CLEAR'),
-              onPressed: () {
-                setState(() {
-                  flutterViewEvents.clear();
-                  embeddedViewEvents.clear();
-                });
-              },
-            ),
-            RaisedButton(
-              child: const Text('SAVE'),
-              onPressed: () {
-                const StandardMessageCodec codec = StandardMessageCodec();
-                saveRecordedEvents(
-                    codec.encodeMessage(flutterViewEvents), context);
-              },
-            ),
-            RaisedButton(
-              key: const ValueKey<String>('play'),
-              child: const Text('PLAY FILE'),
-              onPressed: () { playEventsFile(); },
-            ),
-          ],
-        ),
-      ],
-    );
-  }
-
-  Future<String> playEventsFile() async {
-    const StandardMessageCodec codec = StandardMessageCodec();
-    try {
-      final ByteData data = await rootBundle.load('packages/assets_for_android_views/assets/touchEvents');
-      final List<dynamic> unTypedRecordedEvents = codec.decodeMessage(data);
-      final List<Map<String, dynamic>> recordedEvents = unTypedRecordedEvents
-          .cast<Map<dynamic, dynamic>>()
-          .map<Map<String, dynamic>>((Map<dynamic, dynamic> e) =>e.cast<String, dynamic>())
-          .toList();
-      await channel.invokeMethod<void>('pipeFlutterViewEvents');
-      await viewChannel.invokeMethod<void>('pipeTouchEvents');
-      print('replaying ${recordedEvents.length} motion events');
-      for (Map<String, dynamic> event in recordedEvents.reversed) {
-        await channel.invokeMethod<void>('synthesizeEvent', event);
-      }
-
-      await channel.invokeMethod<void>('stopFlutterViewEvents');
-      await viewChannel.invokeMethod<void>('stopTouchEvents');
-
-      if (flutterViewEvents.length != embeddedViewEvents.length)
-        return 'Synthesized ${flutterViewEvents.length} events but the embedded view received ${embeddedViewEvents.length} events';
-
-      final StringBuffer diff = StringBuffer();
-      for (int i = 0; i < flutterViewEvents.length; ++i) {
-        final String currentDiff = diffMotionEvents(flutterViewEvents[i], embeddedViewEvents[i]);
-        if (currentDiff.isEmpty)
-          continue;
-        if (diff.isNotEmpty)
-          diff.write(', ');
-        diff.write(currentDiff);
-      }
-      return diff.toString();
-    } catch(e) {
-      return e.toString();
-    }
-  }
-
-  @override
-  void initState() {
-    super.initState();
-    channel.setMethodCallHandler(onMethodChannelCall);
-  }
-
-  Future<void> saveRecordedEvents(ByteData data, BuildContext context) async {
-    if (!await channel.invokeMethod<bool>('getStoragePermission')) {
-      showMessage(
-          context, 'External storage permissions are required to save events');
-      return;
-    }
-    try {
-      final Directory outDir = await getExternalStorageDirectory();
-      // This test only runs on Android so we can assume path separator is '/'.
-      final File file = File('${outDir.path}/$kEventsFileName');
-      await file.writeAsBytes(data.buffer.asUint8List(0, data.lengthInBytes), flush: true);
-      showMessage(context, 'Saved original events to ${file.path}');
-    } catch (e) {
-      showMessage(context, 'Failed saving ${e.toString()}');
-    }
-  }
-
-  void showMessage(BuildContext context, String message) {
-    Scaffold.of(context).showSnackBar(SnackBar(
-      content: Text(message),
-      duration: const Duration(seconds: 3),
-    ));
-  }
-
-  void onPlatformViewCreated(int id) {
-    viewChannel = MethodChannel('simple_view/$id');
-    viewChannel.setMethodCallHandler(onViewMethodChannelCall);
-    driverDataHandler.handlerCompleter.complete(handleDriverMessage);
-  }
-
-  void listenToFlutterViewEvents() {
-    channel.invokeMethod<void>('pipeFlutterViewEvents');
-    viewChannel.invokeMethod<void>('pipeTouchEvents');
-    Timer(const Duration(seconds: 3), () {
-      channel.invokeMethod<void>('stopFlutterViewEvents');
-      viewChannel.invokeMethod<void>('stopTouchEvents');
-    });
-  }
-
-  Future<String> handleDriverMessage(String message) async {
-    switch (message) {
-      case 'run test':
-        return playEventsFile();
-    }
-    return 'unknown message: "$message"';
-  }
-
-  Future<dynamic> onMethodChannelCall(MethodCall call) {
-    switch (call.method) {
-      case 'onTouch':
-        final Map<dynamic, dynamic> map = call.arguments;
-        flutterViewEvents.insert(0, map.cast<String, dynamic>());
-        if (flutterViewEvents.length > kEventsBufferSize)
-          flutterViewEvents.removeLast();
-        setState(() {});
-        break;
-    }
-    return Future<dynamic>.sync(null);
-  }
-
-  Future<dynamic> onViewMethodChannelCall(MethodCall call) {
-    switch (call.method) {
-      case 'onTouch':
-        final Map<dynamic, dynamic> map = call.arguments;
-        embeddedViewEvents.insert(0, map.cast<String, dynamic>());
-        if (embeddedViewEvents.length > kEventsBufferSize)
-          embeddedViewEvents.removeLast();
-        setState(() {});
-        break;
-    }
-    return Future<dynamic>.sync(null);
-  }
-
-  Widget buildEventTile(BuildContext context, int index) {
-    if (embeddedViewEvents.length > index)
-      return TouchEventDiff(
-          flutterViewEvents[index], embeddedViewEvents[index]);
-    return Text(
-        'Unmatched event, action: ${flutterViewEvents[index]['action']}');
-  }
-}
-
-class TouchEventDiff extends StatelessWidget {
-  const TouchEventDiff(this.originalEvent, this.synthesizedEvent);
-
-  final Map<String, dynamic> originalEvent;
-  final Map<String, dynamic> synthesizedEvent;
-
-  @override
-  Widget build(BuildContext context) {
-
-    Color color;
-    final String diff = diffMotionEvents(originalEvent, synthesizedEvent);
-    String msg;
-    final int action = synthesizedEvent['action'];
-    final String actionName = getActionName(getActionMasked(action), action);
-    if (diff.isEmpty) {
-      color = Colors.green;
-      msg = 'Matched event (action $actionName)';
-    } else {
-      color = Colors.red;
-      msg = '[$actionName] $diff';
-    }
-    return GestureDetector(
-      onLongPress: () {
-        print('expected:');
-        prettyPrintEvent(originalEvent);
-        print('\nactual:');
-        prettyPrintEvent(synthesizedEvent);
-      },
-      child: Container(
-        color: color,
-        margin: const EdgeInsets.only(bottom: 2.0),
-        child: Text(msg),
       ),
     );
   }
 
-  void prettyPrintEvent(Map<String, dynamic> event) {
-    final StringBuffer buffer = StringBuffer();
-    final int action = event['action'];
-    final int maskedAction = getActionMasked(action);
-    final String actionName = getActionName(maskedAction, action);
-
-    buffer.write('$actionName ');
-    if (maskedAction == 5 || maskedAction == 6) {
-     buffer.write('pointer: ${getPointerIdx(action)} ');
-    }
-
-    final List<Map<dynamic, dynamic>> coords = event['pointerCoords'].cast<Map<dynamic, dynamic>>();
-    for (int i = 0; i < coords.length; i++) {
-      buffer.write('p$i x: ${coords[i]['x']} y: ${coords[i]['y']}, pressure: ${coords[i]['pressure']} ');
-    }
-    print(buffer.toString());
+  void _pushPage(BuildContext context, Page page) {
+    Navigator.of(context).push(MaterialPageRoute<void>(
+        builder: (_) => Scaffold(
+              body: page,
+            )));
   }
 }
-
diff --git a/dev/integration_tests/android_views/lib/motion_events_page.dart b/dev/integration_tests/android_views/lib/motion_events_page.dart
new file mode 100644
index 0000000..4d5d7ad
--- /dev/null
+++ b/dev/integration_tests/android_views/lib/motion_events_page.dart
@@ -0,0 +1,292 @@
+// Copyright 2018 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 'dart:async';
+import 'dart:io';
+import 'dart:typed_data';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_driver/driver_extension.dart';
+import 'package:path_provider/path_provider.dart';
+
+import 'motion_event_diff.dart';
+import 'page.dart';
+
+MethodChannel channel = const MethodChannel('android_views_integration');
+
+const String kEventsFileName = 'touchEvents';
+
+class MotionEventsPage extends Page {
+  const MotionEventsPage()
+      : super('Motion Event Tests', const ValueKey<String>('MotionEventsListTile'));
+
+  @override
+  Widget build(BuildContext context) {
+    return MotionEventsBody();
+  }
+}
+
+/// Wraps a flutter driver [DataHandler] with one that waits until a delegate is set.
+///
+/// This allows the driver test to call [FlutterDriver.requestData] before the handler was
+/// set by the app in which case the requestData call will only complete once the app is ready
+/// for it.
+class FutureDataHandler {
+  final Completer<DataHandler> handlerCompleter = Completer<DataHandler>();
+
+  Future<String> handleMessage(String message) async {
+    final DataHandler handler = await handlerCompleter.future;
+    return handler(message);
+  }
+}
+
+FutureDataHandler driverDataHandler = FutureDataHandler();
+
+class MotionEventsBody extends StatefulWidget {
+  @override
+  State createState() => MotionEventsBodyState();
+}
+
+class MotionEventsBodyState extends State<MotionEventsBody> {
+  static const int kEventsBufferSize = 1000;
+
+  MethodChannel viewChannel;
+
+  /// The list of motion events that were passed to the FlutterView.
+  List<Map<String, dynamic>> flutterViewEvents = <Map<String, dynamic>>[];
+
+  /// The list of motion events that were passed to the embedded view.
+  List<Map<String, dynamic>> embeddedViewEvents = <Map<String, dynamic>>[];
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      children: <Widget>[
+        SizedBox(
+          height: 300.0,
+          child: AndroidView(
+              key: const ValueKey<String>('PlatformView'),
+              viewType: 'simple_view',
+              onPlatformViewCreated: onPlatformViewCreated),
+        ),
+        Expanded(
+          child: ListView.builder(
+            itemBuilder: buildEventTile,
+            itemCount: flutterViewEvents.length,
+          ),
+        ),
+        Row(
+          children: <Widget>[
+            RaisedButton(
+              child: const Text('RECORD'),
+              onPressed: listenToFlutterViewEvents,
+            ),
+            RaisedButton(
+              child: const Text('CLEAR'),
+              onPressed: () {
+                setState(() {
+                  flutterViewEvents.clear();
+                  embeddedViewEvents.clear();
+                });
+              },
+            ),
+            RaisedButton(
+              child: const Text('SAVE'),
+              onPressed: () {
+                const StandardMessageCodec codec = StandardMessageCodec();
+                saveRecordedEvents(
+                    codec.encodeMessage(flutterViewEvents), context);
+              },
+            ),
+            RaisedButton(
+              key: const ValueKey<String>('play'),
+              child: const Text('PLAY FILE'),
+              onPressed: () { playEventsFile(); },
+            ),
+          ],
+        ),
+      ],
+    );
+  }
+
+  Future<String> playEventsFile() async {
+    const StandardMessageCodec codec = StandardMessageCodec();
+    try {
+      final ByteData data = await rootBundle.load('packages/assets_for_android_views/assets/touchEvents');
+      final List<dynamic> unTypedRecordedEvents = codec.decodeMessage(data);
+      final List<Map<String, dynamic>> recordedEvents = unTypedRecordedEvents
+          .cast<Map<dynamic, dynamic>>()
+          .map<Map<String, dynamic>>((Map<dynamic, dynamic> e) =>e.cast<String, dynamic>())
+          .toList();
+      await channel.invokeMethod<void>('pipeFlutterViewEvents');
+      await viewChannel.invokeMethod<void>('pipeTouchEvents');
+      print('replaying ${recordedEvents.length} motion events');
+      for (Map<String, dynamic> event in recordedEvents.reversed) {
+        await channel.invokeMethod<void>('synthesizeEvent', event);
+      }
+
+      await channel.invokeMethod<void>('stopFlutterViewEvents');
+      await viewChannel.invokeMethod<void>('stopTouchEvents');
+
+      if (flutterViewEvents.length != embeddedViewEvents.length)
+        return 'Synthesized ${flutterViewEvents.length} events but the embedded view received ${embeddedViewEvents.length} events';
+
+      final StringBuffer diff = StringBuffer();
+      for (int i = 0; i < flutterViewEvents.length; ++i) {
+        final String currentDiff = diffMotionEvents(flutterViewEvents[i], embeddedViewEvents[i]);
+        if (currentDiff.isEmpty)
+          continue;
+        if (diff.isNotEmpty)
+          diff.write(', ');
+        diff.write(currentDiff);
+      }
+      return diff.toString();
+    } catch(e) {
+      return e.toString();
+    }
+  }
+
+  @override
+  void initState() {
+    super.initState();
+    channel.setMethodCallHandler(onMethodChannelCall);
+  }
+
+  Future<void> saveRecordedEvents(ByteData data, BuildContext context) async {
+    if (!await channel.invokeMethod<bool>('getStoragePermission')) {
+      showMessage(
+          context, 'External storage permissions are required to save events');
+      return;
+    }
+    try {
+      final Directory outDir = await getExternalStorageDirectory();
+      // This test only runs on Android so we can assume path separator is '/'.
+      final File file = File('${outDir.path}/$kEventsFileName');
+      await file.writeAsBytes(data.buffer.asUint8List(0, data.lengthInBytes), flush: true);
+      showMessage(context, 'Saved original events to ${file.path}');
+    } catch (e) {
+      showMessage(context, 'Failed saving ${e.toString()}');
+    }
+  }
+
+  void showMessage(BuildContext context, String message) {
+    Scaffold.of(context).showSnackBar(SnackBar(
+      content: Text(message),
+      duration: const Duration(seconds: 3),
+    ));
+  }
+
+  void onPlatformViewCreated(int id) {
+    viewChannel = MethodChannel('simple_view/$id');
+    viewChannel.setMethodCallHandler(onViewMethodChannelCall);
+    driverDataHandler.handlerCompleter.complete(handleDriverMessage);
+  }
+
+  void listenToFlutterViewEvents() {
+    channel.invokeMethod<void>('pipeFlutterViewEvents');
+    viewChannel.invokeMethod<void>('pipeTouchEvents');
+    Timer(const Duration(seconds: 3), () {
+      channel.invokeMethod<void>('stopFlutterViewEvents');
+      viewChannel.invokeMethod<void>('stopTouchEvents');
+    });
+  }
+
+  Future<String> handleDriverMessage(String message) async {
+    switch (message) {
+      case 'run test':
+        return playEventsFile();
+    }
+    return 'unknown message: "$message"';
+  }
+
+  Future<dynamic> onMethodChannelCall(MethodCall call) {
+    switch (call.method) {
+      case 'onTouch':
+        final Map<dynamic, dynamic> map = call.arguments;
+        flutterViewEvents.insert(0, map.cast<String, dynamic>());
+        if (flutterViewEvents.length > kEventsBufferSize)
+          flutterViewEvents.removeLast();
+        setState(() {});
+        break;
+    }
+    return Future<dynamic>.sync(null);
+  }
+
+  Future<dynamic> onViewMethodChannelCall(MethodCall call) {
+    switch (call.method) {
+      case 'onTouch':
+        final Map<dynamic, dynamic> map = call.arguments;
+        embeddedViewEvents.insert(0, map.cast<String, dynamic>());
+        if (embeddedViewEvents.length > kEventsBufferSize)
+          embeddedViewEvents.removeLast();
+        setState(() {});
+        break;
+    }
+    return Future<dynamic>.sync(null);
+  }
+
+  Widget buildEventTile(BuildContext context, int index) {
+    if (embeddedViewEvents.length > index)
+      return TouchEventDiff(
+          flutterViewEvents[index], embeddedViewEvents[index]);
+    return Text(
+        'Unmatched event, action: ${flutterViewEvents[index]['action']}');
+  }
+}
+
+class TouchEventDiff extends StatelessWidget {
+  const TouchEventDiff(this.originalEvent, this.synthesizedEvent);
+
+  final Map<String, dynamic> originalEvent;
+  final Map<String, dynamic> synthesizedEvent;
+
+  @override
+  Widget build(BuildContext context) {
+
+    Color color;
+    final String diff = diffMotionEvents(originalEvent, synthesizedEvent);
+    String msg;
+    final int action = synthesizedEvent['action'];
+    final String actionName = getActionName(getActionMasked(action), action);
+    if (diff.isEmpty) {
+      color = Colors.green;
+      msg = 'Matched event (action $actionName)';
+    } else {
+      color = Colors.red;
+      msg = '[$actionName] $diff';
+    }
+    return GestureDetector(
+      onLongPress: () {
+        print('expected:');
+        prettyPrintEvent(originalEvent);
+        print('\nactual:');
+        prettyPrintEvent(synthesizedEvent);
+      },
+      child: Container(
+        color: color,
+        margin: const EdgeInsets.only(bottom: 2.0),
+        child: Text(msg),
+      ),
+    );
+  }
+
+  void prettyPrintEvent(Map<String, dynamic> event) {
+    final StringBuffer buffer = StringBuffer();
+    final int action = event['action'];
+    final int maskedAction = getActionMasked(action);
+    final String actionName = getActionName(maskedAction, action);
+
+    buffer.write('$actionName ');
+    if (maskedAction == 5 || maskedAction == 6) {
+     buffer.write('pointer: ${getPointerIdx(action)} ');
+    }
+
+    final List<Map<dynamic, dynamic>> coords = event['pointerCoords'].cast<Map<dynamic, dynamic>>();
+    for (int i = 0; i < coords.length; i++) {
+      buffer.write('p$i x: ${coords[i]['x']} y: ${coords[i]['y']}, pressure: ${coords[i]['pressure']} ');
+    }
+    print(buffer.toString());
+  }
+}
diff --git a/dev/integration_tests/android_views/lib/page.dart b/dev/integration_tests/android_views/lib/page.dart
new file mode 100644
index 0000000..c75bfae
--- /dev/null
+++ b/dev/integration_tests/android_views/lib/page.dart
@@ -0,0 +1,22 @@
+// Copyright 2018 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/material.dart';
+
+/// The base class of all the testing pages
+//
+/// A testing page has to override this in order to be put as one of the items in the main page.
+abstract class Page extends StatelessWidget {
+  const Page(this.title, this.tileKey);
+
+  /// The title of the testing page
+  ///
+  /// It will be shown on the main page as the text on the link which opens the page.
+  final String title;
+
+  /// The key of the ListTile that navigates to the page.
+  ///
+  /// Used by the integration test to navigate to the corresponding page.
+  final ValueKey<String> tileKey;
+}
diff --git a/dev/integration_tests/android_views/test_driver/main_test.dart b/dev/integration_tests/android_views/test_driver/main_test.dart
index 4c193ed..70af1d8 100644
--- a/dev/integration_tests/android_views/test_driver/main_test.dart
+++ b/dev/integration_tests/android_views/test_driver/main_test.dart
@@ -3,17 +3,31 @@
 // found in the LICENSE file.
 
 import 'dart:async';
-
+import 'dart:io' show Platform;
 import 'package:flutter_driver/flutter_driver.dart';
 import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
 
 Future<void> main() async {
-  test('MotionEvents recomposition', () async {
-    final FlutterDriver driver = await FlutterDriver.connect();
-    final String errorMessage = await driver.requestData('run test');
+  FlutterDriver driver;
 
-    expect(errorMessage, '');
-    driver?.close();
+  setUpAll(() async {
+    driver = await FlutterDriver.connect();
+  });
+
+  tearDownAll(() {
+    driver.close();
+  });
+
+  group('MotionEvents tests ', () {
+    test('recomposition', () async {
+      if (Platform.isAndroid) {
+        final SerializableFinder motionEventsListTile =
+        find.byValueKey('MotionEventsListTile');
+        await driver.tap(motionEventsListTile);
+        await driver.waitFor(find.byValueKey('PlatformView'));
+        final String errorMessage = await driver.requestData('run test');
+        expect(errorMessage, '');
+      }
+    });
   });
 }
-