1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'dart:convert';
6
7import 'package:file_testing/file_testing.dart';
8import 'package:flutter_tools/src/base/error_handling_io.dart';
9import 'package:flutter_tools/src/base/file_system.dart';
10
11import '../src/common.dart';
12import 'swift_package_manager_utils.dart';
13import 'test_utils.dart';
14
15void main() {
16 final List<String> platforms = <String>['ios', 'macos'];
17 for (final String platformName in platforms) {
18 final List<String> iosLanguages = <String>[if (platformName == 'ios') 'objc', 'swift'];
19 final SwiftPackageManagerPlugin integrationTestPlugin =
20 SwiftPackageManagerUtils.integrationTestPlugin(platformName);
21
22 for (final String iosLanguage in iosLanguages) {
23 test(
24 'Swift Package Manager integration for $platformName with $iosLanguage',
25 () async {
26 final Directory workingDirectory = fileSystem.systemTempDirectory.createTempSync(
27 'swift_package_manager_enabled.',
28 );
29 final String workingDirectoryPath = workingDirectory.path;
30
31 addTearDown(() async {
32 await SwiftPackageManagerUtils.disableSwiftPackageManager(
33 flutterBin,
34 workingDirectoryPath,
35 );
36 ErrorHandlingFileSystem.deleteIfExists(workingDirectory, recursive: true);
37 });
38
39 // Create and build an app using the CocoaPods version of
40 // integration_test.
41 await SwiftPackageManagerUtils.disableSwiftPackageManager(
42 flutterBin,
43 workingDirectoryPath,
44 );
45 final String appDirectoryPath = await SwiftPackageManagerUtils.createApp(
46 flutterBin,
47 workingDirectoryPath,
48 iosLanguage: iosLanguage,
49 platform: platformName,
50 usesSwiftPackageManager: true,
51 options: <String>['--platforms=$platformName'],
52 );
53 SwiftPackageManagerUtils.addDependency(
54 appDirectoryPath: appDirectoryPath,
55 plugin: integrationTestPlugin,
56 );
57 await SwiftPackageManagerUtils.buildApp(
58 flutterBin,
59 appDirectoryPath,
60 options: <String>[platformName, '--debug', '-v'],
61 expectedLines: SwiftPackageManagerUtils.expectedLines(
62 platform: platformName,
63 appDirectoryPath: appDirectoryPath,
64 cocoaPodsPlugin: integrationTestPlugin,
65 ),
66 unexpectedLines: SwiftPackageManagerUtils.unexpectedLines(
67 platform: platformName,
68 appDirectoryPath: appDirectoryPath,
69 cocoaPodsPlugin: integrationTestPlugin,
70 ),
71 );
72 expect(
73 fileSystem
74 .directory(appDirectoryPath)
75 .childDirectory(platformName)
76 .childFile('Podfile'),
77 exists,
78 );
79 expect(
80 fileSystem
81 .directory(appDirectoryPath)
82 .childDirectory(platformName)
83 .childDirectory('Flutter')
84 .childDirectory('ephemeral')
85 .childDirectory('Packages')
86 .childDirectory('FlutterGeneratedPluginSwiftPackage'),
87 isNot(exists),
88 );
89
90 final SwiftPackageManagerPlugin createdCocoaPodsPlugin =
91 await SwiftPackageManagerUtils.createPlugin(
92 flutterBin,
93 workingDirectoryPath,
94 platform: platformName,
95 iosLanguage: iosLanguage,
96 );
97
98 // Rebuild app with Swift Package Manager enabled, migrating the app and using the Swift Package Manager version of
99 // integration_test.
100 await SwiftPackageManagerUtils.enableSwiftPackageManager(
101 flutterBin,
102 workingDirectoryPath,
103 );
104 await SwiftPackageManagerUtils.buildApp(
105 flutterBin,
106 appDirectoryPath,
107 options: <String>[platformName, '--debug', '-v'],
108 expectedLines: SwiftPackageManagerUtils.expectedLines(
109 platform: platformName,
110 appDirectoryPath: appDirectoryPath,
111 swiftPackageMangerEnabled: true,
112 swiftPackagePlugin: integrationTestPlugin,
113 migrated: true,
114 ),
115 unexpectedLines: SwiftPackageManagerUtils.unexpectedLines(
116 platform: platformName,
117 appDirectoryPath: appDirectoryPath,
118 swiftPackageMangerEnabled: true,
119 swiftPackagePlugin: integrationTestPlugin,
120 migrated: true,
121 ),
122 );
123
124 expect(
125 fileSystem
126 .directory(appDirectoryPath)
127 .childDirectory(platformName)
128 .childFile('Podfile'),
129 exists,
130 );
131 expect(
132 fileSystem
133 .directory(appDirectoryPath)
134 .childDirectory(platformName)
135 .childDirectory('Flutter')
136 .childDirectory('ephemeral')
137 .childDirectory('Packages')
138 .childDirectory('FlutterGeneratedPluginSwiftPackage'),
139 exists,
140 );
141
142 // Build an app using both a CocoaPods and Swift Package Manager plugin.
143 SwiftPackageManagerUtils.addDependency(
144 appDirectoryPath: appDirectoryPath,
145 plugin: createdCocoaPodsPlugin,
146 );
147 await SwiftPackageManagerUtils.buildApp(
148 flutterBin,
149 appDirectoryPath,
150 options: <String>[platformName, '--debug', '-v'],
151 expectedLines: SwiftPackageManagerUtils.expectedLines(
152 platform: platformName,
153 appDirectoryPath: appDirectoryPath,
154 cocoaPodsPlugin: createdCocoaPodsPlugin,
155 swiftPackageMangerEnabled: true,
156 swiftPackagePlugin: integrationTestPlugin,
157 ),
158 unexpectedLines: SwiftPackageManagerUtils.unexpectedLines(
159 platform: platformName,
160 appDirectoryPath: appDirectoryPath,
161 cocoaPodsPlugin: createdCocoaPodsPlugin,
162 swiftPackageMangerEnabled: true,
163 swiftPackagePlugin: integrationTestPlugin,
164 ),
165 );
166
167 expect(
168 fileSystem
169 .directory(appDirectoryPath)
170 .childDirectory(platformName)
171 .childFile('Podfile'),
172 exists,
173 );
174 expect(
175 fileSystem
176 .directory(appDirectoryPath)
177 .childDirectory(platformName)
178 .childDirectory('Flutter')
179 .childDirectory('ephemeral')
180 .childDirectory('Packages')
181 .childDirectory('FlutterGeneratedPluginSwiftPackage'),
182 exists,
183 );
184
185 // Build app again but with Swift Package Manager disabled by config.
186 // App will now use CocoaPods version of integration_test plugin.
187 await SwiftPackageManagerUtils.disableSwiftPackageManager(
188 flutterBin,
189 workingDirectoryPath,
190 );
191 await SwiftPackageManagerUtils.cleanApp(flutterBin, appDirectoryPath);
192 await SwiftPackageManagerUtils.buildApp(
193 flutterBin,
194 appDirectoryPath,
195 options: <String>[platformName, '--debug', '-v'],
196 expectedLines: SwiftPackageManagerUtils.expectedLines(
197 platform: platformName,
198 appDirectoryPath: appDirectoryPath,
199 cocoaPodsPlugin: integrationTestPlugin,
200 ),
201 unexpectedLines: SwiftPackageManagerUtils.unexpectedLines(
202 platform: platformName,
203 appDirectoryPath: appDirectoryPath,
204 cocoaPodsPlugin: integrationTestPlugin,
205 ),
206 );
207
208 // Build app again but with Swift Package Manager disabled by pubspec.
209 // App will still use CocoaPods version of integration_test plugin.
210 await SwiftPackageManagerUtils.enableSwiftPackageManager(
211 flutterBin,
212 workingDirectoryPath,
213 );
214 await SwiftPackageManagerUtils.cleanApp(flutterBin, appDirectoryPath);
215 SwiftPackageManagerUtils.disableSwiftPackageManagerByPubspec(
216 appDirectoryPath: appDirectoryPath,
217 );
218 await SwiftPackageManagerUtils.buildApp(
219 flutterBin,
220 appDirectoryPath,
221 options: <String>[platformName, '--debug', '-v'],
222 expectedLines: SwiftPackageManagerUtils.expectedLines(
223 platform: platformName,
224 appDirectoryPath: appDirectoryPath,
225 cocoaPodsPlugin: integrationTestPlugin,
226 ),
227 unexpectedLines: SwiftPackageManagerUtils.unexpectedLines(
228 platform: platformName,
229 appDirectoryPath: appDirectoryPath,
230 cocoaPodsPlugin: integrationTestPlugin,
231 ),
232 );
233 },
234 skip: !platform.isMacOS, // [intended] Swift Package Manager only works on macos.
235 );
236 }
237
238 test('Build $platformName-framework with non-module app uses CocoaPods', () async {
239 final Directory workingDirectory = fileSystem.systemTempDirectory.createTempSync(
240 'swift_package_manager_build_framework.',
241 );
242 final String workingDirectoryPath = workingDirectory.path;
243
244 addTearDown(() async {
245 await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
246 ErrorHandlingFileSystem.deleteIfExists(workingDirectory, recursive: true);
247 });
248
249 // Create and build an app using the Swift Package Manager version of
250 // integration_test.
251 await SwiftPackageManagerUtils.enableSwiftPackageManager(flutterBin, workingDirectoryPath);
252
253 final String appDirectoryPath = await SwiftPackageManagerUtils.createApp(
254 flutterBin,
255 workingDirectoryPath,
256 iosLanguage: 'swift',
257 platform: platformName,
258 usesSwiftPackageManager: true,
259 options: <String>['--platforms=$platformName'],
260 );
261 SwiftPackageManagerUtils.addDependency(
262 appDirectoryPath: appDirectoryPath,
263 plugin: integrationTestPlugin,
264 );
265
266 await SwiftPackageManagerUtils.buildApp(
267 flutterBin,
268 appDirectoryPath,
269 options: <String>[platformName, '--config-only', '-v'],
270 );
271
272 expect(
273 fileSystem.directory(appDirectoryPath).childDirectory(platformName).childFile('Podfile'),
274 isNot(exists),
275 );
276 expect(
277 fileSystem
278 .directory(appDirectoryPath)
279 .childDirectory(platformName)
280 .childDirectory('Flutter')
281 .childDirectory('ephemeral')
282 .childDirectory('Packages')
283 .childDirectory('FlutterGeneratedPluginSwiftPackage'),
284 exists,
285 );
286
287 // Create and build framework using the CocoaPods version of
288 // integration_test even though Swift Package Manager is enabled.
289 await SwiftPackageManagerUtils.buildApp(
290 flutterBin,
291 appDirectoryPath,
292 options: <String>['$platformName-framework', '--no-debug', '--no-profile', '-v'],
293 expectedLines: <String>[
294 'Swift Package Manager does not yet support this command. CocoaPods will be used instead.',
295 ],
296 );
297
298 expect(
299 fileSystem
300 .directory(appDirectoryPath)
301 .childDirectory('build')
302 .childDirectory(platformName)
303 .childDirectory('framework')
304 .childDirectory('Release')
305 .childDirectory('${integrationTestPlugin.pluginName}.xcframework'),
306 exists,
307 );
308 }, skip: !platform.isMacOS); // [intended] Swift Package Manager only works on macos.
309
310 test(
311 'Caches build targets between builds with Swift Package Manager on $platformName',
312 () async {
313 final Directory workingDirectory = fileSystem.systemTempDirectory.createTempSync(
314 'swift_package_manager_caching.',
315 );
316 final String workingDirectoryPath = workingDirectory.path;
317
318 addTearDown(() async {
319 await SwiftPackageManagerUtils.disableSwiftPackageManager(
320 flutterBin,
321 workingDirectoryPath,
322 );
323 ErrorHandlingFileSystem.deleteIfExists(workingDirectory, recursive: true);
324 });
325
326 // Create and build an app using the Swift Package Manager version of
327 // integration_test.
328 await SwiftPackageManagerUtils.enableSwiftPackageManager(flutterBin, workingDirectoryPath);
329
330 final String appDirectoryPath = await SwiftPackageManagerUtils.createApp(
331 flutterBin,
332 workingDirectoryPath,
333 iosLanguage: 'swift',
334 platform: platformName,
335 usesSwiftPackageManager: true,
336 options: <String>['--platforms=$platformName'],
337 );
338 SwiftPackageManagerUtils.addDependency(
339 appDirectoryPath: appDirectoryPath,
340 plugin: integrationTestPlugin,
341 );
342
343 final String unpackTarget = 'debug_unpack_$platformName';
344 final String bundleFlutterAssetsTarget = 'debug_${platformName}_bundle_flutter_assets';
345 final bool noCodesign = platformName == 'ios';
346 await SwiftPackageManagerUtils.buildApp(
347 flutterBin,
348 appDirectoryPath,
349 options: <String>[platformName, '--debug', '-v', if (noCodesign) '--no-codesign'],
350 expectedLines: <Pattern>[
351 r'SchemeAction Run\ Prepare\ Flutter\ Framework\ Script',
352 '$unpackTarget: Starting due to',
353 '-dPreBuildAction=PrepareFramework $unpackTarget',
354 ],
355 unexpectedLines: <String>[],
356 );
357
358 await SwiftPackageManagerUtils.buildApp(
359 flutterBin,
360 appDirectoryPath,
361 options: <String>[platformName, '--debug', '-v', if (noCodesign) '--no-codesign'],
362 expectedLines: <Pattern>[
363 r'SchemeAction Run\ Prepare\ Flutter\ Framework\ Script',
364 'Skipping target: $unpackTarget',
365 'Skipping target: $bundleFlutterAssetsTarget',
366 ],
367 unexpectedLines: <String>['Starting due to'],
368 );
369 },
370 skip: !platform.isMacOS, // [intended] Swift Package Manager only works on macos.
371 );
372 }
373
374 test('Build ios-framework with module app uses CocoaPods', () async {
375 final Directory workingDirectory = fileSystem.systemTempDirectory.createTempSync(
376 'swift_package_manager_build_framework_module.',
377 );
378 final String workingDirectoryPath = workingDirectory.path;
379
380 addTearDown(() async {
381 await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
382 ErrorHandlingFileSystem.deleteIfExists(workingDirectory, recursive: true);
383 });
384
385 // Create and build module and framework using the CocoaPods version of
386 // integration_test even though Swift Package Manager is enabled.
387 await SwiftPackageManagerUtils.enableSwiftPackageManager(flutterBin, workingDirectoryPath);
388
389 final String appDirectoryPath = await SwiftPackageManagerUtils.createApp(
390 flutterBin,
391 workingDirectoryPath,
392 iosLanguage: 'swift',
393 platform: 'ios',
394 usesSwiftPackageManager: true,
395 options: <String>['--template=module'],
396 );
397 final SwiftPackageManagerPlugin integrationTestPlugin =
398 SwiftPackageManagerUtils.integrationTestPlugin('ios');
399 SwiftPackageManagerUtils.addDependency(
400 appDirectoryPath: appDirectoryPath,
401 plugin: integrationTestPlugin,
402 );
403
404 await SwiftPackageManagerUtils.buildApp(
405 flutterBin,
406 appDirectoryPath,
407 options: <String>['ios', '--config-only', '-v'],
408 );
409
410 expect(
411 fileSystem.directory(appDirectoryPath).childDirectory('.ios').childFile('Podfile'),
412 exists,
413 );
414 expect(
415 fileSystem
416 .directory(appDirectoryPath)
417 .childDirectory('.ios')
418 .childDirectory('Flutter')
419 .childDirectory('ephemeral')
420 .childDirectory('Packages')
421 .childDirectory('FlutterGeneratedPluginSwiftPackage'),
422 isNot(exists),
423 );
424 final File pbxprojFile = fileSystem
425 .directory(appDirectoryPath)
426 .childDirectory('.ios')
427 .childDirectory('Runner.xcodeproj')
428 .childFile('project.pbxproj');
429 expect(pbxprojFile, exists);
430 expect(pbxprojFile.readAsStringSync(), isNot(contains('FlutterGeneratedPluginSwiftPackage')));
431 final File xcschemeFile = fileSystem
432 .directory(appDirectoryPath)
433 .childDirectory('.ios')
434 .childDirectory('Runner.xcodeproj')
435 .childDirectory('xcshareddata')
436 .childDirectory('xcschemes')
437 .childFile('Runner.xcscheme');
438 expect(xcschemeFile, exists);
439 expect(
440 xcschemeFile.readAsStringSync(),
441 isNot(contains('Run Prepare Flutter Framework Script')),
442 );
443
444 await SwiftPackageManagerUtils.buildApp(
445 flutterBin,
446 appDirectoryPath,
447 options: <String>['ios-framework', '--no-debug', '--no-profile', '-v'],
448 unexpectedLines: <String>[
449 'Adding Swift Package Manager integration...',
450 'Swift Package Manager does not yet support this command. CocoaPods will be used instead.',
451 ],
452 );
453
454 expect(
455 fileSystem
456 .directory(appDirectoryPath)
457 .childDirectory('build')
458 .childDirectory('ios')
459 .childDirectory('framework')
460 .childDirectory('Release')
461 .childDirectory('${integrationTestPlugin.pluginName}.xcframework'),
462 exists,
463 );
464 }, skip: !platform.isMacOS); // [intended] Swift Package Manager only works on macos.
465
466 test('Build ios-framework with non module app uses CocoaPods', () async {
467 final Directory workingDirectory = fileSystem.systemTempDirectory.createTempSync(
468 'swift_package_manager_build_framework_non_module.',
469 );
470 final String workingDirectoryPath = workingDirectory.path;
471
472 addTearDown(() async {
473 await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
474 ErrorHandlingFileSystem.deleteIfExists(workingDirectory, recursive: true);
475 });
476
477 // Create and build a regular app and framework using the CocoaPods version of
478 // integration_test even though Swift Package Manager is enabled.
479 await SwiftPackageManagerUtils.enableSwiftPackageManager(flutterBin, workingDirectoryPath);
480
481 final String appDirectoryPath = await SwiftPackageManagerUtils.createApp(
482 flutterBin,
483 workingDirectoryPath,
484 iosLanguage: 'swift',
485 platform: 'ios',
486 usesSwiftPackageManager: true,
487 options: <String>[],
488 );
489 final SwiftPackageManagerPlugin integrationTestPlugin =
490 SwiftPackageManagerUtils.integrationTestPlugin('ios');
491 SwiftPackageManagerUtils.addDependency(
492 appDirectoryPath: appDirectoryPath,
493 plugin: integrationTestPlugin,
494 );
495
496 await SwiftPackageManagerUtils.cleanApp(flutterBin, appDirectoryPath);
497
498 await SwiftPackageManagerUtils.buildApp(
499 flutterBin,
500 appDirectoryPath,
501 options: <String>['ios-framework', '--xcframework', '--no-debug', '--no-profile', '-v'],
502 expectedLines: <String>[
503 'Swift Package Manager does not yet support this command. CocoaPods will be used instead.',
504 ],
505 unexpectedLines: <String>['Adding Swift Package Manager integration...'],
506 );
507
508 expect(fileSystem.directory(appDirectoryPath).childDirectory('.ios'), isNot(exists));
509
510 // Verify the generated Swift Package Manager manifest file has no dependencies.
511 final File generatedManifestFile = fileSystem
512 .directory(appDirectoryPath)
513 .childDirectory('ios')
514 .childDirectory('Flutter')
515 .childDirectory('ephemeral')
516 .childDirectory('Packages')
517 .childDirectory('FlutterGeneratedPluginSwiftPackage')
518 .childFile('Package.swift');
519
520 expect(generatedManifestFile, exists);
521
522 final String generatedManifest = generatedManifestFile.readAsStringSync();
523 const String expected = 'dependencies: [\n \n ],\n';
524 expect(generatedManifest, contains(expected));
525
526 expect(
527 fileSystem
528 .directory(appDirectoryPath)
529 .childDirectory('build')
530 .childDirectory('ios')
531 .childDirectory('framework')
532 .childDirectory('Release')
533 .childDirectory('${integrationTestPlugin.pluginName}.xcframework'),
534 exists,
535 );
536
537 final File flutterPluginsDependenciesFile = fileSystem
538 .directory(appDirectoryPath)
539 .childFile('.flutter-plugins-dependencies');
540
541 expect(flutterPluginsDependenciesFile, exists);
542
543 final String dependenciesString = flutterPluginsDependenciesFile.readAsStringSync();
544 final Map<String, dynamic>? dependenciesJson =
545 json.decode(dependenciesString) as Map<String, dynamic>?;
546 final Map<String, dynamic>? swiftPackageManagerEnabled =
547 dependenciesJson?['swift_package_manager_enabled'] as Map<String, dynamic>?;
548 final bool? swiftPackageManagerEnabledIos = swiftPackageManagerEnabled?['ios'] as bool?;
549
550 expect(swiftPackageManagerEnabledIos, isFalse);
551 }, skip: !platform.isMacOS); // [intended] Swift Package Manager only works on macos.
552
553 test("Generated Swift package uses iOS's project minimum deployment", () async {
554 final Directory workingDirectory = fileSystem.systemTempDirectory.createTempSync(
555 'swift_package_manager_minimum_deployment_ios.',
556 );
557 final String workingDirectoryPath = workingDirectory.path;
558
559 addTearDown(() async {
560 await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
561 ErrorHandlingFileSystem.deleteIfExists(workingDirectory, recursive: true);
562 });
563
564 await SwiftPackageManagerUtils.enableSwiftPackageManager(flutterBin, workingDirectoryPath);
565 final String appDirectoryPath = await SwiftPackageManagerUtils.createApp(
566 flutterBin,
567 workingDirectoryPath,
568 iosLanguage: 'swift',
569 platform: 'ios',
570 usesSwiftPackageManager: true,
571 options: <String>['--platforms=ios'],
572 );
573
574 // Modify the project to raise the deployment version.
575 final File projectFile = fileSystem
576 .directory(appDirectoryPath)
577 .childDirectory('ios')
578 .childDirectory('Runner.xcodeproj')
579 .childFile('project.pbxproj');
580
581 final String oldProject = projectFile.readAsStringSync();
582 final String newProject = oldProject.replaceAll(
583 RegExp(r'IPHONEOS_DEPLOYMENT_TARGET = \d+\.\d+;'),
584 'IPHONEOS_DEPLOYMENT_TARGET = 15.1;',
585 );
586
587 projectFile.writeAsStringSync(newProject);
588
589 // Build the app. This generates Flutter's Swift package.
590 await SwiftPackageManagerUtils.buildApp(
591 flutterBin,
592 appDirectoryPath,
593 options: <String>['ios', '--debug', '-v'],
594 );
595
596 // Verify the generated Swift package uses the project's minimum deployment.
597 final File generatedManifestFile = fileSystem
598 .directory(appDirectoryPath)
599 .childDirectory('ios')
600 .childDirectory('Flutter')
601 .childDirectory('ephemeral')
602 .childDirectory('Packages')
603 .childDirectory('FlutterGeneratedPluginSwiftPackage')
604 .childFile('Package.swift');
605
606 expect(generatedManifestFile, exists);
607
608 final String generatedManifest = generatedManifestFile.readAsStringSync();
609 const String expected = '''
610 platforms: [
611 .iOS("15.1")
612 ],
613''';
614
615 expect(generatedManifest.contains(expected), isTrue);
616 }, skip: !platform.isMacOS); // [intended] Swift Package Manager only works on macos.
617
618 test("Generated Swift package uses macOS's project minimum deployment", () async {
619 final Directory workingDirectory = fileSystem.systemTempDirectory.createTempSync(
620 'swift_package_manager_minimum_deployment_macos.',
621 );
622 final String workingDirectoryPath = workingDirectory.path;
623
624 addTearDown(() async {
625 await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
626 ErrorHandlingFileSystem.deleteIfExists(workingDirectory, recursive: true);
627 });
628
629 await SwiftPackageManagerUtils.enableSwiftPackageManager(flutterBin, workingDirectoryPath);
630 final String appDirectoryPath = await SwiftPackageManagerUtils.createApp(
631 flutterBin,
632 workingDirectoryPath,
633 iosLanguage: 'swift',
634 platform: 'macos',
635 usesSwiftPackageManager: true,
636 options: <String>['--platforms=macos'],
637 );
638
639 // Modify the project to raise the deployment version.
640 final File projectFile = fileSystem
641 .directory(appDirectoryPath)
642 .childDirectory('macos')
643 .childDirectory('Runner.xcodeproj')
644 .childFile('project.pbxproj');
645
646 final String oldProject = projectFile.readAsStringSync();
647 final String newProject = oldProject.replaceAll(
648 RegExp(r'MACOSX_DEPLOYMENT_TARGET = \d+\.\d+;'),
649 'MACOSX_DEPLOYMENT_TARGET = 15.1;',
650 );
651
652 projectFile.writeAsStringSync(newProject);
653
654 // Build the app. This generates Flutter's Swift package.
655 await SwiftPackageManagerUtils.buildApp(
656 flutterBin,
657 appDirectoryPath,
658 options: <String>['macos', '--debug', '-v'],
659 );
660
661 // Verify the generated Swift package uses the project's minimum deployment.
662 final File generatedManifestFile = fileSystem
663 .directory(appDirectoryPath)
664 .childDirectory('macos')
665 .childDirectory('Flutter')
666 .childDirectory('ephemeral')
667 .childDirectory('Packages')
668 .childDirectory('FlutterGeneratedPluginSwiftPackage')
669 .childFile('Package.swift');
670
671 expect(generatedManifestFile, exists);
672
673 final String generatedManifest = generatedManifestFile.readAsStringSync();
674 const String expected = '''
675 platforms: [
676 .macOS("15.1")
677 ],
678''';
679
680 expect(generatedManifest, contains(expected));
681 }, skip: !platform.isMacOS); // [intended] Swift Package Manager only works on macos.
682
683 test('Removing the last plugin updates the generated Swift package', () async {
684 final Directory workingDirectory = fileSystem.systemTempDirectory.createTempSync(
685 'swift_package_manager_remove_last_plugin.',
686 );
687 final String workingDirectoryPath = workingDirectory.path;
688
689 addTearDown(() async {
690 await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
691 ErrorHandlingFileSystem.deleteIfExists(workingDirectory, recursive: true);
692 });
693
694 await SwiftPackageManagerUtils.enableSwiftPackageManager(flutterBin, workingDirectoryPath);
695
696 // Create an app with a plugin.
697 final String appDirectoryPath = await SwiftPackageManagerUtils.createApp(
698 flutterBin,
699 workingDirectoryPath,
700 iosLanguage: 'swift',
701 platform: 'ios',
702 usesSwiftPackageManager: true,
703 options: <String>['--platforms=ios'],
704 );
705
706 final SwiftPackageManagerPlugin integrationTestPlugin =
707 SwiftPackageManagerUtils.integrationTestPlugin('ios');
708
709 SwiftPackageManagerUtils.addDependency(
710 appDirectoryPath: appDirectoryPath,
711 plugin: integrationTestPlugin,
712 );
713
714 // Build the app to generate the Swift package.
715 await SwiftPackageManagerUtils.buildApp(
716 flutterBin,
717 appDirectoryPath,
718 options: <String>['ios', '--config-only', '-v'],
719 );
720
721 // Verify the generated Swift package depends on the plugin.
722 final File generatedManifestFile = fileSystem
723 .directory(appDirectoryPath)
724 .childDirectory('ios')
725 .childDirectory('Flutter')
726 .childDirectory('ephemeral')
727 .childDirectory('Packages')
728 .childDirectory('FlutterGeneratedPluginSwiftPackage')
729 .childFile('Package.swift');
730
731 expect(generatedManifestFile, exists);
732
733 String generatedManifest = generatedManifestFile.readAsStringSync();
734 final String generatedSwiftDependency = '''
735 dependencies: [
736 .package(name: "integration_test", path: "${integrationTestPlugin.swiftPackagePlatformPath}")
737 ],
738''';
739
740 expect(generatedManifest.contains(generatedSwiftDependency), isTrue);
741
742 // Remove the plugin and rebuild the app to re-generate the Swift package.
743 SwiftPackageManagerUtils.removeDependency(
744 appDirectoryPath: appDirectoryPath,
745 plugin: integrationTestPlugin,
746 );
747
748 await SwiftPackageManagerUtils.buildApp(
749 flutterBin,
750 appDirectoryPath,
751 options: <String>['ios', '--config-only', '-v'],
752 );
753
754 // Verify the generated Swift package does not depend on the plugin.
755 expect(generatedManifestFile, exists);
756
757 generatedManifest = generatedManifestFile.readAsStringSync();
758 const String emptyDependencies = 'dependencies: [\n \n ],\n';
759
760 expect(generatedManifest, isNot(contains(generatedSwiftDependency)));
761 expect(generatedManifest, contains(emptyDependencies));
762 }, skip: !platform.isMacOS); // [intended] Swift Package Manager only works on macos.
763
764 test('Migrated app builds after Swift Package Manager is turned off', () async {
765 final Directory workingDirectory = fileSystem.systemTempDirectory.createTempSync(
766 'swift_package_manager_turned_off.',
767 );
768 final String workingDirectoryPath = workingDirectory.path;
769
770 addTearDown(() async {
771 await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
772 ErrorHandlingFileSystem.deleteIfExists(workingDirectory, recursive: true);
773 });
774
775 await SwiftPackageManagerUtils.enableSwiftPackageManager(flutterBin, workingDirectoryPath);
776
777 // Create an app with a plugin and Swift Package Manager integration.
778 final String appDirectoryPath = await SwiftPackageManagerUtils.createApp(
779 flutterBin,
780 workingDirectoryPath,
781 iosLanguage: 'swift',
782 platform: 'ios',
783 usesSwiftPackageManager: true,
784 options: <String>['--platforms=ios'],
785 );
786
787 final SwiftPackageManagerPlugin integrationTestPlugin =
788 SwiftPackageManagerUtils.integrationTestPlugin('ios');
789
790 SwiftPackageManagerUtils.addDependency(
791 appDirectoryPath: appDirectoryPath,
792 plugin: integrationTestPlugin,
793 );
794
795 // Build the app.
796 await SwiftPackageManagerUtils.buildApp(
797 flutterBin,
798 appDirectoryPath,
799 options: <String>['ios', '--config-only', '-v'],
800 );
801
802 // The app should have SwiftPM integration.
803 final File xcodeProjectFile = fileSystem
804 .directory(appDirectoryPath)
805 .childDirectory('ios')
806 .childDirectory('Runner.xcodeproj')
807 .childFile('project.pbxproj');
808 final File generatedManifestFile = fileSystem
809 .directory(appDirectoryPath)
810 .childDirectory('ios')
811 .childDirectory('Flutter')
812 .childDirectory('ephemeral')
813 .childDirectory('Packages')
814 .childDirectory('FlutterGeneratedPluginSwiftPackage')
815 .childFile('Package.swift');
816 final Directory cocoaPodsPluginFramework = fileSystem
817 .directory(appDirectoryPath)
818 .childDirectory('build')
819 .childDirectory('ios')
820 .childDirectory('iphoneos')
821 .childDirectory('Runner.app')
822 .childDirectory('Frameworks')
823 .childDirectory('${integrationTestPlugin.pluginName}.framework');
824
825 expect(xcodeProjectFile, exists);
826 expect(generatedManifestFile, exists);
827 expect(cocoaPodsPluginFramework, isNot(exists));
828
829 String xcodeProject = xcodeProjectFile.readAsStringSync();
830 String generatedManifest = generatedManifestFile.readAsStringSync();
831 final String generatedSwiftDependency = '''
832 dependencies: [
833 .package(name: "integration_test", path: "${integrationTestPlugin.swiftPackagePlatformPath}")
834 ],
835''';
836
837 expect(xcodeProject, contains('FlutterGeneratedPluginSwiftPackage'));
838 expect(generatedManifest, contains(generatedSwiftDependency));
839
840 // Disable Swift Package Manager and do a clean re-build of the app.
841 // The build should succeed.
842 await SwiftPackageManagerUtils.disableSwiftPackageManager(flutterBin, workingDirectoryPath);
843
844 await SwiftPackageManagerUtils.cleanApp(flutterBin, appDirectoryPath);
845
846 await SwiftPackageManagerUtils.buildApp(
847 flutterBin,
848 appDirectoryPath,
849 options: <String>['ios', '-v'],
850 );
851
852 // The app should still have SwiftPM integration,
853 // but the plugin should be added using CocoaPods.
854 expect(xcodeProjectFile, exists);
855 expect(generatedManifestFile, exists);
856
857 xcodeProject = xcodeProjectFile.readAsStringSync();
858 generatedManifest = generatedManifestFile.readAsStringSync();
859 const String emptyDependencies = 'dependencies: [\n \n ],\n';
860
861 expect(xcodeProject, contains('FlutterGeneratedPluginSwiftPackage'));
862 expect(generatedManifest, isNot(contains('integration_test')));
863 expect(generatedManifest, contains(emptyDependencies));
864 expect(cocoaPodsPluginFramework, exists);
865 }, skip: !platform.isMacOS); // [intended] Swift Package Manager only works on macos.
866}
867

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com