diff --git a/packages/shorebird_cli/lib/src/commands/release/ios_framework_releaser.dart b/packages/shorebird_cli/lib/src/commands/release/ios_framework_releaser.dart index b6d89b010..116889f5a 100644 --- a/packages/shorebird_cli/lib/src/commands/release/ios_framework_releaser.dart +++ b/packages/shorebird_cli/lib/src/commands/release/ios_framework_releaser.dart @@ -115,6 +115,9 @@ class IosFrameworkReleaser extends Releaser { p.join(targetLibraryDirectory.path, 'ShorebirdFlutter.xcframework'), ); + // Generate a podspec so users can integrate via CocoaPods if preferred. + _writePodspec(targetLibraryDirectory); + return targetLibraryDirectory; } @@ -148,6 +151,28 @@ class IosFrameworkReleaser extends Releaser { ), ); + /// Writes a podspec that wraps the release xcframework output, enabling + /// CocoaPods-based integration as an alternative to manual Xcode embedding. + void _writePodspec(Directory releaseDir) { + final podspecPath = p.join( + releaseDir.path, + 'ShorebirdFlutter.podspec', + ); + File(podspecPath).writeAsStringSync(''' +Pod::Spec.new do |s| + s.name = 'ShorebirdFlutter' + s.version = '0.0.1' + s.summary = 'Shorebird Flutter framework for add-to-app integration.' + s.homepage = 'https://shorebird.dev' + s.license = { :type => 'BSD-3-Clause' } + s.author = 'Shorebird' + s.source = { :path => '.' } + s.platform = :ios, '12.0' + s.vendored_frameworks = 'App.xcframework', 'ShorebirdFlutter.xcframework' +end +'''); + } + @override String get postReleaseInstructions { final relativeFrameworkDirectoryPath = p.relative(releaseDirectory.path); @@ -155,11 +180,15 @@ class IosFrameworkReleaser extends Releaser { Your next step is to add the .xcframework files found in the ${lightCyan.wrap(relativeFrameworkDirectoryPath)} directory to your iOS app. -To do this: - 1. Add the relative path to the ${lightCyan.wrap(relativeFrameworkDirectoryPath)} directory to your app's Framework Search Paths in your Xcode build settings. - 2. Embed the App.xcframework and ShorebirdFlutter.framework in your Xcode project. +${styleBold.wrap('Option A: CocoaPods')} + Add the following to your app's Podfile: + ${lightCyan.wrap("pod 'ShorebirdFlutter', :path => '$relativeFrameworkDirectoryPath'")} + Then run ${lightCyan.wrap('pod install')}. -Instructions for these steps can be found at https://docs.flutter.dev/add-to-app/ios/project-setup#option-b---embed-frameworks-in-xcode. +${styleBold.wrap('Option B: Manual Xcode embedding')} + 1. Add the relative path to the ${lightCyan.wrap(relativeFrameworkDirectoryPath)} directory to your app's Framework Search Paths in your Xcode build settings. + 2. Embed the App.xcframework and ShorebirdFlutter.xcframework in your Xcode project. + Instructions: https://docs.flutter.dev/add-to-app/ios/project-setup#option-b---embed-frameworks-in-xcode '''; } } diff --git a/packages/shorebird_cli/test/src/commands/release/ios_framework_releaser_test.dart b/packages/shorebird_cli/test/src/commands/release/ios_framework_releaser_test.dart index 49ddadabd..ef7172aed 100644 --- a/packages/shorebird_cli/test/src/commands/release/ios_framework_releaser_test.dart +++ b/packages/shorebird_cli/test/src/commands/release/ios_framework_releaser_test.dart @@ -479,6 +479,24 @@ void main() { verify(() => artifactBuilder.buildIosFramework(args: [])).called(1); }); + test('generates podspec in release directory', () async { + await runWithOverrides(iosFrameworkReleaser.buildReleaseArtifacts); + + final podspecFile = File( + p.join(projectRoot.path, 'release', 'ShorebirdFlutter.podspec'), + ); + expect(podspecFile.existsSync(), isTrue); + final content = podspecFile.readAsStringSync(); + expect(content, contains("s.name = 'ShorebirdFlutter'")); + expect( + content, + contains( + "s.vendored_frameworks = 'App.xcframework', " + "'ShorebirdFlutter.xcframework'", + ), + ); + }); + group('when --obfuscate is passed', () { setUp(() { when(() => argResults['obfuscate']).thenReturn(true); @@ -686,18 +704,22 @@ void main() { final relativeFrameworkDirectoryPath = p.relative( p.join(projectRoot.path, 'release'), ); + final instructions = runWithOverrides( + () => iosFrameworkReleaser.postReleaseInstructions, + ); + expect(instructions, contains('Option A: CocoaPods')); + expect(instructions, contains('Option B: Manual Xcode embedding')); expect( - runWithOverrides(() => iosFrameworkReleaser.postReleaseInstructions), - equals(''' - -Your next step is to add the .xcframework files found in the ${lightCyan.wrap(relativeFrameworkDirectoryPath)} directory to your iOS app. - -To do this: - 1. Add the relative path to the ${lightCyan.wrap(relativeFrameworkDirectoryPath)} directory to your app's Framework Search Paths in your Xcode build settings. - 2. Embed the App.xcframework and ShorebirdFlutter.framework in your Xcode project. - -Instructions for these steps can be found at https://docs.flutter.dev/add-to-app/ios/project-setup#option-b---embed-frameworks-in-xcode. -'''), + instructions, + contains( + "pod 'ShorebirdFlutter', :path => " + "'$relativeFrameworkDirectoryPath'", + ), + ); + expect(instructions, contains('pod install')); + expect( + instructions, + contains('App.xcframework and ShorebirdFlutter.xcframework'), ); }); });