Add create app and plugin templates for Swift Package Manager (#147082)

When Swift Package Manager feature is enabled, create app and create plugin will have Swift Package Manager integration already added and will not need to undergo a migration.

Fixes https://github.com/flutter/flutter/issues/146371.

```
flutter config --enable-swift-package-manager

flutter create --ios-language swift --platforms ios,macos swift_app_name

flutter create --ios-language objc --platforms ios objc_app_name

flutter create --template=plugin --ios-language swift --platforms ios,macos swift_plugin_name

flutter create --template=plugin --ios-language objc --platforms ios objc_plugin_name
```
This commit is contained in:
Victoria Ashworth 2024-04-24 17:46:20 -05:00 committed by GitHub
parent d85571b46b
commit 5a63b1df95
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 1197 additions and 451 deletions

View file

@ -21,6 +21,8 @@ import '../flutter_manifest.dart';
import '../flutter_project_metadata.dart';
import '../globals.dart' as globals;
import '../ios/code_signing.dart';
import '../macos/swift_package_manager.dart';
import '../macos/swift_packages.dart';
import '../project.dart';
import '../reporting/reporting.dart';
import '../runner/flutter_command.dart';
@ -324,6 +326,7 @@ class CreateCommand extends CreateBase {
projectDescription: stringArg('description'),
flutterRoot: flutterRoot,
withPlatformChannelPluginHook: generateMethodChannelsPlugin,
withSwiftPackageManager: featureFlags.isSwiftPackageManagerEnabled,
withFfiPluginHook: generateFfiPlugin,
withFfiPackage: generateFfiPackage,
withEmptyMain: emptyArgument,
@ -603,8 +606,21 @@ Your $application code is in $relativeAppMain.
? stringArg('description')
: 'A new Flutter plugin project.';
templateContext['description'] = description;
final String? projectName = templateContext['projectName'] as String?;
final List<String> templates = <String>['plugin', 'plugin_shared'];
if ((templateContext['ios'] == true || templateContext['macos'] == true) && featureFlags.isSwiftPackageManagerEnabled) {
templates.add('plugin_swift_package_manager');
templateContext['swiftLibraryName'] = projectName?.replaceAll('_', '-');
templateContext['swiftToolsVersion'] = minimumSwiftToolchainVersion;
templateContext['iosSupportedPlatform'] = SwiftPackageManager.iosSwiftPackageSupportedPlatform.format();
templateContext['macosSupportedPlatform'] = SwiftPackageManager.macosSwiftPackageSupportedPlatform.format();
} else {
templates.add('plugin_cocoapods');
}
generatedCount += await renderMerged(
<String>['plugin', 'plugin_shared'],
templates,
directory,
templateContext,
overwrite: overwrite,
@ -618,7 +634,6 @@ Your $application code is in $relativeAppMain.
project: project, requireAndroidSdk: false);
}
final String? projectName = templateContext['projectName'] as String?;
final String organization = templateContext['organization']! as String; // Required to make the context.
final String? androidPluginIdentifier = templateContext['androidIdentifier'] as String?;
final String exampleProjectName = '${projectName}_example';

View file

@ -351,6 +351,7 @@ abstract class CreateBase extends FlutterCommand {
String? kotlinVersion,
String? gradleVersion,
bool withPlatformChannelPluginHook = false,
bool withSwiftPackageManager = false,
bool withFfiPluginHook = false,
bool withFfiPackage = false,
bool withEmptyMain = false,
@ -404,6 +405,7 @@ abstract class CreateBase extends FlutterCommand {
'withFfiPackage': withFfiPackage,
'withFfiPluginHook': withFfiPluginHook,
'withPlatformChannelPluginHook': withPlatformChannelPluginHook,
'withSwiftPackageManager': withSwiftPackageManager,
'withPluginHook': withFfiPluginHook || withFfiPackage || withPlatformChannelPluginHook,
'withEmptyMain': withEmptyMain,
'androidLanguage': androidLanguage,

View file

@ -30,12 +30,12 @@ class SwiftPackageManager {
static const String _defaultFlutterPluginsSwiftPackageName = 'FlutterGeneratedPluginSwiftPackage';
static final SwiftPackageSupportedPlatform _iosSwiftPackageSupportedPlatform = SwiftPackageSupportedPlatform(
static final SwiftPackageSupportedPlatform iosSwiftPackageSupportedPlatform = SwiftPackageSupportedPlatform(
platform: SwiftPackagePlatform.ios,
version: Version(12, 0, null),
);
static final SwiftPackageSupportedPlatform _macosSwiftPackageSupportedPlatform = SwiftPackageSupportedPlatform(
static final SwiftPackageSupportedPlatform macosSwiftPackageSupportedPlatform = SwiftPackageSupportedPlatform(
platform: SwiftPackagePlatform.macos,
version: Version(10, 14, null),
);
@ -66,9 +66,9 @@ class SwiftPackageManager {
final SwiftPackageSupportedPlatform swiftSupportedPlatform;
if (platform == SupportedPlatform.ios) {
swiftSupportedPlatform = _iosSwiftPackageSupportedPlatform;
swiftSupportedPlatform = iosSwiftPackageSupportedPlatform;
} else {
swiftSupportedPlatform = _macosSwiftPackageSupportedPlatform;
swiftSupportedPlatform = macosSwiftPackageSupportedPlatform;
}
// FlutterGeneratedPluginSwiftPackage must be statically linked to ensure
@ -169,10 +169,10 @@ class SwiftPackageManager {
final SwiftPackageSupportedPlatform defaultPlatform;
final SwiftPackagePlatform packagePlatform;
if (platform == SupportedPlatform.ios) {
defaultPlatform = _iosSwiftPackageSupportedPlatform;
defaultPlatform = iosSwiftPackageSupportedPlatform;
packagePlatform = SwiftPackagePlatform.ios;
} else {
defaultPlatform = _macosSwiftPackageSupportedPlatform;
defaultPlatform = macosSwiftPackageSupportedPlatform;
packagePlatform = SwiftPackagePlatform.macos;
}

View file

@ -10,6 +10,9 @@
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C80F4294D02FB00263BE5 /* RunnerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 331C80F3294D02FB00263BE5 /* RunnerTests.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
{{#withSwiftPackageManager}}
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
{{/withSwiftPackageManager}}
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 */; };
@ -71,6 +74,9 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
{{#withSwiftPackageManager}}
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
{{/withSwiftPackageManager}}
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -176,6 +182,11 @@
dependencies = (
);
name = Runner;
{{#withSwiftPackageManager}}
packageProductDependencies = (
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
);
{{/withSwiftPackageManager}}
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
@ -208,6 +219,11 @@
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
{{#withSwiftPackageManager}}
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
);
{{/withSwiftPackageManager}}
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
@ -619,6 +635,22 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
{{#withSwiftPackageManager}}
/* Begin XCLocalSwiftPackageReference section */
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};
/* End XCLocalSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
isa = XCSwiftPackageProductDependency;
productName = FlutterGeneratedPluginSwiftPackage;
};
/* End XCSwiftPackageProductDependency section */
{{/withSwiftPackageManager}}
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View file

@ -5,6 +5,26 @@
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
{{#withSwiftPackageManager}}
<PreActions>
<ExecutionAction
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Prepare Flutter Framework Script"
scriptText = "/bin/sh &quot;$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh&quot; prepare&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</EnvironmentBuildable>
</ActionContent>
</ExecutionAction>
</PreActions>
{{/withSwiftPackageManager}}
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"

View file

@ -3,6 +3,11 @@
#import <XCTest/XCTest.h>
{{#withPlatformChannelPluginHook}}
{{#withSwiftPackageManager}}
// If your plugin has been explicitly set to "type: .dynamic" in the Package.swift,
// you will need to add your plugin as a dependency of RunnerTests within Xcode.
{{/withSwiftPackageManager}}
@import {{pluginProjectName}};
// This demonstrates a simple unit test of the Objective-C portion of this plugin's implementation.

View file

@ -11,6 +11,9 @@
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
{{#withSwiftPackageManager}}
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
{{/withSwiftPackageManager}}
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 */; };
@ -62,6 +65,9 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
{{#withSwiftPackageManager}}
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
{{/withSwiftPackageManager}}
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -157,6 +163,11 @@
dependencies = (
);
name = Runner;
{{#withSwiftPackageManager}}
packageProductDependencies = (
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
);
{{/withSwiftPackageManager}}
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
@ -190,6 +201,11 @@
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
{{#withSwiftPackageManager}}
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
);
{{/withSwiftPackageManager}}
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
@ -620,6 +636,22 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
{{#withSwiftPackageManager}}
/* Begin XCLocalSwiftPackageReference section */
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};
/* End XCLocalSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
isa = XCSwiftPackageProductDependency;
productName = FlutterGeneratedPluginSwiftPackage;
};
/* End XCSwiftPackageProductDependency section */
{{/withSwiftPackageManager}}
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View file

@ -5,6 +5,26 @@
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
{{#withSwiftPackageManager}}
<PreActions>
<ExecutionAction
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Prepare Flutter Framework Script"
scriptText = "/bin/sh &quot;$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh&quot; prepare&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</EnvironmentBuildable>
</ActionContent>
</ExecutionAction>
</PreActions>
{{/withSwiftPackageManager}}
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"

View file

@ -3,6 +3,11 @@ import UIKit
import XCTest
{{#withPlatformChannelPluginHook}}
{{#withSwiftPackageManager}}
// If your plugin has been explicitly set to "type: .dynamic" in the Package.swift,
// you will need to add your plugin as a dependency of RunnerTests within Xcode.
{{/withSwiftPackageManager}}
@testable import {{pluginProjectName}}
// This demonstrates a simple unit test of the Swift portion of this plugin's implementation.

View file

@ -27,6 +27,9 @@
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
{{#withSwiftPackageManager}}
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
{{/withSwiftPackageManager}}
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -92,6 +95,9 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
{{#withSwiftPackageManager}}
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
{{/withSwiftPackageManager}}
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -216,6 +222,11 @@
33CC11202044C79F0003C045 /* PBXTargetDependency */,
);
name = Runner;
{{#withSwiftPackageManager}}
packageProductDependencies = (
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
);
{{/withSwiftPackageManager}}
productName = Runner;
productReference = 33CC10ED2044A3C60003C045 /* {{projectName}}.app */;
productType = "com.apple.product-type.application";
@ -260,6 +271,11 @@
Base,
);
mainGroup = 33CC10E42044A3C60003C045;
{{#withSwiftPackageManager}}
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
);
{{/withSwiftPackageManager}}
productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
projectDirPath = "";
projectRoot = "";
@ -700,6 +716,22 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
{{#withSwiftPackageManager}}
/* Begin XCLocalSwiftPackageReference section */
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};
/* End XCLocalSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
isa = XCSwiftPackageProductDependency;
productName = FlutterGeneratedPluginSwiftPackage;
};
/* End XCSwiftPackageProductDependency section */
{{/withSwiftPackageManager}}
};
rootObject = 33CC10E52044A3C60003C045 /* Project object */;
}

View file

@ -5,6 +5,26 @@
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
{{#withSwiftPackageManager}}
<PreActions>
<ExecutionAction
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Prepare Flutter Framework Script"
scriptText = "&quot;$FLUTTER_ROOT&quot;/packages/flutter_tools/bin/macos_assemble.sh prepare&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "{{projectName}}.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</EnvironmentBuildable>
</ActionContent>
</ExecutionAction>
</PreActions>
{{/withSwiftPackageManager}}
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"

View file

@ -3,6 +3,11 @@ import FlutterMacOS
import XCTest
{{#withPlatformChannelPluginHook}}
{{#withSwiftPackageManager}}
// If your plugin has been explicitly set to "type: .dynamic" in the Package.swift,
// you will need to add your plugin as a dependency of RunnerTests within Xcode.
{{/withSwiftPackageManager}}
@testable import {{pluginProjectName}}
// This demonstrates a simple unit test of the Swift portion of this plugin's implementation.

View file

@ -13,8 +13,14 @@ Pod::Spec.new do |s|
s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => 'email@example.com' }
s.source = { :path => '.' }
{{#withSwiftPackageManager}}
s.source_files = '{{projectName}}/Sources/{{projectName}}/**/*'
s.public_header_files = '{{projectName}}/Sources/{{projectName}}/include/{{projectName}}/**/*.h'
{{/withSwiftPackageManager}}
{{^withSwiftPackageManager}}
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h'
{{/withSwiftPackageManager}}
s.dependency 'Flutter'
s.platform = :ios, '12.0'

View file

@ -13,7 +13,12 @@ Pod::Spec.new do |s|
s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => 'email@example.com' }
s.source = { :path => '.' }
{{#withSwiftPackageManager}}
s.source_files = '{{projectName}}/Sources/{{projectName}}/**/*'
{{/withSwiftPackageManager}}
{{^withSwiftPackageManager}}
s.source_files = 'Classes/**/*'
{{/withSwiftPackageManager}}
s.dependency 'Flutter'
s.platform = :ios, '12.0'

View file

@ -20,7 +20,12 @@ Pod::Spec.new do |s|
# `../src/*` so that the C sources can be shared among all target platforms.
{{/withFfiPluginHook}}
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
{{#withSwiftPackageManager}}
s.source_files = '{{projectName}}/Sources/{{projectName}}/**/*'
{{/withSwiftPackageManager}}
{{^withSwiftPackageManager}}
s.source_files = 'Classes/**/*'
{{/withSwiftPackageManager}}
s.dependency 'FlutterMacOS'
s.platform = :osx, '10.11'

View file

@ -0,0 +1,27 @@
// swift-tools-version: {{swiftToolsVersion}}
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "{{projectName}}",
platforms: [
{{iosSupportedPlatform}}
],
products: [
.library(name: "{{swiftLibraryName}}", targets: ["{{projectName}}"])
],
dependencies: [],
targets: [
.target(
name: "{{projectName}}",
dependencies: [],
resources: [
.process("Resources"),
],
cSettings: [
.headerSearchPath("include/{{projectName}}"),
]
)
]
)

View file

@ -0,0 +1,4 @@
#import <Flutter/Flutter.h>
@interface {{pluginClass}} : NSObject<FlutterPlugin>
@end

View file

@ -0,0 +1,20 @@
#import "{{pluginClass}}.h"
@implementation {{pluginClass}}
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"{{projectName}}"
binaryMessenger:[registrar messenger]];
{{pluginClass}}* instance = [[{{pluginClass}} alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"getPlatformVersion" isEqualToString:call.method]) {
result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
} else {
result(FlutterMethodNotImplemented);
}
}
@end

View file

@ -0,0 +1,24 @@
// swift-tools-version: {{swiftToolsVersion}}
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "{{projectName}}",
platforms: [
{{iosSupportedPlatform}}
],
products: [
.library(name: "{{swiftLibraryName}}", targets: ["{{projectName}}"])
],
dependencies: [],
targets: [
.target(
name: "{{projectName}}",
dependencies: [],
resources: [
.process("Resources"),
]
)
]
)

View file

@ -0,0 +1,19 @@
import Flutter
import UIKit
public class {{pluginClass}}: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "{{projectName}}", binaryMessenger: registrar.messenger())
let instance = {{pluginClass}}()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "getPlatformVersion":
result("iOS " + UIDevice.current.systemVersion)
default:
result(FlutterMethodNotImplemented)
}
}
}

View file

@ -0,0 +1,24 @@
// swift-tools-version: {{swiftToolsVersion}}
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "{{projectName}}",
platforms: [
{{macosSupportedPlatform}}
],
products: [
.library(name: "{{swiftLibraryName}}", targets: ["{{projectName}}"])
],
dependencies: [],
targets: [
.target(
name: "{{projectName}}",
dependencies: [],
resources: [
.process("Resources"),
]
)
]
)

View file

@ -0,0 +1,19 @@
import Cocoa
import FlutterMacOS
public class {{pluginClass}}: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "{{projectName}}", binaryMessenger: registrar.messenger)
let instance = {{pluginClass}}()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "getPlatformVersion":
result("macOS " + ProcessInfo.processInfo.operatingSystemVersionString)
default:
result(FlutterMethodNotImplemented)
}
}
}

View file

@ -40,13 +40,13 @@
"templates/app_shared/android.tmpl/gradle/wrapper/gradle-wrapper.properties.tmpl",
"templates/app_shared/android.tmpl/settings.gradle",
"templates/app_shared/ios-objc.tmpl/Runner.xcodeproj/project.pbxproj.tmpl",
"templates/app_shared/ios-objc.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
"templates/app_shared/ios-objc.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme.tmpl",
"templates/app_shared/ios-objc.tmpl/Runner/AppDelegate.h",
"templates/app_shared/ios-objc.tmpl/Runner/AppDelegate.m",
"templates/app_shared/ios-objc.tmpl/Runner/main.m",
"templates/app_shared/ios-objc.tmpl/RunnerTests/RunnerTests.m.tmpl",
"templates/app_shared/ios-swift.tmpl/Runner.xcodeproj/project.pbxproj.tmpl",
"templates/app_shared/ios-swift.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
"templates/app_shared/ios-swift.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme.tmpl",
"templates/app_shared/ios-swift.tmpl/Runner/AppDelegate.swift",
"templates/app_shared/ios-swift.tmpl/Runner/Runner-Bridging-Header.h",
"templates/app_shared/ios-swift.tmpl/RunnerTests/RunnerTests.swift.tmpl",
@ -277,13 +277,9 @@
"templates/plugin/android.tmpl/gradle.properties.tmpl",
"templates/plugin/android.tmpl/settings.gradle.tmpl",
"templates/plugin/android.tmpl/src/main/AndroidManifest.xml.tmpl",
"templates/plugin/ios-objc.tmpl/Classes/pluginClass.h.tmpl",
"templates/plugin/ios-objc.tmpl/Classes/pluginClass.m.tmpl",
"templates/plugin/ios-objc.tmpl/projectName.podspec.tmpl",
"templates/plugin/ios-swift.tmpl/Classes/pluginClass.swift.tmpl",
"templates/plugin/ios-swift.tmpl/projectName.podspec.tmpl",
"templates/plugin/ios.tmpl/.gitignore",
"templates/plugin/ios.tmpl/Assets/.gitkeep",
"templates/plugin/lib/projectName.dart.tmpl",
"templates/plugin/lib/projectName_platform_interface.dart.tmpl",
"templates/plugin/lib/projectName_method_channel.dart.tmpl",
@ -292,7 +288,6 @@
"templates/plugin/linux.tmpl/pluginClassSnakeCase.cc.tmpl",
"templates/plugin/linux.tmpl/pluginClassSnakeCase_private.h.tmpl",
"templates/plugin/linux.tmpl/test/pluginClassSnakeCase_test.cc.tmpl",
"templates/plugin/macos.tmpl/Classes/pluginClass.swift.tmpl",
"templates/plugin/README.md.tmpl",
"templates/plugin/test/projectName_test.dart.tmpl",
"templates/plugin/test/projectName_method_channel_test.dart.tmpl",
@ -338,6 +333,22 @@
"templates/plugin_shared/pubspec.yaml.tmpl",
"templates/plugin_shared/windows.tmpl/.gitignore",
"templates/plugin_cocoapods/ios-objc.tmpl/Classes/pluginClass.h.tmpl",
"templates/plugin_cocoapods/ios-objc.tmpl/Classes/pluginClass.m.tmpl",
"templates/plugin_cocoapods/ios-swift.tmpl/Classes/pluginClass.swift.tmpl",
"templates/plugin_cocoapods/ios.tmpl/Assets/.gitkeep",
"templates/plugin_cocoapods/macos.tmpl/Classes/pluginClass.swift.tmpl",
"templates/plugin_swift_package_manager/ios-objc.tmpl/projectName.tmpl/Sources/projectName.tmpl/include/projectName.tmpl/pluginClass.h.tmpl",
"templates/plugin_swift_package_manager/ios-objc.tmpl/projectName.tmpl/Sources/projectName.tmpl/pluginClass.m.tmpl",
"templates/plugin_swift_package_manager/ios-objc.tmpl/projectName.tmpl/Package.swift.tmpl",
"templates/plugin_swift_package_manager/ios-swift.tmpl/projectName.tmpl/Sources/projectName.tmpl/pluginClass.swift.tmpl",
"templates/plugin_swift_package_manager/ios-swift.tmpl/projectName.tmpl/Package.swift.tmpl",
"templates/plugin_swift_package_manager/ios.tmpl/projectName.tmpl/Sources/projectName.tmpl/Resources/.gitkeep",
"templates/plugin_swift_package_manager/macos.tmpl/projectName.tmpl/Sources/projectName.tmpl/Resources/.gitkeep",
"templates/plugin_swift_package_manager/macos.tmpl/projectName.tmpl/Sources/projectName.tmpl/pluginClass.swift.tmpl",
"templates/plugin_swift_package_manager/macos.tmpl/projectName.tmpl/Package.swift.tmpl",
"templates/skeleton/assets/images/2.0x/flutter_logo.png.img.tmpl",
"templates/skeleton/assets/images/3.0x/flutter_logo.png.img.tmpl",
"templates/skeleton/assets/images/flutter_logo.png.img.tmpl",

View file

@ -87,6 +87,7 @@ void main() {
globals.fs.path.join('flutter', 'packages', 'flutter_tools', 'templates', 'plugin'),
globals.fs.path.join('flutter', 'packages', 'flutter_tools', 'templates', 'plugin_ffi'),
globals.fs.path.join('flutter', 'packages', 'flutter_tools', 'templates', 'plugin_shared'),
globals.fs.path.join('flutter', 'packages', 'flutter_tools', 'templates', 'plugin_cocoapods'),
];
for (final String templatePath in templatePaths) {
globals.fs.directory(templatePath).createSync(recursive: true);

View file

@ -718,6 +718,55 @@ void main() {
);
});
testUsingContext('swift plugin project with Swift Package Manager', () async {
return _createProject(
projectDir,
<String>['--no-pub', '--template=plugin', '--ios-language', 'swift', '--platforms', 'ios,macos'],
<String>[
'ios/flutter_project/Package.swift',
'ios/flutter_project/Sources/flutter_project/FlutterProjectPlugin.swift',
'ios/flutter_project/Sources/flutter_project/Resources/.gitkeep',
'macos/flutter_project/Package.swift',
'macos/flutter_project/Sources/flutter_project/FlutterProjectPlugin.swift',
'macos/flutter_project/Sources/flutter_project/Resources/.gitkeep',
],
unexpectedPaths: <String>[
'ios/Classes/FlutterProjectPlugin.swift',
'macos/Classes/FlutterProjectPlugin.swift',
'ios/Classes/FlutterProjectPlugin.h',
'ios/Classes/FlutterProjectPlugin.m',
'ios/Assets/.gitkeep',
'macos/Assets/.gitkeep',
],
);
}, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(
isSwiftPackageManagerEnabled: true,
isMacOSEnabled: true,
),
});
testUsingContext('objc plugin project with Swift Package Manager', () async {
return _createProject(
projectDir,
<String>['--no-pub', '--template=plugin', '--ios-language', 'objc', '--platforms', 'ios'],
<String>[
'ios/flutter_project/Package.swift',
'ios/flutter_project/Sources/flutter_project/include/flutter_project/FlutterProjectPlugin.h',
'ios/flutter_project/Sources/flutter_project/FlutterProjectPlugin.m',
'ios/flutter_project/Sources/flutter_project/Resources/.gitkeep',
],
unexpectedPaths: <String>[
'ios/Classes/FlutterProjectPlugin.swift',
'ios/Classes/FlutterProjectPlugin.h',
'ios/Classes/FlutterProjectPlugin.m',
'ios/Assets/.gitkeep',
],
);
}, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isSwiftPackageManagerEnabled: true),
});
testUsingContext('plugin project with custom org', () async {
return _createProject(
projectDir,

View file

@ -0,0 +1,151 @@
// Copyright 2014 The Flutter 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_tools/src/base/error_handling_io.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import '../src/common.dart';
import 'swift_package_manager_utils.dart';
import 'test_utils.dart';
void main() {
final String flutterBin = fileSystem.path.join(
getFlutterRoot(),
'bin',
'flutter',
);
final List<String> platforms = <String>['ios', 'macos'];
for (final String platformName in platforms) {
final List<String> iosLanguages = <String>[
if (platformName == 'ios') 'objc',
'swift',
];
for (final String iosLanguage in iosLanguages) {
test('Create $platformName $iosLanguage app with Swift Package Manager disabled', () async {
final Directory workingDirectory = fileSystem.systemTempDirectory
.createTempSync('swift_package_manager_create_app_disabled.');
final String workingDirectoryPath = workingDirectory.path;
try {
await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
final String appDirectoryPath = await SwiftPackageManagerUtils.createApp(
flutterBin,
workingDirectoryPath,
iosLanguage: iosLanguage,
platform: platformName,
options: <String>['--platforms=$platformName'],
);
final File pbxprojFile = fileSystem
.directory(appDirectoryPath)
.childDirectory(platformName)
.childDirectory('Runner.xcodeproj')
.childFile('project.pbxproj');
expect(pbxprojFile.existsSync(), isTrue);
expect(
pbxprojFile.readAsStringSync().contains('FlutterGeneratedPluginSwiftPackage'),
isFalse,
);
final File xcschemeFile = fileSystem
.directory(appDirectoryPath)
.childDirectory(platformName)
.childDirectory('Runner.xcodeproj')
.childDirectory('xcshareddata')
.childDirectory('xcschemes')
.childFile('Runner.xcscheme');
expect(xcschemeFile.existsSync(), isTrue);
expect(
xcschemeFile.readAsStringSync().contains('Run Prepare Flutter Framework Script'),
isFalse,
);
await SwiftPackageManagerUtils.buildApp(
flutterBin,
appDirectoryPath,
options: <String>[platformName, '--debug', '-v'],
expectedLines: SwiftPackageManagerUtils.expectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
),
unexpectedLines: SwiftPackageManagerUtils.unexpectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
),
);
} finally {
await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
ErrorHandlingFileSystem.deleteIfExists(
workingDirectory,
recursive: true,
);
}
}, skip: !platform.isMacOS); // [intended] Swift Package Manager only works on macos.
test('Create $platformName $iosLanguage app with Swift Package Manager enabled', () async {
final Directory workingDirectory = fileSystem.systemTempDirectory
.createTempSync('swift_package_manager_create_app_enabled.');
final String workingDirectoryPath = workingDirectory.path;
try {
await SwiftPackageManagerUtils.enableSwiftPackageManager(flutterBin, workingDirectoryPath);
final String appDirectoryPath = await SwiftPackageManagerUtils.createApp(
flutterBin,
workingDirectoryPath,
iosLanguage: iosLanguage,
platform: platformName,
options: <String>['--platforms=$platformName'],
);
final File pbxprojFile = fileSystem
.directory(appDirectoryPath)
.childDirectory(platformName)
.childDirectory('Runner.xcodeproj')
.childFile('project.pbxproj');
expect(pbxprojFile.existsSync(), isTrue);
expect(
pbxprojFile.readAsStringSync(),
contains('FlutterGeneratedPluginSwiftPackage'),
);
final File xcschemeFile = fileSystem
.directory(appDirectoryPath)
.childDirectory(platformName)
.childDirectory('Runner.xcodeproj')
.childDirectory('xcshareddata')
.childDirectory('xcschemes')
.childFile('Runner.xcscheme');
expect(xcschemeFile.existsSync(), isTrue);
expect(
xcschemeFile.readAsStringSync(),
contains('Run Prepare Flutter Framework Script'),
);
await SwiftPackageManagerUtils.buildApp(
flutterBin,
appDirectoryPath,
options: <String>[platformName, '--debug', '-v'],
expectedLines: SwiftPackageManagerUtils.expectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
),
unexpectedLines: SwiftPackageManagerUtils.unexpectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
),
);
} finally {
await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
ErrorHandlingFileSystem.deleteIfExists(
workingDirectory,
recursive: true,
);
}
}, skip: !platform.isMacOS); // [intended] Swift Package Manager only works on macos.
}
}
}

View file

@ -0,0 +1,175 @@
// Copyright 2014 The Flutter 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_tools/src/base/error_handling_io.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import '../src/common.dart';
import 'swift_package_manager_utils.dart';
import 'test_utils.dart';
void main() {
final String flutterBin = fileSystem.path.join(
getFlutterRoot(),
'bin',
'flutter',
);
final List<String> platforms = <String>['ios', 'macos'];
for (final String platformName in platforms) {
final List<String> iosLanguages = <String>[
if (platformName == 'ios') 'objc',
'swift',
];
for (final String iosLanguage in iosLanguages) {
test('Create $platformName $iosLanguage plugin with Swift Package Manager disabled', () async {
final Directory workingDirectory = fileSystem.systemTempDirectory
.createTempSync('swift_package_manager_create_plugin_disabled.');
final String workingDirectoryPath = workingDirectory.path;
try {
await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
final SwiftPackageManagerPlugin createdCocoaPodsPlugin = await SwiftPackageManagerUtils.createPlugin(
flutterBin,
workingDirectoryPath,
platform: platformName,
iosLanguage: iosLanguage,
);
final String appDirectoryPath = createdCocoaPodsPlugin.exampleAppPath;
final File pbxprojFile = fileSystem
.directory(appDirectoryPath)
.childDirectory(platformName)
.childDirectory('Runner.xcodeproj')
.childFile('project.pbxproj');
expect(pbxprojFile.existsSync(), isTrue);
expect(
pbxprojFile.readAsStringSync().contains('FlutterGeneratedPluginSwiftPackage'),
isFalse,
);
final File xcschemeFile = fileSystem
.directory(appDirectoryPath)
.childDirectory(platformName)
.childDirectory('Runner.xcodeproj')
.childDirectory('xcshareddata')
.childDirectory('xcschemes')
.childFile('Runner.xcscheme');
expect(xcschemeFile.existsSync(), isTrue);
expect(
xcschemeFile.readAsStringSync().contains('Run Prepare Flutter Framework Script'),
isFalse,
);
final File podspec = fileSystem
.directory(createdCocoaPodsPlugin.pluginPath)
.childDirectory(platformName)
.childFile('${createdCocoaPodsPlugin.pluginName}.podspec');
expect(podspec.existsSync(), isTrue);
expect(podspec.readAsStringSync(), contains('Classes'));
expect(podspec.readAsStringSync().contains('Sources'), isFalse);
await SwiftPackageManagerUtils.buildApp(
flutterBin,
appDirectoryPath,
options: <String>[platformName, '--debug', '-v'],
expectedLines: SwiftPackageManagerUtils.expectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
cocoaPodsPlugin: createdCocoaPodsPlugin,
),
unexpectedLines: SwiftPackageManagerUtils.unexpectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
cocoaPodsPlugin: createdCocoaPodsPlugin,
),
);
} finally {
await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
ErrorHandlingFileSystem.deleteIfExists(
workingDirectory,
recursive: true,
);
}
}, skip: !platform.isMacOS); // [intended] Swift Package Manager only works on macos.
test('Create $platformName $iosLanguage plugin with Swift Package Manager enabled', () async {
final Directory workingDirectory = fileSystem.systemTempDirectory
.createTempSync('swift_package_manager_create_plugin_enabled.');
final String workingDirectoryPath = workingDirectory.path;
try {
await SwiftPackageManagerUtils.enableSwiftPackageManager(flutterBin, workingDirectoryPath);
final SwiftPackageManagerPlugin createdSwiftPackagePlugin = await SwiftPackageManagerUtils.createPlugin(
flutterBin,
workingDirectoryPath,
platform: platformName,
iosLanguage: iosLanguage,
);
final String appDirectoryPath = createdSwiftPackagePlugin.exampleAppPath;
final File pbxprojFile = fileSystem
.directory(appDirectoryPath)
.childDirectory(platformName)
.childDirectory('Runner.xcodeproj')
.childFile('project.pbxproj');
expect(pbxprojFile.existsSync(), isTrue);
expect(
pbxprojFile.readAsStringSync(),
contains('FlutterGeneratedPluginSwiftPackage'),
);
final File xcschemeFile = fileSystem
.directory(appDirectoryPath)
.childDirectory(platformName)
.childDirectory('Runner.xcodeproj')
.childDirectory('xcshareddata')
.childDirectory('xcschemes')
.childFile('Runner.xcscheme');
expect(xcschemeFile.existsSync(), isTrue);
expect(
xcschemeFile.readAsStringSync(),
contains('Run Prepare Flutter Framework Script'),
);
final File podspec = fileSystem
.directory(createdSwiftPackagePlugin.pluginPath)
.childDirectory(platformName)
.childFile('${createdSwiftPackagePlugin.pluginName}.podspec');
expect(podspec.existsSync(), isTrue);
expect(podspec.readAsStringSync(), contains('Sources'));
expect(podspec.readAsStringSync().contains('Classes'), isFalse);
await SwiftPackageManagerUtils.buildApp(
flutterBin,
appDirectoryPath,
options: <String>[platformName, '--debug', '-v'],
expectedLines: SwiftPackageManagerUtils.expectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
swiftPackagePlugin: createdSwiftPackagePlugin,
swiftPackageMangerEnabled: true,
),
unexpectedLines: SwiftPackageManagerUtils.unexpectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
swiftPackagePlugin: createdSwiftPackagePlugin,
swiftPackageMangerEnabled: true,
),
);
} finally {
await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
ErrorHandlingFileSystem.deleteIfExists(
workingDirectory,
recursive: true,
);
}
}, skip: !platform.isMacOS); // [intended] Swift Package Manager only works on macos.
}
}
}

View file

@ -2,13 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:flutter_tools/src/base/error_handling_io.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import '../src/common.dart';
import 'swift_package_manager_utils.dart';
import 'test_utils.dart';
void main() {
@ -24,39 +22,36 @@ void main() {
if (platformName == 'ios') 'objc',
'swift',
];
final _Plugin integrationTestPlugin = _integrationTestPlugin(platformName);
final SwiftPackageManagerPlugin integrationTestPlugin = SwiftPackageManagerUtils.integrationTestPlugin(platformName);
for (final String iosLanguage in iosLanguages) {
test('Swift Package Manager not used when feature is disabled for $platformName with $iosLanguage', () async {
test('Swift Package Manager integration for $platformName with $iosLanguage', () async {
final Directory workingDirectory = fileSystem.systemTempDirectory
.createTempSync('swift_package_manager_disabled.');
.createTempSync('swift_package_manager_enabled.');
final String workingDirectoryPath = workingDirectory.path;
try {
await _disableSwiftPackageManager(flutterBin, workingDirectoryPath);
// Create and build an app using the CocoaPods version of
// integration_test.
final String appDirectoryPath = await _createApp(
await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
final String appDirectoryPath = await SwiftPackageManagerUtils.createApp(
flutterBin,
workingDirectoryPath,
iosLanguage: iosLanguage,
platform: platformName,
usesSwiftPackageManager: true,
options: <String>['--platforms=$platformName'],
);
_addDependency(
appDirectoryPath: appDirectoryPath,
plugin: integrationTestPlugin,
);
await _buildApp(
SwiftPackageManagerUtils.addDependency(appDirectoryPath: appDirectoryPath, plugin: integrationTestPlugin);
await SwiftPackageManagerUtils.buildApp(
flutterBin,
appDirectoryPath,
options: <String>[platformName, '--debug', '-v'],
expectedLines: _expectedLines(
expectedLines: SwiftPackageManagerUtils.expectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
cocoaPodsPlugin: integrationTestPlugin,
),
unexpectedLines: _unexpectedLines(
unexpectedLines: SwiftPackageManagerUtils.unexpectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
cocoaPodsPlugin: integrationTestPlugin,
@ -81,47 +76,34 @@ void main() {
.existsSync(),
isFalse,
);
} finally {
ErrorHandlingFileSystem.deleteIfExists(
workingDirectory,
recursive: true,
);
}
}, skip: !platform.isMacOS); // [intended] Swift Package Manager only works on macos.
test('Swift Package Manager integration for $platformName with $iosLanguage', () async {
final Directory workingDirectory = fileSystem.systemTempDirectory
.createTempSync('swift_package_manager_enabled.');
final String workingDirectoryPath = workingDirectory.path;
try {
// Create and build an app using the Swift Package Manager version of
// integration_test.
await _enableSwiftPackageManager(flutterBin, workingDirectoryPath);
final String appDirectoryPath = await _createApp(
final SwiftPackageManagerPlugin createdCocoaPodsPlugin = await SwiftPackageManagerUtils.createPlugin(
flutterBin,
workingDirectoryPath,
iosLanguage: iosLanguage,
platform: platformName,
usesSwiftPackageManager: true,
options: <String>['--platforms=$platformName'],
iosLanguage: iosLanguage,
);
_addDependency(appDirectoryPath: appDirectoryPath, plugin: integrationTestPlugin);
await _buildApp(
// Rebuild app with Swift Package Manager enabled, migrating the app and using the Swift Package Manager version of
// integration_test.
await SwiftPackageManagerUtils.enableSwiftPackageManager(flutterBin, workingDirectoryPath);
await SwiftPackageManagerUtils.buildApp(
flutterBin,
appDirectoryPath,
options: <String>[platformName, '--debug', '-v'],
expectedLines: _expectedLines(
expectedLines: SwiftPackageManagerUtils.expectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
swiftPackageMangerEnabled: true,
swiftPackagePlugin: integrationTestPlugin,
migrated: true,
),
unexpectedLines: _unexpectedLines(
unexpectedLines: SwiftPackageManagerUtils.unexpectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
swiftPackageMangerEnabled: true,
swiftPackagePlugin: integrationTestPlugin,
migrated: true,
),
);
@ -131,7 +113,7 @@ void main() {
.childDirectory(platformName)
.childFile('Podfile')
.existsSync(),
isFalse,
isTrue,
);
expect(
fileSystem
@ -146,29 +128,22 @@ void main() {
);
// Build an app using both a CocoaPods and Swift Package Manager plugin.
await _cleanApp(flutterBin, appDirectoryPath);
final _Plugin createdCocoaPodsPlugin = await _createPlugin(
flutterBin,
workingDirectoryPath,
platform: platformName,
iosLanguage: iosLanguage,
);
_addDependency(
SwiftPackageManagerUtils.addDependency(
appDirectoryPath: appDirectoryPath,
plugin: createdCocoaPodsPlugin,
);
await _buildApp(
await SwiftPackageManagerUtils.buildApp(
flutterBin,
appDirectoryPath,
options: <String>[platformName, '--debug', '-v'],
expectedLines: _expectedLines(
expectedLines: SwiftPackageManagerUtils.expectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
cocoaPodsPlugin: createdCocoaPodsPlugin,
swiftPackageMangerEnabled: true,
swiftPackagePlugin: integrationTestPlugin,
),
unexpectedLines: _unexpectedLines(
unexpectedLines: SwiftPackageManagerUtils.unexpectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
cocoaPodsPlugin: createdCocoaPodsPlugin,
@ -199,18 +174,18 @@ void main() {
// Build app again but with Swift Package Manager disabled by config.
// App will now use CocoaPods version of integration_test plugin.
await _disableSwiftPackageManager(flutterBin, workingDirectoryPath);
await _cleanApp(flutterBin, appDirectoryPath);
await _buildApp(
await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
await SwiftPackageManagerUtils.cleanApp(flutterBin, appDirectoryPath);
await SwiftPackageManagerUtils.buildApp(
flutterBin,
appDirectoryPath,
options: <String>[platformName, '--debug', '-v'],
expectedLines: _expectedLines(
expectedLines: SwiftPackageManagerUtils.expectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
cocoaPodsPlugin: integrationTestPlugin,
),
unexpectedLines: _unexpectedLines(
unexpectedLines: SwiftPackageManagerUtils.unexpectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
cocoaPodsPlugin: integrationTestPlugin,
@ -219,26 +194,26 @@ void main() {
// Build app again but with Swift Package Manager disabled by pubspec.
// App will still use CocoaPods version of integration_test plugin.
await _enableSwiftPackageManager(flutterBin, workingDirectoryPath);
await _cleanApp(flutterBin, appDirectoryPath);
_disableSwiftPackageManagerByPubspec(appDirectoryPath: appDirectoryPath);
await _buildApp(
await SwiftPackageManagerUtils.enableSwiftPackageManager(flutterBin, workingDirectoryPath);
await SwiftPackageManagerUtils.cleanApp(flutterBin, appDirectoryPath);
SwiftPackageManagerUtils.disableSwiftPackageManagerByPubspec(appDirectoryPath: appDirectoryPath);
await SwiftPackageManagerUtils.buildApp(
flutterBin,
appDirectoryPath,
options: <String>[platformName, '--debug', '-v'],
expectedLines: _expectedLines(
expectedLines: SwiftPackageManagerUtils.expectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
cocoaPodsPlugin: integrationTestPlugin,
),
unexpectedLines: _unexpectedLines(
unexpectedLines: SwiftPackageManagerUtils.unexpectedLines(
platform: platformName,
appDirectoryPath: appDirectoryPath,
cocoaPodsPlugin: integrationTestPlugin,
),
);
} finally {
await _disableSwiftPackageManager(flutterBin, workingDirectoryPath);
await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
ErrorHandlingFileSystem.deleteIfExists(
workingDirectory,
recursive: true,
@ -254,9 +229,9 @@ void main() {
try {
// Create and build an app using the Swift Package Manager version of
// integration_test.
await _enableSwiftPackageManager(flutterBin, workingDirectoryPath);
await SwiftPackageManagerUtils.enableSwiftPackageManager(flutterBin, workingDirectoryPath);
final String appDirectoryPath = await _createApp(
final String appDirectoryPath = await SwiftPackageManagerUtils.createApp(
flutterBin,
workingDirectoryPath,
iosLanguage: 'swift',
@ -264,15 +239,12 @@ void main() {
usesSwiftPackageManager: true,
options: <String>['--platforms=$platformName'],
);
_addDependency(appDirectoryPath: appDirectoryPath, plugin: integrationTestPlugin);
SwiftPackageManagerUtils.addDependency(appDirectoryPath: appDirectoryPath, plugin: integrationTestPlugin);
await _buildApp(
await SwiftPackageManagerUtils.buildApp(
flutterBin,
appDirectoryPath,
options: <String>[platformName, '--config-only', '-v'],
expectedLines: <String>[
'Adding Swift Package Manager integration...'
]
);
expect(
@ -297,7 +269,7 @@ void main() {
// Create and build framework using the CocoaPods version of
// integration_test even though Swift Package Manager is enabled.
await _buildApp(
await SwiftPackageManagerUtils.buildApp(
flutterBin,
appDirectoryPath,
options: <String>[
@ -323,7 +295,7 @@ void main() {
isTrue,
);
} finally {
await _disableSwiftPackageManager(flutterBin, workingDirectoryPath);
await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
ErrorHandlingFileSystem.deleteIfExists(
workingDirectory,
recursive: true,
@ -339,9 +311,9 @@ void main() {
try {
// Create and build module and framework using the CocoaPods version of
// integration_test even though Swift Package Manager is enabled.
await _enableSwiftPackageManager(flutterBin, workingDirectoryPath);
await SwiftPackageManagerUtils.enableSwiftPackageManager(flutterBin, workingDirectoryPath);
final String appDirectoryPath = await _createApp(
final String appDirectoryPath = await SwiftPackageManagerUtils.createApp(
flutterBin,
workingDirectoryPath,
iosLanguage: 'swift',
@ -349,16 +321,13 @@ void main() {
usesSwiftPackageManager: true,
options: <String>['--template=module'],
);
final _Plugin integrationTestPlugin = _integrationTestPlugin('ios');
_addDependency(appDirectoryPath: appDirectoryPath, plugin: integrationTestPlugin);
final SwiftPackageManagerPlugin integrationTestPlugin = SwiftPackageManagerUtils.integrationTestPlugin('ios');
SwiftPackageManagerUtils.addDependency(appDirectoryPath: appDirectoryPath, plugin: integrationTestPlugin);
await _buildApp(
await SwiftPackageManagerUtils.buildApp(
flutterBin,
appDirectoryPath,
options: <String>['ios', '--config-only', '-v'],
unexpectedLines: <String>[
'Adding Swift Package Manager integration...'
]
);
expect(
@ -380,8 +349,30 @@ void main() {
.existsSync(),
isFalse,
);
final File pbxprojFile = fileSystem
.directory(appDirectoryPath)
.childDirectory('.ios')
.childDirectory('Runner.xcodeproj')
.childFile('project.pbxproj');
expect(pbxprojFile.existsSync(), isTrue);
expect(
pbxprojFile.readAsStringSync().contains('FlutterGeneratedPluginSwiftPackage'),
isFalse,
);
final File xcschemeFile = fileSystem
.directory(appDirectoryPath)
.childDirectory('.ios')
.childDirectory('Runner.xcodeproj')
.childDirectory('xcshareddata')
.childDirectory('xcschemes')
.childFile('Runner.xcscheme');
expect(xcschemeFile.existsSync(), isTrue);
expect(
xcschemeFile.readAsStringSync().contains('Run Prepare Flutter Framework Script'),
isFalse,
);
await _buildApp(
await SwiftPackageManagerUtils.buildApp(
flutterBin,
appDirectoryPath,
options: <String>[
@ -408,7 +399,7 @@ void main() {
isTrue,
);
} finally {
await _disableSwiftPackageManager(flutterBin, workingDirectoryPath);
await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
ErrorHandlingFileSystem.deleteIfExists(
workingDirectory,
recursive: true,
@ -416,355 +407,3 @@ void main() {
}
}, skip: !platform.isMacOS); // [intended] Swift Package Manager only works on macos.
}
Future<void> _enableSwiftPackageManager(
String flutterBin,
String workingDirectory,
) async {
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'config',
'--enable-swift-package-manager',
'-v',
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to enable Swift Package Manager: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
verbose: true,
);
}
Future<void> _disableSwiftPackageManager(
String flutterBin,
String workingDirectory,
) async {
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'config',
'--no-enable-swift-package-manager',
'-v',
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to disable Swift Package Manager: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
verbose: true,
);
}
Future<String> _createApp(
String flutterBin,
String workingDirectory, {
required String platform,
required String iosLanguage,
required List<String> options,
bool usesSwiftPackageManager = false,
}) async {
final String appTemplateType = usesSwiftPackageManager ? 'spm' : 'default';
final String appName = '${platform}_${iosLanguage}_${appTemplateType}_app';
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'create',
'--org',
'io.flutter.devicelab',
'-i',
iosLanguage,
...options,
appName,
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to create app: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
return fileSystem.path.join(
workingDirectory,
appName,
);
}
Future<void> _buildApp(
String flutterBin,
String workingDirectory, {
required List<String> options,
List<Pattern>? expectedLines,
List<String>? unexpectedLines,
}) async {
final List<Pattern> remainingExpectedLines = expectedLines ?? <Pattern>[];
final List<String> unexpectedLinesFound = <String>[];
final List<String> command = <String>[
flutterBin,
...getLocalEngineArguments(),
'build',
...options,
];
final ProcessResult result = await processManager.run(
command,
workingDirectory: workingDirectory,
);
final List<String> stdout = LineSplitter.split(result.stdout.toString()).toList();
final List<String> stderr = LineSplitter.split(result.stderr.toString()).toList();
final List<String> output = stdout + stderr;
for (final String line in output) {
// Remove "[ +3 ms] " prefix
String trimmedLine = line.trim();
if (trimmedLine.startsWith('[')) {
final int prefixEndIndex = trimmedLine.indexOf(']');
if (prefixEndIndex > 0) {
trimmedLine = trimmedLine
.substring(prefixEndIndex + 1, trimmedLine.length)
.trim();
}
}
remainingExpectedLines.remove(trimmedLine);
remainingExpectedLines.removeWhere((Pattern expectedLine) => trimmedLine.contains(expectedLine));
if (unexpectedLines != null && unexpectedLines.contains(trimmedLine)) {
unexpectedLinesFound.add(trimmedLine);
}
}
expect(
result.exitCode,
0,
reason: 'Failed to build app for "${command.join(' ')}":\n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
expect(
remainingExpectedLines,
isEmpty,
reason: 'Did not find expected lines for "${command.join(' ')}":\n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
expect(
unexpectedLinesFound,
isEmpty,
reason: 'Found unexpected lines for "${command.join(' ')}":\n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
}
Future<void> _cleanApp(String flutterBin, String workingDirectory) async {
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'clean',
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to clean app: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
}
Future<_Plugin> _createPlugin(
String flutterBin,
String workingDirectory, {
required String platform,
required String iosLanguage,
bool usesSwiftPackageManager = false,
}) async {
final String dependencyManager = usesSwiftPackageManager ? 'spm' : 'cocoapods';
// Create plugin
final String pluginName = '${platform}_${iosLanguage}_${dependencyManager}_plugin';
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'create',
'--org',
'io.flutter.devicelab',
'--template=plugin',
'--platforms=$platform',
'-i',
iosLanguage,
pluginName,
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to create plugin: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
final Directory pluginDirectory = fileSystem.directory(
fileSystem.path.join(workingDirectory, pluginName),
);
return _Plugin(
pluginName: pluginName,
pluginPath: pluginDirectory.path,
platform: platform,
);
}
void _addDependency({
required _Plugin plugin,
required String appDirectoryPath,
}) {
final File pubspec = fileSystem.file(
fileSystem.path.join(appDirectoryPath, 'pubspec.yaml'),
);
final String pubspecContent = pubspec.readAsStringSync();
pubspec.writeAsStringSync(
pubspecContent.replaceFirst(
'\ndependencies:\n',
'\ndependencies:\n ${plugin.pluginName}:\n path: ${plugin.pluginPath}\n',
),
);
}
void _disableSwiftPackageManagerByPubspec({
required String appDirectoryPath,
}) {
final File pubspec = fileSystem.file(
fileSystem.path.join(appDirectoryPath, 'pubspec.yaml'),
);
final String pubspecContent = pubspec.readAsStringSync();
pubspec.writeAsStringSync(
pubspecContent.replaceFirst(
'\n# The following section is specific to Flutter packages.\nflutter:\n',
'\n# The following section is specific to Flutter packages.\nflutter:\n disable-swift-package-manager: true',
),
);
}
_Plugin _integrationTestPlugin(String platform) {
final String flutterRoot = getFlutterRoot();
return _Plugin(
platform: platform,
pluginName:
(platform == 'ios') ? 'integration_test' : 'integration_test_macos',
pluginPath: (platform == 'ios')
? fileSystem.path.join(flutterRoot, 'packages', 'integration_test')
: fileSystem.path.join(flutterRoot, 'packages', 'integration_test', 'integration_test_macos'),
);
}
List<Pattern> _expectedLines({
required String platform,
required String appDirectoryPath,
_Plugin? cocoaPodsPlugin,
_Plugin? swiftPackagePlugin,
bool swiftPackageMangerEnabled = false,
}) {
final String frameworkName = platform == 'ios' ? 'Flutter' : 'FlutterMacOS';
final String appPlatformDirectoryPath = fileSystem.path.join(
appDirectoryPath,
platform,
);
final List<Pattern> expectedLines = <Pattern>[];
if (swiftPackageMangerEnabled) {
expectedLines.addAll(<String>[
'FlutterGeneratedPluginSwiftPackage: $appPlatformDirectoryPath/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage',
"➜ Explicit dependency on target 'FlutterGeneratedPluginSwiftPackage' in project 'FlutterGeneratedPluginSwiftPackage'",
]);
}
if (swiftPackagePlugin != null) {
// If using a Swift Package plugin, but Swift Package Manager is not enabled, it falls back to being used as a CocoaPods plugin.
if (swiftPackageMangerEnabled) {
expectedLines.addAll(<Pattern>[
RegExp('${swiftPackagePlugin.pluginName}: [/private]*${swiftPackagePlugin.pluginPath}/$platform/${swiftPackagePlugin.pluginName} @ local'),
"➜ Explicit dependency on target '${swiftPackagePlugin.pluginName}' in project '${swiftPackagePlugin.pluginName}'",
]);
} else {
expectedLines.addAll(<String>[
'-> Installing ${swiftPackagePlugin.pluginName} (0.0.1)',
"➜ Explicit dependency on target '${swiftPackagePlugin.pluginName}' in project 'Pods'",
]);
}
}
if (cocoaPodsPlugin != null) {
expectedLines.addAll(<String>[
'Running pod install...',
'-> Installing $frameworkName (1.0.0)',
'-> Installing ${cocoaPodsPlugin.pluginName} (0.0.1)',
"Target 'Pods-Runner' in project 'Pods'",
"➜ Explicit dependency on target '$frameworkName' in project 'Pods'",
"➜ Explicit dependency on target '${cocoaPodsPlugin.pluginName}' in project 'Pods'",
]);
}
return expectedLines;
}
List<String> _unexpectedLines({
required String platform,
required String appDirectoryPath,
_Plugin? cocoaPodsPlugin,
_Plugin? swiftPackagePlugin,
bool swiftPackageMangerEnabled = false,
}) {
final String frameworkName = platform == 'ios' ? 'Flutter' : 'FlutterMacOS';
final List<String> unexpectedLines = <String>[];
if (cocoaPodsPlugin == null) {
unexpectedLines.addAll(<String>[
'Running pod install...',
'-> Installing $frameworkName (1.0.0)',
"Target 'Pods-Runner' in project 'Pods'",
]);
}
if (swiftPackagePlugin != null) {
if (swiftPackageMangerEnabled) {
unexpectedLines.addAll(<String>[
'-> Installing ${swiftPackagePlugin.pluginName} (0.0.1)',
"➜ Explicit dependency on target '${swiftPackagePlugin.pluginName}' in project 'Pods'",
]);
} else {
unexpectedLines.addAll(<String>[
'${swiftPackagePlugin.pluginName}: ${swiftPackagePlugin.pluginPath}/$platform/${swiftPackagePlugin.pluginName} @ local',
"➜ Explicit dependency on target '${swiftPackagePlugin.pluginName}' in project '${swiftPackagePlugin.pluginName}'",
]);
}
}
return unexpectedLines;
}
class _Plugin {
_Plugin({
required this.pluginName,
required this.pluginPath,
required this.platform,
});
final String pluginName;
final String pluginPath;
final String platform;
String get exampleAppPath => fileSystem.path.join(pluginPath, 'example');
String get exampleAppPlatformPath => fileSystem.path.join(exampleAppPath, platform);
}

View file

@ -0,0 +1,379 @@
// Copyright 2014 The Flutter 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:convert';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import '../src/common.dart';
import 'test_utils.dart';
class SwiftPackageManagerUtils {
static Future<void> enableSwiftPackageManager(
String flutterBin,
String workingDirectory,
) async {
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'config',
'--enable-swift-package-manager',
'-v',
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to enable Swift Package Manager: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
verbose: true,
);
}
static Future<void> disableSwiftPackageManager(
String flutterBin,
String workingDirectory,
) async {
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'config',
'--no-enable-swift-package-manager',
'-v',
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to disable Swift Package Manager: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
verbose: true,
);
}
static Future<String> createApp(
String flutterBin,
String workingDirectory, {
required String platform,
required String iosLanguage,
required List<String> options,
bool usesSwiftPackageManager = false,
}) async {
final String appTemplateType = usesSwiftPackageManager ? 'spm' : 'default';
final String appName = '${platform}_${iosLanguage}_${appTemplateType}_app';
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'create',
'--org',
'io.flutter.devicelab',
'-i',
iosLanguage,
...options,
appName,
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to create app: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
return fileSystem.path.join(
workingDirectory,
appName,
);
}
static Future<void> buildApp(
String flutterBin,
String workingDirectory, {
required List<String> options,
List<Pattern>? expectedLines,
List<String>? unexpectedLines,
}) async {
final List<Pattern> remainingExpectedLines = expectedLines ?? <Pattern>[];
final List<String> unexpectedLinesFound = <String>[];
final List<String> command = <String>[
flutterBin,
...getLocalEngineArguments(),
'build',
...options,
];
final ProcessResult result = await processManager.run(
command,
workingDirectory: workingDirectory,
);
final List<String> stdout = LineSplitter.split(result.stdout.toString()).toList();
final List<String> stderr = LineSplitter.split(result.stderr.toString()).toList();
final List<String> output = stdout + stderr;
for (final String line in output) {
// Remove "[ +3 ms] " prefix
String trimmedLine = line.trim();
if (trimmedLine.startsWith('[')) {
final int prefixEndIndex = trimmedLine.indexOf(']');
if (prefixEndIndex > 0) {
trimmedLine = trimmedLine
.substring(prefixEndIndex + 1, trimmedLine.length)
.trim();
}
}
remainingExpectedLines.remove(trimmedLine);
remainingExpectedLines.removeWhere((Pattern expectedLine) => trimmedLine.contains(expectedLine));
if (unexpectedLines != null && unexpectedLines.contains(trimmedLine)) {
unexpectedLinesFound.add(trimmedLine);
}
}
expect(
result.exitCode,
0,
reason: 'Failed to build app for "${command.join(' ')}":\n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
expect(
remainingExpectedLines,
isEmpty,
reason: 'Did not find expected lines for "${command.join(' ')}":\n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
expect(
unexpectedLinesFound,
isEmpty,
reason: 'Found unexpected lines for "${command.join(' ')}":\n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
}
static Future<void> cleanApp(String flutterBin, String workingDirectory) async {
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'clean',
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to clean app: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
}
static Future<SwiftPackageManagerPlugin> createPlugin(
String flutterBin,
String workingDirectory, {
required String platform,
required String iosLanguage,
bool usesSwiftPackageManager = false,
}) async {
final String dependencyManager = usesSwiftPackageManager ? 'spm' : 'cocoapods';
// Create plugin
final String pluginName = '${platform}_${iosLanguage}_${dependencyManager}_plugin';
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'create',
'--org',
'io.flutter.devicelab',
'--template=plugin',
'--platforms=$platform',
'-i',
iosLanguage,
pluginName,
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to create plugin: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
final Directory pluginDirectory = fileSystem.directory(
fileSystem.path.join(workingDirectory, pluginName),
);
return SwiftPackageManagerPlugin(
pluginName: pluginName,
pluginPath: pluginDirectory.path,
platform: platform,
);
}
static void addDependency({
required SwiftPackageManagerPlugin plugin,
required String appDirectoryPath,
}) {
final File pubspec = fileSystem.file(
fileSystem.path.join(appDirectoryPath, 'pubspec.yaml'),
);
final String pubspecContent = pubspec.readAsStringSync();
pubspec.writeAsStringSync(
pubspecContent.replaceFirst(
'\ndependencies:\n',
'\ndependencies:\n ${plugin.pluginName}:\n path: ${plugin.pluginPath}\n',
),
);
}
static void disableSwiftPackageManagerByPubspec({
required String appDirectoryPath,
}) {
final File pubspec = fileSystem.file(
fileSystem.path.join(appDirectoryPath, 'pubspec.yaml'),
);
final String pubspecContent = pubspec.readAsStringSync();
pubspec.writeAsStringSync(
pubspecContent.replaceFirst(
'\n# The following section is specific to Flutter packages.\nflutter:\n',
'\n# The following section is specific to Flutter packages.\nflutter:\n disable-swift-package-manager: true',
),
);
}
static SwiftPackageManagerPlugin integrationTestPlugin(String platform) {
final String flutterRoot = getFlutterRoot();
return SwiftPackageManagerPlugin(
platform: platform,
pluginName:
(platform == 'ios') ? 'integration_test' : 'integration_test_macos',
pluginPath: (platform == 'ios')
? fileSystem.path.join(flutterRoot, 'packages', 'integration_test')
: fileSystem.path.join(flutterRoot, 'packages', 'integration_test', 'integration_test_macos'),
);
}
static List<Pattern> expectedLines({
required String platform,
required String appDirectoryPath,
SwiftPackageManagerPlugin? cocoaPodsPlugin,
SwiftPackageManagerPlugin? swiftPackagePlugin,
bool swiftPackageMangerEnabled = false,
bool migrated = false,
}) {
final String frameworkName = platform == 'ios' ? 'Flutter' : 'FlutterMacOS';
final String appPlatformDirectoryPath = fileSystem.path.join(
appDirectoryPath,
platform,
);
final List<Pattern> expectedLines = <Pattern>[];
if (swiftPackageMangerEnabled) {
expectedLines.addAll(<String>[
'FlutterGeneratedPluginSwiftPackage: $appPlatformDirectoryPath/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage',
"➜ Explicit dependency on target 'FlutterGeneratedPluginSwiftPackage' in project 'FlutterGeneratedPluginSwiftPackage'",
]);
}
if (swiftPackagePlugin != null) {
// If using a Swift Package plugin, but Swift Package Manager is not enabled, it falls back to being used as a CocoaPods plugin.
if (swiftPackageMangerEnabled) {
expectedLines.addAll(<Pattern>[
RegExp('${swiftPackagePlugin.pluginName}: [/private]*${swiftPackagePlugin.pluginPath}/$platform/${swiftPackagePlugin.pluginName} @ local'),
"➜ Explicit dependency on target '${swiftPackagePlugin.pluginName}' in project '${swiftPackagePlugin.pluginName}'",
]);
} else {
expectedLines.addAll(<String>[
'-> Installing ${swiftPackagePlugin.pluginName} (0.0.1)',
"➜ Explicit dependency on target '${swiftPackagePlugin.pluginName}' in project 'Pods'",
]);
}
}
if (cocoaPodsPlugin != null) {
expectedLines.addAll(<String>[
'Running pod install...',
'-> Installing $frameworkName (1.0.0)',
'-> Installing ${cocoaPodsPlugin.pluginName} (0.0.1)',
"Target 'Pods-Runner' in project 'Pods'",
"➜ Explicit dependency on target '$frameworkName' in project 'Pods'",
"➜ Explicit dependency on target '${cocoaPodsPlugin.pluginName}' in project 'Pods'",
]);
}
if (migrated) {
expectedLines.addAll(<String>[
'Adding Swift Package Manager integration...',
'Running pod install...',
"Target 'Pods-Runner' in project 'Pods'",
]);
}
return expectedLines;
}
static List<String> unexpectedLines({
required String platform,
required String appDirectoryPath,
SwiftPackageManagerPlugin? cocoaPodsPlugin,
SwiftPackageManagerPlugin? swiftPackagePlugin,
bool swiftPackageMangerEnabled = false,
bool migrated = false,
}) {
final String frameworkName = platform == 'ios' ? 'Flutter' : 'FlutterMacOS';
final List<String> unexpectedLines = <String>[];
if (cocoaPodsPlugin == null && !migrated) {
unexpectedLines.addAll(<String>[
'Running pod install...',
'-> Installing $frameworkName (1.0.0)',
"Target 'Pods-Runner' in project 'Pods'",
]);
}
if (swiftPackagePlugin != null) {
if (swiftPackageMangerEnabled) {
unexpectedLines.addAll(<String>[
'-> Installing ${swiftPackagePlugin.pluginName} (0.0.1)',
"➜ Explicit dependency on target '${swiftPackagePlugin.pluginName}' in project 'Pods'",
]);
} else {
unexpectedLines.addAll(<String>[
'${swiftPackagePlugin.pluginName}: ${swiftPackagePlugin.pluginPath}/$platform/${swiftPackagePlugin.pluginName} @ local',
"➜ Explicit dependency on target '${swiftPackagePlugin.pluginName}' in project '${swiftPackagePlugin.pluginName}'",
]);
}
}
if (!migrated) {
unexpectedLines.addAll(<String>[
'Adding Swift Package Manager integration...',
]);
}
return unexpectedLines;
}
}
class SwiftPackageManagerPlugin {
SwiftPackageManagerPlugin({
required this.pluginName,
required this.pluginPath,
required this.platform,
});
final String pluginName;
final String pluginPath;
final String platform;
String get exampleAppPath => fileSystem.path.join(pluginPath, 'example');
String get exampleAppPlatformPath => fileSystem.path.join(exampleAppPath, platform);
}