0

我在我的应用程序的 UIWebView 中加载 youku.com 视频时遇到问题。我很确定这是由于应用程序传输安全性,因为用 HTTPS URL 替换嵌入可以正常工作。当然,没有 HTTPS 等效 URL,因为中国。

我已经阅读了各种 NSAppTransportSecurity 设置。我的第一直觉当然是尝试使用 NSAllowsArbitraryLoads 来至少验证问题,但这并没有奏效。然后我按照各种在线指南展示了如何像你应该做的那样使用 NSExceptionDomains,但这也不起作用。

现在我被困住了。FWIW,我正在捕获这样的 URL 加载错误:

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
    ...
    if (error.code == NSURLErrorCancelled)
    {
        NSLog(@"NSURLErrorCancelled: URL %@ error %@", urlString, error);
    }
}

目前我正在使用一个虚拟测试 URL exon.name,这会产生:

2015-12-02 15:47:22.312 ZaoMengShe[81707:903426] NSURLErrorCancelled: URL https://dev1.zaomengshe.com/c/54260 error Error Domain=NSURLErrorDomain Code=-999 "(null)" UserInfo={NSErrorFailingURLKey=http://exon.name/, NSErrorFailingURLStringKey=http://exon.name/}

确认一下,-999 是 App Transport Security 执行此操作时的错误,对吗?(这不是一个信息量很大的错误!)

另一件事,如NSAllowsArbitraryLoads not working中所述,您必须编辑“Info.plist”文件。我没有这样的文件。我有“ZaoMengShe-Info.plist”(“ZaoMengShe”是我的应用程序的名称)。但是没有一个问题显示包含文件名的实际屏幕截图,所以据我所知,每个人的 Info.plist 文件实际上都包含应用程序的名称,这很正常。我弄错了吗?

应用传输安全设置 Info.plist 设置

4

2 回答 2

2

事实证明 NSAllowsArbitraryLoads 在这种情况下工作正常。我的问题是我遇到了另一个限制。在新的安全策略中,您不能在安全 (HTTPS) 页面中加载不安全 (HTTP) 活动内容。在浏览器和 UIWebView 中都是如此。似乎没有任何方法可以关闭此行为。

这是一些额外的日志,用于显示关闭然后打开 NSAllowsArbitraryLoads 的错误消息。无论哪种方式,它都会失败,但在第一种情况下我会收到一条额外的错误消息:

2015-12-07 17:58:10.589 TestWeb[13583:4566542] about to load url https://dev1.zaomengshe.com/c/54260
2015-12-07 17:58:15.966 TestWeb[13583:4569606] App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
2015-12-07 17:58:16.045 TestWeb[13583:4566542] failed to load
2015-12-07 17:58:40.879 TestWeb[13583:4566542] NSURLErrorCancelled: error Error Domain=NSURLErrorDomain Code=-999 "(null)" UserInfo={NSErrorFailingURLKey=http://exon.name/, NSErrorFailingURLStringKey=http://exon.name/}
2015-12-07 17:58:40.895 TestWeb[13583:4569023] void SendDelegateMessage(NSInvocation *): delegate (webView:decidePolicyForNavigationAction:request:frame:decisionListener:) failed to return after waiting 10 seconds. main run loop mode: kCFRunLoopDefaultMode
2015-12-07 17:58:41.878 TestWeb[13583:4569606] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
2015-12-07 17:58:41.884 TestWeb[13583:4566542] finished load urlString: https://dev1.zaomengshe.com/c/54260

2015-12-07 17:54:57.431 TestWeb[13503:4532874] about to load url https://dev1.zaomengshe.com/c/54260
2015-12-07 17:55:02.339 TestWeb[13503:4532874] failed to load
2015-12-07 17:55:15.310 TestWeb[13503:4532874] NSURLErrorCancelled: error Error Domain=NSURLErrorDomain Code=-999 "(null)" UserInfo={NSErrorFailingURLKey=http://exon.name/, NSErrorFailingURLStringKey=http://exon.name/}
2015-12-07 17:55:15.313 TestWeb[13503:4533886] void SendDelegateMessage(NSInvocation *): delegate (webView:decidePolicyForNavigationAction:request:frame:decisionListener:) failed to return after waiting 10 seconds. main run loop mode: kCFRunLoopDefaultMode
2015-12-07 17:55:16.210 TestWeb[13503:4534307] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9843)
2015-12-07 17:55:16.653 TestWeb[13503:4532874] finished load urlString: https://dev1.zaomengshe.com/c/54260

就我而言,我在 iframe 中加载了不安全的优酷视频,而 iframe 被视为活动内容。所以没有办法让它工作。优酷不提供 HTTPS 内容。

解决方案非常简单:将整个应用程序移回我网站的 HTTP 版本并保留 NSAllowsArbitraryLoads 标志。万岁!这对每个人来说都是一个有趣的 HTTPS 实验,谢谢。一定要在它工作时回复我。

于 2015-12-07T12:04:23.703 回答
0

请检查您的目标设置。您的 .plist 文件的名称必须在名为 Info.plist 文件的参数中的 Build Settings 的 Packaging 部分中。它必须是包含项目文件的文件夹中 .plist 文件的相对路径。

更新:您的错误消息包含 URL https://dev1.zaomengshe.com/c/54260 如果您从浏览器打开此 URL,您将看到它的 https 证书不受信任。因此,取消您的请求不是由于应用程序传输安全性,而是 UIWebView 不受信任的证书安全性。

这种情况有一种解决方案。在 UIWebView 开始从不受信任的 URL 加载请求之前,您必须使其受信任。URL 加载系统缓存您的请求。当你以编程方式告诉它无论如何都要下载时,UIWebView 会从这个 URL 开始加载。

这是我在项目中使用的代码片段:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
    if([request.URL.scheme isEqualToString:@"https"] && ![request.URL.absoluteString hasPrefix:[AppData sharedInstance].serverBaseUrl] && ![self.authenticatedUrls containsObject:request.URL.absoluteString]){
        __weak NBTransferFromCardConfirmationVC * weakself = self;
        NBInsecureSslAuth * auth=[NBInsecureSslAuth new];
        [auth authInsecureUrlRequet:request
        success:^{
            [weakself.authenticatedUrls addObject:request.URL.absoluteString];
            [webView loadRequest:request];
        } failure:^(NSError *error) {
            [weakself.authenticatedUrls addObject:request.URL.absoluteString];
            [webView loadRequest:request];
//            showErrorWithTitle(@"Error", error.localizedDescription);
        }];
        return NO;
    }else{
        return YES;
    }
}

NBInsecureSslAuth 的源代码:

@implementation NBInsecureSslAuth

- (void)authInsecureUrlRequet:(NSURLRequest*)request success:(void (^)(void))success failure:(void (^)(NSError * error))failure{

AFHTTPClient* client = [[AFHTTPClient alloc] initWithBaseURL:request.URL];

client.allowsInvalidSSLCertificate=YES;

[client setDefaultHeader:@"User-Agent" value:[NSString stringWithFormat:@"%@/%@ (iOS %@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleExecutableKey] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleIdentifierKey], [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleVersionKey], [[NSProcessInfo processInfo] operatingSystemVersionString]]];

NSMutableURLRequest * authRequest=[client requestWithMethod:request.HTTPMethod path:@"" parameters:nil];

AFHTTPRequestOperation * operation=
[client HTTPRequestOperationWithRequest:authRequest
                                success:^(AFHTTPRequestOperation *operation, id responseObject) {
                                    if(success){
                                        success();
                                    }
                                }
                                failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                    if(failure){
                                        failure(error);
                                    }
                                }];

[client enqueueHTTPRequestOperation:operation];


}


@end
于 2015-12-02T08:44:24.543 回答