From 92d141ae8ba2e4ac437c573a0fdc5beb5ed0ee6b Mon Sep 17 00:00:00 2001 From: Yann Date: Sat, 23 May 2026 15:44:28 -0300 Subject: [PATCH 1/4] Add iOS SwiftPM support --- .github/workflows/publish.yml | 38 ++++++++++++++----- .gitignore | 2 + CHANGELOG.md | 8 ++++ README.md | 4 ++ example/pubspec.yaml | 4 +- ios/Assets/.gitkeep | 0 ios/open_settings_plus.podspec | 6 +-- ios/open_settings_plus/Package.swift | 23 +++++++++++ .../OpenSettingsPlusPlugin.swift | 0 pubspec.yaml | 4 +- 10 files changed, 73 insertions(+), 16 deletions(-) delete mode 100644 ios/Assets/.gitkeep create mode 100644 ios/open_settings_plus/Package.swift rename ios/{Classes => open_settings_plus/Sources/open_settings_plus}/OpenSettingsPlusPlugin.swift (100%) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7dafee2..3dbf04f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,4 +1,4 @@ -name: Publish to pub.dev +name: Validate and publish on: push: @@ -6,16 +6,15 @@ on: - 'main' tags: - 'v[0-9]+.[0-9]+.[0-9]+*' + pull_request: + branches: + - 'main' jobs: - publish: - strategy: - matrix: - flutter-version: - - "3.13.0" + validate-and-publish: permissions: id-token: write - runs-on: ubuntu-latest + runs-on: macos-latest steps: - name: ๐Ÿ“š Git Checkout uses: actions/checkout@v4 @@ -23,16 +22,35 @@ jobs: - name: ๐Ÿฆ Setup Flutter uses: subosito/flutter-action@v2 with: - flutter-version: ${{ matrix.flutter-version }} + channel: stable + cache: true + + - name: ๐Ÿ”Ž Show tool versions + run: | + flutter --version + dart --version + xcodebuild -version + pod --version - name: ๐Ÿ“ฆ Install Dependencies run: flutter pub get - + - name: โœจ Check Formatting run: dart format --set-exit-if-changed . - name: ๐Ÿ•ต๏ธ Analyze run: dart analyze --fatal-infos --fatal-warnings . + - name: ๐Ÿงช Test + run: flutter test + + - name: ๐ŸŽ Validate iOS example with Swift Package Manager + run: | + flutter config --enable-swift-package-manager + flutter pub get + flutter build ios --no-codesign --verbose + working-directory: example + - name: ๐Ÿš€ Publish - run: dart pub publish --force \ No newline at end of file + if: startsWith(github.ref, 'refs/tags/v') + run: dart pub publish --force diff --git a/.gitignore b/.gitignore index 96486fd..93e0452 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ migrate_working_dir/ .dart_tool/ .packages build/ +.build/ +.swiftpm/ diff --git a/CHANGELOG.md b/CHANGELOG.md index aa699a0..230191c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## Unreleased + +### ๐Ÿ’ก Technical Improvements +- Added iOS Swift Package Manager support while keeping CocoaPods compatibility. +- Moved the iOS Swift plugin source into the SwiftPM target layout and updated the podspec source path. +- Raised the Flutter/Dart lower bounds required by Flutter's current SPM plugin integration. +- Updated the example app to opt into Swift Package Manager and added macOS CI validation for `flutter build ios --no-codesign`. + ## 0.4.2 ### ๐Ÿš€ New Features diff --git a/README.md b/README.md index cfe39c1..55e8235 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ We are aware that the shortcuts in open_settings_plus are not functioning proper A fix is being actively worked on and will be released as soon as possible. +## ๐Ÿ“ฆ Installation + +Add `open_settings_plus` to your `pubspec.yaml` as usual. On iOS, the plugin supports both CocoaPods and Swift Package Manager (SPM). CocoaPods remains supported for existing Flutter projects, while SPM is available when using Flutter `3.41.0` or newer with Flutter's Swift Package Manager integration enabled. The iOS deployment target is `12.0`. + ## ๐Ÿš€ Usage To integrate `open_settings_plus` into your project, add it as a dependency in your `pubspec.yaml` file. diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 324dafa..a243264 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -6,7 +6,7 @@ publish_to: "none" version: 1.0.0+1 environment: - sdk: ">=3.1.0" + sdk: ^3.11.0 dependencies: flutter: @@ -25,3 +25,5 @@ dev_dependencies: flutter: uses-material-design: true + config: + enable-swift-package-manager: true diff --git a/ios/Assets/.gitkeep b/ios/Assets/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/ios/open_settings_plus.podspec b/ios/open_settings_plus.podspec index d5af0b8..6c8efc3 100644 --- a/ios/open_settings_plus.podspec +++ b/ios/open_settings_plus.podspec @@ -4,7 +4,7 @@ # Pod::Spec.new do |s| s.name = 'open_settings_plus' - s.version = '0.0.1' + s.version = '0.4.2' s.summary = 'Open settings easily.' s.description = <<-DESC The most complete flutter plugin packages for open various settings screen, covering newer versions of ios and android. @@ -13,9 +13,9 @@ Pod::Spec.new do |s| s.license = { :file => '../LICENSE' } s.author = { 'Yann Cabral' => 'iamyanndias@gmail.com' } s.source = { :path => '.' } - s.source_files = 'Classes/**/*' + s.source_files = 'open_settings_plus/Sources/open_settings_plus/**/*' s.dependency 'Flutter' - s.platform = :ios, '11.0' + s.platform = :ios, '12.0' # Flutter.framework does not contain a i386 slice. s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } diff --git a/ios/open_settings_plus/Package.swift b/ios/open_settings_plus/Package.swift new file mode 100644 index 0000000..96b9def --- /dev/null +++ b/ios/open_settings_plus/Package.swift @@ -0,0 +1,23 @@ +// swift-tools-version: 5.9 +import PackageDescription + +let package = Package( + name: "open_settings_plus", + platforms: [ + .iOS("12.0") + ], + products: [ + .library(name: "open-settings-plus", targets: ["open_settings_plus"]) + ], + dependencies: [ + .package(name: "FlutterFramework", path: "../FlutterFramework") + ], + targets: [ + .target( + name: "open_settings_plus", + dependencies: [ + .product(name: "FlutterFramework", package: "FlutterFramework") + ] + ) + ] +) diff --git a/ios/Classes/OpenSettingsPlusPlugin.swift b/ios/open_settings_plus/Sources/open_settings_plus/OpenSettingsPlusPlugin.swift similarity index 100% rename from ios/Classes/OpenSettingsPlusPlugin.swift rename to ios/open_settings_plus/Sources/open_settings_plus/OpenSettingsPlusPlugin.swift diff --git a/pubspec.yaml b/pubspec.yaml index 024e8ea..8c79cd9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,8 +4,8 @@ version: 0.4.2 homepage: https://github.com/yanncabral/open_settings_plus environment: - sdk: ">=2.19.0 <4.0.0" - flutter: ">=2.5.0" + sdk: ^3.11.0 + flutter: ">=3.41.0" dependencies: flutter: From b0e9e73a236185ddc4fd3be474888cafbad30ffc Mon Sep 17 00:00:00 2001 From: Yann Date: Sat, 23 May 2026 15:45:20 -0300 Subject: [PATCH 2/4] Trigger PR validation From 33743a79c1869512954bf8027698d21b04f6eaba Mon Sep 17 00:00:00 2001 From: Yann Date: Sat, 23 May 2026 15:49:24 -0300 Subject: [PATCH 3/4] Format Dart sources with current SDK --- example/lib/main.dart | 10 +- .../open_settings_plus_method_channel.dart | 9 +- lib/core/open_settings_plus_android.dart | 163 +++++------------- test/open_settings_plus_test.dart | 6 +- 4 files changed, 50 insertions(+), 138 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index ac985eb..abf3b97 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -17,9 +17,7 @@ class MyApp extends StatelessWidget { const SliverAppBar( pinned: true, backgroundColor: Colors.blue, - flexibleSpace: FlexibleSpaceBar( - title: Text("Open settings +"), - ), + flexibleSpace: FlexibleSpaceBar(title: Text("Open settings +")), centerTitle: true, expandedHeight: 220, ), @@ -27,11 +25,7 @@ class MyApp extends StatelessWidget { body: switch (OpenSettingsPlus.shared) { OpenSettingsPlusAndroid settings => _buildAndroidList(settings), OpenSettingsPlusIOS settings => _buildIOSList(settings), - _ => const Center( - child: Text( - "Unsupported platform.", - ), - ), + _ => const Center(child: Text("Unsupported platform.")), }, ), ), diff --git a/lib/bridge/open_settings_plus_method_channel.dart b/lib/bridge/open_settings_plus_method_channel.dart index a034d76..030aa4f 100644 --- a/lib/bridge/open_settings_plus_method_channel.dart +++ b/lib/bridge/open_settings_plus_method_channel.dart @@ -10,12 +10,9 @@ class MethodChannelOpenSettingsPlus extends OpenSettingsPlusPlatform { @override Future sendMessageToNative(String message) async { - final success = await methodChannel.invokeMethod( - 'openSettings', - { - 'settingToOpen': message, - }, - ); + final success = await methodChannel.invokeMethod('openSettings', { + 'settingToOpen': message, + }); return success ?? false; } diff --git a/lib/core/open_settings_plus_android.dart b/lib/core/open_settings_plus_android.dart index adfc233..f228ec9 100644 --- a/lib/core/open_settings_plus_android.dart +++ b/lib/core/open_settings_plus_android.dart @@ -9,18 +9,16 @@ class OpenSettingsPlusAndroid extends OpenSettingsPlus { /// {@macro open_settings_plus_android} const OpenSettingsPlusAndroid(); - static const MethodChannel _androidMethodChannel = - MethodChannel('open_settings_plus'); + static const MethodChannel _androidMethodChannel = MethodChannel( + 'open_settings_plus', + ); /// Open Android settings using a raw intent action. /// returns operation successful or failure. Future sendAndroidIntent(String action) async { final success = await _androidMethodChannel.invokeMethod( 'openAndroidIntent', - { - 'action': action, - 'appSpecific': false, - }, + {'action': action, 'appSpecific': false}, ); return success ?? false; @@ -31,10 +29,7 @@ class OpenSettingsPlusAndroid extends OpenSettingsPlus { Future sendAndroidAppIntent(String action) async { final success = await _androidMethodChannel.invokeMethod( 'openAndroidIntent', - { - 'action': action, - 'appSpecific': true, - }, + {'action': action, 'appSpecific': true}, ); return success ?? false; @@ -43,152 +38,114 @@ class OpenSettingsPlusAndroid extends OpenSettingsPlus { /// Open Android settings. /// returns operation successful or failure. Future call() { - return sendCustomMessage( - 'android.settings.SETTINGS', - ); + return sendCustomMessage('android.settings.SETTINGS'); } /// Open Android settings in `Wi-Fi` section. /// returns operation successful or failure. Future wifi() { - return sendCustomMessage( - 'android.settings.WIFI_SETTINGS', - ); + return sendCustomMessage('android.settings.WIFI_SETTINGS'); } /// Open Android settings in `NFC` section. Future nfc() { - return sendCustomMessage( - 'android.settings.NFC_SETTINGS', - ); + return sendCustomMessage('android.settings.NFC_SETTINGS'); } /// Open Android settings in `Data & Roaming` section. /// returns operation successful or failure. Future dataRoaming() { - return sendCustomMessage( - 'android.settings.DATA_ROAMING_SETTINGS', - ); + return sendCustomMessage('android.settings.DATA_ROAMING_SETTINGS'); } /// Open Android settings in `Location` section. /// returns operation successful or failure. Future locationSource() { - return sendCustomMessage( - 'android.settings.LOCATION_SOURCE_SETTINGS', - ); + return sendCustomMessage('android.settings.LOCATION_SOURCE_SETTINGS'); } /// Open Android settings in `App Settings` section. /// returns operation successful or failure. Future appSettings() { - return sendCustomMessage( - 'android.settings.APPLICATION_SETTINGS', - ); + return sendCustomMessage('android.settings.APPLICATION_SETTINGS'); } /// Open Android settings in `Bluetooth` section. /// returns operation successful or failure. Future bluetooth() { - return sendCustomMessage( - 'android.settings.BLUETOOTH_SETTINGS', - ); + return sendCustomMessage('android.settings.BLUETOOTH_SETTINGS'); } /// Open Android settings in `Notification` section. /// returns operation successful or failure. Future notification() { - return sendCustomMessage( - 'android.settings.NOTIFICATION_SETTINGS', - ); + return sendCustomMessage('android.settings.NOTIFICATION_SETTINGS'); } /// Open Android settings in `Security` section. /// returns operation successful or failure. Future security() { - return sendCustomMessage( - 'android.settings.SECURITY_SETTINGS', - ); + return sendCustomMessage('android.settings.SECURITY_SETTINGS'); } /// Open Android settings in `Sound` section. /// returns operation successful or failure. Future sound() { - return sendCustomMessage( - 'android.settings.SOUND_SETTINGS', - ); + return sendCustomMessage('android.settings.SOUND_SETTINGS'); } /// Open Android settings in `Display` section. /// returns operation successful or failure. Future display() { - return sendCustomMessage( - 'android.settings.DISPLAY_SETTINGS', - ); + return sendCustomMessage('android.settings.DISPLAY_SETTINGS'); } /// Open Android settings in `Date` section. /// returns operation successful or failure. Future date() { - return sendCustomMessage( - 'android.settings.DATE_SETTINGS', - ); + return sendCustomMessage('android.settings.DATE_SETTINGS'); } /// Open Android settings in `Device Info` section. /// returns operation successful or failure. Future deviceInfo() { - return sendCustomMessage( - 'android.settings.DEVICE_INFO_SETTINGS', - ); + return sendCustomMessage('android.settings.DEVICE_INFO_SETTINGS'); } /// Open Android settings in `Internal Storage` section. /// returns operation successful or failure. Future internalStorage() { - return sendCustomMessage( - 'android.settings.INTERNAL_STORAGE_SETTINGS', - ); + return sendCustomMessage('android.settings.INTERNAL_STORAGE_SETTINGS'); } /// Open Android settings in `Memory Card` section. /// returns operation successful or failure. Future memoryCard() { - return sendCustomMessage( - 'android.settings.MEMORY_CARD_SETTINGS', - ); + return sendCustomMessage('android.settings.MEMORY_CARD_SETTINGS'); } /// Open Android settings in `Accessbility` section. /// returns operation successful or failure. Future accessibility() { - return sendCustomMessage( - 'android.settings.ACCESSIBILITY_SETTINGS', - ); + return sendCustomMessage('android.settings.ACCESSIBILITY_SETTINGS'); } /// Open Android settings in `Add Account` section. /// returns operation successful or failure. Future addAccount() { - return sendCustomMessage( - 'android.settings.ADD_ACCOUNT_SETTINGS', - ); + return sendCustomMessage('android.settings.ADD_ACCOUNT_SETTINGS'); } /// Open Android settings in `Airplane Mode` section. /// returns operation successful or failure. Future airplaneMode() { - return sendCustomMessage( - 'android.settings.AIRPLANE_MODE_SETTINGS', - ); + return sendCustomMessage('android.settings.AIRPLANE_MODE_SETTINGS'); } /// Open Android settings in `Apn Settings` section. /// returns operation successful or failure. Future apnSettings() { - return sendCustomMessage( - 'android.settings.APN_SETTINGS', - ); + return sendCustomMessage('android.settings.APN_SETTINGS'); } /// Open Android settings in `Application Details` section. @@ -217,57 +174,43 @@ class OpenSettingsPlusAndroid extends OpenSettingsPlus { /// Open Android settings in `Application Settings` section. /// returns operation successful or failure. Future applicationSettings() { - return sendCustomMessage( - 'android.settings.APPLICATION_SETTINGS', - ); + return sendCustomMessage('android.settings.APPLICATION_SETTINGS'); } /// Open Android settings in `Application Write Settings` section. /// returns operation successful or failure. Future applicationWriteSettings() { - return sendCustomMessage( - 'android.settings.APPLICATION_WRITE_SETTINGS', - ); + return sendCustomMessage('android.settings.APPLICATION_WRITE_SETTINGS'); } /// Open Android settings in `Battery Saver` section. /// returns operation successful or failure. Future batterySaver() { - return sendCustomMessage( - 'android.settings.BATTERY_SAVER_SETTINGS', - ); + return sendCustomMessage('android.settings.BATTERY_SAVER_SETTINGS'); } /// Open Android settings in `Captioning` section. /// returns operation successful or failure. Future captioning() { - return sendCustomMessage( - 'android.settings.CAPTIONING_SETTINGS', - ); + return sendCustomMessage('android.settings.CAPTIONING_SETTINGS'); } /// Open Android settings in `Cast` section. /// returns operation successful or failure. Future cast() { - return sendCustomMessage( - 'android.settings.CAST_SETTINGS', - ); + return sendCustomMessage('android.settings.CAST_SETTINGS'); } /// Open Android settings in `Data Usage` section. /// returns operation successful or failure. Future dataUsage() { - return sendCustomMessage( - 'android.settings.DATA_USAGE_SETTINGS', - ); + return sendCustomMessage('android.settings.DATA_USAGE_SETTINGS'); } /// Open Android settings in `Mobile Hotspot & Tethering` section. /// returns operation successful or failure. Future tether() { - return sendCustomMessage( - 'android.settings.TETHER_SETTINGS', - ); + return sendCustomMessage('android.settings.TETHER_SETTINGS'); } /// Open Android settings in `App Notification Bubble` section. @@ -281,9 +224,7 @@ class OpenSettingsPlusAndroid extends OpenSettingsPlus { /// Open Android settings in `App Notification` section. /// returns operation successful or failure. Future appNotification() { - return sendAndroidAppIntent( - 'android.settings.APP_NOTIFICATION_SETTINGS', - ); + return sendAndroidAppIntent('android.settings.APP_NOTIFICATION_SETTINGS'); } /// Open Android settings in `Open by default` section. @@ -297,33 +238,25 @@ class OpenSettingsPlusAndroid extends OpenSettingsPlus { /// Open Android settings in `Search` section. /// returns operation successful or failure. Future search() { - return sendCustomMessage( - 'android.search.action.SEARCH_SETTINGS', - ); + return sendCustomMessage('android.search.action.SEARCH_SETTINGS'); } /// Open Android settings in `Biometric Enroll` section. /// returns operation successful or failure. Future biometricEnroll() { - return sendCustomMessage( - 'android.settings.BIOMETRIC_ENROLL', - ); + return sendCustomMessage('android.settings.BIOMETRIC_ENROLL'); } /// Open Android settings in `HardKeyboard` section. /// returns operation successful or failure. Future hardwareKeyboard() { - return sendCustomMessage( - 'android.settings.HARD_KEYBOARD_SETTINGS', - ); + return sendCustomMessage('android.settings.HARD_KEYBOARD_SETTINGS'); } /// Open Android settings in `Home` section. /// returns operation successful or failure. Future home() { - return sendCustomMessage( - 'android.settings.HOME_SETTINGS', - ); + return sendCustomMessage('android.settings.HOME_SETTINGS'); } /// Open Android settings in `Ignore Background Data Restrictions` section. @@ -345,25 +278,19 @@ class OpenSettingsPlusAndroid extends OpenSettingsPlus { /// Open Android settings in `Input Method` section. /// returns operation successful or failure. Future inputMethod() { - return sendCustomMessage( - 'android.settings.INPUT_METHOD_SETTINGS', - ); + return sendCustomMessage('android.settings.INPUT_METHOD_SETTINGS'); } /// Open Android settings in `Input Method Subtype` section. /// returns operation successful or failure. Future inputMethodSubtype() { - return sendCustomMessage( - 'android.settings.INPUT_METHOD_SUBTYPE_SETTINGS', - ); + return sendCustomMessage('android.settings.INPUT_METHOD_SUBTYPE_SETTINGS'); } /// Open Android settings in `Locale` section. /// returns operation successful or failure. Future locale() { - return sendCustomMessage( - 'android.settings.LOCALE_SETTINGS', - ); + return sendCustomMessage('android.settings.LOCALE_SETTINGS'); } /// Open Android settings in `Manage All Applications` section. @@ -377,17 +304,13 @@ class OpenSettingsPlusAndroid extends OpenSettingsPlus { /// Open Android settings in `Manage Application` section. /// returns operation successful or failure. Future manageApplication() { - return sendCustomMessage( - 'android.settings.MANAGE_APPLICATIONS_SETTINGS', - ); + return sendCustomMessage('android.settings.MANAGE_APPLICATIONS_SETTINGS'); } /// Open Android settings in `Manage Default Apps` section. /// returns operation successful or failure. Future manageDefaultApps() { - return sendCustomMessage( - 'android.settings.MANAGE_DEFAULT_APPS_SETTINGS', - ); + return sendCustomMessage('android.settings.MANAGE_DEFAULT_APPS_SETTINGS'); } /// Open Android settings in `Manage External Sources` section. @@ -401,8 +324,6 @@ class OpenSettingsPlusAndroid extends OpenSettingsPlus { /// Open Android settings in `Manage Overlay` section. /// returns operation successful or failure. Future manageOverlay() { - return sendCustomMessage( - 'android.settings.MANAGE_OVERLAY_PERMISSION', - ); + return sendCustomMessage('android.settings.MANAGE_OVERLAY_PERMISSION'); } } diff --git a/test/open_settings_plus_test.dart b/test/open_settings_plus_test.dart index 643a34c..3cea948 100644 --- a/test/open_settings_plus_test.dart +++ b/test/open_settings_plus_test.dart @@ -52,9 +52,9 @@ void main() { lastCall = null; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, (call) async { - lastCall = call; - return true; - }); + lastCall = call; + return true; + }); }); tearDown(() { From 37f12bb9b81a6f9bc14b01be6a9fedf51075646f Mon Sep 17 00:00:00 2001 From: Yann Date: Sat, 23 May 2026 16:11:34 -0300 Subject: [PATCH 4/4] Bump version to 0.5.0 --- CHANGELOG.md | 2 +- ios/open_settings_plus.podspec | 2 +- pubspec.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 230191c..f10cff0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## Unreleased +## 0.5.0 ### ๐Ÿ’ก Technical Improvements - Added iOS Swift Package Manager support while keeping CocoaPods compatibility. diff --git a/ios/open_settings_plus.podspec b/ios/open_settings_plus.podspec index 6c8efc3..d594a01 100644 --- a/ios/open_settings_plus.podspec +++ b/ios/open_settings_plus.podspec @@ -4,7 +4,7 @@ # Pod::Spec.new do |s| s.name = 'open_settings_plus' - s.version = '0.4.2' + s.version = '0.5.0' s.summary = 'Open settings easily.' s.description = <<-DESC The most complete flutter plugin packages for open various settings screen, covering newer versions of ios and android. diff --git a/pubspec.yaml b/pubspec.yaml index 8c79cd9..400a06f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: open_settings_plus description: The most complete flutter plugin packages for open various settings screen, covering newer versions of ios and android. -version: 0.4.2 +version: 0.5.0 homepage: https://github.com/yanncabral/open_settings_plus environment: