ปลั๊กอินสำหรับการสร้างและจัดการงานดาวน์โหลด รองรับ iOS และ Android
ปลั๊กอินนี้ใช้ WorkManager
บน Android และ NSURLSessionDownloadTask
บน iOS เพื่อรันงานดาวน์โหลดในเบื้องหลัง
การเปลี่ยนแปลง API ที่จัดเก็บข้อมูลภายนอกใน Android 11 ทำให้เกิดปัญหากับการใช้งานปัจจุบัน ฉันตัดสินใจออกแบบปลั๊กอินนี้ใหม่ด้วยกลยุทธ์ใหม่เพื่อจัดการตำแหน่งไฟล์ดาวน์โหลด ยังอยู่ระหว่างการพิจารณาและหารือในการประชาสัมพันธ์ครั้งนี้ เรารู้สึกยินดีเป็นอย่างยิ่งที่ได้รับความช่วยเหลือและข้อเสนอแนะจากนักพัฒนา Flutter เพื่อการออกแบบปลั๊กอินที่ดีขึ้น
ในเวอร์ชันก่อนหน้าของแพ็คเกจนี้ มีช่องโหว่ที่ทราบที่เกี่ยวข้องกับการแทรก SQL การแทรก SQL เป็นช่องโหว่ด้านความปลอดภัยประเภทหนึ่งที่สามารถอนุญาตให้ผู้ใช้ที่เป็นอันตรายจัดการการสืบค้น SQL ที่ดำเนินการโดยแอปพลิเคชัน ซึ่งอาจนำไปสู่การเข้าถึงหรือการจัดการฐานข้อมูลโดยไม่ได้รับอนุญาต
ขอแนะนำอย่างยิ่งให้อัปเกรดเป็นเวอร์ชันล่าสุดของแพ็คเกจนี้เพื่อให้แน่ใจว่าแอปพลิเคชันของคุณไม่เสี่ยงต่อการแทรก SQL เวอร์ชันล่าสุดประกอบด้วยการปรับปรุงความปลอดภัยและแพตช์ที่จำเป็นเพื่อลดความเสี่ยงดังกล่าว
ขั้นตอนต่อไปนี้จำเป็นต้องเปิดโปรเจ็กต์ ios
ของคุณใน Xcode
เปิดใช้งานโหมดพื้นหลัง
เพิ่มไลบรารี sqlite
กำหนดค่า AppDelegate
:
วัตถุประสงค์-C:
/// AppDelegate.h#import#import @interface AppDelegate : FlutterAppDelegate@end
// AppDelegate.m#include "AppDelegate.h"#include "GeneratedPluginRegistrant.h"#include "FlutterDownloaderPlugin.h"@implementation AppDelegatevoid registerPlugins(NSObject* รีจิสทรี) { ถ้า (![registry hasPlugin:@"FlutterDownloaderPlugin" ]) { [FlutterDownloaderPlugin ลงทะเบียนด้วยนายทะเบียน: [นายทะเบียนรีจิสทรีสำหรับปลั๊กอิน:@ "FlutterDownloaderPlugin"]]; - - - (BOOL) แอปพลิเคชัน: (UIApplication *) แอปพลิเคชันเสร็จสิ้นการเปิดตัวด้วยตัวเลือก: (NSDictionary *) การเปิดตัวตัวเลือก { [GeneratedPluginRegistrant registerWithRegistry:self]; [FlutterDownloaderPlugin setPluginRegistrantCallback: registerPlugins]; // แทนที่จุดสำหรับการปรับแต่งหลังจากเปิดแอปพลิเคชัน กลับ [แอปพลิเคชันขั้นสูง: แอปพลิเคชันทำเสร็จสิ้นการเปิดตัวด้วยตัวเลือก: เปิดตัวตัวเลือก]; }@จบ
หรือสวิฟท์:
นำเข้า UIKit นำเข้ากระพือ นำเข้า flutter_downloader@UIApplicationMain@objc คลาส AppDelegate: FlutterAppDelegate { แทนที่แอปพลิเคชัน func ( _ แอปพลิเคชัน: แอปพลิเคชัน UI, DidFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any] หรือไม่ ) -> Bool { GeneratedPluginRegistrant.register (ด้วย: ตนเอง) FlutterDownloaderPlugin.setPluginRegistrantCallback (registerPlugins) ส่งคืน super.application (แอปพลิเคชัน didFinishLaunchingWithOptions: launchOptions) }} func registerPlugins ส่วนตัว (รีจิสทรี: FlutterPluginRegistry) { if (!registry.hasPlugin("FlutterDownloaderPlugin")) { FlutterDownloaderPlugin.register (พร้อม: register.registrar (สำหรับปลั๊กอิน: "FlutterDownloaderPlugin")!) }}
รองรับคำขอ HTTP: หากคุณต้องการดาวน์โหลดไฟล์ด้วยคำขอ HTTP คุณต้องปิดการใช้งานคุณสมบัติ Apple Transport Security (ATS) มีสองตัวเลือก:
ปิดการใช้งาน ATS สำหรับโดเมนที่ระบุเท่านั้น: (เพิ่มรหัสต่อไปนี้ลงในไฟล์ Info.plist
ของคุณ)
<คีย์>NSAppTransportSecurityคีย์> <คำบอกกล่าว> <คีย์>NSExceptionDomainsคีย์> <คำบอกกล่าว> <คีย์>www.yourserver.comNSIncludesSubdomains <คีย์>NSTemporaryExceptionAllowsInsecureHTTPLoads <คีย์>NSTemporaryExceptionMinimumTLSVersionคีย์> TLSv1.1 ตามคำบอก> ตามคำบอก> ตามคำบอก>
ปิดการใช้งาน ATS โดยสมบูรณ์ เพิ่มสิ่งต่อไปนี้ลงในไฟล์ Info.plist
ของคุณ)
<คีย์>NSAppTransportSecurityคีย์> <คำบอกกล่าว> <คีย์>NSAllowsArbitraryLoadsตามคำบอก>
กำหนดค่าจำนวนงานที่เกิดขึ้นพร้อมกันสูงสุด: ปลั๊กอินอนุญาตให้ดาวน์โหลด 3 งานที่ทำงานในขณะนั้นโดยค่าเริ่มต้น (หากคุณจัดคิวมากกว่า 3 งาน จะมีเพียง 3 งานที่ทำงานอยู่ งานอื่น ๆ จะถูกจัดอยู่ในสถานะรอดำเนินการ) คุณสามารถเปลี่ยนหมายเลขนี้ได้โดยเพิ่มรหัสต่อไปนี้ลงในไฟล์ Info.plist
ของคุณ
FDMaximumConcurrentTasks <จำนวนเต็ม>5จำนวนเต็ม>
แปลข้อความแจ้งเตือน: ปลั๊กอินจะส่งข้อความแจ้งเตือนเพื่อแจ้งให้ผู้ใช้ทราบในกรณีที่ไฟล์ทั้งหมดถูกดาวน์โหลดไฟล์ในขณะที่แอปพลิเคชันของคุณไม่ได้ทำงานอยู่เบื้องหน้า ข้อความนี้เป็นภาษาอังกฤษโดยค่าเริ่มต้น คุณสามารถแปลข้อความนี้ได้โดยการเพิ่มและแปลข้อความต่อไปนี้ในไฟล์ Info.plist
(คุณสามารถดูรายละเอียดของการแปล Info.plist
ได้ในลิงค์นี้)
<คีย์>FDAllFilesDownloadedMessageคีย์>ดาวน์โหลดไฟล์ทั้งหมดแล้ว
บันทึก:
ปลั๊กอินนี้รองรับเฉพาะไฟล์บันทึกใน NSDocumentDirectory
เท่านั้น
คุณไม่จำเป็นต้องทำอะไรเพิ่มเติมเพื่อให้ปลั๊กอินทำงานบน Android
มีการตั้งค่าเพิ่มเติมบางอย่างที่คุณอาจต้องการกำหนดค่า
หากต้องการให้แตะการแจ้งเตือนให้เปิดไฟล์ที่ดาวน์โหลดบน Android ให้เพิ่มโค้ดต่อไปนี้ใน AndroidManifest.xml
:
<ผู้ให้บริการ android:name="vn.hunghd.flutterdownloader.DownloadedFileProvider" android:authorities="${applicationId}.flutter_downloader.provider" android:exported="false" android:grantUriPermissions="true">ผู้ให้บริการ>
หมายเหตุ
คุณต้องบันทึกไฟล์ที่ดาวน์โหลดไว้ในที่จัดเก็บข้อมูลภายนอก (โดยที่แอปพลิเคชันอื่นได้รับอนุญาตให้อ่านไฟล์ของคุณ)
ไฟล์ที่ดาวน์โหลดจะสามารถเปิดได้เฉพาะในกรณีที่อุปกรณ์ของคุณมีแอปพลิเคชันอย่างน้อยหนึ่งตัวที่สามารถอ่านไฟล์ประเภทเหล่านี้ได้ (mp3, pdf ฯลฯ)
ปลั๊กอินขึ้นอยู่กับไลบรารี WorkManager
และ WorkManager
ขึ้นอยู่กับจำนวนโปรเซสเซอร์ที่มีอยู่เพื่อกำหนดค่าจำนวนงานสูงสุดที่ทำงานอยู่ในขณะนั้น คุณสามารถตั้งค่าหมายเลขคงที่สำหรับการกำหนดค่านี้ได้โดยเพิ่มโค้ดต่อไปนี้ลงใน AndroidManifest.xml
ของคุณ :
ผู้ให้บริการ>
คุณสามารถแปลข้อความในการแจ้งเตือนความคืบหน้าการดาวน์โหลดโดยแปลข้อความต่อไปนี้
เริ่มต้นการดาวน์โหลด อยู่ระหว่างการดาวน์โหลด การดาวน์โหลดถูกยกเลิก การดาวน์โหลดล้มเหลว ดาวน์โหลดเสร็จสมบูรณ์ การดาวน์โหลดหยุดชั่วคราว
คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับการแปลเป็นภาษาท้องถิ่นบน Android ได้ที่นี่
หากต้องการเปิดและติดตั้งไฟล์ .apk
แอปพลิเคชันของคุณต้องได้รับอนุญาต REQUEST_INSTALL_PACKAGES
เพิ่มสิ่งต่อไปนี้ใน AndroidManifest.xml
ของคุณ:
ดูเพิ่มเติมที่:
แก้ไขข้อผิดพลาด Cleartext Traffic บน Android 9 Pie
นำเข้า 'แพ็คเกจ: flutter_downloader/flutter_downloader.dart'; โมฆะ main () { WidgetsFlutterBinding.ensureInitialized (); // ต้องเริ่มต้นปลั๊กอินก่อนใช้งาน await FlutterDownloader.initialize( แก้ไขข้อบกพร่อง: จริง // ตัวเลือก: ตั้งค่าเป็นเท็จเพื่อปิดการใช้งานบันทึกการพิมพ์ไปยังคอนโซล (ค่าเริ่มต้น: จริง) ไม่สนใจSsl: จริง // ตัวเลือก: ตั้งค่าเป็นเท็จเพื่อปิดใช้งานการทำงานกับลิงก์ http (ค่าเริ่มต้น: เท็จ) - runApp(/*...*/) -
TaskId สุดท้าย = รอ FlutterDownloader.enqueue ( url: 'ลิงค์ดาวน์โหลดของคุณ', ส่วนหัว: {}, // ตัวเลือก: ส่วนหัวส่งด้วย url (โทเค็นการรับรองความถูกต้อง ฯลฯ ) saveDir: 'เส้นทางของไดเร็กทอรีที่คุณต้องการบันทึกไฟล์ที่ดาวน์โหลด', showNotification: จริง // แสดงความคืบหน้าการดาวน์โหลดในแถบสถานะ (สำหรับ Android) openFileFromNotification: จริง // คลิกที่การแจ้งเตือนเพื่อเปิดไฟล์ที่ดาวน์โหลด (สำหรับ Android));
รอ FlutterDownloader.registerCallback (โทรกลับ); // callback เป็นฟังก์ชันระดับบนสุดหรือแบบคงที่
สำคัญ
UI ถูกเรนเดอร์บนไอโซเลทหลัก ในขณะที่กิจกรรมการดาวน์โหลดมาจากไอโซเลทพื้นหลัง (หรืออีกนัยหนึ่ง โค้ดใน callback
จะทำงานในไอโซเลทเบื้องหลัง) ดังนั้นคุณต้องจัดการการสื่อสารระหว่างสองไอโซเลท ตัวอย่างเช่น:
ReceiverPort _port = ReceiverPort();@overridevoid initState() { super.initState(); IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port'); _port.listen((ข้อมูลไดนามิก) { String id = data[0]; DownloadTaskStatus status = DownloadTaskStatus(data[1]); intความคืบหน้า = data[2]; setState((){ }); - FlutterDownloader.registerCallback (ดาวน์โหลดโทรกลับ); }@overridevoid กำจัด() { IsolateNameServer.removePortNameMapping('downloader_send_port'); ซุปเปอร์.ทิ้ง(); }@pragma('vm:entry-point')downloadCallback เป็นโมฆะคงที่ (รหัสสตริง สถานะ int ความคืบหน้าของ int) { ส่ง SendPort สุดท้าย = IsolateNameServer.lookupPortByName('downloader_send_port'); send.send([id, สถานะ, ความคืบหน้า]); -
ต้องวาง @pragma('vm:entry-point')
ไว้เหนือฟังก์ชัน callback
เพื่อหลีกเลี่ยงการสั่นไหวของต้นไม้ในโหมด Release สำหรับ Android
งานสุดท้าย = รอ FlutterDownloader.loadTasks();
งานสุดท้าย = รอ FlutterDownloader.loadTasksWithRawQuery (แบบสอบถาม: แบบสอบถาม);
เพื่อที่จะแยกวิเคราะห์ข้อมูลลงในออบเจ็กต์ DownloadTask
ได้สำเร็จ คุณควรโหลดข้อมูลด้วยฟิลด์ทั้งหมดจากฐานข้อมูล (หรืออีกนัยหนึ่งคือใช้ SELECT *
) ตัวอย่างเช่น:
SELECT * จากงาน WHERE สถานะ = 3
ด้านล่างนี้คือสคีมาของตาราง task
ที่ปลั๊กอิน flutter_downloader
เก็บข้อมูลเกี่ยวกับงานดาวน์โหลด
สร้างตาราง `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 , `ดำเนินการต่อได้` TINYINT DEFAULT 0, `headers` TEXT, `show_notification` TINYINT DEFAULT 0, `open_file_from_notification` TINYINT DEFAULT 0, `time_created` INTEGER DEFAULT 0);
FlutterDownloader.cancel (รหัสงาน: รหัสงาน);
FlutterDownloader.cancelAll();
FlutterDownloader.pause (รหัสงาน: รหัสงาน);
FlutterDownloader.resume (รหัสงาน: รหัสงาน);
resume()
จะส่งคืน taskId
ใหม่ที่สอดคล้องกับงานพื้นหลังใหม่ที่สร้างขึ้นเพื่อดำเนินการดาวน์โหลดต่อไป คุณควรแทนที่ taskId
เก่า (ที่มีสถานะ paused
) ด้วย taskId
ใหม่เพื่อติดตามความคืบหน้าการดาวน์โหลดต่อไป
FlutterDownloader.retry (taskId: รหัสงาน);
retry()
จะส่งคืน taskId
ใหม่ (เช่นเดียวกับ resume()
)
FlutterDownloader.remove (taskId: TaskId, ควรลบเนื้อหา: false);
FlutterDownloader.open(taskId: รหัสงาน);
บน Android คุณสามารถเปิดไฟล์ที่ดาวน์โหลดมาได้ก็ต่อเมื่อไฟล์นั้นอยู่ในที่จัดเก็บข้อมูลภายนอก และมีแอปพลิเคชันอย่างน้อยหนึ่งแอปพลิเคชันที่สามารถอ่านไฟล์ประเภทนั้นบนอุปกรณ์ของคุณได้
อย่าลังเลที่จะเปิดปัญหาหากคุณพบปัญหาใดๆ หรือคิดว่าปลั๊กอินขาดคุณสมบัติบางอย่าง
คำขอดึงก็ยินดีเป็นอย่างยิ่ง!