From a600fe7f1304cf9f8b1bfbe7b72e40437cb56680 Mon Sep 17 00:00:00 2001 From: Mikkel Nygaard Ravn Date: Tue, 25 Sep 2018 21:21:13 +0200 Subject: [PATCH] Support materializing Flutter module host app on iOS (#21276) * Prototype * Fix paths to Flutter library resources * Invoke pod install as necessary for materialized modules * Add devicelab test for module use on iOS * Remove debug output * Rebase, reame materialize editable * Add devicelab test editable iOS host app * Removed add2app test section --- dev/devicelab/bin/tasks/module_test.dart | 40 +- dev/devicelab/bin/tasks/module_test_ios.dart | 137 ++++++ dev/devicelab/manifest.yaml | 7 + .../ios_host_app/Config/Debug.xcconfig | 2 + .../ios_host_app/Config/Flutter.xcconfig | 2 + .../ios_host_app/Config/Release.xcconfig | 3 + .../Host.xcodeproj/project.pbxproj | 449 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../Host.xcworkspace/contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../UserInterfaceState.xcuserstate | Bin 0 -> 26773 bytes .../ios_host_app/Host/AppDelegate.h | 5 + .../ios_host_app/Host/AppDelegate.m | 4 + .../AppIcon.appiconset/Contents.json | 98 ++++ .../Host/Assets.xcassets/Contents.json | 6 + .../Host/Base.lproj/LaunchScreen.storyboard | 25 + .../Host/Base.lproj/Main.storyboard | 24 + .../ios_host_app/Host/Info.plist | 45 ++ .../ios_host_app/Host/ViewController.h | 5 + .../ios_host_app/Host/ViewController.m | 23 + .../ios_host_app/Host/main.m | 8 + dev/integration_tests/ios_host_app/Podfile | 6 + packages/flutter_tools/bin/xcode_backend.sh | 3 + .../flutter_tools/lib/src/ios/cocoapods.dart | 4 +- packages/flutter_tools/lib/src/ios/mac.dart | 18 +- packages/flutter_tools/lib/src/plugins.dart | 3 +- packages/flutter_tools/lib/src/project.dart | 74 ++- .../Config.tmpl/Flutter.xcconfig | 2 + .../project.pbxproj.tmpl | 8 +- .../Podfile.copy.tmpl | 2 +- .../ios/library/Flutter.tmpl/podhelper.rb | 29 +- .../test/ios/cocoapods_test.dart | 2 +- packages/flutter_tools/test/project_test.dart | 14 +- 34 files changed, 994 insertions(+), 87 deletions(-) create mode 100644 dev/devicelab/bin/tasks/module_test_ios.dart create mode 100644 dev/integration_tests/ios_host_app/Config/Debug.xcconfig create mode 100644 dev/integration_tests/ios_host_app/Config/Flutter.xcconfig create mode 100644 dev/integration_tests/ios_host_app/Config/Release.xcconfig create mode 100644 dev/integration_tests/ios_host_app/Host.xcodeproj/project.pbxproj create mode 100644 dev/integration_tests/ios_host_app/Host.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 dev/integration_tests/ios_host_app/Host.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 dev/integration_tests/ios_host_app/Host.xcworkspace/contents.xcworkspacedata create mode 100644 dev/integration_tests/ios_host_app/Host.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 dev/integration_tests/ios_host_app/Host.xcworkspace/xcuserdata/mravn.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 dev/integration_tests/ios_host_app/Host/AppDelegate.h create mode 100644 dev/integration_tests/ios_host_app/Host/AppDelegate.m create mode 100644 dev/integration_tests/ios_host_app/Host/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 dev/integration_tests/ios_host_app/Host/Assets.xcassets/Contents.json create mode 100644 dev/integration_tests/ios_host_app/Host/Base.lproj/LaunchScreen.storyboard create mode 100644 dev/integration_tests/ios_host_app/Host/Base.lproj/Main.storyboard create mode 100644 dev/integration_tests/ios_host_app/Host/Info.plist create mode 100644 dev/integration_tests/ios_host_app/Host/ViewController.h create mode 100644 dev/integration_tests/ios_host_app/Host/ViewController.m create mode 100644 dev/integration_tests/ios_host_app/Host/main.m create mode 100644 dev/integration_tests/ios_host_app/Podfile create mode 100644 packages/flutter_tools/templates/module/ios/host_app_editable_cocoapods/Config.tmpl/Flutter.xcconfig diff --git a/dev/devicelab/bin/tasks/module_test.dart b/dev/devicelab/bin/tasks/module_test.dart index 0014939f6c..45e48b2e55 100644 --- a/dev/devicelab/bin/tasks/module_test.dart +++ b/dev/devicelab/bin/tasks/module_test.dart @@ -24,6 +24,7 @@ Future main() async { section('Create Flutter module project'); final Directory tempDir = Directory.systemTemp.createTempSync('flutter_module_test.'); + final Directory projectDir = Directory(path.join(tempDir.path, 'hello')); try { await inDirectory(tempDir, () async { await flutter( @@ -34,14 +35,14 @@ Future main() async { section('Add plugins'); - final File pubspec = File(path.join(tempDir.path, 'hello', 'pubspec.yaml')); + final File pubspec = File(path.join(projectDir.path, 'pubspec.yaml')); String content = await pubspec.readAsString(); content = content.replaceFirst( '\ndependencies:\n', '\ndependencies:\n battery:\n package_info:\n', ); await pubspec.writeAsString(content, flush: true); - await inDirectory(Directory(path.join(tempDir.path, 'hello')), () async { + await inDirectory(projectDir, () async { await flutter( 'packages', options: ['get'], @@ -50,7 +51,7 @@ Future main() async { section('Build Flutter module library archive'); - await inDirectory(Directory(path.join(tempDir.path, 'hello', '.android')), () async { + await inDirectory(Directory(path.join(projectDir.path, '.android')), () async { await exec( './gradlew', ['flutter:assembleDebug'], @@ -59,8 +60,7 @@ Future main() async { }); final bool aarBuilt = exists(File(path.join( - tempDir.path, - 'hello', + projectDir.path, '.android', 'Flutter', 'build', @@ -75,7 +75,7 @@ Future main() async { section('Build ephemeral host app'); - await inDirectory(Directory(path.join(tempDir.path, 'hello')), () async { + await inDirectory(projectDir, () async { await flutter( 'build', options: ['apk'], @@ -83,8 +83,7 @@ Future main() async { }); final bool ephemeralHostApkBuilt = exists(File(path.join( - tempDir.path, - 'hello', + projectDir.path, 'build', 'host', 'outputs', @@ -99,31 +98,30 @@ Future main() async { section('Clean build'); - await inDirectory(Directory(path.join(tempDir.path, 'hello')), () async { + await inDirectory(projectDir, () async { await flutter('clean'); }); - section('Running `flutter make-host-app-editable` to Materialize host app'); + section('Make Android host app editable'); - await inDirectory(Directory(path.join(tempDir.path, 'hello')), () async { + await inDirectory(projectDir, () async { await flutter( 'make-host-app-editable', options: ['android'], ); }); - section('Build materialized host app'); + section('Build editable host app'); - await inDirectory(Directory(path.join(tempDir.path, 'hello')), () async { + await inDirectory(projectDir, () async { await flutter( 'build', options: ['apk'], ); }); - final bool materializedHostApkBuilt = exists(File(path.join( - tempDir.path, - 'hello', + final bool editableHostApkBuilt = exists(File(path.join( + projectDir.path, 'build', 'host', 'outputs', @@ -132,11 +130,11 @@ Future main() async { 'app-release.apk', ))); - if (!materializedHostApkBuilt) { - return TaskResult.failure('Failed to build materialized host .apk'); + if (!editableHostApkBuilt) { + return TaskResult.failure('Failed to build editable host .apk'); } - section('Add to Android app'); + section('Add to existing Android app'); final Directory hostApp = Directory(path.join(tempDir.path, 'hello_host_app')); mkdir(hostApp); @@ -145,11 +143,11 @@ Future main() async { hostApp, ); copy( - File(path.join(tempDir.path, 'hello', '.android', 'gradlew')), + File(path.join(projectDir.path, '.android', 'gradlew')), hostApp, ); copy( - File(path.join(tempDir.path, 'hello', '.android', 'gradle', 'wrapper', 'gradle-wrapper.jar')), + File(path.join(projectDir.path, '.android', 'gradle', 'wrapper', 'gradle-wrapper.jar')), Directory(path.join(hostApp.path, 'gradle', 'wrapper')), ); diff --git a/dev/devicelab/bin/tasks/module_test_ios.dart b/dev/devicelab/bin/tasks/module_test_ios.dart new file mode 100644 index 0000000000..b69db061ae --- /dev/null +++ b/dev/devicelab/bin/tasks/module_test_ios.dart @@ -0,0 +1,137 @@ +// Copyright (c) 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 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/framework/ios.dart'; +import 'package:flutter_devicelab/framework/utils.dart'; +import 'package:path/path.dart' as path; + +/// Tests that the Flutter module project template works and supports +/// adding Flutter to an existing iOS app. +Future main() async { + await task(() async { + + section('Create Flutter module project'); + + final Directory tempDir = Directory.systemTemp.createTempSync('flutter_module_test.'); + final Directory projectDir = Directory(path.join(tempDir.path, 'hello')); + try { + await inDirectory(tempDir, () async { + await flutter( + 'create', + options: ['--org', 'io.flutter.devicelab', '-t', 'module', 'hello'], + ); + }); + await prepareProvisioningCertificates(projectDir.path); + + section('Build ephemeral host app without CocoaPods'); + + await inDirectory(projectDir, () async { + await flutter( + 'build', + options: ['ios'], + ); + }); + + final bool ephemeralHostAppBuilt = exists(Directory(path.join( + projectDir.path, + 'build', + 'ios', + 'iphoneos', + 'Runner.app', + ))); + + if (!ephemeralHostAppBuilt) { + return TaskResult.failure('Failed to build ephemeral host .app'); + } + + section('Clean build'); + + await inDirectory(projectDir, () async { + await flutter('clean'); + }); + + section('Add plugins'); + + final File pubspec = File(path.join(projectDir.path, 'pubspec.yaml')); + String content = await pubspec.readAsString(); + content = content.replaceFirst( + '\ndependencies:\n', + '\ndependencies:\n battery:\n package_info:\n', + ); + await pubspec.writeAsString(content, flush: true); + await inDirectory(projectDir, () async { + await flutter( + 'packages', + options: ['get'], + ); + }); + + section('Build ephemeral host app with CocoaPods'); + + await inDirectory(projectDir, () async { + await flutter( + 'build', + options: ['ios'], + ); + }); + + final bool ephemeralHostAppWithCocoaPodsBuilt = exists(Directory(path.join( + projectDir.path, + 'build', + 'ios', + 'iphoneos', + 'Runner.app', + ))); + + if (!ephemeralHostAppWithCocoaPodsBuilt) { + return TaskResult.failure('Failed to build ephemeral host .app with CocoaPods'); + } + + section('Clean build'); + + await inDirectory(projectDir, () async { + await flutter('clean'); + }); + + section('Make iOS host app editable'); + + await inDirectory(projectDir, () async { + await flutter( + 'make-host-app-editable', + options: ['ios'], + ); + }); + + section('Build editable host app'); + + await inDirectory(projectDir, () async { + await flutter( + 'build', + options: ['ios'], + ); + }); + + final bool editableHostAppBuilt = exists(Directory(path.join( + projectDir.path, + 'build', + 'ios', + 'iphoneos', + 'Runner.app', + ))); + + if (!editableHostAppBuilt) { + return TaskResult.failure('Failed to build editable host .app'); + } + return TaskResult.success(null); + } catch (e) { + return TaskResult.failure(e.toString()); + } finally { + //rmTree(tempDir); + } + }); +} diff --git a/dev/devicelab/manifest.yaml b/dev/devicelab/manifest.yaml index 793421dde1..0078092fd6 100644 --- a/dev/devicelab/manifest.yaml +++ b/dev/devicelab/manifest.yaml @@ -297,6 +297,13 @@ tasks: stage: devicelab_ios required_agent_capabilities: ["mac/ios"] + module_test_ios: + description: > + Checks that the module project template works and supports add2app on iOS. + stage: devicelab + required_agent_capabilities: ["mac/ios"] + flaky: true + external_ui_integration_test_ios: description: > Checks that external UIs work on iOS. diff --git a/dev/integration_tests/ios_host_app/Config/Debug.xcconfig b/dev/integration_tests/ios_host_app/Config/Debug.xcconfig new file mode 100644 index 0000000000..55d2bd85f8 --- /dev/null +++ b/dev/integration_tests/ios_host_app/Config/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "Flutter.xcconfig" +#include "Pods/Target Support Files/Pods-Host/Pods-Host.debug.xcconfig" diff --git a/dev/integration_tests/ios_host_app/Config/Flutter.xcconfig b/dev/integration_tests/ios_host_app/Config/Flutter.xcconfig new file mode 100644 index 0000000000..ccfdd63404 --- /dev/null +++ b/dev/integration_tests/ios_host_app/Config/Flutter.xcconfig @@ -0,0 +1,2 @@ +#include "../../hello/.ios/Flutter/Generated.xcconfig" +ENABLE_BITCODE=NO diff --git a/dev/integration_tests/ios_host_app/Config/Release.xcconfig b/dev/integration_tests/ios_host_app/Config/Release.xcconfig new file mode 100644 index 0000000000..a0a0197543 --- /dev/null +++ b/dev/integration_tests/ios_host_app/Config/Release.xcconfig @@ -0,0 +1,3 @@ +#include "Flutter.xcconfig" +#include "Pods/Target Support Files/Pods-Host/Pods-Host.release.xcconfig" +FLUTTER_BUILD_MODE=release diff --git a/dev/integration_tests/ios_host_app/Host.xcodeproj/project.pbxproj b/dev/integration_tests/ios_host_app/Host.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..c6086b7cc2 --- /dev/null +++ b/dev/integration_tests/ios_host_app/Host.xcodeproj/project.pbxproj @@ -0,0 +1,449 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 74DB4A4E2152F3F900E9B550 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 74DB4A4D2152F3F900E9B550 /* AppDelegate.m */; }; + 74DB4A512152F3F900E9B550 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 74DB4A502152F3F900E9B550 /* ViewController.m */; }; + 74DB4A542152F3F900E9B550 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 74DB4A522152F3F900E9B550 /* Main.storyboard */; }; + 74DB4A562152F3FB00E9B550 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 74DB4A552152F3FB00E9B550 /* Assets.xcassets */; }; + 74DB4A592152F3FB00E9B550 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 74DB4A572152F3FB00E9B550 /* LaunchScreen.storyboard */; }; + 74DB4A5C2152F3FB00E9B550 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 74DB4A5B2152F3FB00E9B550 /* main.m */; }; + 74DB4A872154203700E9B550 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 74DB4A862154203700E9B550 /* flutter_assets */; }; + 74DB4A8B2154205B00E9B550 /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 74DB4A842154201200E9B550 /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 74DB4A8E2154205F00E9B550 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 74DB4A882154204700E9B550 /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + F34F00DB71F8C65CEA61A90A /* libPods-Host.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A7845ED770D25CF67B243D1A /* libPods-Host.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 74DB4A8C2154205B00E9B550 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 74DB4A8B2154205B00E9B550 /* App.framework in Embed Frameworks */, + 74DB4A8E2154205F00E9B550 /* Flutter.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 74DB4A492152F3F900E9B550 /* Host.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Host.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 74DB4A4C2152F3F900E9B550 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 74DB4A4D2152F3F900E9B550 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 74DB4A4F2152F3F900E9B550 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + 74DB4A502152F3F900E9B550 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + 74DB4A532152F3F900E9B550 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 74DB4A552152F3FB00E9B550 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 74DB4A582152F3FB00E9B550 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 74DB4A5A2152F3FB00E9B550 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 74DB4A5B2152F3FB00E9B550 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 74DB4A7F2152F49200E9B550 /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 74DB4A802152F4A400E9B550 /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 74DB4A8221541FEE00E9B550 /* Flutter.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Flutter.xcconfig; sourceTree = ""; }; + 74DB4A842154201200E9B550 /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = ../../hello/.ios/Flutter/App.framework; sourceTree = ""; }; + 74DB4A862154203700E9B550 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = ../../hello/.ios/Flutter/flutter_assets; sourceTree = ""; }; + 74DB4A882154204700E9B550 /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = ../../hello/.ios/Flutter/engine/Flutter.framework; sourceTree = ""; }; + A7845ED770D25CF67B243D1A /* libPods-Host.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Host.a"; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 74DB4A462152F3F900E9B550 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F34F00DB71F8C65CEA61A90A /* libPods-Host.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 74DB4A402152F3F900E9B550 = { + isa = PBXGroup; + children = ( + 74DB4A8121541FDF00E9B550 /* Flutter */, + 74DB4A7E2152F47500E9B550 /* Config */, + 74DB4A4B2152F3F900E9B550 /* Host */, + 74DB4A4A2152F3F900E9B550 /* Products */, + D22B5E2B5577AC172019DDE2 /* Pods */, + 76443A8345AFB0A4BBAA0AC0 /* Frameworks */, + ); + sourceTree = ""; + }; + 74DB4A4A2152F3F900E9B550 /* Products */ = { + isa = PBXGroup; + children = ( + 74DB4A492152F3F900E9B550 /* Host.app */, + ); + name = Products; + sourceTree = ""; + }; + 74DB4A4B2152F3F900E9B550 /* Host */ = { + isa = PBXGroup; + children = ( + 74DB4A4C2152F3F900E9B550 /* AppDelegate.h */, + 74DB4A4D2152F3F900E9B550 /* AppDelegate.m */, + 74DB4A4F2152F3F900E9B550 /* ViewController.h */, + 74DB4A502152F3F900E9B550 /* ViewController.m */, + 74DB4A522152F3F900E9B550 /* Main.storyboard */, + 74DB4A552152F3FB00E9B550 /* Assets.xcassets */, + 74DB4A572152F3FB00E9B550 /* LaunchScreen.storyboard */, + 74DB4A5A2152F3FB00E9B550 /* Info.plist */, + 74DB4A5B2152F3FB00E9B550 /* main.m */, + ); + path = Host; + sourceTree = ""; + }; + 74DB4A7E2152F47500E9B550 /* Config */ = { + isa = PBXGroup; + children = ( + 74DB4A8221541FEE00E9B550 /* Flutter.xcconfig */, + 74DB4A7F2152F49200E9B550 /* Debug.xcconfig */, + 74DB4A802152F4A400E9B550 /* Release.xcconfig */, + ); + path = Config; + sourceTree = ""; + }; + 74DB4A8121541FDF00E9B550 /* Flutter */ = { + isa = PBXGroup; + children = ( + 74DB4A882154204700E9B550 /* Flutter.framework */, + 74DB4A862154203700E9B550 /* flutter_assets */, + 74DB4A842154201200E9B550 /* App.framework */, + ); + path = Flutter; + sourceTree = ""; + }; + 76443A8345AFB0A4BBAA0AC0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + A7845ED770D25CF67B243D1A /* libPods-Host.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + D22B5E2B5577AC172019DDE2 /* Pods */ = { + isa = PBXGroup; + children = ( + ); + name = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 74DB4A482152F3F900E9B550 /* Host */ = { + isa = PBXNativeTarget; + buildConfigurationList = 74DB4A752152F3FB00E9B550 /* Build configuration list for PBXNativeTarget "Host" */; + buildPhases = ( + 30AC91A315B5AD0C33571E2F /* [CP] Check Pods Manifest.lock */, + 74DB4A452152F3F900E9B550 /* Sources */, + 74DB4A462152F3F900E9B550 /* Frameworks */, + 74DB4A472152F3F900E9B550 /* Resources */, + 00F45C5930D73692644264A6 /* [CP] Embed Pods Frameworks */, + 74DB4A8C2154205B00E9B550 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Host; + productName = Host; + productReference = 74DB4A492152F3F900E9B550 /* Host.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 74DB4A412152F3F900E9B550 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0940; + ORGANIZATIONNAME = Flutter; + TargetAttributes = { + 74DB4A482152F3F900E9B550 = { + CreatedOnToolsVersion = 9.4.1; + }; + }; + }; + buildConfigurationList = 74DB4A442152F3F900E9B550 /* Build configuration list for PBXProject "Host" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 74DB4A402152F3F900E9B550; + productRefGroup = 74DB4A4A2152F3F900E9B550 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 74DB4A482152F3F900E9B550 /* Host */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 74DB4A472152F3F900E9B550 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74DB4A592152F3FB00E9B550 /* LaunchScreen.storyboard in Resources */, + 74DB4A872154203700E9B550 /* flutter_assets in Resources */, + 74DB4A562152F3FB00E9B550 /* Assets.xcassets in Resources */, + 74DB4A542152F3F900E9B550 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 00F45C5930D73692644264A6 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-Host/Pods-Host-frameworks.sh", + "${PODS_ROOT}/../../tst04/.ios/Flutter/engine/Flutter.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Host/Pods-Host-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 30AC91A315B5AD0C33571E2F /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Host-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; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 74DB4A452152F3F900E9B550 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74DB4A512152F3F900E9B550 /* ViewController.m in Sources */, + 74DB4A5C2152F3FB00E9B550 /* main.m in Sources */, + 74DB4A4E2152F3F900E9B550 /* AppDelegate.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 74DB4A522152F3F900E9B550 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 74DB4A532152F3F900E9B550 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 74DB4A572152F3FB00E9B550 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 74DB4A582152F3FB00E9B550 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 74DB4A732152F3FB00E9B550 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + 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_DOCUMENTATION_COMMENTS = YES; + 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; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.4; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 74DB4A742152F3FB00E9B550 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + 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_DOCUMENTATION_COMMENTS = YES; + 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; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.4; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 74DB4A762152F3FB00E9B550 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 74DB4A7F2152F49200E9B550 /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = Host/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + DEVELOPMENT_TEAM = RW9CXS8BK2; + PRODUCT_BUNDLE_IDENTIFIER = io.flutter.add2app.Host; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 74DB4A772152F3FB00E9B550 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 74DB4A802152F4A400E9B550 /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = Host/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + DEVELOPMENT_TEAM = RW9CXS8BK2; + PRODUCT_BUNDLE_IDENTIFIER = io.flutter.add2app.Host; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 74DB4A442152F3F900E9B550 /* Build configuration list for PBXProject "Host" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 74DB4A732152F3FB00E9B550 /* Debug */, + 74DB4A742152F3FB00E9B550 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 74DB4A752152F3FB00E9B550 /* Build configuration list for PBXNativeTarget "Host" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 74DB4A762152F3FB00E9B550 /* Debug */, + 74DB4A772152F3FB00E9B550 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 74DB4A412152F3F900E9B550 /* Project object */; +} diff --git a/dev/integration_tests/ios_host_app/Host.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/dev/integration_tests/ios_host_app/Host.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..8ee5ee9ff6 --- /dev/null +++ b/dev/integration_tests/ios_host_app/Host.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/dev/integration_tests/ios_host_app/Host.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/dev/integration_tests/ios_host_app/Host.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/dev/integration_tests/ios_host_app/Host.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/dev/integration_tests/ios_host_app/Host.xcworkspace/contents.xcworkspacedata b/dev/integration_tests/ios_host_app/Host.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..8e65b678a3 --- /dev/null +++ b/dev/integration_tests/ios_host_app/Host.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/dev/integration_tests/ios_host_app/Host.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/dev/integration_tests/ios_host_app/Host.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/dev/integration_tests/ios_host_app/Host.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/dev/integration_tests/ios_host_app/Host.xcworkspace/xcuserdata/mravn.xcuserdatad/UserInterfaceState.xcuserstate b/dev/integration_tests/ios_host_app/Host.xcworkspace/xcuserdata/mravn.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..40eb4bcb278d93199c9eb48c97cf44fab874d88d GIT binary patch literal 26773 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 +#import + +@interface AppDelegate : FlutterAppDelegate +@end diff --git a/dev/integration_tests/ios_host_app/Host/AppDelegate.m b/dev/integration_tests/ios_host_app/Host/AppDelegate.m new file mode 100644 index 0000000000..9432fc57e0 --- /dev/null +++ b/dev/integration_tests/ios_host_app/Host/AppDelegate.m @@ -0,0 +1,4 @@ +#import "AppDelegate.h" + +@implementation AppDelegate +@end diff --git a/dev/integration_tests/ios_host_app/Host/Assets.xcassets/AppIcon.appiconset/Contents.json b/dev/integration_tests/ios_host_app/Host/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..d8db8d65fd --- /dev/null +++ b/dev/integration_tests/ios_host_app/Host/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/dev/integration_tests/ios_host_app/Host/Assets.xcassets/Contents.json b/dev/integration_tests/ios_host_app/Host/Assets.xcassets/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/dev/integration_tests/ios_host_app/Host/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/dev/integration_tests/ios_host_app/Host/Base.lproj/LaunchScreen.storyboard b/dev/integration_tests/ios_host_app/Host/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000..f83f6fd581 --- /dev/null +++ b/dev/integration_tests/ios_host_app/Host/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/integration_tests/ios_host_app/Host/Base.lproj/Main.storyboard b/dev/integration_tests/ios_host_app/Host/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..d7c78a1255 --- /dev/null +++ b/dev/integration_tests/ios_host_app/Host/Base.lproj/Main.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/integration_tests/ios_host_app/Host/Info.plist b/dev/integration_tests/ios_host_app/Host/Info.plist new file mode 100644 index 0000000000..16be3b6811 --- /dev/null +++ b/dev/integration_tests/ios_host_app/Host/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/dev/integration_tests/ios_host_app/Host/ViewController.h b/dev/integration_tests/ios_host_app/Host/ViewController.h new file mode 100644 index 0000000000..143825c2d5 --- /dev/null +++ b/dev/integration_tests/ios_host_app/Host/ViewController.h @@ -0,0 +1,5 @@ +#import + +@interface ViewController : UIViewController +@end + diff --git a/dev/integration_tests/ios_host_app/Host/ViewController.m b/dev/integration_tests/ios_host_app/Host/ViewController.m new file mode 100644 index 0000000000..b8db22bc3e --- /dev/null +++ b/dev/integration_tests/ios_host_app/Host/ViewController.m @@ -0,0 +1,23 @@ +#import "ViewController.h" +#import "Flutter/Flutter.h" +#import "FlutterPluginRegistrant/GeneratedPluginRegistrant.h" + +@implementation ViewController +- (void)viewDidLoad { + [super viewDidLoad]; + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; + [button addTarget:self + action:@selector(handleButtonAction) + forControlEvents:UIControlEventTouchUpInside]; + [button setTitle:@"Press me" forState:UIControlStateNormal]; + [button setBackgroundColor:[UIColor blueColor]]; + button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0); + [self.view addSubview:button]; +} + +- (void)handleButtonAction { + FlutterViewController* flutterViewController = [[FlutterViewController alloc] init]; + [GeneratedPluginRegistrant registerWithRegistry:flutterViewController]; + [self presentViewController:flutterViewController animated:false completion:nil]; +} +@end diff --git a/dev/integration_tests/ios_host_app/Host/main.m b/dev/integration_tests/ios_host_app/Host/main.m new file mode 100644 index 0000000000..81e84cbb78 --- /dev/null +++ b/dev/integration_tests/ios_host_app/Host/main.m @@ -0,0 +1,8 @@ +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/dev/integration_tests/ios_host_app/Podfile b/dev/integration_tests/ios_host_app/Podfile new file mode 100644 index 0000000000..bac985d148 --- /dev/null +++ b/dev/integration_tests/ios_host_app/Podfile @@ -0,0 +1,6 @@ +platform :ios, '9.0' + +target 'Host' do + flutter_application_path = '../hello' + eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding) +end diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh index 100b158ffc..655040ab27 100755 --- a/packages/flutter_tools/bin/xcode_backend.sh +++ b/packages/flutter_tools/bin/xcode_backend.sh @@ -80,6 +80,9 @@ BuildApp() { AssertExists "${project_path}" local derived_dir="${SOURCE_ROOT}/Flutter" + if [[ -e "${project_path}/.ios" ]]; then + derived_dir="${SOURCE_ROOT}/../.ios/Flutter" + fi RunCommand mkdir -p -- "$derived_dir" AssertExists "$derived_dir" diff --git a/packages/flutter_tools/lib/src/ios/cocoapods.dart b/packages/flutter_tools/lib/src/ios/cocoapods.dart index 96f7d324f4..184a24c62b 100644 --- a/packages/flutter_tools/lib/src/ios/cocoapods.dart +++ b/packages/flutter_tools/lib/src/ios/cocoapods.dart @@ -156,7 +156,7 @@ class CocoaPods { // Don't do anything for iOS when host platform doesn't support it. return; } - final Directory runnerProject = iosProject.directory.childDirectory('Runner.xcodeproj'); + final Directory runnerProject = iosProject.xcodeProject; if (!runnerProject.existsSync()) { return; } @@ -223,7 +223,7 @@ class CocoaPods { final Status status = logger.startProgress('Running pod install...', expectSlowOperation: true); final ProcessResult result = await processManager.run( ['pod', 'install', '--verbose'], - workingDirectory: iosProject.directory.path, + workingDirectory: iosProject.hostAppRoot.path, environment: { // For backward compatibility with previously created Podfile only. 'FLUTTER_FRAMEWORK_DIR': engineDirectory, diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index 53c822cdb8..d86bf9ba2b 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -291,7 +291,7 @@ Future buildXcodeProject({ modern: false, ); - final XcodeProjectInfo projectInfo = xcodeProjectInterpreter.getInfo(app.project.directory.path); + final XcodeProjectInfo projectInfo = xcodeProjectInterpreter.getInfo(app.project.hostAppRoot.path); if (!projectInfo.targets.contains('Runner')) { printError('The Xcode project does not define target "Runner" which is needed by Flutter tooling.'); printError('Open Xcode to fix the problem:'); @@ -326,7 +326,7 @@ Future buildXcodeProject({ // Before the build, all service definitions must be updated and the dylibs // copied over to a location that is suitable for Xcodebuild to find them. - await _addServicesToBundle(app.project.directory); + await _addServicesToBundle(app.project.hostAppRoot); final FlutterProject project = await FlutterProject.current(); await updateGeneratedXcodeProperties( @@ -334,8 +334,8 @@ Future buildXcodeProject({ targetOverride: targetOverride, buildInfo: buildInfo, ); - - if (hasPlugins(project)) { + refreshPluginsList(project); + if (hasPlugins(project) || (project.isModule && project.ios.podfile.existsSync())) { // If the Xcode project, Podfile, or Generated.xcconfig have changed since // last run, pods should be updated. final Fingerprinter fingerprinter = Fingerprinter( @@ -381,7 +381,7 @@ Future buildXcodeProject({ buildCommands.add('-allowProvisioningDeviceRegistration'); } - final List contents = app.project.directory.listSync(); + final List contents = app.project.hostAppRoot.listSync(); for (FileSystemEntity entity in contents) { if (fs.path.extension(entity.path) == '.xcworkspace') { buildCommands.addAll([ @@ -446,7 +446,7 @@ Future buildXcodeProject({ initialBuildStatus = logger.startProgress('Starting Xcode build...'); final RunResult buildResult = await runAsync( buildCommands, - workingDirectory: app.project.directory.path, + workingDirectory: app.project.hostAppRoot.path, allowReentrantFlutter: true ); buildSubStatus?.stop(); @@ -473,7 +473,7 @@ Future buildXcodeProject({ '-allowProvisioningDeviceRegistration', ].contains(buildCommand); }).toList(), - workingDirectory: app.project.directory.path, + workingDirectory: app.project.hostAppRoot.path, )); if (buildResult.exitCode != 0) { @@ -492,7 +492,7 @@ Future buildXcodeProject({ stderr: buildResult.stderr, xcodeBuildExecution: XcodeBuildExecution( buildCommands: buildCommands, - appDirectory: app.project.directory.path, + appDirectory: app.project.hostAppRoot.path, buildForPhysicalDevice: buildForDevice, buildSettings: buildSettings, ), @@ -677,7 +677,7 @@ Future upgradePbxProjWithFlutterAssets(IosProject project) async { assert(await xcodeProjectFile.exists()); final List lines = await xcodeProjectFile.readAsLines(); - if (lines.any((String line) => line.contains('path = Flutter/flutter_assets'))) + if (lines.any((String line) => line.contains('flutter_assets in Resources'))) return true; const String l1 = ' 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };'; diff --git a/packages/flutter_tools/lib/src/plugins.dart b/packages/flutter_tools/lib/src/plugins.dart index ea5f79829e..d0906a4ad0 100644 --- a/packages/flutter_tools/lib/src/plugins.dart +++ b/packages/flutter_tools/lib/src/plugins.dart @@ -228,6 +228,7 @@ Depends on all your plugins, and provides a function to register them. s.source_files = "Classes", "Classes/**/*.{h,m}" s.source = { :path => '.' } s.public_header_files = './Classes/**/*.h' + s.dependency 'Flutter' {{#plugins}} s.dependency '{{name}}' {{/plugins}} @@ -296,7 +297,7 @@ Future injectPlugins(FlutterProject project) async { final List plugins = findPlugins(project); await _writeAndroidPluginRegistrant(project, plugins); await _writeIOSPluginRegistrant(project, plugins); - if (!project.isModule && project.ios.directory.existsSync()) { + if (!project.isModule && project.ios.hostAppRoot.existsSync()) { final CocoaPods cocoaPods = CocoaPods(); if (plugins.isNotEmpty) cocoaPods.setupPodfile(project.ios); diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index ed8258cd6f..9df371afdd 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -157,37 +157,53 @@ class IosProject { /// The parent of this project. final FlutterProject parent; - /// The directory of this project. - Directory get directory => parent.directory.childDirectory(isModule ? '.ios' : 'ios'); + Directory get _ephemeralDirectory => parent.directory.childDirectory('.ios'); + Directory get _editableDirectory => parent.directory.childDirectory('ios'); + /// This parent folder of `Runner.xcodeproj`. + Directory get hostAppRoot { + if (!isModule || _editableDirectory.existsSync()) + return _editableDirectory; + return _ephemeralDirectory; + } + + /// The root directory of the iOS wrapping of Flutter and plugins. This is the + /// parent of the `Flutter/` folder into which Flutter artifacts are written + /// during build. + /// + /// This is the same as [hostAppRoot] except when the project is + /// a Flutter module with an editable host app. + Directory get _flutterLibRoot => isModule ? _ephemeralDirectory : _editableDirectory; + + /// The bundle name of the host app, `Runner.app`. String get hostAppBundleName => '$_hostAppBundleName.app'; /// True, if the parent Flutter project is a module. bool get isModule => parent.isModule; /// The xcode config file for [mode]. - File xcodeConfigFor(String mode) => directory.childDirectory('Flutter').childFile('$mode.xcconfig'); + File xcodeConfigFor(String mode) => _flutterLibRoot.childDirectory('Flutter').childFile('$mode.xcconfig'); /// The 'Podfile'. - File get podfile => directory.childFile('Podfile'); + File get podfile => hostAppRoot.childFile('Podfile'); /// The 'Podfile.lock'. - File get podfileLock => directory.childFile('Podfile.lock'); + File get podfileLock => hostAppRoot.childFile('Podfile.lock'); /// The 'Manifest.lock'. - File get podManifestLock => directory.childDirectory('Pods').childFile('Manifest.lock'); + File get podManifestLock => hostAppRoot.childDirectory('Pods').childFile('Manifest.lock'); /// The 'Info.plist' file of the host app. - File get hostInfoPlist => directory.childDirectory(_hostAppBundleName).childFile('Info.plist'); + File get hostInfoPlist => hostAppRoot.childDirectory(_hostAppBundleName).childFile('Info.plist'); /// '.xcodeproj' folder of the host app. - Directory get xcodeProject => directory.childDirectory('$_hostAppBundleName.xcodeproj'); + Directory get xcodeProject => hostAppRoot.childDirectory('$_hostAppBundleName.xcodeproj'); /// The '.pbxproj' file of the host app. File get xcodeProjectInfoFile => xcodeProject.childFile('project.pbxproj'); /// Xcode workspace directory of the host app. - Directory get xcodeWorkspace => directory.childDirectory('$_hostAppBundleName.xcworkspace'); + Directory get xcodeWorkspace => hostAppRoot.childDirectory('$_hostAppBundleName.xcworkspace'); /// Xcode workspace shared data directory for the host app. Directory get xcodeWorkspaceSharedData => xcodeWorkspace.childDirectory('xcshareddata'); @@ -232,8 +248,12 @@ class IosProject { Future ensureReadyForPlatformSpecificTooling() async { _regenerateFromTemplateIfNeeded(); - if (!directory.existsSync()) + if (!_flutterLibRoot.existsSync()) return; + await _updateGeneratedXcodeConfigIfNeeded(); + } + + Future _updateGeneratedXcodeConfigIfNeeded() async { if (Cache.instance.isOlderThanToolsStamp(generatedXcodePropertiesFile)) { await xcode.updateGeneratedXcodeProperties( project: parent, @@ -246,28 +266,40 @@ class IosProject { void _regenerateFromTemplateIfNeeded() { if (!isModule) return; - final bool pubspecChanged = isOlderThanReference(entity: directory, referenceFile: parent.pubspecFile); - final bool toolingChanged = Cache.instance.isOlderThanToolsStamp(directory); + final bool pubspecChanged = isOlderThanReference(entity: _ephemeralDirectory, referenceFile: parent.pubspecFile); + final bool toolingChanged = Cache.instance.isOlderThanToolsStamp(_ephemeralDirectory); if (!pubspecChanged && !toolingChanged) return; - _deleteIfExistsSync(directory); - _overwriteFromTemplate(fs.path.join('module', 'ios', 'library'), directory); - _overwriteFromTemplate(fs.path.join('module', 'ios', 'host_app_ephemeral'), directory); - if (hasPlugins(parent)) { - _overwriteFromTemplate(fs.path.join('module', 'ios', 'host_app_ephemeral_cocoapods'), directory); + _deleteIfExistsSync(_ephemeralDirectory); + _overwriteFromTemplate(fs.path.join('module', 'ios', 'library'), _ephemeralDirectory); + // Add ephemeral host app, if a editable host app does not already exist. + if (!_editableDirectory.existsSync()) { + _overwriteFromTemplate(fs.path.join('module', 'ios', 'host_app_ephemeral'), _ephemeralDirectory); + if (hasPlugins(parent)) { + _overwriteFromTemplate(fs.path.join('module', 'ios', 'host_app_ephemeral_cocoapods'), _ephemeralDirectory); + } } } Future makeHostAppEditable() async { - throwToolExit('making host app editable has not yet been implemented for iOS'); + assert(isModule); + if (_editableDirectory.existsSync()) + throwToolExit('iOS host app is already editable. To start fresh, delete the ios/ folder.'); + _deleteIfExistsSync(_ephemeralDirectory); + _overwriteFromTemplate(fs.path.join('module', 'ios', 'library'), _ephemeralDirectory); + _overwriteFromTemplate(fs.path.join('module', 'ios', 'host_app_ephemeral'), _editableDirectory); + _overwriteFromTemplate(fs.path.join('module', 'ios', 'host_app_ephemeral_cocoapods'), _editableDirectory); + _overwriteFromTemplate(fs.path.join('module', 'ios', 'host_app_editable_cocoapods'), _editableDirectory); + await _updateGeneratedXcodeConfigIfNeeded(); + await injectPlugins(parent); } - File get generatedXcodePropertiesFile => directory.childDirectory('Flutter').childFile('Generated.xcconfig'); + File get generatedXcodePropertiesFile => _flutterLibRoot.childDirectory('Flutter').childFile('Generated.xcconfig'); Directory get pluginRegistrantHost { return isModule - ? directory.childDirectory('Flutter').childDirectory('FlutterPluginRegistrant') - : directory.childDirectory(_hostAppBundleName); + ? _flutterLibRoot.childDirectory('Flutter').childDirectory('FlutterPluginRegistrant') + : hostAppRoot.childDirectory(_hostAppBundleName); } void _overwriteFromTemplate(String path, Directory target) { diff --git a/packages/flutter_tools/templates/module/ios/host_app_editable_cocoapods/Config.tmpl/Flutter.xcconfig b/packages/flutter_tools/templates/module/ios/host_app_editable_cocoapods/Config.tmpl/Flutter.xcconfig new file mode 100644 index 0000000000..f6b0378f5b --- /dev/null +++ b/packages/flutter_tools/templates/module/ios/host_app_editable_cocoapods/Config.tmpl/Flutter.xcconfig @@ -0,0 +1,2 @@ +#include "../../.ios/Flutter/Generated.xcconfig" +ENABLE_BITCODE=NO diff --git a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.pbxproj.tmpl b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.pbxproj.tmpl index 7b0eeb1f88..8d4b827eba 100644 --- a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.pbxproj.tmpl +++ b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.pbxproj.tmpl @@ -36,15 +36,15 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; - 741F495E21355F27001E2961 /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/engine/Flutter.framework; sourceTree = ""; }; - 741F496521356807001E2961 /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = ../.ios/Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; + 741F495E21355F27001E2961 /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = ../.ios/Flutter/engine/Flutter.framework; sourceTree = ""; }; + 741F496521356807001E2961 /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = ../.ios/Flutter/App.framework; sourceTree = ""; }; 74974046213559DB008C567A /* Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 74974047213559DB008C567A /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; 7497404A213559E7008C567A /* Flutter.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Flutter.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = ../.ios/Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; diff --git a/packages/flutter_tools/templates/module/ios/host_app_ephemeral_cocoapods/Podfile.copy.tmpl b/packages/flutter_tools/templates/module/ios/host_app_ephemeral_cocoapods/Podfile.copy.tmpl index f11c13a1ad..3457cfd81b 100644 --- a/packages/flutter_tools/templates/module/ios/host_app_ephemeral_cocoapods/Podfile.copy.tmpl +++ b/packages/flutter_tools/templates/module/ios/host_app_ephemeral_cocoapods/Podfile.copy.tmpl @@ -2,5 +2,5 @@ platform :ios, '8.0' target 'Runner' do flutter_application_path = '../' - eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb'))) + eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding) end diff --git a/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb b/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb index eec077a7a4..0ac9d7c9fc 100644 --- a/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb +++ b/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb @@ -20,11 +20,6 @@ def parse_KV_file(file, separator='=') return pods_array end -# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock -# referring to absolute paths on developers' machines. -system('rm -rf .symlinks') -system('mkdir -p .symlinks/plugins') - def flutter_root(f) generated_xcode_build_settings = parse_KV_file(File.join(f, File.join('.ios', 'Flutter', 'Generated.xcconfig'))) if generated_xcode_build_settings.empty? @@ -38,32 +33,26 @@ def flutter_root(f) } end -framework_dir = File.join(File.expand_path(File.dirname(__FILE__)), 'Flutter') +framework_dir = File.join(flutter_application_path, '.ios', 'Flutter') + engine_dir = File.join(framework_dir, 'engine') if !File.exist?(engine_dir) # Copy the debug engine to have something to link against if the xcode backend script has not run yet. debug_framework_dir = File.join(flutter_root(flutter_application_path), 'bin', 'cache', 'artifacts', 'engine', 'ios') - FileUtils.mkdir(engine_dir) + FileUtils.mkdir_p(engine_dir) FileUtils.cp_r(File.join(debug_framework_dir, 'Flutter.framework'), engine_dir) FileUtils.cp(File.join(debug_framework_dir, 'Flutter.podspec'), engine_dir) end -symlink = File.join('.symlinks', 'flutter') - -File.symlink(framework_dir, symlink) -pod 'Flutter', :path => File.join(symlink, 'engine') - +pod 'Flutter', :path => engine_dir +pod 'FlutterPluginRegistrant', :path => File.join(framework_dir, 'FlutterPluginRegistrant') +symlinks_dir = File.join(framework_dir, '.symlinks') +FileUtils.mkdir_p(symlinks_dir) plugin_pods = parse_KV_file(File.join(flutter_application_path, '.flutter-plugins')) - plugin_pods.map { |r| - symlink = File.join('.symlinks', 'plugins', r[:name]) - + symlink = File.join(symlinks_dir, r[:name]) + FileUtils.rm_f(symlink) File.symlink(r[:path], symlink) pod r[:name], :path => File.join(symlink, 'ios') } - -symlink = File.join('.symlinks', 'FlutterApp') -File.symlink(File.absolute_path(flutter_application_path), symlink) - -pod 'FlutterPluginRegistrant', :path => File.join(symlink, '.ios', 'Flutter','FlutterPluginRegistrant') diff --git a/packages/flutter_tools/test/ios/cocoapods_test.dart b/packages/flutter_tools/test/ios/cocoapods_test.dart index 435bb963ad..a69b5ac6f2 100644 --- a/packages/flutter_tools/test/ios/cocoapods_test.dart +++ b/packages/flutter_tools/test/ios/cocoapods_test.dart @@ -46,7 +46,7 @@ void main() { mockProcessManager = MockProcessManager(); mockXcodeProjectInterpreter = MockXcodeProjectInterpreter(); projectUnderTest = await FlutterProject.fromDirectory(fs.directory('project')); - projectUnderTest.ios.directory.childDirectory('Runner.xcodeproj').createSync(recursive: true); + projectUnderTest.ios.xcodeProject.createSync(recursive: true); cocoaPodsUnderTest = CocoaPods(); pretendPodVersionIs('1.5.0'); fs.file(fs.path.join( diff --git a/packages/flutter_tools/test/project_test.dart b/packages/flutter_tools/test/project_test.dart index b0efc88c5d..63e80571da 100644 --- a/packages/flutter_tools/test/project_test.dart +++ b/packages/flutter_tools/test/project_test.dart @@ -148,20 +148,20 @@ void main() { testInMemory('does nothing in plugin or package root project', () async { final FlutterProject project = await aPluginProject(); await project.ensureReadyForPlatformSpecificTooling(); - expectNotExists(project.ios.directory.childDirectory('Runner').childFile('GeneratedPluginRegistrant.h')); + expectNotExists(project.ios.hostAppRoot.childDirectory('Runner').childFile('GeneratedPluginRegistrant.h')); expectNotExists(androidPluginRegistrant(project.android.hostAppGradleRoot.childDirectory('app'))); - expectNotExists(project.ios.directory.childDirectory('Flutter').childFile('Generated.xcconfig')); + expectNotExists(project.ios.hostAppRoot.childDirectory('Flutter').childFile('Generated.xcconfig')); expectNotExists(project.android.hostAppGradleRoot.childFile('local.properties')); }); testInMemory('injects plugins for iOS', () async { final FlutterProject project = await someProject(); await project.ensureReadyForPlatformSpecificTooling(); - expectExists(project.ios.directory.childDirectory('Runner').childFile('GeneratedPluginRegistrant.h')); + expectExists(project.ios.hostAppRoot.childDirectory('Runner').childFile('GeneratedPluginRegistrant.h')); }); testInMemory('generates Xcode configuration for iOS', () async { final FlutterProject project = await someProject(); await project.ensureReadyForPlatformSpecificTooling(); - expectExists(project.ios.directory.childDirectory('Flutter').childFile('Generated.xcconfig')); + expectExists(project.ios.hostAppRoot.childDirectory('Flutter').childFile('Generated.xcconfig')); }); testInMemory('injects plugins for Android', () async { final FlutterProject project = await someProject(); @@ -183,7 +183,7 @@ void main() { testInMemory('creates iOS pod in module', () async { final FlutterProject project = await aModuleProject(); await project.ensureReadyForPlatformSpecificTooling(); - final Directory flutter = project.ios.directory.childDirectory('Flutter'); + final Directory flutter = project.ios.hostAppRoot.childDirectory('Flutter'); expectExists(flutter.childFile('podhelper.rb')); expectExists(flutter.childFile('Generated.xcconfig')); final Directory pluginRegistrantClasses = flutter @@ -201,7 +201,7 @@ void main() { expect(project.android.isModule, isTrue); expect(project.ios.isModule, isTrue); expect(project.android.hostAppGradleRoot.basename, '.android'); - expect(project.ios.directory.basename, '.ios'); + expect(project.ios.hostAppRoot.basename, '.ios'); }); testInMemory('is known for non-module', () async { final FlutterProject project = await someProject(); @@ -209,7 +209,7 @@ void main() { expect(project.android.isModule, isFalse); expect(project.ios.isModule, isFalse); expect(project.android.hostAppGradleRoot.basename, 'android'); - expect(project.ios.directory.basename, 'ios'); + expect(project.ios.hostAppRoot.basename, 'ios'); }); });