flutter_secure_storage: MissingPluginException - lets fix this

There are currently all these open issues for flutter_secure_storage, all mention the exception MissingPluginException(No implementation found for method read on channel plugins.it_nomads.com/flutter_secure_storage) in the issue or in the comments:

#5 - Sporadic finalizer exceptions for underlying KeyStore on Android #49 - MissingPluginException (MissingPluginException(No implementation found for method read on channel plugins.it_nomads.com/flutter_secure_storage)) #71 - MissingPluginException #83 - MissingPluginException(No implementation found for method write on channel plugins.it_nomads.com/flutter_secure_storage) #85 - doesn’t work on api level 23 #118 - Android 4.4.2: MissingPluginException(No implementation found for method write on cannel plugins.it_nomads.com/flutter_secure_storage)) #129 - Not Working in android 5.1.1 and 4.4.4 #136 - Can’t run flutter test due to MissingPluginException in flutter_secure_storage

I’m also experiencing this exception with my end users, but with 8 open issues it’s difficult to have to a sensible conversation - can I suggest we use this one thread to resolve this?

Most suggested “solutions” are to uninstall / reinstall the app, flutter clean, etc. however this simply isn’t a solution - you can’t ask end users to reinstall your app.

One suggestion I have is that based on the data below, it looks like this is an Android only problem - so perhaps there is a problem with how the plugin is registered on Android? The fact that it only happens sometimes, for some users, then occasionally it magically disappears, also suggests it is a timing issue.

Affected versions

After a quick survey of the issues, the exception has been reported on the following versions:

  • Flutter versions: 1.17.0, 1.17.5, 1.7.8, 1.12.13,
  • Android versions: 4.4.4, 5.1.1, 6, 8, 10

Affected devices

  • Emulator and real devices
  • Devices: Samsung J3, Samsung Galaxy Grand 2, Galaxy Tabs, Moto e5, pixel 3a, Galaxy J7 2015, Samsung note 3

Some questions for flutter_secure_storage developers

To try to help, when looking through the code the following questions came to mind (I’m not a plugin developer so you may have to bear with me!)

Silently swallowing exceptions There are a couple of places where you catch Exceptions, but then just Log and do nothing else:

try {
          applicationContext = context.getApplicationContext();
          ...
          channel.setMethodCallHandler(this);
      } catch (Exception e) {
          Log.e("FlutterSecureStoragePl", "Registration failed", e);
      }
try {
    Log.d("FlutterSecureStoragePl", "Initializing StorageCipher");
    storageCipher = new StorageCipher18Implementation(applicationContext);
    Log.d("FlutterSecureStoragePl", "StorageCipher initialization complete");
} catch (Exception e) {
    Log.e("FlutterSecureStoragePl", "StorageCipher initialization failed", e);
}

Could these be surfaced to flutter via an error Result instead of silently discarded? This might reveal where there are actual problems when encountered.

Use of volatile You’re using volatile here:

private volatile StorageCipher storageCipher;

and link to a very long and complicated article on double-checked locking. Can you explain the reason behind using this instead of simply using an AsyncTask to perform work on a separate thread? If I had to bet money on why we get MissingPluginException, this would be it - edge case race conditions caused by complex multi-threading code.

Are you passing the right context? In initInstance you are doing this:

applicationContext = context.getApplicationContext();
preferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
charset = Charset.forName("UTF-8");

StorageCipher18Implementation.moveSecretFromPreferencesIfNeeded(preferences, context);

Notice you are getting and assigning the application context first, but then passing the context from the parameter to the moveSecretFromPreferencesIfNeeded method - is that right? I have no idea if that’s a problem, just thought I should ask the question.

BinaryMessenger

It looks like you’re getting a BinaryMessenger directly from the binding object here to give to the MethodChannel:

@Override
public void onAttachedToEngine(FlutterPluginBinding binding) {
   initInstance(binding.getBinaryMessenger(), binding.getApplicationContext());
}

However the latest plugin template gets the BinaryMessenger via the flutter engine like this:

channel = MethodChannel(flutterPluginBinding.binaryMessenger.getFlutterEngine().getDartExecutor(), "flutter_plugin")

Is that a problem do you think?

Setting method channel to null

onDetachedFromEngine you’re setting channel to null. Is this necessary? Might it not cause a problem if channel is accessed after this is called? The latest plugin template doesn’t do this, it just sets channel.setMethodCallHandler(null) and nothing else.

@Override
public void onDetachedFromEngine(FlutterPluginBinding binding) {
   channel.setMethodCallHandler(null);
   channel = null;
}

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 28
  • Comments: 58 (4 by maintainers)

Most upvoted comments

Same problem here… please fix

My problem is solved and I think it is a compatibility issue between plugins. I created a new project and added the plugins one by one. Arrived at the flutter_barcode_scanner: ^1.0.2 plugin the error appeared. So I just removed it and my app works fine with version 4.1.0 of flutter_secure_storage Hope this helps other people.

I hit this yesterday and just figured it out! This is not related to the plugin directly. For secure storage to work on Android I had to modify the MainActivity.kt file. (NOTE: from what I was reading, a lot of Flutter projects are using JAVA and the solution was slightly different but also in the MainActivity.java file)

Instead of MainActivity extending FlutterActivity, I had to extend from FlutterFragmentActivity in order for Touch ID to work on Android. When I did this it broke the project but I normally work on iOS so I didn’t notice. Flutter generates a class named GeneratedPluginRegistrant.java. If this doesn’t get called then Flutter can’t see the plugin and you get the MissingPluginException.

I believe FlutterActivity is calling the plugin registration for you (at least in newer versions of Flutter). FlutterFragmentActivity doesn’t make that call so you need to explicitly do it. Here is my new MainActivity.kt that is working:

import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant

class MainActivity: FlutterFragmentActivity() {

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        GeneratedPluginRegistrant.registerWith(flutterEngine)
    }

}

If you have a MainActivity.java file, here is what I found online that I had to translate to Kotlin. Note that the only difference is you override OnCreate instead:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    GeneratedPluginRegistrant.registerWith(this)
}

I figure out that this happens with all other keychain package flutter_keychain , flutter_secured_storage , flutter_secure_storage , store_critical_data , impiger_securestroage i dont know why all package have same problem, may all have same codebase or there are problem with flutter itself or all make same bug

After upgrade flutter to 2.5.0 works fine in android and emulators

@Rubensb @juliansteenbakker

So, this is a common issue. I ran into it unit testing flutter app.

Here is the error:

package:flutter/src/services/platform_channel.dart 157:7  MethodChannel._invokeMethod

MissingPluginException(No implementation found for method read on channel plugins.it_nomads.com/flutter_secure_storage)

Running the latest plugin: flutter_secure_storage: ^3.3.5

Testing on physical device: OnePlus 8T

Here’s the setup:

khalid@linux:~$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel master, 1.25.0-5.0.pre.90, on Linux, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
[✓] Android Studio
[✓] VS Code (version 1.52.1)
[✓] Connected device (1 available)

• No issues found!

So I ran into this issue and for an entire day I proceeded to try every single solution I found. After quite a while I actually found out this issue was caused by another dependency: flutter_facebook_login: ^3.0.0.

Temporarely removing this dependency would allow secure_storage to work just fine.

I realized I did not setup the flutter_facebook_login library properly as stated in their documentation, some stuff needed to be added in the AndroidManifest.xml. Once added, everything is back to normal.

I know I’m probably the only one here that ran into this specific issue but might be able to help someone.

@antoinepemeja I believe it’s a different error, and actually not an error, as it’s expected behavior. The plugin requires iOS or Android, that you don’t have in unit test environment.

Try to use mocks for unit testing, see details in https://pub.dev/packages/mockito.

It may be related to android backup feature, this plugin handles it very badly. The workaround is to delete all values on first run, or add try catch on every read and delete the value in case of errors.