flutterfire
flutterfire copied to clipboard
🐛 [firebase_storage] MissingPluginException when using firebase_storage via flutter_isolate
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:
- Check out the provided sample project
- Configure a firebase project
- 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]
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.
facing the same issue does anyone have any solution for this as it is running absolutely fine in android but throws MissingPluginException on iOS.
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.
same with workmanager (Flutter version 3.7.10).
Anybody found a workaround?
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)
Facing this issue as well.
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?
I have the same problem. Any solution?
@yoman07 I have downgraded my Firebase storage dependency to 10.x for now. That seems to work for now.
Thank you @eran247 . I fixed it by modified firebase_storage plugin but it it's just temporary hack
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.
I'm seeing the same thing.
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');
}
}
@scottynoshotty Could you post your cloud function, please?
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"});
}
});
Is there a solution for uploading images to Firebase Storage using Isolate that works on both Android and iOS?
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'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...
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: https://github.com/flutter/flutter/issues/119207
This won't work until the above issue is resolved.