Skip to content

MOBILE-146: SPM support and Example update#199

Open
justSmK wants to merge 10 commits into
developfrom
feature/MOBILE-146-SPM
Open

MOBILE-146: SPM support and Example update#199
justSmK wants to merge 10 commits into
developfrom
feature/MOBILE-146-SPM

Conversation

@justSmK
Copy link
Copy Markdown
Collaborator

@justSmK justSmK commented Jun 1, 2026

justSmK added 9 commits May 28, 2026 15:12
Ship a Package.swift alongside the existing podspec, so the plugin
resolves via SPM (Flutter ≥ 3.29) and via CocoaPods unchanged. Swift
sources move to ios/mindbox_ios/Sources/mindbox_ios/ — the layout
required by SwiftPM — and the podspec source_files now points there
plus the legacy ObjC AppDelegate from Classes/.

Drop the Objective-C plugin bridge (MindboxIosPlugin.{h,m}); the plugin
registers directly through the renamed Swift class MindboxIosPlugin
(the `Swift` prefix was a carry-over from the ObjC bridge era and
stopped describing anything once the bridge was deleted). Flutter's
GeneratedPluginRegistrant.m falls back from `#import` of the missing
ObjC header to `@import mindbox_ios;`, which picks up the Swift class
via the auto-generated mindbox_ios-Swift.h. The corresponding stale
#import in the ObjC AppDelegate goes away too.

ObjC MindboxFlutterAppDelegateObjc stays in Classes/ for existing
CocoaPods consumers, marked deprecated. It is intentionally not exposed
via the SPM target — gating that on Flutter ≥ 3.41 (the documented
minimum for SPM ObjC plugins with FlutterFramework) is not worth
bumping the SPM-minimum for a deprecated path.

Misc cleanups in the moved Swift files: drop the unused
'MindboxNotifications' import in MindboxFlutterAppDelegate.swift, and
simplify writeNativeLog by seeding the local 'level' var from
'Mindbox.logger.logLevel' to inherit the LogLevel type via inference.
That drops the 'import MindboxLogger' from the plugin — which would
otherwise fail in SPM mode since MindboxLogger is a target in
ios-sdk's Package.swift but not exposed as a product.

Verified locally on Flutter 3.44 (Example) and Flutter 3.29
(flutter-app) on iPhone 17 Pro simulator: both SPM and CocoaPods builds
initialize the SDK, return an APNS token and device UUID. No crash, no
duplicate framework load. 'pod lib lint mindbox_ios.podspec' passes
after dropping the local cocoapods-spm gem (its macro_pods hook breaks
unrelated specs).
Drop the artificial Dart 2 compat-mode constraint ('<3.0.0') on all
four packages — mindbox, mindbox_ios, mindbox_android,
mindbox_platform_interface. Lower bound (>=2.12.0) is unchanged, so
this is hygiene, not a consumer-visible breaking change.

Motivated by the SDK ecosystem catching up to Dart 3; clients on modern
Flutter no longer need a 'dependency_overrides' shim to satisfy the
constraint.
Integrate MindboxNotifications into the example's notification extensions
through Swift Package Manager instead of CocoaPods, so the example builds
the SDK entirely via SPM in SPM mode.

- Add the mindbox-cloud/ios-sdk package at the Xcode project level and link
  its products to the extension targets:
    MindboxNotificationsService -> MindboxNotificationServiceExtension
    MindboxNotificationsContent -> MindboxNotificationContentExtension
  Mindbox itself is NOT linked to Runner (left as "None"): the main app gets
  it transitively via FlutterGeneratedPluginSwiftPackage -> mindbox_ios.
  SPM unifies this project-level ios-sdk with the one the plugin pulls into
  the same package identity, so the whole app resolves to a single ios-sdk
  version (verified: Package.resolved lists ios-sdk once at 2.15.1).
- Use an "up to next major" rule (>= 2.15.1, < 3.0.0) for that package so it
  auto-aligns with whatever exact version the plugin pins, surviving 2.x
  releases without manual pbxproj edits. A conflicting/too-narrow rule would
  fail resolution loudly rather than drift silently.
- Drop the CocoaPods extension blocks (pod 'MindboxNotifications') from the
  Podfile; extensions no longer use CocoaPods. The Podfile stays only for the
  Runner target, since shared_preference_app_group and permission_handler_apple
  have no SPM support yet.
- Drop the duplicate top-level pod 'Mindbox' from Runner (it double-loaded the
  Mindbox framework and mismatched versions, crashing inside MBDatabaseRepository
  on first launch). Pin platform :ios, '13.0' so CocoaPods stops auto-assigning
  15.0. Hard-set flutter.config.enable-swift-package-manager: true so the
  example always exercises the SPM path.

.gitignore picks up dev-only artifacts (pubspec_overrides.yaml, ios/.spm.pods/,
**/xcshareddata/swiftpm/). pubspec.lock regenerated from the Dart SDK bound bump.

Verified on Flutter 3.44, iPhone 17 Pro simulator: clean build with no Mindbox
pods, NSE/NCE compile against MindboxNotifications via SPM, app launches and the
SDK initializes.
The native iOS SDK version prompted by the release tooling now also
bumps the 'exact:' pin in mindbox_ios/ios/mindbox_ios/Package.swift,
alongside the existing podspec bump. Without this hook a release would
ship a podspec on the new native SDK but an SPM manifest still pinned
to the previous one.

Two release entry points exist and both are updated in lockstep:
- git-release-branch.sh — local interactive bash script (BSD sed).
- .github/workflows/manual-prepare_release_branch.yml — the actual
  CI-driven release prep (GNU sed on Ubuntu, runs under
  'set -euo pipefail').

The substitution is addressed by the 'mindbox-cloud/ios-sdk' URL so
unrelated 'exact:' pins (if more SPM dependencies are added later)
stay untouched. Verified with both BSD and GNU sed against normal
X.Y.Z, X.Y.Z-rc, multi-digit versions, repeated runs (idempotent),
and a synthetic Package.swift with a second unrelated 'exact:' pin.
Flutter's SPM docs don't cover the Mindbox-specific steps: wiring the
notification extensions to the ios-sdk products in Xcode, and removing the
CocoaPods Mindbox pods (Runner's `pod 'Mindbox'` and the extensions'
`pod 'MindboxNotifications'`) so the SDK isn't loaded by both pod and SPM —
which duplicates the framework and crashes at runtime. SPM_MIGRATION.md
documents this (mirroring UISCENE_MIGRATION.md) and is linked from the README;
the CocoaPods path is unchanged.
permission_handler 12 and shared_preference_app_group 2 now ship Swift Package Manager support, so every iOS plugin in the example resolves via SPM — CocoaPods is no longer needed. Deintegrated it: removed the Podfile, the Pods xcconfig includes, the Pods workspace reference, the empty Pods group, the now-dead Pods framework/header search paths on the notification extensions, and an orphan Mindbox.framework reference. Runner.xcworkspace stays (Flutter needs it to manage SPM integration; it errors 'Xcode workspace not found' without it) but now references only Runner.xcodeproj.

Bump the remaining direct deps to latest (permission_handler ^12, shared_preference_app_group ^2, flutter_lints ^6) and align the extensions' marketing version with the app (1.0.0) to clear the parent/extension version-match warning. Verified pod-free build and run on the simulator: SDK init, permission grant, and in-app all work.
The example's notification-extension targets referenced MindboxNotificationsService/Content only through their Frameworks build phase — the targets' packageProductDependencies arrays were missing (a known Xcode SPM wiring bug; see ios-app SPM-NOTES). Re-adding the ios-sdk package wires each product into both the build phase and the target's packageProductDependencies, so the structure is complete and Xcode manages add/remove correctly. Pin (Up to Next Major 2.15.1), Mindbox=None on Runner, and product→target mapping are unchanged. objectVersion bumped 54→60 to match the toolchain. Verified: pod-free build + in-app on the simulator.
Removed the obsolete ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES (the Swift runtime ships with iOS 13+), enabled String Catalog symbol generation, bumped LastUpgradeCheck. Kept CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER off at the project level — enabling it floods unfixable warnings from Flutter.framework's own quoted-include headers. Verified: clean build + in-app on the simulator.
flutter_lints 6 enables strict_top_level_inference, which flags the example's static ViewModel methods that have no explicit return type — failing `flutter analyze` in CI. Add void return types to the eight methods. No behavior change.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds Swift Package Manager (SPM) support for the Mindbox Flutter SDK’s iOS implementation (while keeping CocoaPods support), updates the example app to exercise the SPM path, and adjusts release automation to bump the iOS SPM pin alongside the podspec.

Changes:

  • Added SPM migration documentation and a README section describing SPM setup (including extension wiring).
  • Introduced an iOS Package.swift for mindbox_ios and updated iOS plugin sources to build without MindboxLogger being directly imported in SPM mode.
  • Updated example app iOS project to be “pure SPM” (remove Pods/Podfile), refreshed dependencies, and tightened release scripts/workflow to verify version substitutions.

Reviewed changes

Copilot reviewed 27 out of 31 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
SPM_MIGRATION.md New guide for using the plugin with Flutter SPM + extension wiring + pod removal.
README.md Adds a short “iOS Swift Package Manager” section linking to the migration doc.
mindbox/pubspec.yaml Expands Dart SDK upper bound to <4.0.0.
mindbox_platform_interface/pubspec.yaml Expands Dart SDK upper bound to <4.0.0.
mindbox_ios/pubspec.yaml Expands Dart SDK upper bound to <4.0.0.
mindbox_android/pubspec.yaml Expands Dart SDK upper bound to <4.0.0.
mindbox_ios/ios/mindbox_ios/Sources/mindbox_ios/MindboxIosPlugin.swift Renames plugin class, removes MindboxLogger import, and adjusts log-level handling for SPM.
mindbox_ios/ios/mindbox_ios/Sources/mindbox_ios/MindboxFlutterAppDelegate.swift Removes MindboxNotifications import (SPM compatibility).
mindbox_ios/ios/mindbox_ios/Sources/mindbox_ios/inappCallbacks/Callbacks.swift Adds in-app callback delegate glue types used by the plugin.
mindbox_ios/ios/mindbox_ios/Sources/mindbox_ios/Constants.swift Adds a constants container for the plugin channel name.
mindbox_ios/ios/mindbox_ios/Package.swift New SwiftPM manifest pinning ios-sdk for SPM builds.
mindbox_ios/ios/mindbox_ios.podspec Updates source_files to point at SwiftPM-style Sources/ layout and retains pod dependencies.
mindbox_ios/ios/Classes/MindboxIosPlugin.m Removes the Objective-C shim for plugin registration (deleted).
mindbox_ios/ios/Classes/MindboxIosPlugin.h Removes the Objective-C shim header (deleted).
mindbox_ios/ios/Classes/MindboxFlutterAppDelegate.m Removes now-unneeded include of the removed plugin header.
mindbox_ios/ios/Classes/MindboxFlutterAppDelegate.h Deprecates the ObjC AppDelegate base class with a removal notice.
mindbox_ios/.gitignore Ignores SwiftPM build artifacts under the plugin package.
git-release-branch.sh Adds substitution assertions and bumps iOS SPM pin in addition to the podspec.
.github/workflows/manual-prepare_release_branch.yml Adds pin assertions and bumps iOS SPM pin during manual release prep.
example/flutter_example/pubspec.yaml Updates deps and forces SPM via per-project Flutter config.
example/flutter_example/pubspec.lock Updates lockfile (currently includes path-sourced Mindbox packages).
example/flutter_example/lib/view_model/view_model.dart Adds explicit void return types and updates method signatures.
example/flutter_example/ios/.../Package.resolved (2 files) Commits SPM resolution for reproducible native dependency locking.
example/flutter_example/ios/Runner.xcworkspace/contents.xcworkspacedata Removes Pods project reference from the workspace.
example/flutter_example/ios/Runner.xcodeproj/.../Runner.xcscheme Updates scheme version.
example/flutter_example/ios/Runner.xcodeproj/project.pbxproj Removes CocoaPods phases/configs and wires Mindbox extension products via SPM.
example/flutter_example/ios/Podfile Removes CocoaPods integration for the example (deleted).
example/flutter_example/ios/Flutter/Debug.xcconfig Removes Pods xcconfig include.
example/flutter_example/ios/Flutter/Release.xcconfig Removes Pods xcconfig include.
example/flutter_example/.gitignore Ignores SwiftPM workspace scratch while keeping Package.resolved; ignores pubspec_overrides.yaml.
Files not reviewed (1)
  • example/flutter_example/ios/Runner.xcworkspace/contents.xcworkspacedata: Language not supported
Comments suppressed due to low confidence (2)

mindbox_ios/ios/mindbox_ios/Sources/mindbox_ios/MindboxIosPlugin.swift:17

  • The Swift plugin is now the only implementation (the ObjC shim files were removed), but there is no public Objective-C entry point/header left for GeneratedPluginRegistrant in Objective-C Flutter apps to import/call. This is likely to break CocoaPods consumers (and any ObjC-based Runner) because the default registrant expects an ObjC-visible MindboxIosPlugin symbol.
    example/flutter_example/lib/view_model/view_model.dart:62
  • Use a typed callback (and fix the complition typo) so callers get proper type checking and IDE support.
  static void getDeviceUUID(Function complition) {
    Mindbox.instance.getDeviceUUID((value) {
      print(value);
      complition(value);
    });

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread example/flutter_example/lib/view_model/view_model.dart Outdated
Comment thread example/flutter_example/lib/view_model/view_model.dart Outdated
Address PR #199 review: replace the untyped 'Function complition' parameter with 'void Function(String) completion' in getSDKVersion/getToken/getDeviceUUID so callers get proper type checking, and fix the typo. flutter analyze clean.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 31 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • example/flutter_example/ios/Runner.xcworkspace/contents.xcworkspacedata: Language not supported

Comment on lines +16 to 19
s.source_files = 'mindbox_ios/Sources/mindbox_ios/**/*.swift', 'Classes/MindboxFlutterAppDelegate.{h,m}'
s.dependency 'Flutter'
s.dependency 'Mindbox', '2.15.1'
s.dependency 'MindboxNotifications', '2.15.1'
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plugin is a standard Swift plugin, so no ObjC shim/header is needed:

MindboxIosPlugin is public class MindboxIosPlugin: NSObject, FlutterPlugin → it's Objective-C-visible through the generated mindbox_ios-Swift.h (NSObject subclass + the @objc register(with:) from FlutterPlugin), so ObjC can call +[MindboxIosPlugin registerWithRegistrar:].
The generated GeneratedPluginRegistrant.m already handles the missing ObjC header:

#if __has_include(<mindbox_ios/MindboxIosPlugin.h>)
#import <mindbox_ios/MindboxIosPlugin.h>
#else
@import mindbox_ios;        // ← shim removed ⇒ falls back here
#endif

[MindboxIosPlugin registerWithRegistrar:[registry registrarForPlugin:@"MindboxIosPlugin"]];
Verified on an ObjC-based Runner + CocoaPods (our pushok_objc regression app): it builds, registers the plugin, and runs. Removing the ObjC shim is correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants