11
11
12
12
#define KEY_URL @" url"
13
13
#define KEY_SAVED_DIR @" saved_dir"
14
- # define KEY_SEARCH_DIR @" search_dir "
14
+
15
15
#define KEY_FILE_NAME @" file_name"
16
16
#define KEY_PROGRESS @" progress"
17
17
#define KEY_ID @" id"
@@ -58,8 +58,6 @@ @implementation FlutterDownloaderPlugin
58
58
static int _step = 10 ;
59
59
static NSMutableDictionary <NSString *, NSMutableDictionary *> *_runningTaskById = nil ;
60
60
61
- static NSSearchPathDirectory const kDefaultSearchPathDirectory = NSDocumentDirectory;
62
-
63
61
@synthesize databaseQueue;
64
62
65
63
- (instancetype )init : (NSObject <FlutterPluginRegistrar> *)registrar ;
@@ -98,11 +96,6 @@ - (instancetype)init:(NSObject<FlutterPluginRegistrar> *)registrar;
98
96
99
97
_dbManager = [[DBManager alloc ] initWithDatabaseFilePath: dbPath];
100
98
101
- __typeof__ (self) __weak weakSelf = self;
102
- [self executeInDatabaseQueueForTask: ^{
103
- [weakSelf addDatabaseColumnForMakingFileCouldSaveInAnyDirectory ];
104
- }];
105
-
106
99
if (_runningTaskById == nil ) {
107
100
_runningTaskById = [[NSMutableDictionary alloc ] init ];
108
101
}
@@ -315,13 +308,6 @@ - (void)executeInDatabaseQueueForTask:(void (^)(void))task {
315
308
});
316
309
}
317
310
318
- + (NSArray <NSNumber *> *)avaliableCommonDirectories {
319
- return @[@(NSCachesDirectory),
320
- @(NSApplicationSupportDirectory),
321
- @(NSLibraryDirectory),
322
- @(kDefaultSearchPathDirectory ),
323
- @(NSDownloadsDirectory)];;
324
- }
325
311
326
312
- (BOOL )openDocumentWithURL : (NSURL *)url {
327
313
if (debug) {
@@ -382,31 +368,10 @@ - (NSURL*)fileUrlOf:(NSString*)taskId taskInfo:(NSDictionary*)taskInfo downloadT
382
368
return [self fileUrlFromDict: mutableTaskInfo];
383
369
}
384
370
385
- - (NSString *)absoluteSavedDirPathWithShortSavedDir : (NSString *)shortSavedDir searchPathDirectory : (NSSearchPathDirectory )searchPathDirectory {
386
- return [[NSSearchPathForDirectoriesInDomains (searchPathDirectory, NSUserDomainMask, YES ) firstObject ] stringByAppendingPathComponent: shortSavedDir];
387
- }
388
-
389
371
- (NSString *)sanitizeFilename : (nullable NSString *)filename {
390
372
// Define a list of allowed characters for filenames
391
- NSMutableCharacterSet *allowedCharacters = [[NSMutableCharacterSet alloc ] init ];
392
-
393
- // Allow alphabetical characters (lowercase and uppercase)
394
- [allowedCharacters formUnionWithCharacterSet: [NSCharacterSet letterCharacterSet ]];
395
-
396
- // Allow digits
397
- [allowedCharacters addCharactersInRange: NSMakeRange (' 0' , 10 )]; // ASCII digits
398
-
399
- // Allow additional characters: -_.()
400
- [allowedCharacters addCharactersInString: @" -_.()" ];
373
+ NSCharacterSet *allowedCharacters = [[NSCharacterSet characterSetWithCharactersInString: @" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.() " ] invertedSet ];
401
374
402
- // Allow empty spaces
403
- [allowedCharacters addCharactersInString: @" " ];
404
-
405
- // Remove the backslash (if you want to disallow it)
406
- [allowedCharacters removeCharactersInString: @" \\ " ];
407
-
408
- // Now, you have a character set that allows the specified characters
409
- NSCharacterSet *finalCharacterSet = [allowedCharacters copy ];
410
375
if (filename == nil || [filename isEqual: [NSNull null ]] || [filename isEqualToString: @" " ]) {
411
376
NSString *defaultFilename = @" default_filename" ;
412
377
return defaultFilename;
@@ -439,39 +404,30 @@ - (NSString *)sanitizeFilename:(nullable NSString *)filename {
439
404
}
440
405
441
406
407
+ - (NSString *)absoluteSavedDirPath : (NSString *)savedDir {
408
+ return [[NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES ) firstObject ] stringByAppendingPathComponent: savedDir];
409
+ }
442
410
443
- - (NSArray *)shortenSavedDirPath : (NSString *)absolutePath {
411
+ - (NSString *)shortenSavedDirPath : (NSString *)absolutePath {
444
412
if (debug) {
445
413
NSLog (@" Absolute savedDir path: %@ " , absolutePath);
446
414
}
447
415
448
- for (NSNumber *element in self.class .avaliableCommonDirectories ) {
449
- NSString *shortSvedDirPath = [self shortenSavedDirPath: absolutePath searchPathDirectory: element.unsignedIntegerValue];
450
- if (shortSvedDirPath) {
451
- return @[shortSvedDirPath, element];
452
- }
453
- }
454
-
455
- return @[@" " , @(kDefaultSearchPathDirectory )];
456
- }
457
-
458
- - (NSString *)shortenSavedDirPath : (NSString *)absolutePath searchPathDirectory : (NSSearchPathDirectory )searchPathDirectory {
459
416
if (absolutePath) {
460
- NSString *searchDirPath = [NSSearchPathForDirectoriesInDomains (searchPathDirectory , NSUserDomainMask, YES ) firstObject ];
461
- if ([absolutePath isEqualToString: searchDirPath ]) {
417
+ NSString * documentDirPath = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory , NSUserDomainMask, YES ) firstObject ];
418
+ if ([absolutePath isEqualToString: documentDirPath ]) {
462
419
return @" " ;
463
420
}
464
- NSRange foundRank = [absolutePath rangeOfString: searchDirPath ];
421
+ NSRange foundRank = [absolutePath rangeOfString: documentDirPath ];
465
422
if (foundRank.length > 0 ) {
466
423
// we increase the location of range by one because we want to remove the file separator as well.
467
- NSString *shortenSavedDirPath = [absolutePath substringWithRange: NSMakeRange (foundRank.length + 1 , absolutePath.length - searchDirPath .length - 1 )];
424
+ NSString *shortenSavedDirPath = [absolutePath substringWithRange: NSMakeRange (foundRank.length + 1 , absolutePath.length - documentDirPath .length - 1 )];
468
425
return shortenSavedDirPath != nil ? shortenSavedDirPath : @" " ;
469
426
}
470
427
}
471
-
472
- return nil ;
473
- }
474
428
429
+ return absolutePath;
430
+ }
475
431
476
432
- (long long )currentTimeInMilliseconds
477
433
{
@@ -480,27 +436,7 @@ - (long long)currentTimeInMilliseconds
480
436
481
437
# pragma mark - Database Accessing
482
438
483
- // / Before version 1.11.1, FlutterDownloader only allows file to be saved in [NSDocumentDirectory]. This limits the freedom of development.
484
- // /
485
- // / This function serves two purposes:
486
- // /
487
- // / 1. Add a database column `search_dir` for determining common root directory such as the flowing directories
488
- // /
489
- // / - NSCachesDirectory
490
- // / - NSApplicationSupportDirectory
491
- // / - NSLibraryDirectory
492
- // / - NSDocumentDirectory
493
- // / - NSDownloadsDirectory
494
- // /
495
- // / Definition of common root directory refers to [path_provider](https://github.com/flutter/packages/blob/main/packages/path_provider/path_provider/lib/path_provider.dart).
496
- // /
497
- // / 2. Resolve previous compatibility issue
498
- - (void )addDatabaseColumnForMakingFileCouldSaveInAnyDirectory {
499
- [_dbManager addLazilyColumnForTable: " task"
500
- column: KEY_SEARCH_DIR.UTF8String
501
- type: " integer"
502
- defaultValue: [NSString stringWithFormat: @" %lu " , kDefaultSearchPathDirectory ].UTF8String]; // kDefaultSearchPathDirectory is [NSDocumentDirectory](9), this is compatible with previous FlutterDownloader versions.
503
- }
439
+
504
440
- (NSString *) escape : (NSString *) origin revert : (BOOL )revert
505
441
{
506
442
if ( origin == (NSString *)[NSNull null ] )
@@ -519,18 +455,16 @@ - (void)addNewTask:(NSString *)taskId
519
455
progress : (int )progress
520
456
filename : (NSString *)filename
521
457
savedDir : (NSString *)savedDir
522
- searchDir : (NSSearchPathDirectory )searchDir
523
458
headers : (NSString *)headers
524
459
resumable : (BOOL )resumable
525
460
showNotification : (BOOL )showNotification
526
461
openFileFromNotification : (BOOL )openFileFromNotification {
527
462
528
463
headers = [self escape: headers revert: NO ];
529
464
530
- NSString *query = @" INSERT INTO task (task_id, url, status, progress, file_name, saved_dir, search_dir, headers, resumable, show_notification, open_file_from_notification, time_created) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" ;
531
- NSNumber *searchDirValue = @(searchDir);
465
+ NSString *query = @" INSERT INTO task (task_id, url, status, progress, file_name, saved_dir, headers, resumable, show_notification, open_file_from_notification, time_created) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" ;
532
466
NSString *sanitizedFileName = [self sanitizeFilename: filename];
533
- NSArray *values = @[taskId, url, @(status), @(progress), sanitizedFileName, savedDir, searchDirValue, headers, @(resumable ? 1 :0 ), @(showNotification ? 1 : 0 ), @(openFileFromNotification ? 1 : 0 ), @([self currentTimeInMilliseconds ])];
467
+ NSArray *values = @[taskId, url, @(status), @(progress), sanitizedFileName, savedDir, headers, @(resumable ? 1 :0 ), @(showNotification ? 1 : 0 ), @(openFileFromNotification ? 1 : 0 ), @([self currentTimeInMilliseconds ])];
534
468
535
469
[_dbManager executeQuery: query withParameters: values];
536
470
@@ -723,16 +657,9 @@ - (NSDictionary*) taskDictFromRecordArray:(NSArray*)record
723
657
int progress = [[record objectAtIndex: [_dbManager.arrColumnNames indexOfObject: @" progress" ]] intValue ];
724
658
NSString *url = [record objectAtIndex: [_dbManager.arrColumnNames indexOfObject: @" url" ]];
725
659
NSString *filename = [record objectAtIndex: [_dbManager.arrColumnNames indexOfObject: @" file_name" ]];
726
- NSString *shortSavedDir = [record objectAtIndex: [_dbManager.arrColumnNames indexOfObject: @" saved_dir" ]];
727
-
728
- NSString *searchDirStr = [record objectAtIndex: [_dbManager.arrColumnNames indexOfObject: KEY_SEARCH_DIR]];
729
- int searchDir = [searchDirStr intValue ];
730
- NSNumber *searchDirNum = [NSNumber numberWithInt: searchDir];
731
-
732
- NSString *savedDir = [self absoluteSavedDirPathWithShortSavedDir: shortSavedDir searchPathDirectory: searchDir];
733
-
660
+ NSString *savedDir = [self absoluteSavedDirPath: [record objectAtIndex: [_dbManager.arrColumnNames indexOfObject: @" saved_dir" ]]];
734
661
NSString *headers = @" " ;
735
- // in certain cases, headers column might not be available and will cause NSRangeException
662
+ // in certain cases, headers column might not be available and will cause NSRangeException
736
663
@try {
737
664
NSString *rawHeaders = [record objectAtIndex: [_dbManager.arrColumnNames indexOfObject: @" headers" ]];
738
665
headers = [self escape: rawHeaders revert: true ];
@@ -743,7 +670,7 @@ - (NSDictionary*) taskDictFromRecordArray:(NSArray*)record
743
670
int showNotification = [[record objectAtIndex: [_dbManager.arrColumnNames indexOfObject: @" show_notification" ]] intValue ];
744
671
int openFileFromNotification = [[record objectAtIndex: [_dbManager.arrColumnNames indexOfObject: @" open_file_from_notification" ]] intValue ];
745
672
long long timeCreated = [[record objectAtIndex: [_dbManager.arrColumnNames indexOfObject: @" time_created" ]] longLongValue ];
746
- return [NSDictionary dictionaryWithObjectsAndKeys: taskId, KEY_TASK_ID, @(status), KEY_STATUS, @(progress), KEY_PROGRESS, url, KEY_URL, filename, KEY_FILE_NAME, headers, KEY_HEADERS, savedDir, KEY_SAVED_DIR, searchDirNum, KEY_SEARCH_DIR, [NSNumber numberWithBool: (resumable == 1 )], KEY_RESUMABLE, [NSNumber numberWithBool: (showNotification == 1 )], KEY_SHOW_NOTIFICATION, [NSNumber numberWithBool: (openFileFromNotification == 1 )], KEY_OPEN_FILE_FROM_NOTIFICATION, @(timeCreated), KEY_TIME_CREATED, nil ];
673
+ return [NSDictionary dictionaryWithObjectsAndKeys: taskId, KEY_TASK_ID, @(status), KEY_STATUS, @(progress), KEY_PROGRESS, url, KEY_URL, filename, KEY_FILE_NAME, headers, KEY_HEADERS, savedDir, KEY_SAVED_DIR, [NSNumber numberWithBool: (resumable == 1 )], KEY_RESUMABLE, [NSNumber numberWithBool: (showNotification == 1 )], KEY_SHOW_NOTIFICATION, [NSNumber numberWithBool: (openFileFromNotification == 1 )], KEY_OPEN_FILE_FROM_NOTIFICATION, @(timeCreated), KEY_TIME_CREATED, nil ];
747
674
} @catch (NSException *exception) {
748
675
NSLog (@" invalid task data: %@ " , exception);
749
676
return [NSDictionary dictionary ];
@@ -789,14 +716,8 @@ - (void) unqueueStatusEvents {
789
716
790
717
- (void )enqueueMethodCall : (FlutterMethodCall*)call result : (FlutterResult)result {
791
718
NSString *urlString = call.arguments [KEY_URL];
792
-
793
- NSString *savedDirFromSource = call.arguments [KEY_SAVED_DIR];
794
- NSArray *shortSavedDirArgs = [self shortenSavedDirPath: savedDirFromSource];
795
- NSString *shortSavedDir = shortSavedDirArgs[0 ];
796
- NSNumber *searchDirNum = shortSavedDirArgs[1 ];
797
- NSSearchPathDirectory searchDir = searchDirNum.unsignedIntegerValue ;
798
- NSString *savedDir = [self absoluteSavedDirPathWithShortSavedDir: shortSavedDir searchPathDirectory: searchDir];
799
-
719
+ NSString *savedDir = call.arguments [KEY_SAVED_DIR];
720
+ NSString *shortSavedDir = [self shortenSavedDirPath: savedDir];
800
721
NSString *fileName = call.arguments [KEY_FILE_NAME];
801
722
NSString *headers = call.arguments [KEY_HEADERS];
802
723
NSNumber *showNotification = call.arguments [KEY_SHOW_NOTIFICATION];
@@ -810,7 +731,6 @@ - (void)enqueueMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result
810
731
urlString, KEY_URL,
811
732
fileName, KEY_FILE_NAME,
812
733
savedDir, KEY_SAVED_DIR,
813
- searchDirNum, KEY_SEARCH_DIR,
814
734
headers, KEY_HEADERS,
815
735
showNotification, KEY_SHOW_NOTIFICATION,
816
736
openFileFromNotification, KEY_OPEN_FILE_FROM_NOTIFICATION,
@@ -822,7 +742,7 @@ - (void)enqueueMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result
822
742
__typeof__ (self) __weak weakSelf = self;
823
743
824
744
[self executeInDatabaseQueueForTask: ^{
825
- [weakSelf addNewTask: taskId url: urlString status: STATUS_ENQUEUED progress: 0 filename: fileName savedDir: shortSavedDir searchDir: searchDir headers: headers resumable: NO showNotification: [showNotification boolValue ] openFileFromNotification: [openFileFromNotification boolValue ]];
745
+ [weakSelf addNewTask: taskId url: urlString status: STATUS_ENQUEUED progress: 0 filename: fileName savedDir: shortSavedDir headers: headers resumable: NO showNotification: [showNotification boolValue ] openFileFromNotification: [openFileFromNotification boolValue ]];
826
746
}];
827
747
result (taskId);
828
748
[self sendUpdateProgressForTaskId: taskId inStatus: @(STATUS_ENQUEUED) andProgress: @0 ];
0 commit comments