Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
104 changes: 104 additions & 0 deletions doc/Integrate-iOS-SPM.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
## 📦 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`).

> **Minimum requirements**
> - Flutter 3.27+
> - Xcode 15+
> - iOS deployment target: 13.0+

---

### 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

```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` |
| 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'
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"
)
],
targets: [
.target(
name: "clevertap_plugin",
dependencies: [
.product(name: "CleverTapSDK", package: "clevertap-ios-sdk")
],
publicHeadersPath: "include/clevertap_plugin",
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
3 changes: 2 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ homepage: https://github.com/CleverTap/clevertap-flutter

environment:
sdk: '>=2.12.0 <4.0.0'
flutter: ">=1.17.0"
flutter: ">=3.41.0"

dependencies:
flutter:
Expand All @@ -28,6 +28,7 @@ flutter:
pluginClass: CleverTapPlugin
ios:
pluginClass: CleverTapPlugin
swiftPackageName: clevertap_plugin
web:
pluginClass: CleverTapPluginWeb
fileName: clevertap_plugin_web.dart