Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manually add a .xcframework to a Flutter iOS Plugin?

I'm trying to create a Flutter Plugin to use a native library. This library I'm trying to use is stored in a private repository and can be used with Swift Dependency Manager.

This is causing me a headache, cause I can't add a private repository dependency in my plugin (I couldn't find a way to do this in .podspec file), so what I've done:

  1. I've added the plugin to the Example project with Swift Package Manager
  2. Manually copied MyDependency.xcframework folder to MyPlugin/ios folder
  3. Referenced it in podspec file, like this:
s.preserve_paths = 'MyDependency.xcframework'
s.xcconfig = { 'OTHER_LDFLAGS' => '-framework MyDependency' }
s.vendored_frameworks = 'MyDependency.xcframework'

Doing this I'm able to use MyDependency inside plugin's sources.

My current problem is: This is only working in Simulator.

Before doing this, the project was running without any problem in real devices.

This is the error message I'm receiving every time I tried to run in a real device: enter image description here

Also, I've made a test using the dependency directly from Swift Dependency Manager and is working fine. I think the problem is the way I'm adding the framework to my plugin.

enter image description here

like image 623
siega Avatar asked Sep 16 '21 20:09

siega


People also ask

How do I add iOS platform to flutter?

If you only want to add support for specific enabled platforms, you can do that by supplying the --platforms argument: flutter create --platforms=web,macos . I get the error No option specified for the output directory. when run flutter create or flutter create --platforms web .

How do I create an xcframework for iPhone and simulators?

When Xcode builds an archive, it builds it for a specific architecture. Therefore if you want to create an XCFramework to run on both iPhone and Simulators, you will need to create two versions of the archive. Here’s the command line for archiving a framework with the iPhone sdk:

How do I create a Xc framework in Xcode?

Creating the XCFramework is just a matter of a simple command in Terminal; the xcodebuild -create-xcframework. Provided options must contain two things: The path to each framework; in this case it’s going to be the path to the framework inside each package as just said right above.

What is xcframework?

A XCFramework can wrap up a variant of a framework that would be working on iOS devices, another variant that would be working on Simulator, another one for macOS, one more for watchOS, and so on. In short, XCFramework can bundle up any framework with flavours for any platform or device that Xcode supports.

How do I link against a library in xcframework?

If your XCFramework includes a library, edit the Header Search Paths and Library Search Paths . If you link against a library that is not part of the same repo, you will need to copy over the public header files as well (in addition of the XCFramework of course!).


2 Answers

I got mine working by adding the following lines to the xxx.podspec:

s.preserve_paths = 'xxxxxx.xcframework/**/*'
s.xcconfig = { 'OTHER_LDFLAGS' => '-framework xxxxxx' }
s.vendored_frameworks = 'xxxxxx.xcframework'

Notice the /**/* at the end of s.preserve_paths

Here is the full xxx.podspec file:

#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint xxx.podspec` to validate before publishing.
#
Pod::Spec.new do |s|
  s.name             = 'xxx'
  s.version          = '1.0.0'
  s.summary          = 'xxx'
  s.description      = <<-DESC
xxx is a flutter plugin
                       DESC
  s.homepage         = 'https://example.com'
  s.license          = { :file => '../LICENSE', :type => 'BSD' }
  s.author           = { 'xxx' => '[email protected]' }
  s.source           = { :path => '.' }
  s.source_files = 'Classes/**/*'
  s.dependency 'Flutter'
  s.platform = :ios, '10.0'

  # Flutter.framework does not contain a i386 slice.
  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
  s.swift_version = '5.0'

  s.preserve_paths = 'xxxxxx.xcframework/**/*'
  s.xcconfig = { 'OTHER_LDFLAGS' => '-framework xxxxxx' }
  s.vendored_frameworks = 'xxxxxx.xcframework'
end

Make sure to copy the xxxxxx.xcframework directory to .../xxx/ios/xxxxxx.xcframework (where your plugin xxx.podspec is located)


Add xxxxxx.xcframework to Pods scheme to be able to import it

The Frameworks directory should be below the Pods scheme when running the flutter command to create a plugin ie.

flutter create --org com.xxx --template=plugin --platforms=android,ios -a java -i swift xxx

Source: Developing packages & plugins

(If not, add it)

Adding framework 1

  1. Navigate to Pods scheme and right-click on Frameworks
  2. Click Add Files to "Pods"...

enter image description here

  1. Navigate to the root of the ios directory where the xxxxxx.xcframework is located
  2. Uncheck Copy items if needed
  3. Select Create folder references
  4. Check Pods-Runner
  5. Check your plugin ie. xxx
  6. Click Add

Embed xxxxxx.xcframework into your project

(this should allow you to run/publish to real devices)

enter image description here

  1. Click on the Pods scheme
  2. In TARGETS select Pods-Runner
  3. Click on the General tab
  4. Ensure the xxxxx.xcframework is present underneath Frameworks and Libraries (if not, add it by clicking on the +)
  5. Change Embed to Embed & Sign

enter image description here

  1. Click on your plugin ie. xxx
  2. Ensure the xxxxx.xcframework is present underneath Frameworks and Libraries
  3. Change Embed to Embed & Sign

enter image description here

  1. Again, for both targets below Pods scheme, the next steps should already be fine, but just check it
  2. Click Build Phases
  3. Click Link Binary With Libraries
  4. Ensure xxxxx.xcframework is present, if not add it by clicking the + and that the Status is set to Required

Now you should be able to import the framework and reference it in your code and should also publish perfectly fine.

Hope this helps, and good luck. I hope this doesn't change again soon

fingers crossed

like image 94
Pierre Avatar answered Nov 10 '22 17:11

Pierre


After doing some research, I've found some links giving me an ideia about the real problem...

To solve this, I've added a simple script to my main project's build process.

This script adds the code signing to inner .framework files.

cd "${CODESIGNING_FOLDER_PATH}/Frameworks/"

# flatten nested frameworks by copying to APP.app/Frameworks
for framework in *; do
    if [ -d "$framework" ]; then
        if [ -d "${framework}/Frameworks" ]; then
            echo "Moving embedded frameworks from ${framework} to ${PRODUCT_NAME}.app/Frameworks"
            cp -R "${framework}/Frameworks/" .
            rm -rf "${framework}/Frameworks"
        fi
    fi
done

# remove any leftover nested frameworks (i.e. 'PackageName_359AFEED79E48935_PackageProduct.framework')
for framework in *; do
    if [ -d "$framework" ]; then
        if [ -d "${framework}/Frameworks" ]; then
            echo "Removing embedded frameworks from ${framework} to ${PRODUCT_NAME}.app/Frameworks"
            rm -rf "${framework}/Frameworks"
        fi
    fi
done

# codesign for Debugging on device
if [ "${CONFIGURATION}" == "Debug" ] & [ "${SDKROOT}" != *Simulator* ] ; then

    echo "Code signing frameworks..."
    find "${CODESIGNING_FOLDER_PATH}/Frameworks" -maxdepth 1 -name '*.framework' -print0 | while read -d $'\0' framework
    do
        # only sign frameworks without a signature
        if ! codesign -v "${framework}"; then
            codesign --force --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --preserve-metadata=identifier,entitlements --timestamp=none "${framework}"
            echo "Added missing signature to '${framework}'"
        fi
    done
fi
like image 31
siega Avatar answered Nov 10 '22 17:11

siega