【问题标题】:NSURLProtocol - startLoading not called after canInitWithRequest returns YES for page resourceNSURLProtocol - 在 canInitWithRequest 为页面资源返回 YES 后未调用 startLoading
【发布时间】:2016-01-10 09:58:50
【问题描述】:

我遇到了一个问题,我的 UIWebView 中的视频资源没有加载。这只是实际设备上的问题 - 在模拟器上一切正常。

注意:我已经检查过了,这里的问题与多次加载相同的内容有关。 NSURLProtocol isn't asked to load after YES response to canInitWithRequest

实际页面加载正常-在我的自定义NSURLProtocol 中,它从canInitWithRequest(多次)返回YES,然后在大约第四次或第五次之后调用startLoading。然后它以类似的方式加载我的 css 文件。然后我看到对我的视频对象的请求从canInitWithRequest 返回YES,但没有任何反应。 startLoading 从来没有被要求请求我的视频资源。这是我加载页面时设备上的简化日志:

canInitWithRequest: https://WebpageURL
canInitWithRequest: https://WebpageURL
canInitWithRequest: https://WebpageURL
canInitWithRequest: https://WebpageURL
canInitWithRequest: https://WebpageURL
START LOADING: https://WebpageURL
canInitWithRequest: https://WebpageURL
canInitWithRequest: https://WebpageURL
canInitWithRequest: https://WebpageURL
canInitWithRequest: https://cssResource
START LOADING: https://cssResource
canInitWithRequest: https://MyVideoResource

当我从在完全相同的设备类型上运行相同 iOS 版本的模拟器加载完全相同的页面时,日志显示资源实际上出于某种原因开始加载:

canInitWithRequest: https://WebpageURL
canInitWithRequest: https://WebpageURL
canInitWithRequest: https://WebpageURL
START LOADING: https://WebpageURL
canInitWithRequest: https://WebpageURL
canInitWithRequest: https://cssResource
START LOADING: https://cssResource
canInitWithRequest: https://MyVideoResource
canInitWithRequest: https://MyVideoResource
START LOADING: https://MyVideoResource  -- WHY NOT ON DEVICE?

该页面留下了一个从不播放的视频 - 只是一个白框,它应该是和它上面的“播放视频”按钮。该页面看起来像是在不断地加载某些东西(状态栏中的活动指示器正在旋转)但什么也没有发生,并且 Xcode 的调试导航器中的网络活动是扁平的。

tl;博士
有谁知道为什么在我的 iPhone 上从未尝试加载此资源?显然模拟器知道需要加载。


编辑:这是我的 NSURLProtocol 中经过略微编辑的相关代码

@implementation CHHTTPURLProtocol
{
    NSURLConnection *connection;
    NSHTTPURLResponse *httpResponse;
    NSData *responseData;
}

+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
    if (/* key exists on request */)
        return NO;
    else if (/* not http or https */)
        return NO;

    NSLog(@"canInitWithRequest: %@", request.URL.absoluteString);

    return YES;
}

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
    return request;
}

- (void)startLoading
{
    NSMutableURLRequest *request = [self.request mutableCopy];
    NSLog(@"START LOADING: %@", request.URL.absoluteString);
    if (authenticate) authenticate(request);
    /* add key to request */
    connection = [NSURLConnection connectionWithRequest:request delegate:self];
}

- (void)stopLoading
{
    [connection cancel];
    connection = nil;
}

/* Other methods like connection:didReceiveData: and connectionDidFinishLoding: */

+ (void)authenticateWithBlock:(AuthenticationBlock)block
{
    authenticate = block;
}

static AuthenticationBlock authenticate;

【问题讨论】:

  • 几个问题:模拟器和设备运行相同的iOS版本?运行模拟器的手机和mac上的网络是否相同?你用来加载视频的源代码?
  • @Lefteris 模拟器和设备都在运行 8.4。两者都连接到同一个 wifi,并加载完全相同的 HTML 资源。帖子已使用相关的 NSURLProtocol 代码更新。
  • 为什么不对所有 canInitWithRequest 返回 YES?或者至少在 canInitWithRequest 中打印出请求以找出区别?
  • 如果请求已经启动,则无需返回 YES,并且我不想加载不是专门通过 http 或 https 的资源。我正在记录请求 URL,只是没有将其包含在上面的代码中。我会再次添加它。注销整个请求只显示请求对象的 URL 和内存位置。

标签: ios objective-c uiwebview nsurlprotocol


【解决方案1】:

我最好的猜测是UIWebView 中使用的视频播放器没有使用通过NSURProtocol 传输的Foundation 服务(NSURLSession/NSURLRequest 等)加载其内容。视频播放器可能正在使用较低级别的CFNetwork api 发出请求。

实现可能因模拟器而异。

我知道您的协议是通过canInitWithRequest 调用轮询的,但这并不一定意味着播放器将使用NSURLSession/NSURLRequest 实际加载资源。

尝试通过自定义协议将视频加载到 MPMoviePlayerViewController 的行为与您所看到的类似:How to play movie with a URL using a custom NSURLProtocol?

【讨论】:

    【解决方案2】:

    我没有明确的答案,但我确实有一些建议可以解决这个问题: 你考虑过缓存吗? If the UIWebView thinks it already has a copy of the video, it won't call.

    when iOS 8 receive an HTTP response with a Keep-Alive header, it keeps this connection to re-use later (as it should), but it keeps it for more than the timeout parameter of the Keep-Alive header。视频是最后加载的东西,如果 Mac 比真实设备快,它可能就是它。查看您的代码,如果 NSURLRequest 在 canInitWithRequest 之后但在 startLoading 之前为零,您仍然会在 NSLog 中看到一些内容。

    1. 模拟器可能正在使用 OSX AVFoundation 播放视频。这意味着 iOS 支持 frameworks are differentfewer codecs
    2. The ios device is case sensitive when it comes to file names whilst the simulator is not.
    3. 假设iOS-Specific Considerations在模拟器和真实设备之间是不同的,如果这是UIWebView中的第二个视频,它肯定不应该在iOS上播放,但可以在模拟器上播放。

    【讨论】:

    • Point 1- 我认为操作系统甚至不知道 URL 的另一端是什么类型的文件,因为它还没有尝试加载它(没有响应头)。第 2 点 - 它不是托管在设备上的文件,它是一个 URL。第 3 点 - 它是页面上唯一的视频。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多