将文件存储在 Flutter 中的 Android 101112+ 下载文件夹中。
Posted 小陈乱敲代码
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将文件存储在 Flutter 中的 Android 101112+ 下载文件夹中。相关的知识,希望对你有一定的参考价值。
在Flutter中,您可能会遇到在 android 10+ 上将文件保存在公共存储中的问题。这可能令人沮丧,因为无法使用path_provider插件或任何其他插件保存文件。也可能是没有授予足够的权限。在本文中,我们将看到如何在使用 Flutter 在 Android 上进行范围存储后将文件保存到下载文件夹中。
我们将创建一个示例,首先使用Dio包从 URL 下载文件,然后将其存储在其中Download/AppName文件夹。
步骤:
1、在pubspec.yaml中添加相关包。
2、在AndroidManifest.xml中添加相关的存储和网络权限。
3、 从flutter调用一个原生的android函数。
4、请求存储运行时权限。
5、下载文件到本地目录。
6、将文件移动到 Download/AppName 文件夹。
第1步:
添加相关包pubspec.yaml
path_provider: ^2.0.11
dio: ^4.0.6
device_info_plus: ^4.0.1
第2步:
在AndroidManifest.xml.
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
第 3 步:
现在,我们必须请求运行时存储权限。我们不会向 Flutter 请求权限,而是要从 Flutter 调用 android 的原生函数,这将请求权限。我们必须向本机函数请求权限,否则这将不起作用。
创建一个Button我们将请求权限的对象。
ElevatedButton(
onPressed: requestStoragePermission,
child: Text('Request Storage Permissions'),
),
创建一个将调用本机 android 方法的函数。
Future<void> requestStoragePermission() async
try
await platform.invokeMethod('requestStoragePermission');
on PlatformException catch (e)
print(e);
在您的 MainActivity 中创建一个名为 CHANNEL 的变量并为其设置一个值。此值应与 dart invokeMethod 值匹配。如果它们不匹配,颤振代码将无法调用 android 方法。
class MainActivity: FlutterActivity()
private val CHANNEL ="com.example.androidstorage.android_12_flutter_storage/storage"
覆盖configureFlutterEngine内部MainActivity并添加MethodChannel代码。
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine)
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler call, result ->
if (call.method == "requestStoragePermission")
requestPermission(this@MainActivity as Context)
else
result.notImplemented()
创建一个名为的新 kt 文件FileUtils.kt并添加一个名为requestPermission.在该方法中,调用ActivityCompat.requestPermissions以请求存储运行时权限。
object FileUtils
fun requestPermission(context: Context)
ActivityCompat.requestPermissions(
context as Activity, arrayOf(
android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
android.Manifest.permission.ACCESS_MEDIA_LOCATION
), 101
);
第4步:
下载文件到本地目录。
ElevatedButton(
onPressed: downloadRecording,
child: const Text('Download Recording!'),
),
void downloadRecording() async
String url =
"https://file-examples.com/storage/fe8faa459062eec049e62d4/2017/11/file_example_MP3_700KB.mp3";
String fileName = "Audio-Recording.mp3";
String path = await _getFilePath(fileName);
await dio.download(
url,
path,
onReceiveProgress: (receivedBytes, totalBytes)
print("Rec: $receivedBytes , Total: $totalBytes");
setState(()
progress = ((receivedBytes / totalBytes) * 100);
if (progress == 100.0)
_saveFileToRecordings(path);
);
,
deleteOnError: true,
).then((value) => print(value.toString()));
Future<void> _saveFileToRecordings(String path) async
DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
final androidInfo = await deviceInfoPlugin.androidInfo;
print("Device Version: $androidInfo.version.sdkInt");
if (Platform.isAndroid && androidInfo.version.sdkInt! >= 29)
try
await platform.invokeMethod('saveFile', 'path': path);
on PlatformException catch (e)
print(e);
else
Future<String> _getFilePath(String fileName) async
DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
final androidInfo = await deviceInfoPlugin.androidInfo;
print("Device Version: $androidInfo.version.sdkInt");
if (Platform.isAndroid && androidInfo.version.sdkInt! >= 29)
final dir = await getExternalStorageDirectory();
print("File Name: $dir!.path/$fileName");
return "$dir.path/$fileName";
else
var dir = Directory('/storage/emulated/0/Download/AppName');
print("File Name: $dir.path/$fileName");
return "$dir.path/$fileName";
第5步:
将文件移动到 Download/AppName 文件夹。
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine)
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler call, result ->
if (call.method == "saveFile")
val hashMap = call.arguments as HashMap<*,*> //Get the arguments as a HashMap
val path = hashMap["path"]
FileUtils.saveBitmapToStorage(this@MainActivity as Context,path.toString())
else if (call.method == "requestStoragePermission")
requestPermission(this@MainActivity as Context)
else
result.notImplemented()
fun checkPermissionForExternalStorage(context: Context): Boolean
return ActivityCompat.checkSelfPermission(
context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE
) === PackageManager.PERMISSION_GRANTED
fun saveBitmapToStorage(context: Context, bitmap: String): Uri?
var result: Uri? = null
if (checkPermissionForExternalStorage(context))
var filename: File? = null
val outputStream: java.io.OutputStream?
val DEFAULT_IMAGE_NAME: String = java.util.UUID.randomUUID().toString()
try
/*Check if the android version is equal or greater than Android 10*/
if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q)
val resolver: ContentResolver = context.getContentResolver()
val contentValues = ContentValues()
contentValues.put(MediaStore.Audio.Media.DISPLAY_NAME, DEFAULT_IMAGE_NAME)
contentValues.put(MediaStore.Audio.Media.TITLE, DEFAULT_IMAGE_NAME)
contentValues.put(
MediaStore.Audio.Media.MIME_TYPE,
getMIMEType(context, bitmap)
)
contentValues.put(MediaStore.Audio.Media.RELATIVE_PATH, "Music/" + "AppName")
val imageUri: Uri? =
resolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, contentValues)
var file = File(bitmap);
outputStream = resolver.openOutputStream(imageUri!!)
val bytesArray: ByteArray = file.readBytes()
outputStream!!.write(bytesArray)
outputStream!!.flush()
result = imageUri
Log.d("FileUtils", bitmap);
SingleMediaScanner(context, file)
else
catch (e: java.lang.Exception)
Log.d("FileUtils", e.message!!);
e.printStackTrace()
return result
fun getMIMEType(con: Context, url: String?): String?
var mType: String? = null
val mExtension = MimeTypeMap.getFileExtensionFromUrl(url)
if (mExtension != null)
mType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(mExtension)
return mType
第6步:
SingleMediaScanner在 android 目录中创建。
import android.content.Context;
import android.media.MediaScannerConnection;
import android.net.Uri;
import java.io.File;
public class SingleMediaScanner implements MediaScannerConnection.MediaScannerConnectionClient
private MediaScannerConnection mMs;
private File mFile;
public SingleMediaScanner(Context context, File f)
mFile = f;
mMs = new MediaScannerConnection(context, this);
mMs.connect();
@Override
public void onMediaScannerConnected()
mMs.scanFile(mFile.getAbsolutePath(), null);
@Override
public void onScanCompleted(String path, Uri uri)
mMs.disconnect();
以上是关于将文件存储在 Flutter 中的 Android 101112+ 下载文件夹中。的主要内容,如果未能解决你的问题,请参考以下文章
Flutter Web 不显示 Firebase 存储中的 NetworkImages,但在 android 模拟器上完美运行
Flutter Android 11 权限,例如 WhatsApp
如何将csv文件保存到flutter中的内部存储下载文件夹中?
Flutter firebase 存储插件需要大量时间来上传文件