Getting a Flutter ffi plugin to compile for iOS

1,365 views
Skip to first unread message

Odev

unread,
Dec 2, 2020, 11:11:38 AM12/2/20
to Dart FFI
Hi,

I've written a Flutter plugin that uses dart:ffi to make calls into C++ code that I've bundled with the plugin (with the source file in myPlugin/ios/Classes). I've followed https://flutter.dev/docs/development/platform-integration/c-interop for this, and it all works great for Android, where I have a myPlugin/android/CMakeLists.txt file handling the compilation of the C++ code.

I'm having trouble understanding what to do for iOS, however. On the c-interop page, it says
"On iOS, you need to tell Xcode to statically link the file:
  1. In Xcode, open Runner.xcworkspace.
  2. Add the C/C++/Objective-C/Swift source files to the Xcode project."
But as far as I can tell, there is no Runner.xcworkspace for the plugin itself. There is one for the example app, but that shouldn't do any configuration for the plugin, should it? Or does the very act of adding the source files to Xcode for the example project actually configure something for the plugin too, in a way that will let whatever app I import the plugin from use the plugin?

Is there anything like a CMakeLists.txt file I can just configure for the iOS side? (I've had a look at the myPlugin.podspec file, which seems relevant, but it's unclear to me that that's actually doing anything at the moment.

Many thanks for any pointers to how to get this iOS toolchain working -- it's currently very mysterious to me. 

Kind regards,
Odev

Daco Harkes

unread,
Dec 3, 2020, 5:13:47 AM12/3/20
to Odev, Jonas Jensen, Dart FFI
cc +Jonas Jensen who had to solve this problem for https://github.com/google/webcrypto.dart.

Kind regards,

 •  Daco Harkes
 •  Software Engineer
 •  dacoh...@google.com 
 •  🔵 Blue Dot Ally


--
You received this message because you are subscribed to the Google Groups "Dart FFI" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dart-ffi+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dart-ffi/ef162f18-82c6-4fcc-91f9-09f9587dcee7n%40googlegroups.com.

Michael Thomsen

unread,
Dec 3, 2020, 5:24:35 AM12/3/20
to Daco Harkes, kwalrath, Odev, Jonas Jensen, Dart FFI
cc @kwalrath; would be great to get docs updated with a few more details here. Jonas, can you detail what those are?

Olof S

unread,
Dec 4, 2020, 8:16:35 AM12/4/20
to Jonas Jensen, Daco Harkes, kwalrath, Michael Thomsen, Dart FFI
Thanks a lot for these pointers! Thanks to these I've got it working, though there were lots of false starts, with Xcode complaining variously about not being able to "#include <algorithm>" (or other standard C++ headers), or linking errors, or relative includes. I'd recommend following Jonas's example from webcrypto.dart, meaning a few changes to the iOS steps listed on https://flutter.dev/docs/development/platform-integration/c-interop

Specifically, after
   flutter create --platforms=android,ios --template=plugin foo_plugin

1. Put the C++ code in its own directory under foo_plugin/ios (not foo_plugin/ios/Classes), say foo_plugin/ios/myNativeCode.
2. Do not do anything in Xcode. Instead, in foo_plugin/ios/foo_plugin.podspec, put
s.public_header_files = 'Classes/**/*.h'
s.source_files = [
  'Classes/**/*',
  'myNativeCode/**/*.{cpp,hpp,c,h},
]

Note that only (the automatically created) Classes/FooPluginPlugin.h will actually be taken as part of public_header_files; your own code from myNativeCode will be considered 'private' according to Podspec:

3. Carry on with Step 3 of the c-interop guide.

Some other useful podspec options:
# add HEADER_SEARCH_PATHS to pod_target_xcconfig, e.g:
s.pod_target_xcconfig = {
    # Allow relative "#include"s from the project base directory:
    'HEADER_SEARCH_PATHS' => [
      '$(PODS_TARGET_SRCROOT)/myNativeCode',
    ],
    # Ensure some particular C++ standard, e.g:
    'CLANG_CXX_LANGUAGE_STANDARD' => 'c++11',
    'DEFINES_MODULE' => 'YES',
    # Flutter.framework does not contain a i386 slice.
    'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386',
  }

# Exclude some files that aren't to be included
s.exclude_files = [ 'myNativeCode/win32/**/*' ]

# Ignore warnings from the compiler
s.compiler_flags = [
    '-GCC_WARN_INHIBIT_ALL_WARNINGS',
    '-w',
]

Something to be aware of when editing your .podspec file (and that caused me a lot of wasted time): CocoaPods and/or Xcode seem to cache a lot of stuff. Updates you make to your podspec might not propagate, unless you clear pod-related information in the destination project first. In the example app for a plugin, it mostly seemed enough to delete the files Podfile, Podfile.lock and the directory Pods in example/ios before trying to build the app again.

A link to the Podspec Syntax Reference:

Thanks for your help,
Odev

On Fri, Dec 4, 2020 at 1:25 AM Jonas Jensen <jon...@google.com> wrote:
Many thanks for any pointers to how to get this iOS toolchain working -- it's currently very mysterious to me. 
On iOS you'll need to build a podspec, I did one here:
I didn't find any good docs on how to write podspecs for C / C++ projects, and I didn't find it easy.


$ flutter create -t plugin --platforms android,ios foo_plugin
Then put sources into ios/Classes/myfolder/myfile.cpp


Set include paths, if you need any:

I couldn't figure out how to link against other libraries, but I'm pretty sure you could pull down dependencies from cocoapods.org
I haven't figured out how to use sub-specs, assembler or C++, but suspect C++ is just a matter of adding .cpp extension to source files.
So there is many other things I didn't figure out, I would recommend starting with the example from:
https://flutter.dev/docs/development/platform-integration/c-interop

--
Regards Jonas Finnemann Jensen.

Reply all
Reply to author
Forward
0 new messages