从远程 url 从 ios 应用程序下载 PDF

Posted

技术标签:

【中文标题】从远程 url 从 ios 应用程序下载 PDF【英文标题】:Downloading PDF from an ios app from remote url 【发布时间】:2014-04-21 06:57:34 【问题描述】:

我正在使用下面的代码从 URL 下载 PDF,但我得到以下输出以及通知和错误。

我的 AppDelegate.h

@interface FileDownload2AppDelegate : UIResponder <UIApplicationDelegate , NSURLConnectionDataDelegate>

        NSMutableData *receivedData;


@property (strong, nonatomic) UIWindow *window;

@end

我的 AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    
        // Override point for customization after application launch.

        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://code.google.com/p/androidnetworktester/downloads/detail?name=1mb.txt"]];
        [NSURLConnection connectionWithRequest:request delegate:self];

        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *localFilePath = [documentsDirectory stringByAppendingPathComponent:@"/Users/awsuser8/1.txt"];
        NSData *thedata = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://code.google.com/p/androidnetworktester/downloads/detail?name=1mb.txt"]];
        [thedata writeToFile:localFilePath atomically:YES];

        NSLog(@"PDF downloaded");

        return YES;
    



- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response

    // This method is called when the server has determined that it
    // has enough information to create the NSURLResponse.

    // It can be called multiple times, for example in the case of a
    // redirect, so each time we reset the data.

    // receivedData is an instance variable declared elsewhere.
    [receivedData setLength:0];



- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
    [receivedData setData:data];

    [receivedData appendData:data];
    NSLog(@"receivedData : %@", receivedData);


- (void)connection:(NSURLConnection *)connection
  didFailWithError:(NSError *)error

    // release the connection, and the data object
    //[connection release];
    // receivedData is declared as a method instance elsewhere
    //[receivedData release];

    // inform the user
    NSLog(@"Connection failed! Error - %@ %@",
          [error localizedDescription],
          [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);


- (void)connectionDidFinishLoading:(NSURLConnection *)connection

    // do something with the data
    // receivedData is declared as a method instance elsewhere
    NSLog(@"Succeeded! Received %d bytes of data",[receivedData length]);

    // release the connection, and the data object
   // [connection release];
   // [receivedData release];

获取输出:

lockdownd[53] <Notice>: 00281000 __copy_itunes_value_block_invoke: com.apple.mobile.iTunes.store/downloaded-apps -> (null)
lockdownd[53] <Notice>: 01a63000 __copy_itunes_value_block_invoke: com.apple.mobile.iTunes.store/downloaded-apps -> (null)
networkd[79] <Warning>: Analytics Engine: double ON for app: com.aasare.FileDownload2
backboardd[28] <Error>: HID: The 'Passive' connection 'FileDownload2' access to protected services is denied.
PDF downloaded
receivedData : (null)
receivedData : (null)
Succeeded! Received 0 bytes of data

【问题讨论】:

在“didReceiveData”方法中,您同时使用了 set 和 appendData。仅使用 appendData 并检查 @user2071152 尝试但得到相同的输出 下载数据是否需要任何身份验证?我们可以观察到错误“backboardd[28] : HID: The 'Passive' connection 'FileDownload2' access to protected services is denied.”。如果是这样,您可以使用“didReceiveAuthenticationChallenge”方法来提供凭据。 此错误消息是否会导致任何问题?我以前从未见过它,但我只是检查了一下。我的所有应用程序都会出现此错误。其中一些位于应用商店中,部署到数千台设备上。此错误出现在来自 App Store 的构建中。我使用 crashlytics 进行崩溃报告。目前我没有看到与此错误相关的任何问题。暂时可以忽略它。 【参考方案1】:

您可能应该在某处实例化receivedData

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
    receivedData = [NSMutableData data];

并且您应该附加接收到的数据。

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
    [receivedData appendData:data];


并且您正在下载文件两次,但您完全放弃了第二次下载。

这个代码块已经下载并保存了数据:

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://code.google.com/p/androidnetworktester/downloads/detail?name=1mb.txt"]];
    [NSURLConnection connectionWithRequest:request delegate:self];

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *localFilePath = [documentsDirectory stringByAppendingPathComponent:@"/Users/awsuser8/1.txt"];
    NSData *thedata = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://code.google.com/p/androidnetworktester/downloads/detail?name=1mb.txt"]];
    [thedata writeToFile:localFilePath atomically:YES];

这在主线程上以同步方式发生。在下载过程中,该应用程序不执行任何其他操作。如果您的下载量很大,或者您的连接速度很慢,您的应用程序可能在启动之前就被终止了。

不要这样做。将文件保存代码放入connectionDidFinishLoading:。这是处理网络请求的异步方式。这就是您应该如何处理与网络相关的所有事情。

另外,您要写入的文件不存在。 writeData: 不创建目录。您可能应该删除整个 /Users... 路径组件。或者自己创建。

例如:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
    // Override point for customization after application launch.
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://code.google.com/p/androidnetworktester/downloads/detail?name=1mb.txt"]];
    [NSURLConnection connectionWithRequest:request delegate:self];
    return YES;


- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
    receivedData = [NSMutableData data];



- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
    [receivedData appendData:data];


- (void)connection:(NSURLConnection *)connection
  didFailWithError:(NSError *)error 
    NSLog(@"Connection failed! Error - %@ %@",
          [error localizedDescription],
          [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);


- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *directoyPath = [documentsDirectory stringByAppendingPathComponent:@"Users/awsuser8"];
    NSError *error;
    if (![[NSFileManager defaultManager] fileExistsAtPath:directoyPath]) 
        if (![[NSFileManager defaultManager] createDirectoryAtPath:directoyPath withIntermediateDirectories:YES attributes:nil error:&error]) 
            NSLog(@"Can't create directoy %@", error);
        
    
    NSString *localFilePath = [directoyPath stringByAppendingPathComponent:@"1.txt"];
    if (![receivedData writeToFile:localFilePath options:NSDataWritingAtomic error:&error]) 
        NSLog(@"Can't write file. %@", error);
    

【讨论】:

如何摆脱这个错误 : HID: The 'Passive' connection 'FileDownload2' access to protected services is denied.【参考方案2】:

尝试更改为 didReceiveData 如下:

if(!receivedData)
    [receivedData setData:data];
else
   [receivedData appendData:data];

【讨论】:

我没有投反对票,但如果您设置receivedData = nil,您的代码将归结为[nil setData:data];。有点没用。 好的,我明白了。如果答案错误或没有用,投反对票是正确的。但我只想知道提高自己的原因。谢谢

以上是关于从远程 url 从 ios 应用程序下载 PDF的主要内容,如果未能解决你的问题,请参考以下文章

java实现从url路径中下载pdf文档到本地

尝试使用Ajax从远程服务器下载文件,而Codeigniter无法正常工作

Android 从 URL 下载 PDF,然后使用 PDF 阅读器打开它

从远程 url 加载 pdf 以作为 Mandrill 附件发送

尝试使用 Ajax 从远程服务器下载文件,但 Codeigniter 不起作用

如何使用IOS Pdf reader Api通过Url查看远程pdf文件?