macOS のアプリのコードでネットからのコンテンツがダウンロードされない!?
macOS の cocoaアプリの新規プロジェクトを作り、こんなコードを書いたら動かない事に気がつきました。
do {
let url = URL(string: "https://www.apple.com")!
var encoding = String.Encoding.utf8
let text = try String(contentsOf: url, usedEncoding: &encoding)
print("contents: \(text)")
}
catch {
print("error: \(error)")
}
エラーのログはだいたいこんな感じです。
dnssd_clientstub ConnectToServer: connect()-> No of tries: 1
dnssd_clientstub ConnectToServer: connect()-> No of tries: 2
dnssd_clientstub ConnectToServer: connect()-> No of tries: 3
dnssd_clientstub ConnectToServer: connect() failed path:/var/run/mDNSResponder Socket:11 Err:-1 Errno:1 Operation not permitted
[] nw_resolver_create_dns_service_locked DNSServiceCreateDelegateConnection failed: ServiceNotRunning(-65563)
TIC TCP Conn Failed [1:0x604000162040]: 10:-72000 Err(-65563)
Task <7E9A6646-3924-4A82-868D-DA280CA5ECFC>.<0> HTTP load failed (error code: -1003 [10:-72000])
NSURLConnection finished with error - code -1003
Error Domain=NSCocoaErrorDomain Code=260 "The file couldn’t be opened because it doesn’t exist." UserInfo={NSURL=https://www.apple.com, NSUnderlyingError=0x6000000500e0 {Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found." UserInfo={NSUnderlyingError=0x608000440ed0 {Error Domain=kCFErrorDomainCFNetwork Code=-1003 "A server with the specified hostname could not be found." UserInfo={NSErrorFailingURLStringKey=https://www.apple.com/, NSErrorFailingURLKey=https://www.apple.com/, _kCFStreamErrorCodeKey=-72000, _kCFStreamErrorDomainKey=10, NSLocalizedDescription=A server with the specified hostname could not be found.}}, NSErrorFailingURLStringKey=https://www.apple.com, NSErrorFailingURLKey=https://www.apple.com, _kCFStreamErrorDomainKey=10, _kCFStreamErrorCodeKey=-72000, NSLocalizedDescription=A server with the specified hostname could not be found.}}}
ちょっと前まで書いていた似たようなコードではちゃんと動いていました。ここで、ひらめきます。「あ!これはあれだ!App Transportation Security
の問題かな?」とそこで、info.plist
を開いてこんな感じで App Transportation Security
を追加して Allow Arbitrary Loads
を YES
にします。
実行するとやはり、同じエラーで、コンテンツをダウンロードしてくれません。そこで、エラーの一部からググってみますが、問題の解決にたどり着けそうにありません。
で、プロジェクトをよく見るとこれまでに見慣れないものが入っている事に気がつきます。「.entitlements」です。「はは〜ん!Xcode 9で新規に作ったcocoaのアプリのプロジェクトにはデフォルトで入るのだな!」そこで、Xcode8 と Xcode9 でそれぞれ新しくcocoaのアプリのプロジェクトを作ってみます。左が Xcode8 で右が Xcode9 です。
やっぱり、Xcode 9で作ったプロジェクトには「.entitlements」がふえています。
そこで com.apple.security.app-sandbox
や com.apple.security.files.user-selected.read-only
で検索してみます。
Enabling App Sandbox
なるほど、Cocoa アプリ が Sandbox化 されるなら、各々の機能別にこれで指定しないとダメだよね。という事で、一覧を眺めて com.apple.security.network.client
を Xcode9 で作成されたプロジェクトに入れてみました。
これで、再度冒頭のスニペットを組み込んで実行させると、見事ネットからURLでコンテンツをロードしてくれました。
なお、エラーメッセージで検索しても、解決できるページにたどりつかなかった為、今後、同様な問題を抱えた人がエラーメッセージを頼りに検索したした時に、ここにだどりつけるように、エラーメッセージなどもほぼそのまま掲載する事とします。
最後に
あと、既に気がついている人はいるかもしれませんが、冒頭のスニペットが動かないので App Transportation Security
で Allow Arbitrary Loads
を YES
すればいいと思いましたが、そもそも https://
でアクセスしてるのでこの思考の流れは残念でした。
また、macOS の Sandbox化が進むとユーザーには良いかもしれませんが、開発者には面倒な時代になっていくなぁという思いが交差しています。
環境に関する表記
Xcode 8: Xcode 8.3.3 (8E3004b)
Xcode 9: Xcode 9 (9A235)