Я пытаюсь POST с iOS на мой сервер PHP и заставить сервер PHP вернуть двоичный файл в мое приложение iOS, используя base64_encode для передачи.
Файл загружается на мое устройство iOS, но AVAsset сообщает, что файл не воспроизводится, и я не могу понять, где моя ошибка. Я также уверен, что каждое из названий является действительными файлами .wav и .mp3 на сервере.
соответствующая часть PHP-файла:
$song_to_download = $_POST['title'];
...(check if file exists, open 'rb', etc)
while (!feof($fp))
{
$block = fread($fp, 57 * 143); // based on php.net base64_encode examples
$base64 = base64_encode($block);
print $base64;
}
соответствующий код iOS:
- (NSUInteger) getFileSizeLocal:(NSString *)path
{
NSFileManager *fm = [NSFileManager defaultManager];
NSError *error;
NSDictionary *dict = [fm attributesOfItemAtPath:path error:&error];
if (dict == nil)
{
NSLog(@"getFileSize - ERROR reading file attributes <%@>", error.localizedDescription);
return 0;
}
return [dict[NSFileSize] unsignedIntegerValue];
}
-(void)URLSession:(NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(nonnull NSURL *)location
{
// decode the base64 'location' file and write it to the final file
NSString *path = location.absoluteString;
if (path.length < 8) {
NSLog(@"ERROR - <%@> length is less than 8", path);
return;
}
NSInteger fileStrLen = 7; // 'file://' length - we keep the first / so its a complete hard path in the filesystem
NSString *filepath = [path substringWithRange:NSMakeRange(fileStrLen, path.length - fileStrLen)]; // strip off 'file://' portion first
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath] == NO)
{
NSLog(@"ERROR - file does NOT exists at path <%@>", filepath);
return;
}
NSFileHandle *fpi = [NSFileHandle fileHandleForReadingAtPath:filepath];
NSUInteger len = [self getFileSizeLocal:filepath];
if (len == 0) {
NSLog(@"ERROR - filesize is zero");
return;
}
NSFileHandle *fpo = [NSFileHandle fileHandleForWritingAtPath:_largePathAndFileToWrite];
if (fpo == nil)
{
[[NSFileManager defaultManager] createFileAtPath:_largePathAndFileToWrite contents:nil attributes:nil];
fpo = [NSFileHandle fileHandleForWritingAtPath:_largePathAndFileToWrite];
}
// Read tmp input file (filepath), WRITE to final filename (_largePathAndFileToWrite)
NSData *data = nil;
NSData *decoded64Data = nil;
NSString *base64String = nil;
NSUInteger step_size = 10868; // based on php.net base64_encode examples
@autoreleasepool
{
for (NSUInteger x = 0; x < len; x += step_size)
{
data = [fpi readDataOfLength:step_size];
base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
decoded64Data = [base64String dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
if (decoded64Data == nil)
{
NSLog(@"ERROR - failed to decode data from tmp input file at idx <%ld>", (long)x);
break;
}
[fpo seekToEndOfFile];
[fpo writeData:decoded64Data];
}
}
[fpo closeFile];
[fpi closeFile];
NSURL *fileURL = [NSURL fileURLWithPath:_largePathAndFileToWrite];
AVAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
if (asset.isPlayable) {
NSLog(@"GOOD");
}
if (asset.isReadable) {
NSLog(@"READABLE");
}
else {
NSLog(@"Asset is BAD %@", _largePathAndFileToWrite);
}
}
Мой вывод всегда говорит «Актив плохой»
Размеры файлов, которые я пробую, составляют менее 50 Мбайт, а размер
сервер того же размера, что и конечный файл на устройстве iOS после
скачать.
Когда я пытался воспроизвести его с AVAudioPlayer, он всегда терпел неудачу:
The operation couldn't be completed.
Любая помощь приветствуется. Я провел несколько часов, пытаясь понять это.
Заранее спасибо!
[Решено]Я пытался сделать это трудным путем. Оказывается, я могу передать это
как двоичный файл без base64 кодирования. Вот окончательное решение для
всем, кому это тоже нужно
Сторона PHP: (работает для .mp3 .wav .m4a, другие не пробовали)
<?php
$filepath = "./slist/mysong.mp3";
if (file_exists($filepath)) {
header('Content-Type: application/octect-stream');
header('Content-Description: File Transfer');
header('Content-Length: ' . filesize($filepath));
ob_clean();
flush();
readfile($filepath);
}
?>
Код IOS:
-(void)URLSession:(NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(nonnull NSURL *)location
{
NSLog(@"downloadTask - didFinishDownloadingToURL <%@>", location.absoluteString);
// decode the base64 'location' file and write it to the final file
NSString *path = location.absoluteString;
if (path.length < 8) {
NSLog(@"ERROR - <%@> length is less than 8", path);
return;
}
NSInteger fileStrLen = 7; // 'file://' length - we keep the first / so its a complete hard path in the filesystem
NSString *filepath = [path substringWithRange:NSMakeRange(fileStrLen, path.length - fileStrLen)]; // strip off 'file://' portion first
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath] == NO)
{
NSLog(@"ERROR - file does NOT exists at path <%@>", filepath);
return;
}
// Just Move it into place
NSError *error;
if ([[NSFileManager defaultManager] moveItemAtPath:filepath toPath:_largePathAndFileToWrite error:&error] == NO)
{
NSLog(@"ERROR - failed to move file - <%@>", error.localizedDescription);
return;
}
}
Задача ещё не решена.
Других решений пока нет …