我正在使用iOS 7,我有一个.mp4视频,我需要在我的应用程序中下载.视频很大(约1 GB),这就是为什么它不包含在应用程序中的原因.我希望用户能够在开始下载后立即开始观看视频.我还希望视频能够在iOS设备上缓存,以便用户以后不需要再次下载.播放视频的常规方法(渐进式下载和实时流式传输)似乎都不允许您缓存视频,因此我创建了自己的Web服务,将视频文件分块并将字节流式传输到客户端.我使用NSURLConnection启动流式HTTP调用:
self.request = [[NSMutableURLRequest alloc] initWithURL:self.url];
[self.request setTimeoutInterval:10]; // Expect data at least every 10 seconds
[self.request setHTTPMethod:@"GET"];
self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:YES];
Run Code Online (Sandbox Code Playgroud)
当我收到数据块时,我将它附加到文件的本地副本的末尾:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:[self videoFilePath]];
[handle truncateFileAtOffset:[handle seekToEndOfFile]];
[handle writeData:data];
}
Run Code Online (Sandbox Code Playgroud)
如果我让设备运行,文件下载成功,我可以使用MPMoviePlayerViewController播放它:
NSURL *url=[NSURL fileURLWithPath:self.videoFilePath];
MPMoviePlayerViewController *controller = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
controller.moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
[self presentMoviePlayerViewControllerAnimated:controller];
Run Code Online (Sandbox Code Playgroud)
但是,如果我在文件完全下载之前启动播放器,则视频开始播放就好了.它甚至可以在顶部擦洗条上显示正确的视频长度.但是当用户到达视频中我在视频开始之前完成下载的位置时,视频就会挂起.如果我关闭并重新打开MPMoviePlayerViewController,那么视频会播放,直到它到达我再次启动MPMoviePlayerViewController时的任何位置.如果我等到整个视频下载完毕,那么视频播放没有问题.
我没有收到任何事件,或者在发生这种情况时打印到控制台的错误消息(视频启动后永远不会发送MPMoviePlayerPlaybackStateDidChangeNotification和MPMoviePlayerPlaybackDidFinishNotification).似乎还有其他东西告诉控制器视频的长度是什么,而不是洗涤器使用的...
有谁知道可能导致这个问题的原因是什么?我不一定要使用MPMoviePlayerViewController,所以如果在这种情况下使用不同的视频播放方法,我就是为了它.
相关未解决的问题:
使用AVURLAssets进行AVPlayer和逐行视频下载
更新1 我发现视频停顿确实是因为视频开始播放时的文件大小.我可以通过在开始下载之前创建一个归零文件来解决这个问题,并在我去的时候覆盖它.由于我可以控制视频流服务器,因此我添加了一个自定义标头,因此我知道正在流式传输的文件的大小(流式文件的默认文件大小标头为-1).我在didReceiveResponse方法中创建文件,如下所示:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// Retrieve the size …Run Code Online (Sandbox Code Playgroud) video-streaming progressive-download mpmovieplayer ios nsurlsessiondownloadtask
我正在使用NSURLSessionDownloadTask对象NSURLSession允许用户在应用程序处于后台/设备锁定状态时下载文档.我还想告知用户个人下载已通过本地通知完成.
为此,我在-URLSession:downloadTask:didFinishDownloadingToURL:下载任务委托方法中触发本地通知,但是我想知道是否有更好的地方添加触发通知的代码,因为Apple解释它的方式,下载任务将传递给系统,从中我得出的是,一旦(或不久之后)应用程序背景化,下载任务的代理将不会再调用这些代理.
我的问题:添加触发本地通知的代码的最佳位置是什么?有没有人在他们的应用程序中添加这种功能有任何经验?
objective-c ios uilocalnotification nsurlsession nsurlsessiondownloadtask
好的,我已成功下载各种m4a文件,并通过URLSession删除它们.我的问题是在URLSessionDownloadDelegate要求的最终"完成"功能中,我有时会将以下内容打印到控制台,即使我在下载func(下载之前)检查文件是否存在于目录中.非常困惑.这是消息:
File download succesfully
“CFNetworkDownload_1wGgxs.tmp” couldn’t be moved to “Documents” because an item with the same name already exists.
The task finished successfully
Run Code Online (Sandbox Code Playgroud)
这是下载功能,我检查显示文件是否存在:
func goDownload()
{
if let audioUrl = downloadUrl { //set at beginning
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let destinationUrl = documentsDirectoryURL.appendingPathComponent(audioUrl.lastPathComponent)
print(destinationUrl)
// to check if it exists before downloading it
if FileManager.default.fileExists(atPath: destinationUrl.path) {
print("********** The file already exists at path")
// if the file doesn't exist
} else {
print("---------------> Starting Download") …Run Code Online (Sandbox Code Playgroud) 我有一个使用新NSURLSessionAPI 下载后台的应用程序.当下载以NSURLSessionDownloadTaskResumeData提供的方式取消或失败时,我存储数据blob以便以后可以恢复.我注意到野外崩溃的时间非常少:
Fatal Exception: NSInvalidArgumentException
Invalid resume data for background download. Background downloads must use http or https and must download to an accessible file.
Run Code Online (Sandbox Code Playgroud)
这里出现的错误,这里resumeData是NSDatablob和session是一个实例NSURLSession:
if (resumeData) {
downloadTask = [session downloadTaskWithResumeData:resumeData];
...
Run Code Online (Sandbox Code Playgroud)
数据由Apple API提供,序列化,然后在以后进行反序列化.它可能已损坏,但它永远不会为零(如if语句检查).
如何提前检查resumeData无效,以免我让应用程序崩溃?
我正在下载一个视频,感谢downloadTaskWithURL,我用这段代码将它保存到我的画廊:
func saveVideoBis(fileStringURL:String){
print("saveVideoBis");
let url = NSURL(string: fileStringURL);
(NSURLSession.sharedSession().downloadTaskWithURL(url!) { (location:NSURL?, r:NSURLResponse?, e:NSError?) -> Void in
let mgr = NSFileManager.defaultManager()
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0];
print(documentsPath);
let destination = NSURL(string: NSString(format: "%@/%@", documentsPath, url!.lastPathComponent!) as String);
print(destination);
try? mgr.moveItemAtPath(location!.path!, toPath: destination!.path!)
PHPhotoLibrary.requestAuthorization({ (a:PHAuthorizationStatus) -> Void in
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideoAtFileURL(destination!);
}) { completed, error in
if completed {
print(error);
print("Video is saved!");
self.sendNotification();
}
}
})
}).resume()
}
Run Code Online (Sandbox Code Playgroud)
它在我的模拟器上工作得非常好,但在我的iPad上,即使print("Video is saved!");显示,视频也不会保存.你知道为什么吗?
我的控制台中也出现了该消息
无法从文件创建数据(null)
所以我很难理解某些东西.这是我对NSURSession的理解:
一般来说,我有2个选项(据我所知)DataTask(ex dataTaskWithRequest)和DownloadTask(ex DownloadTaskWithRequest) - 使用他们的委托方法,或使用完成处理程序,不能两者兼顾.我已经设法使用dataTaskWithRequest接收DATA,如下所示:
let request = NSMutableURLRequest(URL: dataSourceURL!)
request.HTTPMethod = "POST"
let postString = "lastid=\(id)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
println("error=\(error)")
return
}
if data != nil {
println("works")
//Handle data
}
//println("response = \(response)")
}
task.resume()
Run Code Online (Sandbox Code Playgroud)它完美地运作.问题是我需要将数据下载到磁盘而不是下载到内存(我正在下载图像).所以我尝试使用DownloadTaskWithRequest +他的完成处理程序,我注意到他所采用的参数是相同的,期望第一个是NSURL,而DataTaskWithRequest是NSData,因此它使事情变得非常简单.恩.
let task2 = NSURLSession.sharedSession().downloadTaskWithRequest(request, completionHandler: { (location : NSURL!, response : …Run Code Online (Sandbox Code Playgroud) 在应用程序的第一次启动我想从服务器下载所有文件,我想继续下载,即使用户离开应用程序(它不在前台).我需要下载的文件是缩略图,原始大小的照片,其他文件和视频.我想按照我之前写的顺序下载它们.
我正在使用Alamofire并设置会话管理器:
let backgroundManager: Alamofire.SessionManager = {
let bundleIdentifier = "com....."
return Alamofire.SessionManager(
configuration: URLSessionConfiguration.background(withIdentifier: bundleIdentifier + ".background")
)
}()
Run Code Online (Sandbox Code Playgroud)
然后我像这样使用它:
self.backgroundManager.download(fileUrl, to: destination)
.downloadProgress { progress in
//print("Download Progress: \(progress.fractionCompleted)")
}
.response(completionHandler: result)
Run Code Online (Sandbox Code Playgroud)
它在downloadPhoto方法中,我称之为:
for item in items {
self.downloadPhoto(item: item, isThumbnail: true, shouldReloadData: false, indexPath: nil)
self.downloadPhoto(item: item, isThumbnail: false, shouldReloadData: false, indexPath: nil)
}
Run Code Online (Sandbox Code Playgroud)
然后我可以添加文件下载和视频下载等呼叫.但所有这些请求具有相同的优先级,我想首先下载缩略图(因为这是用户最初看到的)然后下载全尺寸图像,然后下载所有图像,然后下载文件和视频.但所有必须在队列中,因为如果用户启动应用程序,然后将其设置为后台并将其保留几个小时,则必须全部下载.这可能吗?我怎么能这样做?
我正在寻找alamofire,它有组件库AlamofireImage,它具有基于优先级的下载,但图像只是我想要优先考虑的文件的一部分.感谢帮助
我正在尝试使用NSURL后台会话下载大量文件 nsurlsessiontask.当应用程序在调试模式下运行时(当设备连接到Xcode时),一切都像魅力一样,当从Xcode上拔下设备(iPad)时不起作用.
我正在使用Xcode 7.3.1和iOS 9.3.5.我已经花了几周时间跟踪这个奇怪的行为,但没有任何突破.可能是我遗漏了一些实现后台下载的东西.最近将Xcode升级到8.1.2,将iOS升级到10.2.1,假设升级可能会解决问题,但事实并非如此.
我已经尝试过网上的各种样本(最后一个是这个样本),以便更好地理解NSUrlSession.
我希望看到的内容:即使触发它们的应用程序被杀死(例如用户通过任务管理器),文件下载仍将继续.然而,这似乎并没有发生.
如果应用程序被终止,这是配置问题还是后台文件传输不起作用?我认为整个想法是iOS将重启应用程序.
NSURLSession委托方法
URLSessionDidFinishEventsForBackgroundURLSession不是Calling?
我已在项目功能设置中启用了后台模式.
这是代码
AppDelegate.h方法
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, copy) void(^backgroundTransferCompletionHandler)();
@end
Run Code Online (Sandbox Code Playgroud)
AppDelegate.m方法
-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{
self.backgroundTransferCompletionHandler = completionHandler;
}
Run Code Online (Sandbox Code Playgroud)
ViewController.m方法
- (void)viewDidLoad
{
[super viewDidLoad];
//Urls
[self initializeFileDownloadDataArray];
NSArray *URLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
self.docDirectoryURL = [URLs objectAtIndex:0];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.GACDemo"];
sessionConfiguration.HTTPMaximumConnectionsPerHost = 5;
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
delegate:self
delegateQueue:nil];
}
Run Code Online (Sandbox Code Playgroud)
NSUrlSession方法
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
AppDelegate *appDelegate = [UIApplication …Run Code Online (Sandbox Code Playgroud) ios ×10
nsurlsession ×6
objective-c ×4
swift ×4
ipad ×2
alamofire ×1
background ×1
ios7 ×1
iphone ×1
nsdata ×1
xcode ×1