- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我需要通过 PUT 将内容上传到 AWS S3,该 PUT 可以使用 NSURLSessionUploadTask 在后台 session 中运行。
到目前为止效果很好。但是,我需要在上传到 S3 完成后调用我的 API 以将其状态更改为完成。
我使用 AWSS3 创建 S3 请求,然后根据 this SO answer 将其复制到 NSURLSessionUploadTask .这在前台和后台都运行,并将文件 ok 上传到 S3。
现在这是我需要帮助的部分。我尝试同时使用 URLSession:task:didCompleteWithError 和 URLSessionDidFinishEventsForBackgroundURLSession 委托(delegate)方法来调用我的附加 API 请求,我使用了标准数据任务以及下载任务,它们似乎不会在后台触发请求,直到我再次打开应用程序。理想情况下,我希望他们立即开火。他们上传的火是在前台。我已经看到奇妙 list 在后台完全按照我的意愿进行操作,但不确定他们是如何做到的。
这是我到目前为止所拥有的......任何帮助/建议都会很棒,这让我发疯! :)
- (IBAction)upload:(id)sender {
AmazonS3Client *s3Client = [[AmazonS3Client alloc] initWithAccessKey:@"ABC" withSecretKey:@"123"];
NSString *identifier = [NSString stringWithFormat:@"com.journeyhq.backgroundSession.%@-%@", @"S3", @"ATTACHMENT_REMOTE_ID"];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"img.jpg"];
NSURL *fromFile = [NSURL fileURLWithPath:filePath isDirectory:NO];
S3PutObjectRequest *s3Request = [[S3PutObjectRequest alloc] initWithKey:[[NSString stringWithFormat:@"%@__%@__%@", @"ATTACHMENT_ID", @"ATTACHMENT_UUID", @"img.jpg"] lowercaseString] inBucket:@"BUCKET_NAME"];
s3Request.cannedACL = [S3CannedACL publicReadWrite];
NSMutableURLRequest *request = [s3Client signS3Request:s3Request];
NSString *urlString = [NSString stringWithFormat:@"https://%@.%@/%@", @"BUCKET_NAME", @"s3-eu-west-1.amazonaws.com", [[NSString stringWithFormat:@"%@__%@__%@", @"ATTACHMENT_ID", @"ATTACHMENT_UUID", @"img.jpg"] lowercaseString]];
request.URL = [NSURL URLWithString:urlString];
NSMutableURLRequest *request2 = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
[request2 setHTTPMethod:@"PUT"];
[request2 setAllHTTPHeaderFields:[request allHTTPHeaderFields]];
[request2 setValue:@"BUCKET_NAME.s3-eu-west-1.amazonaws.com" forHTTPHeaderField:@"Host"];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request2 fromFile:fromFile];
[uploadTask resume];
}
#pragma - NSURLSessionTaskDelegate
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
dispatch_async(dispatch_get_main_queue(), ^{
self.progressView.progress = (float)totalBytesSent / (float) totalBytesExpectedToSend;
});
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
NSURLSessionConfiguration *sessionConfig = [session configuration];
NSString *identifier = [sessionConfig identifier];
NSLog(@"**identifier**: %@", identifier);
NSArray *identifierComponents = [identifier componentsSeparatedByString:@"."];
NSString *lastComponent = [identifierComponents lastObject];
NSArray *components = [lastComponent componentsSeparatedByString:@"-"];
NSString *sessionType = [components firstObject];
NSString *attachmentID = [components lastObject];
NSLog(@"sessionType: %@", sessionType);
NSLog(@"attachmentID: %@", attachmentID);
if (error == nil)
{
NSLog(@"Task %@ completed successfully", task);
if ([sessionType isEqualToString:@"S3"]) {
NSString *downloadIdentifier = [NSString stringWithFormat:@"com.journeyhq.backgroundSession.%@-%@", @"s3Completion", attachmentID];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:downloadIdentifier];
NSURLSession *downloadSession = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
NSString *urlString = @"API_COMPLETION_URL";
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
NSURLSessionDownloadTask *downloadTask = [downloadSession downloadTaskWithRequest:request];
[downloadTask resume];
}
}
else
{
NSLog(@"Task %@ completed with error: %@", task,
[error localizedDescription]);
}
task = nil;
}
AppDelegate.h
- (void)application:(UIApplication *)application
handleEventsForBackgroundURLSession:(NSString *)identifier
completionHandler:(void (^)())completionHandler {
}
EDIT 我也试过以下方法。任务像以前一样创建,当我恢复任务时仍然没有触发。
- (void)application:(UIApplication *)application
handleEventsForBackgroundURLSession:(NSString *)identifier
completionHandler:(void (^)())completionHandler {
NSDictionary *userInfo = @{
@"completionHandler" : completionHandler,
@"sessionIdentifier" : identifier
};
[[NSNotificationCenter defaultCenter]
postNotificationName:@"BackgroundTransferNotification"
object:nil
userInfo:userInfo];
}
然后在 View Controller 中
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleBackgroundTransfer:)
name:@"BackgroundTransferNotification"
object:nil];
}
- (void)handleBackgroundTransfer:(NSNotification *)notification {
// handle the API call as shown in original example
...
}
最佳答案
正如 NSURLSessionDidFinishEventsForBackgroundURLSession
的文档所说:
In iOS, when a background transfer completes or requires credentials, if your app is no longer running, your app is automatically relaunched in the background, and the app’s
UIApplicationDelegate
is sent anapplication:handleEventsForBackgroundURLSession:completionHandler:
message. This call contains the identifier of the session that caused your app to be launched. Your app should then store that completion handler before creating a background configuration object with the same identifier, and creating a session with that configuration. The newly created session is automatically reassociated with ongoing background activity.When your app later receives a
URLSessionDidFinishEventsForBackgroundURLSession:
message, this indicates that all messages previously enqueued for this session have been delivered, and that it is now safe to invoke the previously stored completion handler or to begin any internal updates that may result in invoking the completion handler.
因此,handleEventsForBackgroundURLSession
应该保存 completionHandler
并重新实例化后台 NSURLSession
。然后,URLSessionDidFinishEventsForBackgroundURLSession
应该调用那个 completionHandler
。
当您的应用程序被重新唤醒并调用 handleEventsForBackgroundURLSession
时,我没有看到您在任何地方重新实例化后台 session 。我也没有看到您实现了将调用 completionHandler
的 URLSessionDidFinishEventsForBackgroundURLSession
。
关于ios - NSURLSession backgroundSession 完成时额外的 API 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22919568/
从 Redis 获取消息时,onDone:(){print('done')} 从未起作用。 import 'package:dartis/dartis.dart' as redis show PubS
昨天我玩了一些vim脚本,并设法通过循环来对当前输入的内容进行状态栏预测(请参见屏幕截图(灰色+黄色栏))。 问题是,我不记得我是怎么得到的,也找不到我用于该vim魔术的代码片段(我记得它很简单):它
我尝试加载 bash_completion在我的 bash (3.2.25) 中,它不起作用。没有消息等。我在我的 .bashrc 中使用了以下内容 if [ -f ~/.bash_completio
我正在尝试构建一个 bash 完成例程,它将建议命令行标志和合适的标志值。例如在下面 fstcompose 命令我想比赛套路先建议 compose_filter= 标志,然后建议来自 [alt_seq
当我尝试在重定向符号后完成路径时,bash 完成的行为就好像它仍在尝试在重定向之前完成命令的参数一样。 例如: dpkg -l > /med标签 通过在 /med 之后点击 Tab我希望它完成通往 /
我的类中有几个 CAKeyframeAnimation 对象。 他们都以 self 为代表。 在我的animationDidStop函数中,我如何知道调用来自哪里? 是否有任何变量可以传递给 CAKe
我有一个带有 NSDateFormatter 的 NSTextField。格式化程序接受“mm/dd/yy”。 可以自动补全日期吗?因此,用户可以输入“mm”,格式化程序将完成当前月份和年份。 最佳答
有一个解决方案可以使用以下方法完成 NSTextField : - (NSArray *)control:(NSControl *)control textView:(NSTextView *)tex
我正在阅读 Passport 的文档,我注意到 serialize()和 deserialize() done()被调用而不被返回。 但是,当使用 passport.use() 设置新策略时在回调函数
在 ubuntu 11.10 上的 Firefox 8.0 中,尽管 img.complete 为 false,但仍会调用 onload 函数 draw。我设法用 setTimeout hack 解决
假设我有两个与两个并行执行的计算相对应的 future 。我如何等到第一个 future 准备好?理想情况下,我正在寻找类似于Python asyncio's wait且参数为return_when=
我正在寻找一种 Java 7 数据结构,其行为类似于 java.util.Queue,并且还具有“最终项目已被删除”的概念。 例如,应可以表达如下概念: while(!endingQueue.isFi
这是一个简单的问题。 if ($('.dataTablePageList')) { 我想做的是执行一个 if 语句,该语句表示如果具有 dataTablesPageList 类的对象也具有 menu
我用replaceWith批量替换了许多div中的html。替换后,我使用 jTruncate 来截断文本。然而它不起作用,因为在执行时,replaceWith 还没有完成。 我尝试了回调技巧 ( H
有没有办法调用 javascript 表单 submit() 函数或 JQuery $.submit() 函数并确保它完成提交过程?具体来说,在一个表单中,我试图在一个 IFrame 中提交一个表单。
我有以下方法: function animatePortfolio(fadeElement) { fadeElement.children('article').each(function(i
我刚刚开始使用 AndEngine, 我正在像这样移动 Sprite : if(pValueY < 0 && !jumping) { jumping =
我正在使用 asynctask 来执行冗长的操作,例如数据库读取。我想开始一个新 Activity 并在所有异步任务完成后呈现其内容。实现这一目标的最佳方法是什么? 我知道 onPostExecute
我有一个脚本需要命令名称和该命令的参数作为参数。 所以我想编写一个完成函数来完成命令的名称并完成该命令的参数。 所以我可以这样完成命令的名称 if [[ "$COMP_CWORD" == 1 ]];
我的应用程序有一个相当奇怪的行为。我在 BOOT_COMPLETE 之后启动我的应用程序,因此在我启动设备后它是可见的。 GUI 响应迅速,一切正常,直到我调用 finish(),按下按钮时,什么都没
我是一名优秀的程序员,十分优秀!