-
Notifications
You must be signed in to change notification settings - Fork 511
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to distribute xcframework with nugets ? #10819
Comments
@leonluc-dev was trying to figure out how to make a NuGet package work with binding to an XCFramework in #10774
So far as I know the easiest way to copy the
In my .nuspec file, I set the
The
|
@dkornev Thanks for posting this!, I was able to follow these steps to get a different native Improvement suggestions
Questions
|
Xamarin has limited support for `.xcframework` files, they do not have a built in working solution for NuGet packages yet. This works around the issue by including `OneSignal.xcframework` as-is in the `.nupkg`. It also includes a `.target` file which is setting to add the `OneSignal.xcframework` as a native reference. See the comment in the `Com.OneSignal.nuspec` file for more details. The items under `<NativeReference>` in `Com.OneSignal.targets` is from `OneSignal.iOS.Binding.csproj` in this repo. This was added based on the recommendations from: - xamarin/xamarin-macios#10819 (comment)
Xamarin has limited support for `.xcframework` files, they do not have a built in working solution for NuGet packages yet. This works around the issue by including `OneSignal.xcframework` as-is in the `.nupkg`. It also includes a `.target` file which is setting to add the `OneSignal.xcframework` as a native reference. See the comment in the `Com.OneSignal.nuspec` file for more details. The items under `<NativeReference>` in `Com.OneSignal.targets` is from `OneSignal.iOS.Binding.csproj` in this repo. This was added based on the recommendations from: - xamarin/xamarin-macios#10819 (comment)
@dkornev Combined with some of the tips by @jkasten2 this solution works! It's a shame the official documentation on this is so minimal to non-existent. Especially since over time more third-party libraries are switching to xcframework. A few recommendations for stuff I encountered: Path length
Output folder
|
This will be fixed in .NET, where we'll support |
@rolfbjarne Thanks for the update, good to hear this will be supported! Is there a beta or preview where we can try this out now? |
@jkasten2 that page won't get any updates about XCFrameworks, which is Apple-specific, and that page is more generic. You can try the latest .NET 6 + MAUI preview and it should work there. |
This approach was discussed in xamarin/xamarin-macios#10819 (comment) I was inspired by https://github.com/OneSignal/OneSignal-Xamarin-SDK/blob/4.0.0_release/Com.OneSignal.nuspec and https://github.com/OneSignal/OneSignal-Xamarin-SDK/blob/4.0.0_release/OneSignal.iOS.Binding/Com.OneSignal.targets
@rolfbjarne is there any ETA? or maybe there's a proper known workaround for NuGet while using .xcframework? |
@nrudnyk ETA for .NET is second quarter in 2022 (https://github.com/dotnet/maui/wiki/roadmap).
Other people in this issue seem to have been able to find a solution (#10819 (comment) for instance). |
@rolfbjarne that's exactly what I've tried, but when trying to consume Nuget Package, I've got the following issue |
@leonluc-dev do you have link for final .targets file? or maybe can share one (which includes fixes from above mentioned comments). Thanks |
For what it's worth, I've come up with a different solution which allows one to use the newer compressed binding resource package support and still have it work with the legacy Xamarin.iOS10 target framework when consuming the resulting nuget package from Windows. It was based off of the scheme xamarin/FacebookComponents used with some changes to support the compressed resources being used remotely. It works both locally on a Mac, remotely from Windows and within multi-targeting packages that support both legacy xamarin. and newer net6.0 frameworks, though each target framework will have the same xcframework compressed repeatedly. The Xamarin.iOS10 target xcframework support is rather incomplete/broken in that it doesn't properly support zipped frameworks when used remotely. It is also a giant mess with some work performed by msbuild, MTouch and other tasks rather than all in one place. Zipped frameworks are crucial to avoid long path and file names issues on Windows and for macOS and MacCatalyst to preserve the symlinks since NuGet doesn't pack them properly and thus will fail during codesign. The basic idea is to turn off binding embedding, enable compressing of the binding resources, include a build/buildTransitive targets file in the nuget, import it in the binding project and add a placeholder native reference. The targets file does the work of resolving the placeholder native reference into a real native reference based on the build context to either the xcframework or an inner arch specific framework, and copies the resources zip to a well known location that will get extracted automatically by MTouch during build. Some of the complexity could get simplified if you don't mind duplicating the native reference params in both the binding project and targets file. And most of that complexity only applies to legacy xamarin target frameworks, as the newer net6.0 ones just work when compressing the binding resource package. MyBindingAssembly.csproj:
MyBindingAssembly.targets:
This whole scheme works because MTouch checks for and unzips a resources.zip file that matches the assembly name used for references. It does this to read an embedded manifest file to add additional native references to link with. Unfortunately it does nothing when it encounters an xcframework because it expects an msbuild task ResolveNativeReferences to do that. But we can at least leverage this partial support to automatically unzip the resources for us as long as we can put the resources.zip in the right location. The Ditto task will do just that and does so correctly when run both locally on the Mac and remotely from Windows. Alternatively, the implicit MTouch behavior could be replaced with the Exec task that has SessionId set appropriately and Command set to unzip the resources.zip. Now there is a big problem with the ResolveNativeReferences task in that it doesn't know we have a NativeReference in a nuget package reference that isn't embedded. That is actually because such nuget references are intentionally excluded. The typical workaround is to use the build/buildTransitive targets import to inject NativeReference in the project being built. Alternatively the nuget package references could get forcibly added back to the References ItemGroup. Unfortunately neither option will work because the xcframework is compressed in the resources.zip. If we force it, it even attempts to run /usr/bin/unzip on Windows rather than on the connected Mac, in an effort to inspect the frameworks archs and their info plist files within the zip to perform the resolve, though it would work when run locally on a Mac. The only viable workaround is a variant of the typical one to inject a NativeReference during the build but here we must perform the resolution of an xcframework into a framework ourselves by knowing the available architectures the xcframework supports and checking the various available build properties to select it. Once the correct architecture is determined, it can then be emitted as a NativeReference per usual, avoiding the need for the compressed xcframework to be extracted and bypassing the work ResolveNativeReferences normally performs. Everything would work so much better if the ResolveNativeReferences task was fixed. Why this was never implemented properly in the first place just shows how the xamarin devs don't actually make real apps with their tools and/or fundamentally misunderstand real world development workflows. While the above scheme works, multi-targeting can lead to package bloat. This could potentially be solved by augmenting the _CreateBindingResourcePackage target to exclude the xcframework or using a separate nuspec rather than the pack target and separately zip and include the xcframework in another location. Doing so would also require injecting the NativeReference items for all target frameworks, including the newer net6.0 ones as the automatic support that looks for the assembly.resources.zip with an embedded manifest would no longer function correctly in that case. |
Follow up to questions inside #10774
Both nugets and xcframeworks are meant to distribute binary code that can work on several platforms.
This raise the issue on how a nuget can publish efficiently bindings to an XCFramework.
Before XCFramework a nuget could ship one, or more, assemblies for different platforms.
Those assemblies, when used for bindings, would have (generally embedded) native libraries.
Now we do not want
/iOS/Bindings.dll
to embed an XCFramework that includes binaries for iOS, tvOS, macOS, watchOS and MacCatalyst (...). Even more if the same nuget supports more platforms, e.g.tvOS/Bindings.dll
...Ideally there would be a single
.xcframework
inside the nuget. Symlinks comes to mind but might not be Windows-friendly.The text was updated successfully, but these errors were encountered: