Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
b3d30e8
Create Package.swift file for spm support
reshab-code May 7, 2026
2a7a415
Create symlinks for spm
reshab-code May 7, 2026
5d96862
Add guard to obj c imports in ClevertapPlugin.m
reshab-code May 7, 2026
203c1e3
wrapped both CTJsonTemplateProducer.h and CTCustomTemplatesManager.h …
reshab-code May 7, 2026
b91d176
Narrowed header files in podspec
reshab-code May 7, 2026
c0b7ecf
Relocate Package.swift to ios/clevertap_plugin/ for Flutter SPM detec…
reshab-code May 8, 2026
dfd2cf9
Add swift package name under ios in pubspec.yaml, added guards for th…
reshab-code May 19, 2026
52d2d8e
Fix Package.swift to use same version as podspec to ensure no drift
reshab-code Jun 23, 2026
a7c16ee
Restructure folders and files as per the official flutter docs
reshab-code Jun 23, 2026
8751ec8
Merge branch 'develop' into task/SDK-5694-spm-support-flutter-sdk
reshab-code Jun 25, 2026
9e9fdf6
Fix version in package.swift to match podspec for correct version res…
reshab-code Jun 25, 2026
74ecaa9
Add spm integration doc for flutter
reshab-code Jun 25, 2026
c22b0dc
Fix flutter version in pubspec to 1.1.7 and enable spm for supported …
reshab-code Jun 30, 2026
8230f92
correct and trim the ios spm integration doc, fixing the enabling ste…
akashvercetti Aug 4, 2026
8922ed1
ignore flutter ephemeral, local claude settings, and generated sdk re…
akashvercetti Aug 4, 2026
7fa5ea4
Fix pr comments and add flutter framework dependency for swift pm rou…
reshab-code Aug 15, 2026
25a953a
update integration doc for ct plugin v4.2.0 and core ios sdk verison …
reshab-code Aug 20, 2026
c021559
merge feat/release_4.2.0, resolve usnotifications import conflict in …
reshab-code Aug 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions doc/Integrate-iOS-SPM.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
## 📦 iOS Integration via Swift Package Manager (SPM)

Starting from Flutter 3.27, Flutter supports resolving plugin dependencies via Swift Package Manager in addition to CocoaPods. The CleverTap Flutter plugin ships a `Package.swift` alongside its podspec, so both package managers resolve the same native SDK version (`CleverTap-iOS-SDK 7.7.1`).
Comment thread
nishant-clevertap marked this conversation as resolved.
Outdated

> **Minimum requirements for SPM integration**
> - Flutter 3.27+
> - Xcode 15+
> - iOS deployment target: 13.0+
>
> If you are on Flutter < 3.27, the plugin continues to work via CocoaPods — no action required.

---

### How it works

Flutter's SPM support detects plugins that declare a `swiftPackageName` in their `pubspec.yaml`. The CleverTap plugin sets:

```yaml
# pubspec.yaml (inside the plugin)
ios:
pluginClass: CleverTapPlugin
swiftPackageName: clevertap_plugin
```

Flutter then looks for a `Package.swift` under `ios/<swiftPackageName>/` (`ios/clevertap_plugin/Package.swift`). That manifest pins the CleverTap iOS SDK:

```swift
.package(
url: "https://github.com/CleverTap/clevertap-ios-sdk",
exact: "7.7.1"
)
```

When your app is built, Flutter resolves this package automatically — no manual entry in `Package.swift` of your app is required.

---

### Enabling SPM in your Flutter app

SPM support in Flutter is opt-in. Enable it by setting the `FLTEnableSwiftPackageManagerIntegration` flag in your iOS app's `Info.plist`:

```xml
<key>FLTEnableSwiftPackageManagerIntegration</key>
<true/>
```

Or via the Flutter CLI environment variable when running or building:

```bash
flutter run --enable-swift-package-manager
flutter build ios --enable-swift-package-manager
```

After enabling, run `flutter pub get` and then open your `.xcworkspace` in Xcode. Xcode will resolve the CleverTap iOS SDK via SPM automatically.

---

### AppDelegate changes when using SPM

When Flutter resolves the plugin via SPM, the module name changes. Use conditional imports in your `AppDelegate` to support both CocoaPods and SPM builds:

###### Objective-C
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

```objc
#if __has_include(<CleverTapSDK/CleverTap.h>)
#import <CleverTapSDK/CleverTap.h>
#else
#import "CleverTap.h"
#endif

#if __has_include(<clevertap_plugin/CleverTapPlugin.h>)
#import <clevertap_plugin/CleverTapPlugin.h>
#else
#import "CleverTapPlugin.h"
#endif
```

###### Swift

```swift
import CleverTapSDK
import clevertap_plugin
```

These guards ensure your app compiles correctly regardless of which package manager resolved the dependency.

---

### CocoaPods vs SPM

| | CocoaPods | SPM |
|---|---|---|
| Config file | `ios/clevertap_plugin.podspec` | `ios/clevertap_plugin/Package.swift` |
| SDK version pinned | `7.7.1` | `7.7.1` |
| Deployment target | `13.0` | `13.0` |
Comment thread
reshab-code marked this conversation as resolved.
Outdated
| Opt-in required | No (default) | Yes (see above) |

Both package managers resolve the same CleverTap iOS SDK version to ensure no drift between the two integration paths.

---

### Troubleshooting

- **Xcode doesn't resolve the package**: Run `flutter pub get`, then in Xcode go to **File → Packages → Resolve Package Versions**.
- **Duplicate symbol errors**: Ensure you are not using both CocoaPods and SPM for the same plugin simultaneously. If you have a `Podfile` and SPM enabled, Flutter will prefer SPM for plugins that support it.
- **Build fails with missing headers**: Verify your deployment target is set to `13.0` or higher in both your Xcode project and `Podfile`/`Package.swift`.
9 changes: 9 additions & 0 deletions example/ios/Runner/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@
#import "GeneratedPluginRegistrant.h"
#import <UserNotifications/UserNotifications.h>

#if __has_include(<CleverTapSDK/CleverTap.h>)
#import <CleverTapSDK/CleverTap.h>
#else
#import "CleverTap.h"
#endif
#if __has_include(<clevertap_plugin/CleverTapPlugin.h>)
#import <clevertap_plugin/CleverTapPlugin.h>
#import <clevertap_plugin/CleverTapPluginCustomTemplates.h>
#else
#import "CleverTapPlugin.h"
#import "CleverTapPluginCustomTemplates.h"
#endif

@implementation AppDelegate

Expand Down
4 changes: 3 additions & 1 deletion ios/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ Icon?
.tags*

/Flutter/Generated.xcconfig
/Flutter/flutter_export_environment.sh
/Flutter/flutter_export_environment.sh

.swiftpm/
6 changes: 3 additions & 3 deletions ios/clevertap_plugin.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ Pod::Spec.new do |s|
s.license = { :file => '../LICENSE' }
s.author = { "CleverTap" => "http://www.clevertap.com" }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h'
s.source_files = 'clevertap_plugin/Sources/clevertap_plugin/**/*.{h,m}'
s.public_header_files = 'clevertap_plugin/Sources/clevertap_plugin/include/clevertap_plugin/*.h'
s.dependency 'Flutter'
s.dependency 'CleverTap-iOS-SDK', '7.7.1'
s.ios.deployment_target = '9.0'
s.ios.deployment_target = '13.0'
Comment thread
reshab-code marked this conversation as resolved.
Outdated
end

30 changes: 30 additions & 0 deletions ios/clevertap_plugin/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// swift-tools-version: 5.9
import PackageDescription

let package = Package(
name: "clevertap_plugin",
platforms: [
.iOS("13.0")
],
products: [
.library(name: "clevertap-plugin", targets: ["clevertap_plugin"])
],
dependencies: [
.package(
url: "https://github.com/CleverTap/clevertap-ios-sdk",
exact: "7.7.1"
Comment thread
reshab-code marked this conversation as resolved.
Outdated
)
],
targets: [
.target(
name: "clevertap_plugin",
dependencies: [
.product(name: "CleverTapSDK", package: "clevertap-ios-sdk")
],
publicHeadersPath: "include/clevertap_plugin",
Comment thread
reshab-code marked this conversation as resolved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why is publicHeadersPath added even if not stated in flutter docs? Is it needed? Have you tested this on sample app?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

publicHeadersPath is required for Objective-C targets in SPM as iit tells the package manager where the public headers are so it can generate a module map. The headers physically live at Sources/clevertap_plugin/include/clevertap_plugin/ and the path "include/clevertap_plugin" is relative to that sources dir. Without it, ObjC imports would break. It was tested and verified in the example app with SPM enabled.

cSettings: [
.headerSearchPath("include/clevertap_plugin")
]
)
]
)
Original file line number Diff line number Diff line change
@@ -1,21 +1,101 @@

#if __has_include(<CleverTapSDK/CleverTap.h>)
#import <CleverTapSDK/CleverTap.h>
#else
#import "CleverTap.h"
#endif

#import "CleverTapPlugin.h"

#if __has_include(<CleverTapSDK/CleverTap+Inbox.h>)
#import <CleverTapSDK/CleverTap+Inbox.h>
#else
#import "CleverTap+Inbox.h"
#endif

#if __has_include(<CleverTapSDK/CleverTapUTMDetail.h>)
#import <CleverTapSDK/CleverTapUTMDetail.h>
#else
#import "CleverTapUTMDetail.h"
#endif

#if __has_include(<CleverTapSDK/CleverTapEventDetail.h>)
#import <CleverTapSDK/CleverTapEventDetail.h>
#else
#import "CleverTapEventDetail.h"
#endif

#if __has_include(<CleverTapSDK/CleverTapSyncDelegate.h>)
#import <CleverTapSDK/CleverTapSyncDelegate.h>
#else
#import "CleverTapSyncDelegate.h"
#endif

#if __has_include(<CleverTapSDK/CleverTap+DisplayUnit.h>)
#import <CleverTapSDK/CleverTap+DisplayUnit.h>
#else
#import "CleverTap+DisplayUnit.h"
#endif

#if __has_include(<CleverTapSDK/CleverTap+FeatureFlags.h>)
#import <CleverTapSDK/CleverTap+FeatureFlags.h>
#else
#import "CleverTap+FeatureFlags.h"
#endif

#if __has_include(<CleverTapSDK/CleverTap+ProductConfig.h>)
#import <CleverTapSDK/CleverTap+ProductConfig.h>
#else
#import "CleverTap+ProductConfig.h"
#endif

#if __has_include(<CleverTapSDK/CleverTapPushNotificationDelegate.h>)
#import <CleverTapSDK/CleverTapPushNotificationDelegate.h>
#else
#import "CleverTapPushNotificationDelegate.h"
#endif

#if __has_include(<CleverTapSDK/CleverTapInAppNotificationDelegate.h>)
#import <CleverTapSDK/CleverTapInAppNotificationDelegate.h>
#else
#import "CleverTapInAppNotificationDelegate.h"
#endif

#if __has_include(<CleverTapSDK/CleverTap+InAppNotifications.h>)
#import <CleverTapSDK/CleverTap+InAppNotifications.h>
#else
#import "CleverTap+InAppNotifications.h"
#endif

#if __has_include(<CleverTapSDK/CleverTap+PushPermission.h>)
#import <CleverTapSDK/CleverTap+PushPermission.h>
#else
#import "CleverTap+PushPermission.h"
#endif

#if __has_include(<CleverTapSDK/CTLocalInApp.h>)
#import <CleverTapSDK/CTLocalInApp.h>
#else
#import "CTLocalInApp.h"
#endif

#if __has_include(<CleverTapSDK/CleverTap+CTVar.h>)
#import <CleverTapSDK/CleverTap+CTVar.h>
#else
#import "CleverTap+CTVar.h"
#endif

#if __has_include(<CleverTapSDK/CTVar.h>)
#import <CleverTapSDK/CTVar.h>
#else
#import "CTVar.h"
#endif

#if __has_include(<CleverTapSDK/CTTemplateContext.h>)
#import <CleverTapSDK/CTTemplateContext.h>
#else
#import "CTTemplateContext.h"
#endif

@interface CleverTapPlugin () <CleverTapSyncDelegate, CleverTapInAppNotificationDelegate, CleverTapDisplayUnitDelegate, CleverTapInboxViewControllerDelegate, CleverTapProductConfigDelegate, CleverTapFeatureFlagsDelegate, CleverTapPushNotificationDelegate, CleverTapPushPermissionDelegate>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,18 @@
#import "CleverTapPluginCustomTemplates.h"
#import "CleverTapPluginTemplatePresenter.h"
#import "CleverTapPluginAppFunctionPresenter.h"

#if __has_include(<CleverTapSDK/CTJsonTemplateProducer.h>)
#import <CleverTapSDK/CTJsonTemplateProducer.h>
#else
#import "CTJsonTemplateProducer.h"
#endif

#if __has_include(<CleverTapSDK/CTCustomTemplatesManager.h>)
#import <CleverTapSDK/CTCustomTemplatesManager.h>
#else
#import "CTCustomTemplatesManager.h"
#endif

@implementation CleverTapPluginCustomTemplates

Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ flutter:
pluginClass: CleverTapPlugin
ios:
pluginClass: CleverTapPlugin
swiftPackageName: clevertap_plugin
web:
pluginClass: CleverTapPluginWeb
fileName: clevertap_plugin_web.dart