Skip to content

Commit

Permalink
Optimization
Browse files Browse the repository at this point in the history
1.Optimization android plugin
  • Loading branch information
woodwen committed Jun 13, 2023
1 parent 8c231b3 commit bbdae58
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 73 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.example.imagegallerysaver

import android.annotation.TargetApi
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.media.MediaScannerConnection
import android.net.Uri
import android.os.Environment
import android.os.Build
Expand All @@ -21,111 +23,196 @@ import java.io.FileInputStream
import java.io.IOException
import android.text.TextUtils
import android.webkit.MimeTypeMap

import java.io.OutputStream

class ImageGallerySaverPlugin : FlutterPlugin, MethodCallHandler {
private var applicationContext: Context? = null
private var methodChannel: MethodChannel? = null

override fun onMethodCall(call: MethodCall, result: Result): Unit {
when {
call.method == "saveImageToGallery" -> {
val image = call.argument<ByteArray>("imageBytes") ?: return
val quality = call.argument<Int>("quality") ?: return
val name = call.argument<String>("name")

result.success(saveImageToGallery(BitmapFactory.decodeByteArray(image, 0, image.size), quality, name))
when (call.method) {
"saveImageToGallery" -> {
val image = call.argument<ByteArray?>("imageBytes")
val quality = call.argument<Int?>("quality")
val name = call.argument<String?>("name")

result.success(
saveImageToGallery(
BitmapFactory.decodeByteArray(
image ?: ByteArray(0),
0,
image?.size ?: 0
), quality, name
)
)
}
call.method == "saveFileToGallery" -> {
val path = call.argument<String>("file") ?: return
val name = call.argument<String>("name")

"saveFileToGallery" -> {
val path = call.argument<String?>("file")
val name = call.argument<String?>("name")
result.success(saveFileToGallery(path, name))
}

else -> result.notImplemented()
}

}


private fun generateUri(extension: String = "", name: String? = null): Uri {
private fun generateUri(extension: String = "", name: String? = null): Uri? {
var fileName = name ?: System.currentTimeMillis().toString()

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
var uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI

val values = ContentValues()
values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// >= android 10
val mimeType = getMIMEType(extension)
if (!TextUtils.isEmpty(mimeType)) {
values.put(MediaStore.Images.Media.MIME_TYPE, mimeType)
if (mimeType!!.startsWith("video")) {
uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_MOVIES)
val isVideo = mimeType?.startsWith("video")==true
val uri = when {
isVideo -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
else -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}

val values = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
put(
MediaStore.MediaColumns.RELATIVE_PATH, when {
isVideo -> Environment.DIRECTORY_MOVIES
else -> Environment.DIRECTORY_PICTURES
}
)
if (!TextUtils.isEmpty(mimeType)) {
put(MediaStore.Images.Media.MIME_TYPE, mimeType)
}
}
return applicationContext?.contentResolver?.insert(uri, values)!!

applicationContext?.contentResolver?.insert(uri, values)

} else {
val storePath = Environment.getExternalStorageDirectory().absolutePath + File.separator + Environment.DIRECTORY_PICTURES
val appDir = File(storePath)
if (!appDir.exists()) {
appDir.mkdir()
}
if (extension.isNotEmpty()) {
fileName += (".$extension")
// < android 10
val storePath =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).absolutePath
val appDir = File(storePath).apply {
if (!exists()) {
mkdir()
}
}
return Uri.fromFile(File(appDir, fileName))

val file =
File(appDir, if (extension.isNotEmpty()) "$fileName.$extension" else fileName)
Uri.fromFile(file)
}
}

/**
* get file Mime Type
*
* @param extension extension
* @return file Mime Type
*/
private fun getMIMEType(extension: String): String? {
var type: String? = null;
if (!TextUtils.isEmpty(extension)) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase())
return if (!TextUtils.isEmpty(extension)) {
MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.lowercase())
} else {
null
}
}

/**
* Send storage success notification
*
* @param context context
* @param fileUri file path
*/
private fun sendBroadcast(context: Context, fileUri: Uri?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaScannerConnection.scanFile(context, arrayOf(fileUri?.toString()), null) { _, _ -> }
} else {
context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, fileUri))
}
return type
}

private fun saveImageToGallery(bmp: Bitmap, quality: Int, name: String?): HashMap<String, Any?> {
private fun saveImageToGallery(
bmp: Bitmap?,
quality: Int?,
name: String?
): HashMap<String, Any?> {
// check parameters
if (bmp == null || quality == null) {
return SaveResultModel(false, null, "parameters error").toHashMap()
}
// check applicationContext
val context = applicationContext
val fileUri = generateUri("jpg", name = name)
return try {
val fos = context?.contentResolver?.openOutputStream(fileUri)!!
println("ImageGallerySaverPlugin $quality")
bmp.compress(Bitmap.CompressFormat.JPEG, quality, fos)
fos.flush()
fos.close()
context!!.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, fileUri))
bmp.recycle()
SaveResultModel(fileUri.toString().isNotEmpty(), fileUri.toString(), null).toHashMap()
?: return SaveResultModel(false, null, "applicationContext null").toHashMap()
var fileUri: Uri? = null
var fos: OutputStream? = null
var success = false
try {
fileUri = generateUri("jpg", name = name)
if (fileUri != null) {
fos = context.contentResolver.openOutputStream(fileUri)
if (fos != null) {
println("ImageGallerySaverPlugin $quality")
bmp.compress(Bitmap.CompressFormat.JPEG, quality, fos)
fos.flush()
success = true
}
}
} catch (e: IOException) {
SaveResultModel(false, null, e.toString()).toHashMap()
} finally {
fos?.close()
bmp.recycle()
}
return if (success) {
sendBroadcast(context, fileUri)
SaveResultModel(fileUri.toString().isNotEmpty(), fileUri.toString(), null).toHashMap()
} else {
SaveResultModel(false, null, "saveImageToGallery fail").toHashMap()
}
}

private fun saveFileToGallery(filePath: String, name: String?): HashMap<String, Any?> {
val context = applicationContext
return try {
private fun saveFileToGallery(filePath: String?, name: String?): HashMap<String, Any?> {
// check parameters
if (filePath == null) {
return SaveResultModel(false, null, "parameters error").toHashMap()
}
val context = applicationContext ?: return SaveResultModel(
false,
null,
"applicationContext null"
).toHashMap()
var fileUri: Uri? = null
var outputStream: OutputStream? = null
var fileInputStream: FileInputStream? = null
var success = false

try {
val originalFile = File(filePath)
val fileUri = generateUri(originalFile.extension, name)

val outputStream = context?.contentResolver?.openOutputStream(fileUri)!!
val fileInputStream = FileInputStream(originalFile)

val buffer = ByteArray(10240)
var count = 0
while (fileInputStream.read(buffer).also { count = it } > 0) {
outputStream.write(buffer, 0, count)
if(!originalFile.exists()) return SaveResultModel(false, null, "$filePath does not exist").toHashMap()
fileUri = generateUri(originalFile.extension, name)
if (fileUri != null) {
outputStream = context.contentResolver?.openOutputStream(fileUri)
if (outputStream != null) {
fileInputStream = FileInputStream(originalFile)

val buffer = ByteArray(10240)
var count = 0
while (fileInputStream.read(buffer).also { count = it } > 0) {
outputStream.write(buffer, 0, count)
}

outputStream.flush()
success = true
}
}

outputStream.flush()
outputStream.close()
fileInputStream.close()

context!!.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, fileUri))
SaveResultModel(fileUri.toString().isNotEmpty(), fileUri.toString(), null).toHashMap()
} catch (e: IOException) {
SaveResultModel(false, null, e.toString()).toHashMap()
} finally {
outputStream?.close()
fileInputStream?.close()
}
return if (success) {
// sendBroadcast(context, fileUri)
SaveResultModel(fileUri.toString().isNotEmpty(), fileUri.toString(), null).toHashMap()
} else {
SaveResultModel(false, null, "saveFileToGallery fail").toHashMap()
}
}

Expand Down
6 changes: 3 additions & 3 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: Demonstrates how to use the image_gallery_saver plugin.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# Read more about versioning at semver.org.
version: 2.0.1+1
version: 2.0.2+2

environment:
sdk: '>=2.19.6 <4.0.0'
Expand All @@ -16,10 +16,10 @@ dependencies:
flutter:
sdk: flutter

permission_handler: ^10.2.0
permission_handler: ^10.3.0
fluttertoast: ^8.2.2
path_provider: ^2.0.15
dio: ^5.1.2
dio: ^5.2.1+1

image_gallery_saver:
path: ../
Expand Down
2 changes: 1 addition & 1 deletion ios/image_gallery_saver.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
Pod::Spec.new do |s|
s.name = 'image_gallery_saver'
s.version = '2.0.1'
s.version = '2.0.2'
s.summary = 'A new flutter plugin project.'
s.description = <<-DESC
A new flutter plugin project.
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: image_gallery_saver
description: A flutter plugin for save image to gallery, iOS need to add the following keys to your Info.plist file.
version: 2.0.1
version: 2.0.2
homepage: https://github.com/hui-z/image_gallery_saver

environment:
Expand Down

0 comments on commit bbdae58

Please sign in to comment.