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

865

Solution 1

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

Solution 2

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

Share:
865
siega
Author by

siega

Flutter Developer

Updated on January 01, 2023

Comments

  • siega
    siega over 1 year

    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