diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 6529bec..6799074 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -9,10 +9,10 @@ All code changes MUST comply with the project constitution at `.specify/memory/c This is a **Flutter SDK** wrapping native Optimizely SDKs for iOS and Android. **Technology Stack:** -- **Dart/Flutter**: Cross-platform API layer (>=2.16.2, Flutter >=2.5.0) -- **Swift**: iOS native bridge (Swift 5.0, iOS 10.0+) +- **Dart/Flutter**: Cross-platform API layer (>=2.16.2, Flutter >=3.44.0) +- **Swift**: iOS native bridge (Swift 5.0, iOS 15.0+) - **Kotlin/Java**: Android native bridge (Kotlin 2.1.0, Android 5.0+) -- **Native SDKs**: OptimizelySwiftSDK 5.2.1 (iOS), android-sdk 5.1.1 (Android) +- **Native SDKs**: OptimizelySwiftSDK 5.5.0 (iOS), android-sdk 5.4.0 (Android) ## Folder Structure diff --git a/.github/scripts/check-version-drift.sh b/.github/scripts/check-version-drift.sh deleted file mode 100755 index e3777f5..0000000 --- a/.github/scripts/check-version-drift.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# Verify OptimizelySwiftSDK version is the same in both podspec and Package.swift. -# Exits non-zero if versions diverge (FR-014). - -set -euo pipefail - -PODSPEC="ios/optimizely_flutter_sdk.podspec" -PACKAGE_SWIFT="ios/optimizely_flutter_sdk/Package.swift" - -PODSPEC_VER=$(grep "OptimizelySwiftSDK" "$PODSPEC" | grep -oE "'[0-9]+\.[0-9]+\.[0-9]+'" | tr -d "'") -SPM_VER=$(grep 'exact' "$PACKAGE_SWIFT" | grep -oE '"[0-9]+\.[0-9]+\.[0-9]+"' | tr -d '"') - -if [ -z "$PODSPEC_VER" ] || [ -z "$SPM_VER" ]; then - echo "FAIL: Could not extract version from one or both files" - echo " podspec: ${PODSPEC_VER:-}" - echo " Package.swift: ${SPM_VER:-}" - exit 1 -fi - -if [ "$PODSPEC_VER" != "$SPM_VER" ]; then - echo "FAIL: OptimizelySwiftSDK version mismatch" - echo " podspec: $PODSPEC_VER" - echo " Package.swift: $SPM_VER" - exit 1 -fi - -echo "OK: OptimizelySwiftSDK version matches ($PODSPEC_VER)" diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index e8399b2..a471907 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -17,16 +17,8 @@ on: # default: "master" jobs: - version_drift_check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Check OptimizelySwiftSDK version parity - run: bash .github/scripts/check-version-drift.sh - unit_test_coverage: runs-on: macos-latest - needs: version_drift_check steps: - uses: actions/checkout@v3 @@ -152,7 +144,6 @@ jobs: build_test_ios: runs-on: macos-latest - needs: version_drift_check steps: - uses: actions/checkout@v3 diff --git a/.gitignore b/.gitignore index 0a0224a..3d59528 100644 --- a/.gitignore +++ b/.gitignore @@ -82,7 +82,6 @@ unlinked_spec.ds **/ios/**/.vagrant/ **/ios/**/DerivedData/ **/ios/**/Icon? -**/ios/**/Pods/ **/ios/**/.symlinks/ **/ios/**/profile **/ios/**/xcuserdata @@ -90,7 +89,6 @@ unlinked_spec.ds **/ios/Flutter/.last_build_id **/ios/Flutter/App.framework **/ios/Flutter/Flutter.framework -**/ios/Flutter/Flutter.podspec **/ios/Flutter/Generated.xcconfig **/ios/Flutter/ephemeral **/ios/Flutter/app.flx @@ -102,7 +100,6 @@ unlinked_spec.ds # macOS **/Flutter/ephemeral/ -**/Pods/ **/macos/Flutter/GeneratedPluginRegistrant.swift **/macos/Flutter/ephemeral **/xcuserdata/ diff --git a/.pubignore b/.pubignore index 22ce619..012e365 100644 --- a/.pubignore +++ b/.pubignore @@ -6,3 +6,9 @@ CLAUDE.md # Spec Kit framework files .specify/ + +# Spec Kit feature specs +specs/ + +# Local build output (e.g. flutter test cache) +build/ diff --git a/.specify/feature.json b/.specify/feature.json index 7b91d9a..c03d14c 100644 --- a/.specify/feature.json +++ b/.specify/feature.json @@ -1,3 +1,3 @@ { - "feature_directory": "specs/001-cocoapods-to-spm-migration" + "feature_directory": "specs/003-remove-cocoapods-ios15" } diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md index b5f391e..f3cb67b 100644 --- a/.specify/memory/constitution.md +++ b/.specify/memory/constitution.md @@ -1,19 +1,17 @@ For additional context about technologies to be used, project structure, diff --git a/README.md b/README.md index 6627bb3..c7708c8 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,16 @@ Refer to the [Flutter SDK's developer documentation](https://docs.developers.opt See the [pubspec.yaml](https://github.com/optimizely/optimizely-flutter-sdk/blob/master/pubspec.yaml) file for Flutter version requirements. -On the Android platform, the SDK requires a minimum SDK version of 21 or higher and compile SDK version of 32. +On the Android platform, the SDK requires a minimum SDK version of 21 or higher and compile SDK version of 35. -On the iOS platform, the SDK requires a minimum version of 10.0. The SDK supports both Swift Package Manager (SPM) and CocoaPods for iOS dependency resolution. Flutter 3.44+ uses SPM by default; older versions use CocoaPods. +On the iOS platform, the SDK requires a minimum version of 15.0 and Flutter 3.44 or later. The SDK is integrated through Swift Package Manager (SPM) only; CocoaPods is no longer supported. + +#### Migrating from CocoaPods + +1. Use Flutter 3.44 or later (SPM is enabled by default; otherwise run `flutter config --enable-swift-package-manager`). If your app's `pubspec.yaml` turns SPM off (`flutter: config: enable-swift-package-manager: false`), remove that setting. +2. Set your app's iOS deployment target to 15.0 or higher (Xcode Runner target, and `platform :ios` in your Podfile if you still have one). +3. Run `flutter pub get` and `flutter build ios`. Flutter migrates your Xcode project to SPM automatically. +4. If no other CocoaPods plugins remain, you may run `pod deintegrate` and delete your Podfile. Other Flutter platforms are not currently supported by this SDK. diff --git a/example/ios/.gitignore b/example/ios/.gitignore index ecbb615..8d79986 100644 --- a/example/ios/.gitignore +++ b/example/ios/.gitignore @@ -10,14 +10,12 @@ **/.vagrant/ **/DerivedData/ Icon? -**/Pods/ **/.symlinks/ profile xcuserdata **/.generated/ Flutter/App.framework Flutter/Flutter.framework -Flutter/Flutter.podspec Flutter/Generated.xcconfig Flutter/ephemeral/ Flutter/app.flx diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig index ec97fc6..592ceee 100644 --- a/example/ios/Flutter/Debug.xcconfig +++ b/example/ios/Flutter/Debug.xcconfig @@ -1,2 +1 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig index c4855bf..592ceee 100644 --- a/example/ios/Flutter/Release.xcconfig +++ b/example/ios/Flutter/Release.xcconfig @@ -1,2 +1 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Podfile b/example/ios/Podfile deleted file mode 100644 index 313ea4a..0000000 --- a/example/ios/Podfile +++ /dev/null @@ -1,41 +0,0 @@ -# Uncomment this line to define a global platform for your project -platform :ios, '11.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_ios_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - end -end diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 7a54079..b8fa33a 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -14,7 +14,6 @@ 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 */; }; - E7471FE6544841B0C836D129 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1798EC3215B94C8A840B51 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -33,7 +32,6 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 2407820457C3954D6394333D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -48,9 +46,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - ACF0C93900CB1B99B5E9C0CE /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - D74274CA5486F97165BE309E /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - DC1798EC3215B94C8A840B51 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -59,31 +54,12 @@ buildActionMask = 2147483647; files = ( 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, - E7471FE6544841B0C836D129 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 3B54408533A9D1A272B285B5 /* Pods */ = { - isa = PBXGroup; - children = ( - D74274CA5486F97165BE309E /* Pods-Runner.debug.xcconfig */, - 2407820457C3954D6394333D /* Pods-Runner.release.xcconfig */, - ACF0C93900CB1B99B5E9C0CE /* Pods-Runner.profile.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; - 5922E7F1B4E66D8046FD9D1E /* Frameworks */ = { - isa = PBXGroup; - children = ( - DC1798EC3215B94C8A840B51 /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -104,8 +80,6 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - 3B54408533A9D1A272B285B5 /* Pods */, - 5922E7F1B4E66D8046FD9D1E /* Frameworks */, ); sourceTree = ""; }; @@ -139,7 +113,6 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 73C63109C125F11478860EB1 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, @@ -226,28 +199,6 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 73C63109C125F11478860EB1 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -338,7 +289,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -357,7 +308,7 @@ DEVELOPMENT_TEAM = BDMC9C2X5M; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -417,7 +368,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -466,7 +417,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -487,7 +438,7 @@ DEVELOPMENT_TEAM = BDMC9C2X5M; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -511,7 +462,7 @@ DEVELOPMENT_TEAM = BDMC9C2X5M; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata index 21a3cc1..1d526a1 100644 --- a/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,7 +4,4 @@ - - diff --git a/example/macos/.gitignore b/example/macos/.gitignore index 746adbb..7b58324 100644 --- a/example/macos/.gitignore +++ b/example/macos/.gitignore @@ -1,7 +1,7 @@ # Flutter-related **/Flutter/ephemeral/ -**/Pods/ # Xcode-related **/dgph **/xcuserdata/ +**/swiftpm/ diff --git a/example/macos/Flutter/Flutter-Debug.xcconfig b/example/macos/Flutter/Flutter-Debug.xcconfig index 4b81f9b..c2efd0b 100644 --- a/example/macos/Flutter/Flutter-Debug.xcconfig +++ b/example/macos/Flutter/Flutter-Debug.xcconfig @@ -1,2 +1 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/example/macos/Flutter/Flutter-Release.xcconfig b/example/macos/Flutter/Flutter-Release.xcconfig index 5caa9d1..c2efd0b 100644 --- a/example/macos/Flutter/Flutter-Release.xcconfig +++ b/example/macos/Flutter/Flutter-Release.xcconfig @@ -1,2 +1 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/example/macos/Podfile b/example/macos/Podfile deleted file mode 100644 index dade8df..0000000 --- a/example/macos/Podfile +++ /dev/null @@ -1,40 +0,0 @@ -platform :osx, '10.11' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_macos_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_macos_build_settings(target) - end -end diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index 9f89128..4c2abd3 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXAggregateTarget section */ @@ -26,7 +26,7 @@ 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 */; }; - 90B9B075FD9D5B075E83BE96 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A8DB69DD1CEB9DE6D5A4070 /* Pods_Runner.framework */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -53,7 +53,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 019D04A8C81D7599D2E638FA /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; 33CC10ED2044A3C60003C045 /* optimizely_flutter_sdk_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = optimizely_flutter_sdk_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -68,11 +67,11 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 5A8DB69DD1CEB9DE6D5A4070 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 7EEA78DE428A25C4C9195EC6 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 8D05B77804EBF39FD6D6D079 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; + 784666492D4C4C64000A1A5F /* FlutterFramework */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterFramework; path = ephemeral/Packages/.packages/FlutterFramework; sourceTree = ""; }; + 78DABEA22ED26510000E7860 /* optimizely_flutter_sdk */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = optimizely_flutter_sdk; path = ../../../macos/optimizely_flutter_sdk; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -80,7 +79,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 90B9B075FD9D5B075E83BE96 /* Pods_Runner.framework in Frameworks */, + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -104,8 +103,6 @@ 33FAB671232836740065AC1E /* Runner */, 33CEB47122A05771004F2AC0 /* Flutter */, 33CC10EE2044A3C60003C045 /* Products */, - D73912EC22F37F3D000D13A0 /* Frameworks */, - F74646C1D5F338EF32BE10E1 /* Pods */, ); sourceTree = ""; }; @@ -131,6 +128,9 @@ 33CEB47122A05771004F2AC0 /* Flutter */ = { isa = PBXGroup; children = ( + 78DABEA22ED26510000E7860 /* optimizely_flutter_sdk */, + 784666492D4C4C64000A1A5F /* FlutterFramework */, + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, @@ -152,39 +152,21 @@ path = Runner; sourceTree = ""; }; - D73912EC22F37F3D000D13A0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 5A8DB69DD1CEB9DE6D5A4070 /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - F74646C1D5F338EF32BE10E1 /* Pods */ = { - isa = PBXGroup; - children = ( - 7EEA78DE428A25C4C9195EC6 /* Pods-Runner.debug.xcconfig */, - 8D05B77804EBF39FD6D6D079 /* Pods-Runner.release.xcconfig */, - 019D04A8C81D7599D2E638FA /* Pods-Runner.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 33CC10EC2044A3C60003C045 /* Runner */ = { + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 834CC0346DE4E8E368DFDFD4 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, - F96AA93D7120056FD027BD50 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -200,10 +182,13 @@ /* Begin PBXProject section */ 33CC10E52044A3C60003C045 /* Project object */ = { + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, + ); isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { @@ -256,6 +241,7 @@ /* Begin PBXShellScriptBuildPhase section */ 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -291,45 +277,6 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; - 834CC0346DE4E8E368DFDFD4 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - F96AA93D7120056FD027BD50 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -404,7 +351,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -483,7 +430,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -530,7 +477,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -627,6 +574,18 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ +/* 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 */ }; rootObject = 33CC10E52044A3C60003C045 /* Project object */; } diff --git a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 0ded16c..2ab8be1 100644 --- a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,10 +1,28 @@ + + + + + + + + + + diff --git a/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/example/macos/Runner.xcworkspace/contents.xcworkspacedata index 21a3cc1..1d526a1 100644 --- a/example/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -4,7 +4,4 @@ - - diff --git a/example/macos/Runner/AppDelegate.swift b/example/macos/Runner/AppDelegate.swift index d53ef64..b3c1761 100644 --- a/example/macos/Runner/AppDelegate.swift +++ b/example/macos/Runner/AppDelegate.swift @@ -1,9 +1,13 @@ import Cocoa import FlutterMacOS -@NSApplicationMain +@main class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } } diff --git a/ios/optimizely_flutter_sdk.podspec b/ios/optimizely_flutter_sdk.podspec deleted file mode 100644 index 01a56df..0000000 --- a/ios/optimizely_flutter_sdk.podspec +++ /dev/null @@ -1,21 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint optimizely_flutter_sdk.podspec` to validate before publishing. -# - -Pod::Spec.new do |s| - s.name = 'optimizely_flutter_sdk' - s.version = '0.0.1' - s.summary = 'Optimizely experiment framework for iOS' - s.homepage = "https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs" - s.license = { :type => "Apache License, Version 2.0", :file => "../LICENSE" } - s.author = { "Optimizely" => "support@optimizely.com" } - s.source = { :path => '.' } - s.source_files = 'optimizely_flutter_sdk/Sources/optimizely_flutter_sdk/**/*' - s.dependency 'Flutter' - s.dependency 'OptimizelySwiftSDK', '5.5.0' - s.platform = :ios, '10.0' - # Flutter.framework does not contain a i386 slice. - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } - s.swift_version = '5.0' -end diff --git a/ios/optimizely_flutter_sdk/Package.swift b/ios/optimizely_flutter_sdk/Package.swift index c493fac..1bdcc47 100644 --- a/ios/optimizely_flutter_sdk/Package.swift +++ b/ios/optimizely_flutter_sdk/Package.swift @@ -1,13 +1,10 @@ // swift-tools-version: 5.9 -// ObjC files (OptimizelyFlutterSdkPlugin.m/.h) are excluded from the SPM -// target because SPM does not support mixed Swift/ObjC in a single target. -// They remain on disk for CocoaPods builds, which still use them. import PackageDescription let package = Package( name: "optimizely_flutter_sdk", - platforms: [.iOS("10.0")], + platforms: [.iOS("15.0")], products: [ .library(name: "optimizely-flutter-sdk", targets: ["optimizely_flutter_sdk"]) ], @@ -21,8 +18,7 @@ let package = Package( dependencies: [ .product(name: "FlutterFramework", package: "FlutterFramework"), .product(name: "Optimizely", package: "swift-sdk") - ], - exclude: ["OptimizelyFlutterSdkPlugin.m", "include"] + ] ) ] ) diff --git a/ios/optimizely_flutter_sdk/Sources/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.m b/ios/optimizely_flutter_sdk/Sources/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.m deleted file mode 100644 index 7bb833f..0000000 --- a/ios/optimizely_flutter_sdk/Sources/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.m +++ /dev/null @@ -1,31 +0,0 @@ -/**************************************************************************** - * Copyright 2022, Optimizely, Inc. and contributors * - * * - * Licensed under the Apache License, Version 2.0 (the "License"); * - * you may not use this file except in compliance with the License. * - * You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, software * - * distributed under the License is distributed on an "AS IS" BASIS, * - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * - * See the License for the specific language governing permissions and * - * limitations under the License. * - ***************************************************************************/ - -#import "./include/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.h" -#if __has_include() -#import -#else -// Support project import fallback if the generated compatibility header -// is not copied when this plugin is created as a library. -// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 -#import "optimizely_flutter_sdk-Swift.h" -#endif - -@implementation OptimizelyFlutterSdkPlugin -+ (void)registerWithRegistrar:(NSObject*)registrar { - [SwiftOptimizelyFlutterSdkPlugin registerWithRegistrar:registrar]; -} -@end diff --git a/ios/optimizely_flutter_sdk/Sources/optimizely_flutter_sdk/include/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.h b/ios/optimizely_flutter_sdk/Sources/optimizely_flutter_sdk/include/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.h deleted file mode 100644 index 87294b8..0000000 --- a/ios/optimizely_flutter_sdk/Sources/optimizely_flutter_sdk/include/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.h +++ /dev/null @@ -1,20 +0,0 @@ -/**************************************************************************** - * Copyright 2022, Optimizely, Inc. and contributors * - * * - * Licensed under the Apache License, Version 2.0 (the "License"); * - * you may not use this file except in compliance with the License. * - * You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, software * - * distributed under the License is distributed on an "AS IS" BASIS, * - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * - * See the License for the specific language governing permissions and * - * limitations under the License. * - ***************************************************************************/ - -#import - -@interface OptimizelyFlutterSdkPlugin : NSObject -@end diff --git a/macos/.gitignore b/macos/.gitignore new file mode 100644 index 0000000..2d9f16e --- /dev/null +++ b/macos/.gitignore @@ -0,0 +1,2 @@ +.build/ +.swiftpm/ diff --git a/macos/optimizely_flutter_sdk.podspec b/macos/optimizely_flutter_sdk.podspec deleted file mode 100644 index 9776129..0000000 --- a/macos/optimizely_flutter_sdk.podspec +++ /dev/null @@ -1,23 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint optimizely_flutter_sdk.podspec` to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'optimizely_flutter_sdk' - s.version = '0.0.1' - s.summary = 'A new Flutter plugin project.' - s.description = <<-DESC -A new Flutter plugin project. - DESC - s.homepage = 'http://example.com' - s.license = { :file => '../LICENSE' } - s.author = { 'Your Company' => 'email@example.com' } - - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.dependency 'FlutterMacOS' - - s.platform = :osx, '10.11' - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } - s.swift_version = '5.0' -end diff --git a/macos/optimizely_flutter_sdk/Package.swift b/macos/optimizely_flutter_sdk/Package.swift new file mode 100644 index 0000000..a02f57c --- /dev/null +++ b/macos/optimizely_flutter_sdk/Package.swift @@ -0,0 +1,22 @@ +// swift-tools-version: 5.9 + +import PackageDescription + +let package = Package( + name: "optimizely_flutter_sdk", + platforms: [.macOS("10.15")], + products: [ + .library(name: "optimizely-flutter-sdk", targets: ["optimizely_flutter_sdk"]) + ], + dependencies: [ + .package(name: "FlutterFramework", path: "../FlutterFramework") + ], + targets: [ + .target( + name: "optimizely_flutter_sdk", + dependencies: [ + .product(name: "FlutterFramework", package: "FlutterFramework") + ] + ) + ] +) diff --git a/macos/Classes/OptimizelyFlutterSdkPlugin.swift b/macos/optimizely_flutter_sdk/Sources/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.swift similarity index 100% rename from macos/Classes/OptimizelyFlutterSdkPlugin.swift rename to macos/optimizely_flutter_sdk/Sources/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.swift diff --git a/pubspec.yaml b/pubspec.yaml index 7abd615..cf731a6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/optimizely/optimizely-flutter-sdk environment: sdk: ">=2.16.2 <4.0.0" - flutter: ">=2.5.0" + flutter: ">=3.44.0" dependencies: flutter: diff --git a/specs/003-remove-cocoapods-ios15/spec.md b/specs/003-remove-cocoapods-ios15/spec.md new file mode 100644 index 0000000..412cc83 --- /dev/null +++ b/specs/003-remove-cocoapods-ios15/spec.md @@ -0,0 +1,128 @@ +# Feature Specification: Remove CocoaPods Support and Raise Minimum iOS to 15.0 + +**Feature Branch**: `003-remove-cocoapods-ios15` + +**Created**: 2026-10-12 + +**Status**: Draft + +**Input**: User description: "specify the ticket 1" — [Flutter] Remove CocoaPods support and raise minimum iOS to 15.0. OptimizelySwiftSDK 6.0.0 (Oct 7, 2026) dropped CocoaPods distribution and raised its minimum to iOS 15.0. The Flutter SDK must become SPM-only before it can adopt 6.0.0. Includes updating the `optimizely-flutter-testapp` repo. + +## User Scenarios & Testing *(mandatory)* + +### User Story 1 - SDK Consumers Build iOS via SPM Only (Priority: P1) + +A developer integrating `optimizely_flutter_sdk` into a Flutter app on an SPM-capable Flutter version builds and runs the iOS target exactly as today (`flutter pub get`, `flutter build ios`). The plugin ships only an SPM manifest; no CocoaPods artifacts remain in the published package. All SDK features behave identically to the previous release. + +**Why this priority**: This is the prerequisite for adopting OptimizelySwiftSDK 6.0.0, which has no CocoaPods distribution. Without it the Flutter SDK is stuck on the 5.x native line. + +**Independent Test**: Create a fresh Flutter app on the minimum supported Flutter version with iOS deployment target 15.0, add the SDK as a dependency, run `flutter build ios`, and verify the build succeeds and the native SDK is resolved through SPM. + +**Acceptance Scenarios**: + +1. **Given** a Flutter app on the minimum supported Flutter version with iOS target 15.0, **When** the developer runs `flutter build ios`, **Then** the build succeeds with the native Optimizely dependency resolved via SPM. +2. **Given** the published SDK package, **When** its iOS directory is inspected, **Then** it contains no CocoaPods spec and no source files used only by CocoaPods builds. +3. **Given** an app that previously worked with the SDK, **When** it upgrades to this version, **Then** initialize, decide (sync and async), track, user context, ODP, notification listeners, and logger forwarding behave identically on iOS. + +--- + +### User Story 2 - Developers Below the New Minimums Get a Clear Signal (Priority: P1) + +A developer whose app targets iOS below 15.0, or whose Flutter version cannot consume SPM-only plugins, is told clearly what to change — through version constraints, a build-time error that names the requirement, and a migration note in the README and CHANGELOG — rather than hitting an obscure native build failure. + +**Why this priority**: This is a breaking change. Constitution (Platform Compatibility Standards) requires raised minimums to ship as a major version, and consumers need a clear upgrade path. + +**Independent Test**: Attempt to depend on the SDK from (a) an app with iOS target 14.0 and (b) a project on a Flutter version below the new minimum; verify (a) Flutter raises the app's deployment target to 15.0 and reports it, and (b) dependency resolution fails naming the Flutter constraint, and that the README migration note explains the fix. + +**Acceptance Scenarios**: + +1. **Given** an app with iOS deployment target below 15.0, **When** it builds with the SDK, **Then** Flutter raises the app's iOS deployment target to 15.0, prints "Updating minimum iOS deployment target to 15.0", and the build succeeds (verified 2026-10-12). +2. **Given** a project on a Flutter version below the declared minimum, **When** the developer runs `flutter pub get`, **Then** dependency resolution fails, naming the Flutter version constraint. +3. **Given** the README and CHANGELOG, **When** a developer reads the upgrade section, **Then** it lists the new iOS and Flutter minimums and the steps to migrate an app from CocoaPods to SPM. + +--- + +### User Story 3 - Test App Validates the SPM-Only SDK (Priority: P2) + +The `optimizely-flutter-testapp` repository builds its iOS target via SPM with deployment target 15.0, and its integration suite passes against the SPM-only SDK. Because SDK CI pulls the test app's `master` branch, test-app changes land before (or are coordinated with) the SDK change. + +**Why this priority**: The test app is the end-to-end validation layer for `integration_ios_tests`. If it still depends on CocoaPods or iOS 13, SDK CI breaks. + +**Independent Test**: In the test-app repo, run the iOS build and integration suite against the SDK feature branch; verify all tests pass with no CocoaPods artifacts present. + +**Acceptance Scenarios**: + +1. **Given** the test app with CocoaPods artifacts removed and iOS target 15.0, **When** its iOS CI runs, **Then** the build and all integration tests pass. +2. **Given** the SDK feature branch and the updated test app, **When** SDK CI triggers `integration_ios_tests`, **Then** the job passes. +3. **Given** the test app's Android target, **When** its Android CI runs, **Then** it passes unchanged. + +--- + +### User Story 4 - Maintainers Have One iOS Dependency Path (Priority: P3) + +SDK maintainers maintain a single iOS dependency manifest. CI no longer runs a podspec/SPM version-parity check, the in-repo example app builds via SPM at iOS 15.0, and project guidance (README, CLAUDE.md, constitution) no longer references CocoaPods for iOS. + +**Why this priority**: Reduces maintenance and removes a CI gate that has no purpose once only one manifest exists. Lower priority because it does not affect consumers. + +**Independent Test**: Search the repo for iOS CocoaPods references and run full CI; verify none remain outside historical records (CHANGELOG, prior specs) and all CI jobs pass. + +**Acceptance Scenarios**: + +1. **Given** the SDK repo after the change, **When** CI runs, **Then** there is no version-parity job and all remaining jobs pass. +2. **Given** the in-repo example app, **When** a developer runs it on iOS, **Then** it builds via SPM with deployment target 15.0. +3. **Given** README, CLAUDE.md, and the constitution, **When** reviewed, **Then** they describe SPM as the only iOS integration path and iOS 15.0 as the minimum. + +--- + +### Edge Cases + +- **App has an existing Podfile with other pods**: Other plugins or pods may still use CocoaPods; Flutter's tooling supports mixed apps where SPM-capable plugins resolve via SPM. The SDK makes no assumptions about the app's other dependencies. +- **SPM disabled in the developer's Flutter config**: With no CocoaPods spec, the plugin cannot be integrated. The migration note must tell developers to ensure SPM is enabled. +- **macOS plugin platform**: macOS is experimental (constitution, Platform Compatibility Standards) and its plugin is a template stub. It moves to SPM too (Package.swift at macOS 10.15, Flutter 3.44's minimum), its podspec is removed, and the macOS example and test apps drop CocoaPods. Its behaviour is unchanged. +- **Objective-C registration shim**: The iOS Objective-C plugin files exist only for CocoaPods builds (already excluded from the SPM target). They are removed with CocoaPods; registration continues through the Swift plugin class already declared in `pubspec.yaml`. +- **Test app on `master` lags the SDK**: If the SDK change merges first, `integration_ios_tests` fails. Mitigated by merging the test-app change first or temporarily pointing SDK CI at the test-app feature branch, then reverting. +- **Native SDK version**: This change keeps OptimizelySwiftSDK at its current version (5.5.0, from 3.8.0); the 6.0.0 bump is a separate ticket (Ticket 2) and must not be bundled (constitution VIII.1). + +## Requirements *(mandatory)* + +### Functional Requirements + +- **FR-001**: The SDK MUST NOT ship a CocoaPods spec for iOS; SPM MUST be the only iOS dependency mechanism. +- **FR-002**: The SDK MUST remove iOS source files used only by CocoaPods builds (the Objective-C registration shim and its header). +- **FR-003**: The SDK MUST declare iOS 15.0 as its minimum iOS platform. +- **FR-004**: The SDK MUST declare a minimum Flutter version that resolves SPM-only plugins by default (Flutter 3.44, the version CI already uses with SPM). +- **FR-005**: The SDK MUST keep OptimizelySwiftSDK pinned at its current exact version (5.5.0, from 3.8.0) in this change. +- **FR-006**: The SDK MUST preserve all existing iOS behaviour (MethodChannel handlers, logger bridge, type encoding, main-thread result dispatch) with no Dart public API changes. +- **FR-007**: CI MUST remove the podspec/SPM version-parity check and any job dependencies on it; all remaining CI jobs MUST pass. +- **FR-008**: The in-repo example app MUST build on iOS via SPM with deployment target 15.0 and no CocoaPods artifacts. +- **FR-009**: The `optimizely-flutter-testapp` iOS target MUST build via SPM with deployment target 15.0, with CocoaPods artifacts removed, and its iOS and Android CI MUST pass. +- **FR-010**: README MUST state the new iOS and Flutter minimums and include a CocoaPods-to-SPM migration note for app developers. +- **FR-011**: CLAUDE.md and the constitution (Principle VIII and the Minimum Platform Versions table) MUST be updated to remove iOS CocoaPods references and state iOS 15.0; the constitution amendment MUST follow its amendment procedure. +- **FR-012**: The change MUST be released only as part of a new major SDK version (4.0.0), together with Ticket 2; no intermediate release may ship this change alone. +- **FR-013**: All existing unit tests MUST pass and `flutter analyze` MUST report zero issues. + +### Key Entities + +- **iOS SPM manifest**: The single remaining declaration of the plugin's iOS target, its minimum iOS platform, and the pinned native Optimizely dependency. +- **CocoaPods spec (iOS)**: Removed. Previously a parallel declaration of the same dependency. +- **Version-parity check**: CI gate comparing the two manifests. Removed, as only one manifest remains. +- **Test app**: External repository consumed by SDK CI from its `master` branch; must be migrated in lockstep. + +## Success Criteria *(mandatory)* + +### Measurable Outcomes + +- **SC-001**: A fresh app on the minimum supported Flutter version with iOS target 15.0 builds for iOS on the first attempt with no manual steps beyond `flutter pub get` and `flutter build ios`. +- **SC-002**: Zero iOS CocoaPods references remain in the SDK and test-app repos outside historical records (CHANGELOG, prior specs). +- **SC-003**: 100% of existing unit tests and test-app integration tests pass on both platforms. +- **SC-004**: All SDK CI jobs pass on the feature branch. +- **SC-005**: A developer below the new minimums can identify what to change from the error message or README within 5 minutes. + +## Assumptions + +- Flutter 3.44+ resolves SPM-capable plugins by default (README already states this; CI already uses 3.44.0). +- Existing SPM integration from spec 001 (Package.swift, directory layout, Swift plugin registration) is correct and needs no structural change beyond the platform minimum. +- The Windows plugin platform is out of scope (it has no CocoaPods files). +- Android is unaffected except for test-app CI continuing to pass. +- The release (version files, CHANGELOG, 4.0.0) is handled by Ticket 3, not this change; this change only adds README/migration content. +- Xcode 27 runner migration belongs to Ticket 2 (required by OptimizelySwiftSDK 6.0.0), not this change.