Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 [firebase_storage] MissingPluginException when using firebase_storage via flutter_isolate #10514

Open
guenth39 opened this issue Feb 22, 2023 · 19 comments
Assignees
Labels
blocked: flutter platform: ios Issues / PRs which are specifically for iOS. plugin: storage type: bug Something isn't working

Comments

@guenth39
Copy link

Bug report

Describe the bug
Trying to upload a file in a flutter isolate to firebase storage fails on iOS with the following error message. On Android, everything works as expected. At first, I thought the error was the same as #9790, but it is a different error. For simplicity, I have forked the example project of that ticket and adapted it.

[VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: MissingPluginException(No implementation found for method Task#startPutFile on channel plugins.flutter.io/firebase_storage)
#0      MethodChannel._invokeMethod
platform_channel.dart:313
<asynchronous suspension>

Steps to reproduce

Steps to reproduce the behavior:

  1. Check out the provided sample project
  2. Configure a firebase project
  3. run the app and tap the plus button

Expected behavior

The file should be uploaded correctly as on Android.

Sample project

https://github.com/guenth39/firebase-storage-isolate-issue-sample-app


Flutter doctor

Run flutter doctor and paste the output below:

Click To Expand
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.7.4, on macOS 13.2 22D49 darwin-arm64 (Rosetta), locale de-DE)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0-rc3)
[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2021.2)
[✓] VS Code (version 1.75.1)
[✓] Connected device (4 available)
[✓] HTTP Host Availability

• No issues found!

Flutter dependencies

Run flutter pub deps -- --style=compact and paste the output below:

Click To Expand
Dart SDK 2.19.2
Flutter SDK 3.7.4
sample 10.0.1+423

dependencies:
- firebase_core 2.7.0 [firebase_core_platform_interface firebase_core_web flutter meta]
- firebase_storage 11.0.14 [firebase_core firebase_core_platform_interface firebase_storage_platform_interface firebase_storage_web flutter]
- flutter 0.0.0 [characters collection js material_color_utilities meta vector_math sky_engine]
- flutter_isolate 2.0.4 [flutter uuid]
- path_provider 2.0.12 [flutter path_provider_android path_provider_foundation path_provider_linux path_provider_platform_interface path_provider_windows]

dev dependencies:
- flutter_test 0.0.0 [flutter test_api path fake_async clock stack_trace vector_math async boolean_selector characters collection js matcher material_color_utilities meta source_span stream_channel string_scanner term_glyph]
- integration_test 0.0.0 [flutter flutter_driver flutter_test path vm_service archive async boolean_selector characters clock collection crypto fake_async file js matcher material_color_utilities meta source_span stack_trace stream_channel string_scanner sync_http term_glyph test_api typed_data vector_math webdriver]

transitive dependencies:
- _flutterfire_internals 1.0.16 [collection firebase_core firebase_core_platform_interface flutter meta]
- archive 3.3.2 [crypto path]
- async 2.10.0 [collection meta]
- boolean_selector 2.1.1 [source_span string_scanner]
- characters 1.2.1
- clock 1.1.1
- collection 1.17.0
- crypto 3.0.2 [typed_data]
- fake_async 1.3.1 [clock collection]
- ffi 2.0.1
- file 6.1.4 [meta path]
- firebase_core_platform_interface 4.5.3 [collection flutter flutter_test meta plugin_platform_interface]
- firebase_core_web 2.2.1 [firebase_core_platform_interface flutter flutter_web_plugins js meta]
- firebase_storage_platform_interface 4.1.30 [collection firebase_core flutter meta plugin_platform_interface]
- firebase_storage_web 3.3.23 [_flutterfire_internals async firebase_core firebase_core_web firebase_storage_platform_interface flutter flutter_web_plugins http js meta]
- flutter_driver 0.0.0 [file flutter flutter_test fuchsia_remote_debug_protocol path meta vm_service webdriver archive async boolean_selector characters clock collection crypto js matcher material_color_utilities platform process source_span stack_trace stream_channel string_scanner sync_http term_glyph test_api typed_data vector_math]
- flutter_web_plugins 0.0.0 [flutter js characters collection material_color_utilities meta vector_math]
- fuchsia_remote_debug_protocol 0.0.0 [process vm_service file meta path platform]
- http 0.13.5 [async http_parser meta path]
- http_parser 4.0.2 [collection source_span string_scanner typed_data]
- js 0.6.5 [meta]
- matcher 0.12.13 [meta stack_trace]
- material_color_utilities 0.2.0
- meta 1.8.0
- path 1.8.2
- path_provider_android 2.0.22 [flutter path_provider_platform_interface]
- path_provider_foundation 2.1.1 [flutter path_provider_platform_interface]
- path_provider_linux 2.1.8 [ffi flutter path path_provider_platform_interface xdg_directories]
- path_provider_platform_interface 2.0.5 [flutter platform plugin_platform_interface]
- path_provider_windows 2.1.3 [ffi flutter path path_provider_platform_interface win32]
- platform 3.1.0
- plugin_platform_interface 2.1.3 [meta]
- process 4.2.4 [file path platform]
- sky_engine 0.0.99
- source_span 1.9.1 [collection path term_glyph]
- stack_trace 1.11.0 [path]
- stream_channel 2.1.1 [async]
- string_scanner 1.2.0 [source_span]
- sync_http 0.3.1
- term_glyph 1.2.1
- test_api 0.4.16 [async boolean_selector collection meta source_span stack_trace stream_channel string_scanner term_glyph matcher]
- typed_data 1.3.1 [collection]
- uuid 3.0.7 [crypto]
- vector_math 2.1.4
- vm_service 9.4.0
- webdriver 3.0.1 [archive matcher path stack_trace sync_http]
- win32 3.1.3 [ffi]
- xdg_directories 1.0.0 [meta path process]

@guenth39 guenth39 added Needs Attention This issue needs maintainer attention. type: bug Something isn't working labels Feb 22, 2023
@darshankawar darshankawar added the triage Issue is currently being triaged. label Feb 23, 2023
@darshankawar
Copy link

Thanks for the report. Cloning the repo and then added local firebase app's firebase_options file and ran on iOS. Tapping on the button throws the same error as reported.

@darshankawar darshankawar added plugin: storage platform: ios Issues / PRs which are specifically for iOS. and removed Needs Attention This issue needs maintainer attention. triage Issue is currently being triaged. labels Feb 23, 2023
@makda-mohammad
Copy link

facing the same issue does anyone have any solution for this as it is running absolutely fine in android but throws MissingPluginException on iOS.

@ariefwijaya
Copy link

I also got this error

[VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: MissingPluginException(No implementation found for method Task#writeToFile on channel plugins.flutter.io/firebase_storage)
#0      MethodChannel._invokeMethod
platform_channel.dart:313
<asynchronous suspension>

@nmfisher Do we need to create this ticket to flutter_isolate repo? we have no idea, why this happened on iOS only.

@Doppelklick
Copy link

same with workmanager (Flutter version 3.7.10).

Anybody found a workaround?

@pulpcorn
Copy link

pulpcorn commented Apr 18, 2023

I also got this error.
Any solutions for iOS?

[VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: MissingPluginException(No implementation found for method Task#startPutData on channel plugins.flutter.io/firebase_storage)
#0 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:313:7)

@thecaptainXgod
Copy link

Facing this issue as well.

@eran247
Copy link

eran247 commented Jul 4, 2023

I also got this error. Any solutions for iOS?

[VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: MissingPluginException(No implementation found for method Task#startPutData on channel plugins.flutter.io/firebase_storage)
#0 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:313:7)

3 months later, but facing the same issue. Is there any update yet?

@yoman07
Copy link

yoman07 commented Jul 6, 2023

I have the same problem. Any solution?

@eran247
Copy link

eran247 commented Jul 6, 2023

@yoman07 I have downgraded my Firebase storage dependency to 10.x for now.
That seems to work for now.

@yoman07
Copy link

yoman07 commented Jul 12, 2023

Thank you @eran247 . I fixed it by modified firebase_storage plugin but it it's just temporary hack

@scottynoshotty
Copy link

Seeing the same error. Trying to upload files in the background on iOS using work manager. Can't downgrade firebase_storage due to other dependencies. Stuck until this is resolved.

@ScottAtRedHawk
Copy link

I'm seeing the same thing.

@scottynoshotty
Copy link

I found a workaround. Upload using the cloud storage http resumable upload api. I also created a cloud function to generate the access token.

  static Future<void> uploadLocalMediaInBackground(
      List<LocalMedia> localMedia) async {
    for (LocalMedia media in localMedia) {
      final File file = media.file;
      final fileSize = await file.length();
      final chunkSize = 1024 * 1024;
      // Initialize variables for tracking progress.
      int offset = 0;
      int bytesLeft = fileSize;
      final chunkedStreamReader = ChunkedStreamReader(file.openRead());

      // Initialize the resumable upload session.
      final uploadUrl = await initiateResumableUpload(
          MediaConstants.bucketName, media.cloudStoragePath, fileSize);

      while (bytesLeft > 0) {
        final int bytesToRead = (bytesLeft < chunkSize) ? bytesLeft : chunkSize;

        final chunk = await chunkedStreamReader.readChunk(bytesToRead);

        // Upload the chunk to the Cloud Storage.
        await uploadChunk(uploadUrl, offset, Uint8List.fromList(chunk));

        offset += chunk.length;
        bytesLeft -= chunk.length;
      }

      // Finalize the upload (commit).
      await finalizeUpload(uploadUrl);
    }
  }

  static Future<String> initiateResumableUpload(
      String bucketName, String objectName, int fileSize) async {
    final url =
        'https://storage.googleapis.com/upload/storage/v1/b/$bucketName/o?uploadType=resumable&name=$objectName';
    String? accessToken = await AuthService.getAccessToken();
    if (accessToken == null) {
      throw Exception('Could not get access token, it was null');
    }
    final response = await http.post(
      Uri.parse(url),
      headers: {
        'Authorization': 'Bearer $accessToken',
        // Use your access token here
        'Content-Length': '0',
        // Empty body for initiation
        'X-Upload-Content-Length': '$fileSize',
        // Total file size
      },
    );

    if (response.statusCode == 200) {
      final uploadUrl = response.headers['location'];
      if (uploadUrl != null) {
        return uploadUrl;
      } else {
        throw Exception('Failed to get upload url as it was null');
      }
    } else {
      throw Exception('Failed to initiate resumable upload');
    }
  }

  static Future<void> uploadChunk(
      String uploadUrl, int offset, Uint8List chunk) async {
    final response = await http.put(
      Uri.parse(uploadUrl),
      headers: {
        'Content-Range': 'bytes $offset-${offset + chunk.length - 1}/*',
      },
      body: chunk,
    );
  }

  static Future<void> finalizeUpload(String uploadUrl) async {
    final response = await http.post(
      Uri.parse(uploadUrl),
      headers: {
        'Content-Range': 'bytes */*', // Finalize the upload
      },
    );

    if (response.statusCode != 200) {
      throw Exception('Failed to finalize upload');
    }
  }

@ScottAtRedHawk
Copy link

@scottynoshotty Could you post your cloud function, please?

@scottynoshotty
Copy link

I have the json key from one of my service accounts in the same dir as my functions. I know it's bad security practice but it's what I've found works (certainly won't submit to Github)

export const generateAccessToken = functions.https.onRequest(async (req, res) => {
  try {
    functions.logger.log("Generating access token");

    // Get the service account key from Firebase functions config
    const serviceAccountJson = fs.readFileSync("creds.json", "utf8");

    functions.logger.log("Service Account JSON:", serviceAccountJson);

    // Parse the service account JSON
    const serviceAccount = JSON.parse(serviceAccountJson);

    functions.logger.log("Loaded service account key from functions config");
    functions.logger.log("Service Account Email:", serviceAccount.client_email);
    functions.logger.log("Service Account Scopes:", serviceAccount.scopes);

    // Create a JWT client to generate access tokens
    const client = new JWT({
      email: serviceAccount.client_email,
      key: serviceAccount.private_key,
      scopes: ["https://www.googleapis.com/auth/cloud-platform"],
    });

    functions.logger.log("Created JWT client");

    // Generate an access token
    const accessToken = await client.authorize();


    res.json({data: {accessToken: accessToken.access_token}});
  } catch (error) {
    console.error(error);
    functions.logger.error("Error generating access token:", error);
    res.status(500).json({error: "Unable to generate access token"});
  }
});
@AntoineChauviere
Copy link

Is there a solution for uploading images to Firebase Storage using Isolate that works on both Android and iOS?

@DominicOrga
Copy link

DominicOrga commented Nov 16, 2023

I've been facing the same problem since Feb. However, the error appears to have changed. Currently, the issue manifests as follows on my end:

Unhandled PlatformException(channel-error, Unable to establish connection on channel., null, null)
#0      FirebaseStorageHostApi.referencePutFile (package:firebase_storage_platform_interface/src/pigeon/messages.pigeon.dart:685:7)
<asynchronous suspension>
#1      new MethodChannelTask.mapNativeStream (package:firebase_storage_platform_interface/src/method_channel/method_channel_task.dart:29:26)
@Doppelklick
Copy link

I've been facing the same problem since Feb. However, the error appears to have changed. Currently, the issue manifests as follows on my end:

Unhandled PlatformException(channel-error, Unable to establish connection on channel., null, null)
#0      FirebaseStorageHostApi.referencePutFile (package:firebase_storage_platform_interface/src/pigeon/messages.pigeon.dart:685:7)
<asynchronous suspension>
#1      new MethodChannelTask.mapNativeStream (package:firebase_storage_platform_interface/src/method_channel/method_channel_task.dart:29:26)

I can confirm that it looks like the error has changed. Problem still exists...

@russellwheatley russellwheatley self-assigned this Dec 29, 2023
@russellwheatley
Copy link
Member

russellwheatley commented Jan 2, 2024

Isolates won't work for this task because it uses the event channel (i.e. native -> dart). I tried without the use of flutter_isolates and used essentially what is described here. I received the same exception on android and iOS:

E/flutter (11420): Unsupported operation: Background isolates do not support setMessageHandler(). Messages from the host platform always go to the root isolate.

There is an open issue on Flutter for this specific purpose: flutter/flutter#119207

This won't work until the above issue is resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blocked: flutter platform: ios Issues / PRs which are specifically for iOS. plugin: storage type: bug Something isn't working