Reputation: 323
I'm writing a piece of Android code which stores a file in the user's download folder.
@CapacitorPlugin(name = "Downloads")
class DownloadsPlugin : Plugin() {
@PluginMethod(returnType = PluginMethod.RETURN_NONE)
fun download(call: PluginCall) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val filename = call.getString("fileName")!!
val data = call.getString("data")!!
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
}
val contentResolver = context.contentResolver
val uri =
contentResolver.insert(MediaStore.Files.getContentUri("external"), contentValues)!!
val outputStream = contentResolver.openOutputStream(uri)!!
outputStream.write(data.toByteArray(StandardCharsets.UTF_8))
}
call.resolve()
}
}
The code I've written works correctly on Android 10 (API level 29) or higher. On API level 28 or lower, the code does not work. On calling the download
method, the following error is logged:
2022-10-08 16:10:59.064 23121-23184/com.example.example E/Capacitor: Serious error executing plugin
java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.getcapacitor.PluginHandle.invoke(PluginHandle.java:125)
at com.getcapacitor.Bridge.lambda$callPluginMethod$0$com-getcapacitor-Bridge(Bridge.java:706)
at com.getcapacitor.Bridge$$ExternalSyntheticLambda5.run(Unknown Source:8)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.os.HandlerThread.run(HandlerThread.java:65)
Caused by: java.lang.IllegalArgumentException: no path was provided when inserting new file
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:165)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
at android.content.ContentProviderProxy.insert(ContentProviderNative.java:476)
at android.content.ContentResolver.insert(ContentResolver.java:1587)
at com.example.example.DownloadsPlugin.download(DownloadsPlugin.kt:36)
at java.lang.reflect.Method.invoke(Native Method)
at com.getcapacitor.PluginHandle.invoke(PluginHandle.java:125)
at com.getcapacitor.Bridge.lambda$callPluginMethod$0$com-getcapacitor-Bridge(Bridge.java:706)
at com.getcapacitor.Bridge$$ExternalSyntheticLambda5.run(Unknown Source:8)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.os.HandlerThread.run(HandlerThread.java:65)
How can I correct this error so that the code works on API level 28 or lower?
Upvotes: 3
Views: 665
Reputation: 48
Unfortunatelly It's not supported API 28 and before. At least I couldn't find. change method for legacy
class SaveBitmapToGalleryUseCase @Inject constructor(
@ApplicationContext private val context: Context,
) {
operator fun invoke(
bitmap: Bitmap,
fileName: String = bitmap.hashCode().toString()
): Boolean = runCatching {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
val file = File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"$fileName.jpeg"
)
FileOutputStream(file).use { bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it) }
} else {
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "$fileName.jpg")
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
}
val resolver = context.contentResolver
val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
?: throw Exception("Failed to create new MediaStore record.")
resolver.openOutputStream(uri)?.use { outputStream ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
} ?: throw Exception("Failed to get output stream.")
}
}.onFailure {
Log.e(t = it)
}.getOrDefault(false)
}
Upvotes: 0