はじめに
概要
- はじめに、
NSURLSession
でのプロキシ通信の実装例を示します - つぎに、
AFNetworking 2.x
でのプロキシ通信の実装例を示します - 最後に、補足としてPACファイルからプロキシ設定を取得する実装例を示します
- 実装例は、Mac OS X Yosemite 10.10.3で動作確認しています
AFNetworkingの補足
- AFNetworking 1.xでは
NSURLConnection
を使っており、NSURLConnection
はプロキシをサポートしていないため、CFNetwork系のAPIを使って独自に実装する必要があるようです - 一方、AFNetworking 2.xでは
NSURLSession
を使え、NSURLSession
はNSURLSessionConfiguration.connectionProxyDictionary
でプロキシを指定できます - 参考: ios - how to set proxy details using AFNetworking - Stack Overflow
こちらも参照してください
注意
-
AFNetworking 2.x
は、iOS 6以降、Mac OS X 10.8以降をサポートしています - AFNetworking - Requirements
(NSURLSession) プロキシ通信の実装例
-
NSURLSession``NSURLSessionDataTask
を直接使用する場合の実装例です - 実行環境: OS X Yosemite 10.10.3
- Xcode 6.3.2
- (IBAction)proxyConnectAction:(id)sender {
// NSDictionary *httpProxy = @{(id)kCFNetworkProxiesHTTPEnable: @(1),
// (id)kCFStreamPropertyHTTPProxyHost: host,
// (id)kCFStreamPropertyHTTPProxyPort: port};
// 注意: iOSでは`HTTPS`のkeyが定義されていません
NSDictionary *httpsProxy = @{(id)kCFNetworkProxiesHTTPSEnable: @(1),
(id)kCFStreamPropertyHTTPSProxyHost: @"127.0.0.1",
(id)kCFStreamPropertyHTTPSProxyPort: @(8888)};
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.connectionProxyDictionary = httpsProxy;
NSURL *url = [NSURL URLWithString:@"https://www.example.com/foobar.png"];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"response: %@", response);
NSLog(@"data length: %ld", data.length);
if (error) {
NSLog(@"error:%@", error);
}
}];
[dataTask resume];
}
(AFNetworking 2.x) プロキシ通信の実装例
- AFNetworkingの
AFHTTPSessionManager
を使用する場合の実装例です - 実行環境: OS X Yosemite 10.10.3
- Xcode 6.3.2
- AFNetworking 2.5.4
RestClientの例
RestClient.h
# import <Foundation/Foundation.h>
@interface RestClient : NSObject
@property (copy, nonatomic) NSURL *baseURL;
@property (copy, nonatomic) NSDictionary *proxyDictionary;
@property (nonatomic) BOOL allowInvalidCertificates; // For debugging (Default: NO)
- (instancetype)initWithBaseURL:(NSURL *)baseURL;
- (instancetype)initWithBaseURL:(NSURL *)baseURL proxyDictionary:(NSDictionary *)proxyDictionary;
- (void)getWithPath:(NSString *)path
parameters:(NSDictionary *)parameters
success:(void (^)(id responseObject))success
failure:(void (^)(NSError *error))failure;
@end
-
initWithBaseURL:sessionConfiguration:を使って、
AFHTTPSessionManager
を作成します -
NSURLSessionConfiguration.connectionProxyDictionary
に、プロキシの情報を入れたNSDictionaryを指定します
RestClient.m
# import "RestClient.h"
# import <AFNetworking/AFNetworking.h>
@interface RestClient ()
@property (strong) AFHTTPSessionManager *httpSessionManager;
@end
@implementation RestClient
- (instancetype)initWithBaseURL:(NSURL *)baseURL {
self = [super init];
if (!self) {
return nil;
}
self.baseURL = baseURL;
return self;
}
- (instancetype)initWithBaseURL:(NSURL *)baseURL proxyDictionary:(NSDictionary *)proxyDictionary {
self = [self initWithBaseURL:baseURL];
if (!self) {
return nil;
}
self.proxyDictionary = proxyDictionary;
return self;
}
- (AFHTTPSessionManager *)_sessionManager {
AFHTTPSessionManager *manager = self.httpSessionManager;
if (!manager) {
// Configure AFHTTPSessionManager
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.connectionProxyDictionary = self.proxyDictionary;
manager = [[AFHTTPSessionManager alloc] initWithBaseURL:self.baseURL sessionConfiguration:sessionConfig];
manager.securityPolicy.allowInvalidCertificates = self.allowInvalidCertificates;
// Set Serializer
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
// Configure JSON Request Serializer
manager.requestSerializer.timeoutInterval = 20.0f;
manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringCacheData;
// Set default header to requestSerializer
[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"content-type"];
// Configure JSON Response Serializer
((AFJSONResponseSerializer *)(manager.responseSerializer)).readingOptions |= NSJSONReadingAllowFragments;
self.httpSessionManager = manager;
}
return manager;
}
- (void)getWithPath:(NSString *)path
parameters:(NSDictionary *)parameters
success:(void (^)(id responseObject))success
failure:(void (^)(NSError *error))failure {
AFHTTPSessionManager *manager = [self _sessionManager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager GET:path parameters:parameters success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"task:%@", task);
success(responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"task:%@", task);
failure(error);
}];
}
@end
RestClientを使う側
Example.m
// [proxy] https://127.0.0.1:8888
NSDictionary *httpsProxy = @{(id)kCFNetworkProxiesHTTPSEnable: @(1),
(id)kCFStreamPropertyHTTPSProxyHost: @"127.0.0.1",
(id)kCFStreamPropertyHTTPSProxyPort: @(8888)};
NSURL *baseURL = [self _baseURL];
NSString *path = [self _path];
RestClient *client = [[RestClient alloc] initWithBaseURL:baseURL proxyDictionary:httpsProxy];
[client getWithPath:path parameters:nil success:^(id responseObject) {
NSData *data = (NSData *)responseObject;
NSImage *image = [[NSImage alloc] initWithData:data];
self.imageView.image = image;
} failure:^(NSError *error) {
NSLog(@"error: %@", error);
self.imageView.image = nil;
}];
(補足) PACファイルからプロキシ設定を取得する
システム環境設定
-
システム環境設定
>ネットワーク
>任意のアダプタ
>プロキシ
でPACファイルを指定した場合
実装例
- 実行環境: OS X Yosemite 10.10.3
- Xcode 6.3.2
- CoreFoundationの
CFNetworkCopyProxiesForAutoConfigurationScript()
使うと、これから接続するURLに該当するプロキシの情報を取得できます
- (void)_proxiesWithPACScriptURL:(NSURL *)pacScriptURL intendedURL:(NSURL *)intendedURL {
if (!pacScriptURL || !intendedURL) {
return;
}
NSError *error = nil;
NSString *script;
script = [NSString stringWithContentsOfURL:pacScriptURL usedEncoding:NULL error:&error];
if (error) {
NSLog(@"error: %@", error);
return;
}
CFErrorRef cfErrorRef = NULL;
NSArray *proxies = (__bridge NSArray *)CFNetworkCopyProxiesForAutoConfigurationScript((__bridge CFStringRef)script, (__bridge CFURLRef)intendedURL, &cfErrorRef);
if (cfErrorRef || !proxies.count) {
NSError *error = (__bridge NSError *)cfErrorRef;
NSLog(@"error: %@", error);
return;
}
NSLog(@"proxies: %@", proxies);
}
- (IBAction)getProxyInfoAction:(id)sender {
CFDictionaryRef proxies = SCDynamicStoreCopyProxies(NULL);
NSDictionary *config = (__bridge NSDictionary *)proxies;
NSLog(@"______________________");
NSLog(@"kSCPropNetProxiesProxyAutoDiscoveryEnable: %@", config[(id)kSCPropNetProxiesProxyAutoDiscoveryEnable]);
NSLog(@"kSCPropNetProxiesProxyAutoConfigEnable : %@", config[(id)kSCPropNetProxiesProxyAutoConfigEnable]);
NSLog(@"kSCPropNetProxiesProxyAutoConfigURLString: %@", config[(id)kSCPropNetProxiesProxyAutoConfigURLString]);
NSLog(@"kSCPropNetProxiesHTTPEnable : %@", config[(id)kSCPropNetProxiesHTTPEnable]);
NSLog(@"kSCPropNetProxiesHTTPPort : %@", config[(id)kSCPropNetProxiesHTTPPort]);
NSLog(@"kSCPropNetProxiesHTTPSEnable : %@", config[(id)kSCPropNetProxiesHTTPSEnable]);
NSLog(@"kSCPropNetProxiesHTTPSPort : %@", config[(id)kSCPropNetProxiesHTTPSPort]);
NSLog(@"______________________");
NSURL *pacScriptURL = [NSURL URLWithString:config[(id)kSCPropNetProxiesProxyAutoConfigURLString]];
if (pacScriptURL) {
NSURL *intendedURL = [NSURL URLWithString:@"https://www.apple.com"];
[self _proxiesWithPACScriptURL:pacScriptURL intendedURL:intendedURL];
}
}
PACファイルの例
function FindProxyForURL(url, host) {
if ( isInNet( host, "127.0.0.1", "255.255.255.255" )) {
return "DIRECT";
}
else if ( dnsDomainIs( host, "beta.example.com") ) {
return "PROXY 127.0.0.1:8888"
}
else {
return "PROXY 127.0.0.1:8888"
}
}
実行結果
ProxyInfo[71363:4147289] ______________________
ProxyInfo[71363:4147289] kSCPropNetProxiesProxyAutoDiscoveryEnable: (null)
ProxyInfo[71363:4147289] kSCPropNetProxiesProxyAutoConfigEnable : 1
ProxyInfo[71363:4147289] kSCPropNetProxiesProxyAutoConfigURLString: http://localhost:4567/proxy4.pac
ProxyInfo[71363:4147289] kSCPropNetProxiesHTTPEnable : 0
ProxyInfo[71363:4147289] kSCPropNetProxiesHTTPPort : (null)
ProxyInfo[71363:4147289] kSCPropNetProxiesHTTPSEnable : 0
ProxyInfo[71363:4147289] kSCPropNetProxiesHTTPSPort : (null)
ProxyInfo[71363:4147289] ______________________
ProxyInfo[71363:4147289] proxies: (
{
kCFProxyHostNameKey = "127.0.0.1";
kCFProxyPortNumberKey = 8888;
kCFProxyTypeKey = kCFProxyTypeHTTPS;
}
)