flutter icon indicating copy to clipboard operation
flutter copied to clipboard

Support developing iOS extension targets

Open long1eu opened this issue 8 years ago • 38 comments

Are they any docs on building an iOS extension using Flutter?

long1eu avatar Mar 30 '18 05:03 long1eu

All you need can be found here "https://flutter.io/developing-packages/". For specific iOS Api documentation you can refer to apples docs https://developer.apple.com/documentation/

s-bauer avatar Mar 30 '18 11:03 s-bauer

I'm talking about this https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/index.html :D Not plugins.

long1eu avatar Mar 30 '18 11:03 long1eu

Any news on this one?

mrgrauel avatar Jan 11 '19 10:01 mrgrauel

@mrgrauel Using "add reaction" on the initial comment would increase priority while +1 comments are rather pointless and cause lots of people to get notified for no reason. To get notified yourself use the [Subscribe] button to the top right instead.

zoechi avatar Jan 11 '19 10:01 zoechi

Latest documentation is: https://developer.apple.com/app-extensions/

Hixie avatar Jan 16 '19 00:01 Hixie

@long1eu and @ugoArangino hi! Try to remove all the "Other Linker Flags" within the Target (your Extension) in "Build Settings" (see screen). This caused the linker problems in my project. Removing them, solved it! You don't have to touch the Podfile at all.

flutter-ios-extension

andreasunterhuber avatar Mar 21 '19 13:03 andreasunterhuber

@long1eu and @ugoArangino hi! Try to remove all the "Other Linker Flags" within the Target (your Extension) in "Build Settings" (see screen). This caused the linker problems in my project. Removing them, solved it! You don't have to touch the Podfile at all.

flutter-ios-extension

Hi Andreas! Did you actually manage to run Flutter in an App Extension? Or it is just a Flutter app + native App Extension?

alcsan avatar Apr 03 '19 17:04 alcsan

I'm actively pursuing this in a project I'm currently working on. By using the Add-to-App method I've managed to start a Flutter view from within my extension.

However, the view is simply black, and connecting to the debugger from the observatory, I'm greeted by the following message:

Paused until embedder makes the isolate runnable.

I think I'm missing some important step that tells the Flutter isolate to start running, that is probably coming from the FlutterAppDelegate. (since this is an app extension, I don't have an app delegate, only a ViewController)

Will keep updating here as I try to move further with this...

my code:
import AuthenticationServices
import MobileCoreServices
import UIKit

import Flutter
import FlutterPluginRegistrant

@objc(CredentialProviderViewController)

class CredentialProviderViewController: ASCredentialProviderViewController {
    var flutterEngine: FlutterEngine!
    var flutterViewController: FlutterViewController!

    override func prepareCredentialList(for serviceIdentifiers: [ASCredentialServiceIdentifier]) {
        flutterEngine = FlutterEngine(name: "io.flutter", project: nil)
        flutterEngine.run(withEntrypoint: nil)

        GeneratedPluginRegistrant.register(with: self.flutterEngine)

        flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)!
        view.addSubview(flutterViewController.view)
    }
}

LinusU avatar Apr 11 '19 18:04 LinusU

I'm actively pursuing this in a project I'm currently working on. By using the Add-to-App method I've managed to start a Flutter view from within my extension.

However, the view is simply black, and connecting to the debugger from the observatory, I'm greeted by the following message:

Paused until embedder makes the isolate runnable.

I think I'm missing some important step that tells the Flutter isolate to start running, that is probably coming from the FlutterAppDelegate. (since this is an app extension, I don't have an app delegate, only a ViewController)

Will keep updating here as I try to move further with this...

my code:

import AuthenticationServices
import MobileCoreServices
import UIKit

import Flutter
import FlutterPluginRegistrant

@objc(CredentialProviderViewController)

class CredentialProviderViewController: ASCredentialProviderViewController {
    var flutterEngine: FlutterEngine!
    var flutterViewController: FlutterViewController!

    override func prepareCredentialList(for serviceIdentifiers: [ASCredentialServiceIdentifier]) {
        flutterEngine = FlutterEngine(name: "io.flutter", project: nil)
        flutterEngine.run(withEntrypoint: nil)

        GeneratedPluginRegistrant.register(with: self.flutterEngine)

        flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)!
        view.addSubview(flutterViewController.view)
    }
}

@LinusU Any updates on this?

alcsan avatar Jun 02 '19 17:06 alcsan

Unfortunately not, at the moment our app extension is written using only native code and views 😞

Would love to have support for Flutter here though!

LinusU avatar Jun 03 '19 09:06 LinusU

Even if add-to-app for app extensions worked and the extension lifecycle was hooked up, I believe it would be rejected from the App Store:

ld: warning: linking against a dylib which is not safe for use in application extensions: test_notification_extensions/flutterapp/.ios/Flutter/App.framework/App
ld: warning: linking against a dylib which is not safe for use in application extensions: test_notification_extensions/flutterapp/.ios/Flutter/engine/Flutter.framework/Flutter

https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fapplication-extension

jmagman avatar Sep 18 '19 01:09 jmagman

We managed to run dart code from an extension by starting FlutterEngine and using the platform channel (binaryMessenger) to communicate. (We only wanted to reuse business logic in dart.) However, that only worked for a non-flutter app. Trying the same for a flutter app, CocoaPods complained about pods with the same name: Flutter.framework and App.framework. Using only a single Flutter.framework is possible, but the "App.framework" name is hardcoded in several places: xcode_backend.sh, pod helper.rb, .podspec, AppFrameworkInfo.plist (and maybe others we missed). Also the CFBundleIdentifier of both App.framework is hardcoded, while it must be unique per bundle.

spkersten avatar Oct 24 '19 08:10 spkersten

We managed to run dart code from an extension by starting FlutterEngine and using the platform channel (binaryMessenger) to communicate. (We only wanted to reuse business logic in dart.) However, that only worked for a non-flutter app. Trying the same for a flutter app, CocoaPods complained about pods with the same name: Flutter.framework and App.framework. Using only a single Flutter.framework is possible, but the "App.framework" name is hardcoded in several places: xcode_backend.sh, pod helper.rb, .podspec, AppFrameworkInfo.plist (and maybe others we missed). Also the CFBundleIdentifier of both App.framework is hardcoded, while it must be unique per bundle.

Having two copies of Flutter and the App (compiled dart code) would make the app huge. Probably the Flutter app and extension would need to import that once (two Podfile targets using the same pod) with different entry points into the App.framework. I'm just thinking out loud--the Flutter tooling doesn't support this use-case at the moment.

jmagman avatar Oct 24 '19 23:10 jmagman

Adding @matthew-carroll @xster for their thoughts.

csells avatar Oct 29 '19 23:10 csells

Seems like an interesting use-case, but I'll defer to @jmagman on the technical feasibility as well as timeline.

matthew-carroll avatar Oct 29 '19 23:10 matthew-carroll

https://github.com/flutter/flutter/issues/16092#issuecomment-475237976

@andreasunterhuber this is the solution to my problem that I've spent few hours on! Thank you!

Flutter team, I beg you to add this issue to some flutter.dev website on App Extensions. Adding firebase_* pub packages prevented my app with App Extension to compile. Removing the firebase_* flags with their corresponding -framework pair successfully resolved my problem. Also, remove the $(inherited).

So, to sum it up:

  1. Go to your App Extension target in Xcode
  2. Go into Build Settings -> All Combined
  3. Find Other Linker Flags
  4. Remove the faulty frameworks from all levels with a -framework before each of them
    • For me that was firebase_core, firebase_analytics, and firebase_crashlytics.
  5. Also remove $(inherited) from this list

And this should be it! But keep in mind that you changed those linker settings in case when you'd want to add some pod to your Podspec.

Here's some logs so that Google will hopefully show this issue for other people with the same problem:

ld: warning: linking against a dylib which is not safe for use in application extensions: /Users/vagrant/git/mobile/build/ios/Release-tst-iphoneos/FirebaseCore/FirebaseCore.framework/FirebaseCore
ld: warning: linking against a dylib which is not safe for use in application extensions: /Users/vagrant/git/mobile/build/ios/Release-tst-iphoneos/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.framework/FirebaseCoreDiagnostics
ld: warning: linking against a dylib which is not safe for use in application extensions: /Users/vagrant/git/mobile/build/ios/Release-tst-iphoneos/FirebaseCrashlytics/FirebaseCrashlytics.framework/FirebaseCrashlytics
ld: warning: linking against a dylib which is not safe for use in application extensions: /Users/vagrant/git/mobile/build/ios/Release-tst-iphoneos/FirebaseInstallations/FirebaseInstallations.framework/FirebaseInstallations

ld: warning: Could not find or use auto-linked framework 'Flutter'
Undefined symbols for architecture arm64:
  "_OBJC_CLASS_$_FlutterError", referenced from:
      objc-class-ref in firebase_core(FLTFirebasePlugin.o)
  "_OBJC_CLASS_$_FlutterMethodChannel", referenced from:
      objc-class-ref in firebase_analytics(FLTFirebaseAnalyticsPlugin.o)
      objc-class-ref in firebase_core(FLTFirebaseCorePlugin.o)
      objc-class-ref in firebase_crashlytics(FLTFirebaseCrashlyticsPlugin.o)
  "_FlutterMethodNotImplemented", referenced from:
      -[FLTFirebaseAnalyticsPlugin handleMethodCall:result:] in firebase_analytics(FLTFirebaseAnalyticsPlugin.o)
      -[FLTFirebaseCorePlugin handleMethodCall:result:] in firebase_core(FLTFirebaseCorePlugin.o)
      -[FLTFirebaseCrashlyticsPlugin handleMethodCall:result:] in firebase_crashlytics(FLTFirebaseCrashlyticsPlugin.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Albert221 avatar Apr 14 '21 13:04 Albert221

@Albert221 I don't think you or @andreasunterhuber are talking about using Flutter in an extension, as @alcsan pointed out (and I missed when I last looked at this issue).

Did you actually manage to run Flutter in an App Extension? Or it is just a Flutter app + native App Extension?

And that's not really related to this feature request to use Flutter in an app extension. I'd actually like to take a look at what you were seeing. We want non-Flutter app extensions to be able to be added to Flutter apps without any project files workarounds like the one you figured out.

Would you mind filing a new issue with your original flutter build or run command with the --verbose flag, completely fill out the issue template, and @ me in it? I'm wondering if part of your problem wasn't already fixed with https://github.com/flutter/flutter/pull/78592 in 2.0.4.

jmagman avatar Apr 14 '21 17:04 jmagman

you can create a duplicate of app scheme. named "buildFlutterPKG", remove all extension config of buildFlutterPKG and then edit this app scheme , scheme -> build -> targets ->add (select the build flutterpkg sheme), and set the buildFlutterPkg to the first line. and then disable the "Parallelize build" build the app it's done

izouxv avatar Sep 01 '21 04:09 izouxv

@jmagman Any updates on this issue? Is there a chance that it will be fixed soon if it was added to "iOS Developer Experience"?

alcsan avatar Oct 04 '21 09:10 alcsan

No updates at this time.

jmagman avatar Oct 04 '21 17:10 jmagman

you can create a duplicate of app scheme. named "buildFlutterPKG", remove all extension config of buildFlutterPKG and then edit this app scheme , scheme -> build -> targets ->add (select the build flutterpkg sheme), and set the buildFlutterPkg to the first line. and then disable the "Parallelize build" build the app it's done

@izouxv Is it a way to use Flutter in an App Extension?

alcsan avatar Oct 05 '21 16:10 alcsan

It really depends what kind of extension target you want to add. For example, I wrote up how to add an App Clip extension https://flutter.dev/docs/development/platform-integration/ios-app-clip and https://github.com/flutter/flutter/issues/60029 But unfortunately you can't ship it because the app size grows over 10MB https://github.com/flutter/flutter/issues/71098

So it may be possible depending on what you're doing, but you need to figure out how to only embed the Flutter framework once (and link against it in the extension), and to have different entry points in your dart app (App.framework) for your app vs the extension, and set up the build settings per target to point to the different entry points. We have zero documentation for it.

jmagman avatar Oct 05 '21 23:10 jmagman

We developed Audanika, a serious music app in Flutter. Many of our customers are asking for AUV3 support. Is there someone here from Google, I could talk about?

https://medium.com/@audanika/help-us-to-implement-auv3-support-for-audanika-ea325870fa6a

gatzsche avatar Dec 02 '21 20:12 gatzsche

@gatzsche Maybe I don't understand your use case, but why do you need to use Flutter in your AUv3 extension? Open ios/Runner.xcworkspace and add your extension target as you would in a normal Xcode project. If you need to present UI or subclass AUAudioUnit in your Flutter app, that could be a good use case for a Flutter plugin.

jmagman avatar Dec 02 '21 21:12 jmagman

If you need to present UI or subclass AUAudioUnit in your Flutter app, that could be a good use case for a Flutter plugin.

That is exactly what I want to do. Based on this thread I had doubt that showing a Flutter View Controller in an extension might work. But I will try out.

@jmagman Is there some documentation? If not, how could I contribute to create some?

gatzsche avatar Dec 04 '21 05:12 gatzsche

Based on this thread I had doubt that showing a Flutter View Controller in an extension might work.

I see, then you do what to use Flutter in your extension. By "you need to present UI or subclass AUAudioUnit in your Flutter app, that could be a good use case for a Flutter plugin" I meant in YOUR app that already embeds Flutter and your dart code, not in the extension used by other apps.

You would need to link against and embed the Flutter frameworks in the extension, as well as the framework that contains your compiled Dart code. The tooling doesn't support this and there's no docs, but it can be done manually. As I said, I wrote an example of how to do this with App Clip extensions, though that exact use case didn't work because it hit the 10MB upload limit: https://docs.flutter.dev/development/platform-integration/ios-app-clip.

Your best bet is probably to break out of Flutter for this use case and implement your extension entirely in Swift/Obj-C in Xcode.

jmagman avatar Dec 06 '21 17:12 jmagman

@jmagman Hi Jenn, thanks for your answer. Currently, it looks that Audio Unit Extensions might work with Flutter. The flutter code is executed and also the widget build functions are executed. The only thing: The FlutterViewController does not show the flutter content.

Would you mind checking out this example: https://github.com/gatzsche/flutter-audio-unit-extension-experiments

At the end, you should see the flutter default app in the extension. But it is not shown. Also, no error is output.

Should I create a separate issue for that?

gatzsche avatar Dec 28 '21 10:12 gatzsche

You should create a separate issue. Or maybe someone can help on StackOverflow.

jmagman avatar Jan 04 '22 22:01 jmagman

I've heard that there's memory limit for an ios share extension (120mb). We would also have to be careful about it

Shawn-sudo avatar May 22 '22 22:05 Shawn-sudo

@long1eu and @ugoArangino hi! Try to remove all the "Other Linker Flags" within the Target (your Extension) in "Build Settings" (see screen). This caused the linker problems in my project. Removing them, solved it! You don't have to touch the Podfile at all.

flutter-ios-extension

Isn't this breaking something else? I am working with flavors. in my main app & extension.

  • I can run DebugDev on my device without any problems.
  • I can't run DebugDev on my simulator
  • I can't run DebugAlpha, DebugBeta, DebugProd on my device/simulator

When I remove the Other linker flags it does work. But why are they added if they are not used? Isn't this breaking something else?

vanlooverenkoen avatar Jun 10 '22 06:06 vanlooverenkoen