Skip to content
Merged
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
27 changes: 6 additions & 21 deletions .github/workflows/flutter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,24 +43,9 @@ jobs:
with:
# You should create a personal access token and store it in your repository
token: ${{ secrets.CI_USER_TOKEN }}
repository: 'optimizely/travisci-tools'
path: 'home/runner/travisci-tools'
repository: 'optimizely/ci-helper-tools'
path: 'home/runner/ci-helper-tools'
ref: 'master'
# Set SDK Branch based on input or PR/Push
# - name: Set SDK Branch and Test App Branch
# run: |
# # If manually triggered
# if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
# echo "SDK_BRANCH=${{ github.event.inputs.sdk_branch || 'master' }}" >> $GITHUB_ENV
# echo "TESTAPP_BRANCH=${{ github.event.inputs.testapp_branch || 'master' }}" >> $GITHUB_ENV
# # If triggered by PR
# elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
# echo "SDK_BRANCH=${{ github.head_ref }}" >> $GITHUB_ENV
# # If triggered by push
# else
# echo "SDK_BRANCH=${{ github.ref_name }}" >> $GITHUB_ENV
# echo "TRAVIS_BRANCH=${{ github.ref_name }}" >> $GITHUB_ENV
# fi
- name: set SDK Branch if PR
env:
HEAD_REF: ${{ github.head_ref }}
Expand Down Expand Up @@ -91,7 +76,7 @@ jobs:
EVENT_MESSAGE: ${{ github.event.message }}
HOME: 'home/runner'
run: |
home/runner/travisci-tools/trigger-script-with-status-update.sh
home/runner/ci-helper-tools/trigger-script-with-status-update.sh

integration_ios_tests:
runs-on: ubuntu-latest
Expand All @@ -100,8 +85,8 @@ jobs:
with:
# You should create a personal access token and store it in your repository
token: ${{ secrets.CI_USER_TOKEN }}
repository: 'optimizely/travisci-tools'
path: 'home/runner/travisci-tools'
repository: 'optimizely/ci-helper-tools'
path: 'home/runner/ci-helper-tools'
ref: 'master'
- name: set SDK Branch if PR
env:
Expand Down Expand Up @@ -133,7 +118,7 @@ jobs:
EVENT_MESSAGE: ${{ github.event.message }}
HOME: 'home/runner'
run: |
home/runner/travisci-tools/trigger-script-with-status-update.sh
home/runner/ci-helper-tools/trigger-script-with-status-update.sh

build_test_android:
runs-on: ubuntu-latest
Expand Down
5 changes: 5 additions & 0 deletions .pubignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Project-specific documentation not needed in published package
CLAUDE.md

# Claude Code local configurations
.claude/
50 changes: 50 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,55 @@
# Optimizely Flutter SDK Changelog

## 3.4.1
January 28th, 2026

### Enhancements
* Exclude CMAB decision from UPS ([#96](https://github.com/optimizely/optimizely-flutter-sdk/pull/96))

## 3.4.0
January 7th, 2026

### New Features

* **CMAB (Contextual Multi-Armed Bandit) Support** ([#94](https://github.com/optimizely/optimizely-flutter-sdk/pull/94))
- Added `CmabConfig` class for CMAB initialization with configurable cache settings and custom prediction endpoints.
- Added `decideAsync()` methods to `OptimizelyUserContext` for asynchronous CMAB decision-making.
- New CMAB-specific decide options: `ignoreCmabCache`, `resetCmabCache`, `invalidateUserCmabCache`
* **Add Holdout support for feature experimentation.**
* **Add Multi-Region Support for Data Hosting.**

### Bug Fixes
* **Nested Object Support in Event Metadata for Swift** ([#92](https://github.com/optimizely/optimizely-flutter-sdk/pull/92))
- Enhanced event metadata handling to support complex nested objects in iOS/Swift.

## 3.3.0
October 29th, 2025

### New Feature
* Android custom logger support added ([#90](https://github.com/optimizely/optimizely-flutter-sdk/pull/90))

## 3.2.0
October 24th, 2025

### New Feature
* Swift custom logger support added ([#88](https://github.com/optimizely/optimizely-flutter-sdk/pull/88))

## 3.1.0
October 9th, 2025

This minor release added the following support:
* Android 15 support ([#84](https://github.com/optimizely/optimizely-flutter-sdk/pull/84))
* Update AGP version to 8.7.0
* Update gradle version to 8.10.2
* Update kotlin version to 2.1.0

## 3.0.1
Jun 4th, 2025

### Functionality Enhancements

* Add experiment id and variation id added into decision notification payload ([#80](https://github.com/optimizely/optimizely-flutter-sdk/pull/80))

## 3.0.0
November 28th, 2024

Expand Down
125 changes: 125 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Optimizely Flutter SDK - Cross-platform plugin wrapping native Optimizely SDKs (iOS, Android) for A/B testing, feature flags, CMAB, and ODP integration and others.

**Main Branch:** master

## Project Structure

```
lib/ # Dart: Public API, data models, user context, platform bridge
android/src/main/java/ # Java: OptimizelyFlutterClient.java, Plugin, helpers
ios/Classes/ # Swift: Plugin, logger bridge, helpers
test/ # Unit tests (SDK, CMAB, logger, nested objects)
example/ # Example app
```

## Essential Commands

```bash
# Setup
flutter pub get

# Testing
flutter test # All tests
flutter test test/cmab_test.dart # Specific test
flutter test --coverage # With coverage

# Linting
flutter analyze

# iOS setup
cd ios && pod install

# Run example
cd example && flutter run
```

## Architecture

### Bridge Pattern
```
Dart API (OptimizelyFlutterSdk)
Wrapper (OptimizelyClientWrapper) + MethodChannel
Native (Swift/Java plugin implementations)
Native Optimizely SDKs
```

### Critical Patterns

**1. Response Object Pattern**
- ALL methods return `BaseResponse` derivatives (never throw exceptions)
- Check `success` boolean and `reason` string for errors

**2. Multi-Instance State**
- SDK instances tracked by `sdkKey`
- User contexts: `sdkKey → userContextId → context`
- Notification listeners: `sdkKey → listenerId → callback`
- Call `close()` for cleanup

**3. Platform-Specific Type Encoding**
- **iOS**: Attributes need type metadata: `{"value": 123, "type": "int"}`
- **Android**: Direct primitives: `{"attribute": 123}`
- Conversion in `convertToTypedMap()` (`optimizely_client_wrapper.dart`)

**4. Dual Channels**
- `optimizely_flutter_sdk` - Main API
- `optimizely_flutter_logger` - Native log forwarding

## Key Files

**Dart:**
- `lib/optimizely_flutter_sdk.dart` - Public API entry point
- `lib/src/optimizely_client_wrapper.dart` - Platform channel bridge
- `lib/src/user_context/optimizely_user_context.dart` - User context API
- `lib/src/data_objects/` - 21 response/request models

**Android:**
- `android/src/.../OptimizelyFlutterSdkPlugin.java` - MethodChannel handler
- `android/src/.../OptimizelyFlutterClient.java` - Core client wrapper
- `android/build.gradle` - Dependencies & build config

**iOS:**
- `ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift` - MethodChannel handler
- `ios/optimizely_flutter_sdk.podspec` - Pod dependencies

## Adding Cross-Platform Features

1. Add data models in `lib/src/data_objects/` if needed
2. Update `optimizely_client_wrapper.dart` with method channel call
3. **Android**: Add case in `OptimizelyFlutterClient.java`, parse args, call native SDK
4. **iOS**: Add case in `SwiftOptimizelyFlutterSdkPlugin.swift`, parse args, call native SDK
5. Handle type conversions (iOS requires metadata)
6. Add tests
7. Update public API in `optimizely_flutter_sdk.dart`


## Contributing

### Commit Format
Follow [Angular guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines): `feat:`, `fix:`, `docs:`, `refactor:`, `test:`

### Requirements
- **Never commit directly to `master` branch** - Always create a feature branch
- Tests required for all changes
- PR to `master` branch
- All CI checks must pass (unit tests, build validation, integration tests)
- Apache 2.0 license header on new files

### CI Pipeline
- `unit_test_coverage` (macOS) - Coverage to Coveralls
- `build_test_android/ios` - Build validation
- `integration_android/ios_tests` - External test app triggers

## Platform Requirements

- Dart: >=2.16.2 <4.0.0, Flutter: >=2.5.0
- Android: minSdk 21, compileSdk 35
- iOS: 10.0+, Swift 5.0
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Other Flutter platforms are not currently supported by this SDK.
To add the flutter-sdk to your project dependencies, include the following in your app's pubspec.yaml:

```
optimizely_flutter_sdk: ^3.0.0
optimizely_flutter_sdk: ^3.4.1
```

Then run
Expand Down
5 changes: 5 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
include: package:flutter_lints/flutter.yaml

analyzer:
exclude:
- example/**
- test/**

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
23 changes: 11 additions & 12 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,22 @@ rootProject.allprojects {


ext {
compile_sdk_version = 32
build_tools_version = "30.0.3"
compile_sdk_version = 35
min_sdk_version = 21
target_sdk_version = 29
}

android {
namespace = "com.optimizely.optimizely_flutter_sdk"
compileSdkVersion compile_sdk_version
buildToolsVersion build_tools_version
namespace 'com.optimizely.optimizely_flutter_sdk'
compileSdkVersion rootProject.hasProperty('flutter.compileSdkVersion')
? rootProject.flutter.compileSdkVersion.toInteger()
: compile_sdk_version

buildFeatures {
buildConfig true
}

defaultConfig {
minSdkVersion min_sdk_version
targetSdkVersion target_sdk_version
versionCode 1
versionName version_name
buildConfigField "String", "CLIENT_VERSION", "\"$version_name\""
Expand Down Expand Up @@ -77,10 +76,10 @@ dependencies {
implementation 'com.github.tony19:logback-android:3.0.0'
implementation 'org.slf4j:slf4j-api:2.0.7'

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.10"
implementation "com.optimizely.ab:android-sdk:5.0.0"
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.4'
implementation('com.google.guava:guava:19.0') {
exclude group: 'com.google.guava', module: 'listenablefuture'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.0"
implementation "com.optimizely.ab:android-sdk:5.1.1"
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2'
implementation ('com.google.guava:guava:19.0') {
exclude group:'com.google.guava', module:'listenablefuture'
}
}
7 changes: 6 additions & 1 deletion android/proguard-rules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,10 @@
-keep class com.fasterxml.jackson.** {*;}
# Logback
-keep class ch.qos.** { *; }
-dontwarn javax.mail.** # Suppress warnings for javax.mail, we don't use SMTP

# Mail classes (Logback SMTP appender)
-dontwarn javax.mail.**
-dontwarn javax.mail.internet.**
-dontwarn javax.activation.**

##---------------End: proguard configuration ----------
19 changes: 1 addition & 18 deletions android/src/main/assets/logback.xml
Original file line number Diff line number Diff line change
@@ -1,18 +1 @@
<configuration
xmlns="https://tony19.github.io/logback-android/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://tony19.github.io/logback-android/xml https://cdn.jsdelivr.net/gh/tony19/logback-android/logback.xsd"
>
<appender name="logcat" class="ch.qos.logback.classic.android.LogcatAppender">
<tagEncoder>
<pattern>Optimizely</pattern>
</tagEncoder>
<encoder>
<pattern>%msg</pattern>
</encoder>
</appender>

<root level="DEBUG">
<appender-ref ref="logcat" />
</root>
</configuration>
<!-- We do not use this since all logging is handled programmatically via FlutterLogbackAppender and forwarded to the Dart logger. -->
Loading
Loading