Open EchoEllet opened 1 week ago
Same solution in Kotlin/JVM can be used in Java. ```kotlin // Check if you have access to the URI and the file exists before processing the URI: /** * A method to see if any exceptions can occur * before start reading the file. * * The app can lose access to the [Uri] due to lifecycle changes. * * @throws SecurityException When the app loses access to the [Uri] due to app lifecycle changes * or app restart. * @throws FileNotFoundException Could be thrown when the [Uri] is no longer on the clipboard. * */ @Throws(Exception::class) private fun Uri.readOrThrow( context: Context, ) = try { context.contentResolver.openInputStream(this)?.close() } catch (e: Exception) { throw e } try { imageUri.readOrThrow(context) } catch (e: Exception) { when (e) { is SecurityException -> result.error( "FILE_READ_PERMISSION_DENIED", "An image exists on the clipboard, but the app no longer " + "has permission to access it. This may be due to the app's " + "lifecycle or a recent app restart: ${e.message}", e.toString(), ) is FileNotFoundException -> result.error( "FILE_NOT_FOUND", "The image file can't be found, it might not be on the system clipboard anymore: ${e.message}", e.toString() ) else -> result.error( "UNKNOWN_ERROR_READING_FILE", "An unknown occurred while reading the image file URI: ${e.message}", e.toString() ) } return } // Process further with the URI... ``` Which doesn't fix the issue completely but at least no longer app crashes, since if you try to open the app and you still have that image on your clipboard without copying something else, the app will continue to crash and the system will recommend the user to uninstall the app or report it to the developer, the user will probably delete the app before reaching this state. So it's probably better to return `false` to `canProvide` the image file return it `null`, or have unhandled exception from dart side instead of the Android side as a quick solution. Saving an image to a temporary location is not guaranteed as it can be erased, somewhere in the app document directory is not ideal if we have to save all images on the clipboard to retain access to them on app restart, the plugin might not have full access to the app lifecycle to delete them later or the user don't want to save such images on the user device.
I'm still uncertain why sometimes I get FileNotFoundException
instead of SecurityException
by slightly changing the steps to reproduce each time.
What I'm sure about this issue doesn't happen when not pasting that image into the app (step 2 removed)
This is an issue when using super_clipbaord however the native platform code is in
super_native_extensions
.Steps to reproduce:
flutter run
), you might get a crash.Crash Log
```console Shutting down VM E/flutter ( 7331): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(super_native_extensions_error, "JNI: Java exception was thrown", otherError, null) E/flutter ( 7331): #0 NativeMethodChannel.invokeMethod (package:irondash_message_channel/src/method_channel.dart:45:7) E/flutter ( 7331):Video
Android Emulator API 34. https://github.com/user-attachments/assets/788bde36-d9d7-40ec-919f-48887f269100Similar but not related issue
This issue is not related and doesn't use `super_clipbaord` however a similar issue will occur with the same steps to reproduce. It uses our custom implementation in [Flutter Quill #2230](https://github.com/singerdmx/flutter-quill/pull/2230/) using Kotlin (for Android) directly using the Flutter method channel without Rust. https://github.com/user-attachments/assets/37e0c69c-968a-4dfe-abb0-0e7d5750e797 The difference is that the app doesn't crash: ```console Unhandled Exception: PlatformException(COULD_NOT_DECODE_IMAGE, Could not decode bitmap from Uri: Permission Denial: opening provider org.chromium.chrome.browser.util.ChromeFileProvider from ProcessRecord{b3d4d8e 14685:dev.flutterquill.quill_native_bridge_example/u0a191} (pid=14685, uid=10191) that is not exported from UID 10146, java.lang.SecurityException: Permission Denial: opening provider org.chromium.chrome.browser.util.ChromeFileProvider from ProcessRecord{b3d4d8e 14685:dev.flutterquill.quill_native_bridge_example/u0a191} (pid=14685, uid=10191) that is not exported from UID 10146, null) E/flutter (14685): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:648:7) E/flutter (14685): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:334:18) E/flutter (14685):Hint: The image URI that is given by the
android.content.ClipboardManager
gives the app limited access, and can be restricted to its lifecycle, once the lifecycle is destroyed, the app no longer has access to theandroid.net.Uri
.The
super_clipboard
plugin could check if it has access before processing further, avoid resulting in a crash, and returnnull
(false
for thecanProvide
or throw a dart platform exception) or save the image to somewhere and get access to the image later on app restart and return the image.let me know If more details are needed or unable to reproduce the issue.