Um plugin para criar e gerenciar tarefas de download. Suporta iOS e Android.
Este plugin usa WorkManager
no Android e NSURLSessionDownloadTask
no iOS para executar tarefas de download em segundo plano.
As mudanças nas APIs de armazenamento externo no Android 11 causam alguns problemas na implementação atual. Decido redesenhar este plugin com uma nova estratégia para gerenciar a localização do arquivo de download. Ainda está em triagem e discussão neste PR. Agradecemos muito a contribuição e feedback do desenvolvedor do Flutter para obter um melhor design para o plugin.
Nas versões anteriores deste pacote, havia vulnerabilidades conhecidas relacionadas à injeção de SQL. A injeção de SQL é um tipo de vulnerabilidade de segurança que pode permitir que usuários mal-intencionados manipulem consultas SQL executadas por um aplicativo, levando potencialmente ao acesso não autorizado ou à manipulação do banco de dados.
É altamente recomendável atualizar para a versão mais recente deste pacote para garantir que seu aplicativo não fique exposto a vulnerabilidades de injeção de SQL. A versão mais recente contém as melhorias e patches de segurança necessários para mitigar esses riscos.
As etapas a seguir exigem a abertura do seu projeto ios
no Xcode.
Ative o modo de fundo.
Adicione a biblioteca sqlite
.
Configurar AppDelegate
:
Objetivo-C:
/// AppDelegate.h#import <Flutter/Flutter.h>#import <UIKit/UIKit.h>@interface AppDelegate : FlutterAppDelegate@end
// AppDelegate.m#include "AppDelegate.h"#include "GeneratedPluginRegistrant.h"#include "FlutterDownloaderPlugin.h"@implementation AppDelegatevoid registerPlugins(NSObject<FlutterPluginRegistrant>* registro) { if (![registry hasPlugin:@"FlutterDownloaderPlugin" ]) { [FlutterDownloaderPlugin registreWithRegistrar:[registry registrarForPlugin:@"FlutterDownloaderPlugin"]]; } } - (BOOL)aplicativo:(UIApplication *)aplicativo didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [GeneratedPluginRegistrant RegisterWithRegistry:self]; [FlutterDownloaderPlugin setPluginRegistrantCallback:registerPlugins]; // Substituir ponto para personalização após inicialização do aplicativo. return [super aplicativo: aplicativo didFinishLaunchingWithOptions:launchOptions]; }@fim
Ou rápido:
importar UIKit importar vibração importar flutter_downloader@UIApplicationMain@objc class AppDelegate: FlutterAppDelegate {substituir func application( _ aplicação: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Qualquer]? ) -> Bool { GeneratedPluginRegistrant.register (com: self) FlutterDownloaderPlugin.setPluginRegistrantCallback (registerPlugins) return super.application (application, didFinishLaunchingWithOptions: launchOptions) }}private func RegisterPlugins (registro: FlutterPluginRegistry) { if (!registry.hasPlugin("FlutterDownloaderPlugin")) { FlutterDownloaderPlugin.register(com: Registry.registrar(forPlugin: "FlutterDownloaderPlugin")!) }}
Suporte a solicitação HTTP: se você deseja baixar o arquivo com solicitação HTTP, você precisa desabilitar o recurso Apple Transport Security (ATS). Existem duas opções:
Desative o ATS apenas para um domínio específico: (adicione o seguinte código ao seu arquivo Info.plist
)
<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>www.seuservidor.com</key> <dict> <!-- adicione esta chave para habilitar subdomínios como sub.yourserver.com --> <key>NSIncludesSubdomínios</key> <true/> <!-- adicione esta chave para permitir solicitações HTTP padrão, negando assim o ATS --> <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key> <true/> <!-- adicione esta chave para especificar a versão mínima do TLS a ser aceita --> <key>NSTemporaryExceptionMinimumTLSVersion</key> <string>TLSv1.1</string> </dict> </dict> </dict>
Desative completamente o ATS. Adicione o seguinte ao seu arquivo Info.plist
)
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key><true/> </dict>
Configure o número máximo de tarefas simultâneas: o plugin permite que 3 tarefas de download sejam executadas ao mesmo tempo por padrão (se você enfileirar mais de 3 tarefas, há apenas 3 tarefas em execução, outras tarefas são colocadas em estado pendente). Você pode alterar esse número adicionando o seguinte código ao arquivo Info.plist
.
<!-- altera este número para configurar o número máximo de tarefas simultâneas --><key>FDMaximumConcurrentTasks</key> <inteiro>5</inteiro>
Localizar mensagens de notificação: o plugin enviará uma mensagem de notificação para notificar o usuário caso todos os arquivos sejam baixados enquanto seu aplicativo não estiver sendo executado em primeiro plano. Esta mensagem é em inglês por padrão. Você pode localizar esta mensagem adicionando e localizando a seguinte mensagem no arquivo Info.plist
. (você pode encontrar os detalhes da localização Info.plist
neste link)
<key>FDAllFilesDownloadedMessage</key> <string>Todos os arquivos foram baixados</string>
Observação:
Este plugin só suporta salvar arquivos em NSDocumentDirectory
Você não precisa fazer nada extra para que o plugin funcione no Android.
Existem algumas configurações opcionais que você pode querer definir.
Para fazer com que o toque na notificação abra o arquivo baixado no Android, adicione o seguinte código ao AndroidManifest.xml
:
<provedor android:name="vn.hunghd.flutterdownloader.DownloadedFileProvider" android:authorities="${applicationId}.flutter_downloader.provider" android:exported="false" android:grantUriPermissions="true"> <metadados android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/> </provedor>
Notas
Você deve salvar os arquivos baixados em armazenamento externo (onde os outros aplicativos têm permissão para ler seus arquivos)
Os arquivos baixados só poderão ser abertos se o seu dispositivo tiver pelo menos um aplicativo que possa ler esses tipos de arquivos (mp3, pdf, etc.)
O plugin depende da biblioteca WorkManager
e WorkManager
depende da quantidade de processadores disponíveis para configurar o número máximo de tarefas em execução por momento. Você pode definir um número fixo para esta configuração adicionando o seguinte código ao seu AndroidManifest.xml
:
<!-- Iniciar personalização do FlutterDownloader --><!-- desabilitar o inicializador padrão --><provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" android:exported ="false" ferramentas:node="merge"> <metadados android:name="androidx.work.WorkManagerInitializer" android:value="androidx.startup" ferramentas:node="remove" /> </provider><!-- declarar inicializador personalizado --><provider android:name="vn.hunghd.flutterdownloader.FlutterDownloaderInitializer" android:authorities="${applicationId}.flutter-downloader-init" android:exported=" false"> <!-- altera este número para configurar o número máximo de tarefas simultâneas --> <metadados android:name="vn.hunghd.flutterdownloader.MAX_CONCURRENT_TASKS" android:value="5" /> </provider><!-- Finalizar personalização do FlutterDownloader -->
Você pode localizar textos em notificações de progresso de download localizando as mensagens a seguir.
<string name="flutter_downloader_notification_started">Download iniciado</string> <string name="flutter_downloader_notification_in_progress">Download em andamento</string> <string name="flutter_downloader_notification_canceled">Download cancelado</string> <string name="flutter_downloader_notification_failed">Falha no download</string> <string name="flutter_downloader_notification_complete">Download concluído</string> <string name="flutter_downloader_notification_paused">Download pausado</string>
Você pode aprender mais sobre localização no Android aqui.
Para abrir e instalar arquivos .apk
, seu aplicativo precisa da permissão REQUEST_INSTALL_PACKAGES
. Adicione o seguinte no seu AndroidManifest.xml
:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
Veja também:
Corrigir erro de tráfego de texto claro no Android 9 Pie
importar 'pacote:flutter_downloader/flutter_downloader.dart';void main() { WidgetsFlutterBinding.ensureInitialized(); // O plugin deve ser inicializado antes de usar await FlutterDownloader.initialize( debug: true, // opcional: definido como false para desativar a impressão de logs no console (padrão: true) ignoreSsl: true // opção: defina como false para desabilitar o trabalho com links http (padrão: false) ); runApp(/*...*/) }
tarefa final = aguarda FlutterDownloader.enqueue ( url: 'seu link de download', headers: {}, // opcional: cabeçalho enviado com url (token de autenticação, etc.) saveDir: 'o caminho do diretório onde você deseja salvar os arquivos baixados', showNotification: true, // mostra o progresso do download na barra de status (para Android) openFileFromNotification: true, // clique na notificação para abrir o arquivo baixado (para Android));
aguarde FlutterDownloader.registerCallback(retorno de chamada); // callback é uma função estática ou de nível superior
Importante
A UI é renderizada no isolado principal, enquanto os eventos de download vêm do isolado em segundo plano (em outras palavras, o código no callback
é executado no isolado em segundo plano), portanto, você precisa lidar com a comunicação entre dois isolados. Por exemplo:
ReceivePort _port = ReceivePort();@overridevoid initState() { super.initState(); IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port'); _port.listen((dados dinâmicos) { String id = dados[0]; DownloadTaskStatus status = DownloadTaskStatus(dados[1]); int progresso = dados[2]; setState((){ }); }); FlutterDownloader.registerCallback(downloadCallback); }@overridevoid descarte() { IsolateNameServer.removePortNameMapping('downloader_send_port'); super.dispose(); }@pragma('vm:ponto de entrada')static void downloadCallback(String id, int status, int progress) { final SendPort send = IsolateNameServer.lookupPortByName('downloader_send_port'); send.send([id, status, progresso]); }
@pragma('vm:entry-point')
deve ser colocado acima da função callback
para evitar o tremor da árvore no modo de liberação do Android.
tarefas finais = aguardar FlutterDownloader.loadTasks();
tarefas finais = aguardar FlutterDownloader.loadTasksWithRawQuery(query: query);
Para analisar dados no objeto DownloadTask
com êxito, você deve carregar os dados com todos os campos do banco de dados (em outras palavras, usar SELECT *
). Por exemplo:
SELECIONE * DA tarefa ONDE status = 3
Abaixo está o esquema da tabela task
onde o plugin flutter_downloader
armazena informações sobre tarefas de download
CREATE TABLE `task` ( `id` INTEGER PRIMARY KEY AUTOINCREMENT, `task_id` VARCHAR ( 256 ), `url` TEXT, `status` INTEGER DEFAULT 0, `progress` INTEGER DEFAULT 0, `file_name` TEXT, `saved_dir` TEXT , `resumível` TINYINT DEFAULT 0, `cabeçalhos` TEXTO, `show_notification` TINYINT DEFAULT 0, `open_file_from_notification` TINYINT DEFAULT 0, `time_created` INTEGER DEFAULT 0);
FlutterDownloader.cancel(taskId: taskId);
FlutterDownloader.cancelAll();
FlutterDownloader.pause(taskId: taskId);
FlutterDownloader.resume(taskId: taskId);
resume()
retornará um novo taskId
correspondente a uma nova tarefa em segundo plano criada para continuar o processo de download. Você deve substituir o taskId
antigo (que tem status paused
) pelo novo taskId
para continuar acompanhando o progresso do download.
FlutterDownloader.retry(taskId: taskId);
retry()
retornará um novo taskId
(assim como resume()
)
FlutterDownloader.remove(taskId: taskId, shouldDeleteContent:false);
FlutterDownloader.open(taskId: taskId);
No Android, você só pode abrir um arquivo baixado se ele estiver colocado no armazenamento externo e se houver pelo menos um aplicativo que possa ler esse tipo de arquivo no seu dispositivo.
Sinta-se à vontade para abrir um problema se encontrar algum problema ou achar que falta algum recurso no plugin.
Solicitações pull também são muito bem-vindas!