Justin Pfenning
Justin Pfenning

Reputation: 543

Flutter - Missing Plugin on startup only when adding to existing app

we have an existing iOS app that we are trying to port to Flutter. I have followed the steps laid out in the documentation and things are going smoothly. However, I am hitting the dreaded:

[VERBOSE-2:ui_dart_state.cc(177)] Unhandled Exception: MissingPluginException(No implementation found for method read on channel plugins.it_nomads.com/flutter_secure_storage) #0 MethodChannel._invokeMethod

I have spent days on this and tried all the common things:

  1. Delete app and reinstall
  2. Delete .flutter-plugins-dependencies and .flutter-plugins then pub get again
  3. Clean build directory in xCode
  4. rebuild ios-framework eleventy billion times
  5. drink lots of beer and swear like a sailor's parrot

All did not work. This got me thinking something was off so I refactored the code. If I try to use Flutter's Secure Storage outside of main.dart, it magically works! No problems! Then I thought it might be secure_storage that was the issue, so I decided to use the connectivity package in main.dart instead of later like we use it and reach the exact same error (the only difference is the package name that is throwing the MissingPluginException). I then tried to create a standalone pure flutter program, and it works if I use these packages in main.dart like I am. However, it fails here and fails miserably. I think ideally it should be in main.dart as we need to find out whether or not to show the onboarding screen or the login screen based upon what is actually inside secure storage. Below is my dart code if it helps. Like I said, if I strip this out and use connectivity instead it also fails. And it only fails inside my ios-framework because I am putting this code inside an already existing app.

  flutterEngine.run()
  let flutterViewController =
           FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
  self.window?.rootViewController = flutterViewController
  self.window?.makeKeyAndVisible()

Code:

bool hasSeenOnboarding = false;
String railsKey;
final tripsProvider = ChangeNotifierProvider<TripsProvider>(
  (ref) => TripsProvider(ref.read),
);

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  hasSeenOnboarding = await SecureStorageLtr.hasSeenIntroScreens();
  railsKey = await SecureStorageLtr.getToken();
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      debugShowCheckedModeBanner: false,
      localizationsDelegates: [
        DefaultMaterialLocalizations.delegate,
        DefaultCupertinoLocalizations.delegate,
        DefaultWidgetsLocalizations.delegate,
      ],
      title: 'My Title',
      home: hasSeenOnboarding
          ? railsKey == null
              ? InitialLoginScreen()
              : TabBarLtr()
          : OnboardingScreen(),
      onGenerateRoute: RouteGenerator.generateRoute,
    );
  }
}

Upvotes: 1

Views: 726

Answers (1)

Justin Pfenning
Justin Pfenning

Reputation: 543

So apparently the problem is a simple one, but a big ole pain. You need to register your plugins if they are used this early. I was unable to find any information on the official documentation from Flutter, but instead was able to find it online on some random blog post. After doing this one line, it now magically works for any and all packages this early! Happy Coding!

New swift code:

import FlutterPluginRegistrant

...

  flutterEngine.run()
  GeneratedPluginRegistrant.register(with: self.flutterEngine) //THIS is new line
  let flutterViewController =
           FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
  self.window?.rootViewController = flutterViewController
  self.window?.makeKeyAndVisible()

Upvotes: 3

Related Questions