dart-lang / http

A composable API for making HTTP requests in Dart.
https://pub.dev/packages/http
BSD 3-Clause "New" or "Revised" License
1.02k stars 351 forks source link

Add Swift Package Manager support #1276

Open loic-sharma opened 1 month ago

loic-sharma commented 1 month ago

Hello,

Flutter is migrating to Swift Package Manager. Please add Swift Package Manager support to your plugin.

Flutter will eventually deprecate and then remove support for CocoaPods. Adding Swift Package Manager support future-proofs your plugins.

How to add Swift Package Manager support to your plugins

You can find the migration guide here: https://docs.flutter.dev/packages-and-plugins/swift-package-manager/for-plugin-authors#how-to-add-swift-package-manager-support-to-an-existing-flutter-plugin

If you run into issues or have questions, please reach out to the Flutter team. You can ping me at @loic-sharma, send a message to the #hackers-ios channel on Flutter’s discord, or open a GitHub issue.

Thank you for your wonderful contributions to the Flutter ecosystem!

Why is Flutter migrating to Swift Package Manager?

Swift Package Manager support is one of Flutter’s most requested features: flutter#33850.

Flutter's Swift Package Manager integration has several benefits:

  1. Access to the Swift package ecosystem. Flutter plugins can use the growing ecosystem of Swift packages.
  2. Simplifies Flutter installation. Swift Package Manager is bundled with Xcode. In the future, you won’t need to install Ruby and CocoaPods to target iOS or macOS.
brianquinlan commented 1 month ago

@loic-sharma

I followed the instructions in the migration guide and got these XCode errors after performing step 12 > 2.

Here is what the PR looked like at that point: https://github.com/dart-lang/http/pull/1288

loic-sharma commented 1 month ago

Oops the instructions were incorrect. The files in pkgs/cupertino_http/ios/Sources/cupertino_http/ should be moved to pkgs/cupertino_http/ios/cupertino_http/Sources/cupertino_http/.

I sent a docs fix here: https://github.com/flutter/website/pull/11029

brianquinlan commented 2 weeks ago

Sorry for the long delay - some unrelated changes needed to be made before I could make progress on this.

I don't understand how the header files should be organized. I initially placed all of my headers in "darwin/cupertino_http/Sources/cupertino_http/include/cupertino_http". The worked for top level includes but it did not work for includes in the "dart-sdk" directory (with the podspec build):

--- xcodebuild: WARNING: Using the first of multiple matching destinations:
{ platform:macOS, arch:arm64, id:00006000-001448641406801E, name:My Mac }
{ platform:macOS, arch:x86_64, id:00006000-001448641406801E, name:My Mac }
In file included from /Users/bquinlan/dart/http/pkgs/cupertino_http/darwin/cupertino_http/Sources/cupertino_http/CUPHTTPClientDelegate.m:5:
/Users/bquinlan/dart/http/pkgs/cupertino_http/darwin/cupertino_http/Sources/cupertino_http/include/cupertino_http/CUPHTTPClientDelegate.h:11:10: fatal error: 'dart-sdk/include/dart_api_dl.h' file not found
#include "dart-sdk/include/dart_api_dl.h"
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
** BUILD FAILED **

I didn't understand the phrase in the documentation: "You should consider whether you want all of your headers to be public." When do my headers need to be public vs. non-public? What do I do if I don't want my headers to be public?

Since, AFAIK, I don't need any of my headers to be public, I assumed that the includes should be in the same directory as the sources. That is the current state of https://github.com/dart-lang/http/pull/1288. But it can't seem to find any headers (with the podspec build):

--- xcodebuild: WARNING: Using the first of multiple matching destinations:
{ platform:macOS, arch:arm64, id:00006000-001448641406801E, name:My Mac }
{ platform:macOS, arch:x86_64, id:00006000-001448641406801E, name:My Mac }
error: /Users/bquinlan/dart/http/pkgs/cupertino_http/darwin/cupertino_http/Sources/cupertino_http/include/cupertino_http/CUPHTTPClientDelegate.h: No such file or directory (in target 'cupertino_http' from project 'Pods')
** BUILD FAILED **

Building macOS application...
Error: Build process failed

@loic-sharma Please advise ;-)

loic-sharma commented 2 weeks ago

Thanks for the feedback! I'll take a closer look at this tomorrow, but some initial responses:

But it can't seem to find any headers (with the podspec build):

I'll investigate tomorrow!

When do my headers need to be public vs. non-public?

If a header contains APIs that are meant to be called by code outside of your plugin, it must be public. If a header contains APIs that are only internal for the plugin, ideally the header file would be non-public.

However, it's very common for CocoaPod packages to just make all their headers public. This isn't ideal, folks could start using your internal APIs in unexpected ways; changing your implementation could be an unintentional breaking change. However, converting public header files to non-public is technically also a breaking change.

I didn't understand the phrase in the documentation: "You should consider whether you want all of your headers to be public."

Thanks that's good feedback. I'll expand that section!

loic-sharma commented 2 weeks ago

@brianquinlan I checked out https://github.com/dart-lang/http/pull/1288, and I got different build errors than the one you reported above. I was able to fix the build errors I ran into using this patch:

diff --git a/pkgs/cupertino_http/darwin/cupertino_http.podspec b/pkgs/cupertino_http/darwin/cupertino_http.podspec
index 9e09c66..5bd2846 100644
--- a/pkgs/cupertino_http/darwin/cupertino_http.podspec
+++ b/pkgs/cupertino_http/darwin/cupertino_http.podspec
@@ -12,6 +12,7 @@ Pod::Spec.new do |s|
   s.homepage         = 'https://github.com/dart-lang/http/tree/master/pkgs/cupertino_http'
   s.license          = { :type => 'BSD', :file => '../LICENSE' }
   s.author           = { 'TODO' => 'use-valid-author' }
+  s.source           = { :http => 'https://github.com/dart-lang/http/tree/master/pkgs/cupertino_http' }

   s.source_files = 'cupertino_http/Sources/cupertino_http/**/*'
   s.ios.dependency 'Flutter'
diff --git a/pkgs/cupertino_http/darwin/cupertino_http/Package.swift b/pkgs/cupertino_http/darwin/cupertino_http/Package.swift
index 017f286..7da45e8 100644
--- a/pkgs/cupertino_http/darwin/cupertino_http/Package.swift
+++ b/pkgs/cupertino_http/darwin/cupertino_http/Package.swift
@@ -32,8 +32,9 @@ let package = Package(
             ],
             cSettings: [
                 // TODO: Update your plugin name.
-                .headerSearchPath("include")
-                .headerSearchPath("include/cupertino_http")
+                //.headerSearchPath("include"),
+                .headerSearchPath("include/cupertino_http"),
+                .unsafeFlags(["-fno-objc-arc"]),
             ]
         )
     ]

Here's my fork with this patch applied: https://github.com/loic-sharma/dart-lang-http/commit/12c18673dedaff204ab0d8be11e07256bd7d8142

With this patch, the following steps work as expected:

cd pkgs/cupertino_http/example

flutter config --no-enable-swift-package-manager
flutter build ios

flutter config --enable-swift-package-manager
flutter build ios

Could you try that patch and let me know if that fixes your build issues? If it doesn't, could you share: what steps you're using to get that build error, which Flutter SDK version you're on, which Xcode version you're on.

Also, feel free to drop something on my calendar if you want to hack on this together :)

brianquinlan commented 1 week ago

@loic-sharma That does fix my build issues and the CocoaPods build works fun. Unfortunately, the Swift Package Manager version fails at runtime.

$ flutter config --enable-swift-package-manager
Setting "enable-swift-package-manager" value to "true".

You may need to restart any open editors for them to read new settings.
$ flutter clean
$ flutter run
Connected devices:
macOS (desktop)                 • macos                 • darwin-arm64 • macOS 14.6.1 23G93 darwin-arm64
Mac Designed for iPad (desktop) • mac-designed-for-ipad • darwin       • macOS 14.6.1 23G93 darwin-arm64

No wireless devices were found.

[1]: macOS (macos)
[2]: Mac Designed for iPad (mac-designed-for-ipad)
Please choose one (or "q" to quit): 1
Resolving dependencies...
Downloading packages...
  _fe_analyzer_shared 67.0.0 (73.0.0 available)
  analyzer 6.4.1 (6.8.0 available)
  coverage 1.8.0 (1.9.2 available)
  crypto 3.0.3 (3.0.5 available)
  dart_flutter_team_lints 3.1.0 (3.2.0 available)
  ffi 2.1.2 (2.1.3 available)
  http 1.2.1 (1.2.2 available)
  http_parser 4.0.2 (4.1.0 available)
  leak_tracker 10.0.5 (10.0.7 available)
  leak_tracker_flutter_testing 3.0.5 (3.0.8 available)
  material_color_utilities 0.11.1 (0.12.0 available)
  mime 1.0.5 (1.0.6 available)
  shelf 1.4.1 (1.4.2 available)
  shelf_web_socket 1.0.4 (2.0.0 available)
  source_map_stack_trace 2.1.1 (2.1.2 available)
  vm_service 14.2.4 (14.2.5 available)
  web 0.5.1 (1.0.0 available)
  web_socket 0.1.5 (0.1.6 available)
  web_socket_channel 2.4.5 (3.0.1 available)
Got dependencies!
19 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.
All plugins found for macos are Swift Packages, but your project still has CocoaPods integration. Your project uses a non-standard Podfile and will need to be migrated to
Swift Package Manager manually. Some steps you may need to complete include:
  * In the macos/ directory run "pod deintegrate"
  * Transition any Pod dependencies to Swift Package equivalents. See https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app
  * Transition any custom logic
  * Remove the include to "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" in your macos/Flutter/Flutter-Debug.xcconfig
  * Remove the include to "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" in your macos/Flutter/Flutter-Release.xcconfig

Removing CocoaPods integration will improve the project's build time.
Launching lib/main.dart on macOS in debug mode...
Running pod install...                                             699ms
--- xcodebuild: WARNING: Using the first of multiple matching destinations:
{ platform:macOS, arch:arm64, id:00006000-001448641406801E, name:My Mac }
{ platform:macOS, arch:x86_64, id:00006000-001448641406801E, name:My Mac }
Building macOS application...
✓ Built build/macos/Build/Products/Debug/cupertino_http_example.app
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Invalid argument(s): Failed to load dynamic library 'cupertino_http.framework/cupertino_http': dlopen(cupertino_http.framework/cupertino_http, 0x0001): tried: 'cupertino_http.framework/cupertino_http' (no such file), '/System/Volumes/Preboot/Cryptexes/OScupertino_http.framework/cupertino_http' (no such file), '/Users/bquinlan/dart/http/pkgs/cupertino_http/example/build/macos/Build/Products/Debug/cupertino_http_example.app/Contents/Frameworks/FlutterMacOS.framework/Versions/A/./cupertino_http.framework/cupertino_http' (no such file), '/usr/local/lib/./cupertino_http.framework/cupertino_http' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/usr/local/lib/./cupertino_http.framework/cupertino_http' (no such file), '/Users/bquinlan/dart/http/pkgs/cupertino_http/example/build/macos/Build/Products/Debug/cupertino_http_example.app/Contents/Frameworks/FlutterMacOS.framework/Versions/A/../../../cupertino_http.framework/cupertino_http' (no such file), '/usr/lib/swift/cupertino_http.framework/cupertino_http' (no such file, not in dyld cache), '/System/Volumes/Preboot/Cryptexes/OS/usr/lib/swift/cupertino_http.framework/cupertino_http' (no such file), '/Users/bquinlan/dart/http/pkgs/cupertino_http/example/build/macos/Build/Products/Debug/PackageFrameworks/cupertino_http.framework/cupertino_http' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/Users/bquinlan/dart/http/pkgs/cupertino_http/example/build/macos/Build/Products/Debug/PackageFrameworks/cupertino_http.framework/cupertino_http' (no such file), '/Users/bquinlan/dart/http/pkgs/cupertino_http/example/build/macos/Build/Products/Debug/cupertino_http_example.app/Contents/Frameworks/cupertino_http.framework/cupertino_http' (no such file), '/Users/bquinlan/dart/http/pkgs/cupertino_http/example/build/macos/Build/Products/Debug/cupertino_http_example.app/Contents/MacOS/Frameworks/cupertino_http.framework/cupertino_http' (no such file), '/usr/lib/cupertino_http.framework/cupertino_http' (no such file, not in dyld cache), 'cupertino_http.framework/cupertino_http' (no such file)
#0      _open (dart:ffi-patch/ffi_dynamic_library_patch.dart:11:43)
#1      new DynamicLibrary.open (dart:ffi-patch/ffi_dynamic_library_patch.dart:22:12)
#2      _loadHelperDynamicLibrary (package:cupertino_http/src/utils.dart:32:27)
#3      _loadHelperLibrary (package:cupertino_http/src/utils.dart:40:15)
#4      helperLibs (package:cupertino_http/src/utils.dart:28:44)
#5      helperLibs (package:cupertino_http/src/utils.dart)
#6      URLSession._delegate (package:cupertino_http/src/cupertino_api.dart:1331:59)
#7      URLSession._delegate (package:cupertino_http/src/cupertino_api.dart)
#8      new URLSession.sessionWithConfiguration (package:cupertino_http/src/cupertino_api.dart:1460:43)
#9      new CupertinoClient.fromSessionConfiguration (package:cupertino_http/src/cupertino_client.dart:239:32)
#10     main (package:cupertino_http_example/main.dart:23:34)
#11     _runMain.<anonymous closure> (dart:ui/hooks.dart:301:23)
#12     _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19)
#13     _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)

Syncing files to device macOS...                                   258ms

The Objective-C code is being built because, if I introduce a syntax error, the run fails and I see an error message.

Using CocoaPods:

$ find build/ -name "cupertino_http"
build//macos/Build/Products/Debug/cupertino_http_example.app/Contents/Frameworks/cupertino_http.framework/Versions/A/cupertino_http
build//macos/Build/Products/Debug/cupertino_http_example.app/Contents/Frameworks/cupertino_http.framework/cupertino_http
build//macos/Build/Products/Debug/cupertino_http
build//macos/Build/Products/Debug/cupertino_http/cupertino_http.framework/Versions/A/cupertino_http
build//macos/Build/Products/Debug/cupertino_http/cupertino_http.framework/cupertino_http
$ otool -t -v build//macos/Build/Products/Debug/cupertino_http_example.app/Contents/Frameworks/cupertino_http.framework/cupertino_http
build//macos/Build/Products/Debug/cupertino_http_example.app/Contents/Frameworks/cupertino_http.framework/cupertino_http:
(__TEXT,__text) section
-[CUPHTTPTaskConfiguration initWithPort:]:
...

I can't find an equivalent file with the swift build.