Skip to content

Export a base class for Objective C method channel plugins #9161

Closed

Description

@tvolkert

Basically every plugin we've written thus far (internally in Google) looks like the following:

Seems like there's an opportunity to remove a lot of boilerplate by providing a base class to do this basic wiring.

@mravn-google

@interface FLTExamplePlugin : NSObject
@property(strong, nonatomic, readonly) FlutterViewController *controller;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithController:(FlutterViewController *)controller NS_DESIGNATED_INITIALIZER;
@end

@implementation FLTExamplePlugin {
  FlutterMethodChannel *_channel;
}

- (instancetype)initWithController:(FlutterViewController *)controller {
  if (self = [super init]) {
    _controller = controller;

    _channel =
        [FlutterMethodChannel methodChannelNamed:CHANNEL_NAME
                                 binaryMessenger:controller
                                           codec:[FlutterStandardMethodCodec sharedInstance]];

    __unsafe_unretained typeof(self) weakSelf = self;
    [_channel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResultReceiver result) {
      [weakSelf handleMethod:call sendResultTo:result];
    }];
  }
  return self;
}

- (void)dealloc {
  [_channel setMethodCallHandler:nil];
  _channel = nil;
}

@end

Activity

  1. added this to the milestone on Apr 3, 2017
  2. tvolkert commented on Apr 3, 2017

    @tvolkert
    ContributorAuthor

    Actually, it's better to have the method be:

    - (void)handleMethodCall:(NSString *)method
                   arguments:(id)arguments
                      result:(FlutterResultReceiver)result;
    

    And the base class implementation can just respond with a method not found error.

  3. mravn-google commented on Apr 4, 2017

    @mravn-google
    Contributor

    Things to consider:

    • Maybe it would be easier for ObjC plugins to use a FlutterMethodCallHandler protocol rather than a typedefd callback?
    • A Swift sub-class should look... swifty. Might be enough to add some _Nullable and _Nonnull annotations.
    • Consistency with corresponding Android and Dart APIs. For instance, the Android side uses interfaces, not abstract base classes.
    • We'd like to allow plugin consumers to simply declare a dependency on a plugin in their pubspec.yaml file without any need to touch ObjC/Swift or Android code at all. That requires plugin initialization to be done consistently across the board, making it amenable to code generation during flutter build.
  4. self-assigned this
    on Apr 4, 2017
  5. tvolkert commented on Apr 5, 2017

    @tvolkert
    ContributorAuthor

    Yeah, maybe introducing a FlutterMethodCallHandlerDelegate protocol and having the interface be something the following would make sense:

    - (void)setMethodCallHandlerDelegate:(FlutterMethodCallHandlerDelegate)handler;
    
  6. mravn-google commented on Apr 5, 2017

    @mravn-google
    Contributor

    The delegate could be a property of FlutterMethodChannel, I guess, as an alternative to having the FlutterPlugin base class at all. That would mean we have at least three options:

    • A channel concept using callback blocks (current solution; this issue indicates that is not good enough for many situations, typically because plugins need to maintain state across method calls and/or implement protocols).
    • A plugin base class with a channel property and a method to be overridden to handle incoming method calls on that channel (as suggested here and implemented in Added base class for iOS plugins flutter-team-archive/engine#3561).
    • A method call handler delegate protocol to be implemented by plugins, and a corresponding delegate property on FlutterMethodChannel.

    I have way too little experience with ObjC to know what developers would expect or prefer. Same goes for Swift by the way. @chinmaygarde, do you have an opinion?

  7. tvolkert commented on Apr 5, 2017

    @tvolkert
    ContributorAuthor

    /cc @gavindoughtie as an affluent iOS developer for his thoughts. Gavin, the discussion is about the best plugin API on the ObjC (and Swift when we add that) side of things.

  8. gavindoughtie commented on Apr 5, 2017

    @gavindoughtie

    Oh, I wish I were an affluent iOS developer... :-P

    I'd definitely lean towards defining a couple of delegate protocols (one for the plugin, one for whatever Flutter hands the plugin) as the actual binding contract.

    Then I'd do a BasePlugin that implements the protocol, and then most plugins would just extend that by overriding a couple of methods (like "createViewController" or "handleMethod").

    This way you keep the requirements minimal while still making it easy for more trivial plugins.

  9. tvolkert commented on Apr 5, 2017

    @tvolkert
    ContributorAuthor

    +1 to a base class that implements one or more protocols.

  10. mravn-google commented on May 9, 2017

    @mravn-google
    Contributor

    Fixed by #3645.

  11. tvolkert commented on May 9, 2017

    @tvolkert
    ContributorAuthor
  12. mravn-google commented on May 9, 2017

    @mravn-google
    Contributor

    Yes, thanks.

  13. github-actions commented on Sep 5, 2021

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  14. locked as resolved and limited conversation to collaborators on Sep 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

packageflutter/packages repository. See also p: labels.

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions