読者です 読者をやめる 読者になる 読者になる

NSBlogger

意識高いブログ

iOS10対応でやろうと思っていることまとめ

f:id:Kamekiti:20160911192718p:plain

はじめに

いよいよiOS10がリリースされます。iOSアプリ開発者のみなさんは、運営しているアプリを新iOSに対応させなければなりません。例年通りだと翌年の2月あたりに新iOSに対応していないアプリは審査に出すことすらできなくなります。早めに対応しておきましょう。
以下にiOS10対応でやろうと思っていることをまとめました。

iOS10対応って何をするの?

対応手順

まず「iOS10対応」についてですが、以下のような手順で対応します。

  1. Xcode 8をインストール
  2. 既存のプロジェクトをXcode 8で開く
  3. ビルドする
  4. エラーやクラッシュを修正する
  5. アプリをリリース

Xcode 8はまだ正式にはリリースされていません。iOS10のリリースと同時にアップデートがくるはずです。その時まで待っていてもよいですが、はやく対応したくてたまらない方はXcode 8 betaをインストールしましょう。先日書いた下記の記事も参考にしてみてください。
nsblogger.hatenablog.com

Build Settingsをチェック

Xcode 8でビルドする際に、「PROJECT」→「Build Settings」→「Base SDK」が「Latest iOS (iOS10.0)」になっていればOKです。この状態でビルドすればiOS10に対応したことになります。体感ですが、例年と比べるとすんなりビルドが通るのではないかと思います。
※Swiftでコードを書いている方は後述の「Swift 3.0に対応する」をご参考ください。
f:id:Kamekiti:20160911163330p:plain
その他、iOS10で登場した新機能にも素早く対応しておくと、Appleに気に入られるかもしれません。
では、以下にiOS10対応で最低限やるべきことと、+αとして新機能への対応について紹介します。

1.パーミッションの説明(対応必須)

iOS10になりパーミッションまわりの仕様が変更されました。といっても扱い方が変わったというわけではありません。「パーミッションの利用目的をユーザへ明示」する必要があります。
対応の仕方は簡単。まずInfo.plistを開きましょう。「+」で項目を追加します。「Privacy - 」で始まる項目がその利用目的を記載するためのKeyになっているので、必要なもののみ追加します。
たとえば、カレンダー情報や位置情報を扱う際はこのようになります。

<key>NSCalendarsUsageDescription</key>
	<string>カレンダーのイベント情報を表示するために使います。</string>
<key>NSLocationWhenInUseUsageDescription</key>
	<string>現在地周辺の情報を探索するために使います。</string>

f:id:Kamekiti:20160911163944p:plain

実際の画面にはこのように表示されます。

f:id:Kamekiti:20160911164000p:plain

この設定を行わないと、パーミッション取得時のダイアログ表示時にアプリがクラッシュします。

2.ATS(来年以降対応必須)

ATSって何?

ATSというのは超簡単にいうと「ある一定基準を満たしたHTTPSを使え」ということです。APIHTTPSに対応していない企業は焦り始めている頃ではないでしょうか。
ATSとiOS10は直接的な関係はありません。単純にATSに対応していないアプリは来年から審査が通らなくなるという話です。今まで「ATSをオフにする」という設定でしのいできた方も多いのではないでしょうか。しかしその設定だと来年からは審査に通さないよというわけです。
じゃあ年内にATSをちゃんと設定しないと…というわけですが、ATSの設定をする際、iOS9以前とiOS10とでその設定の解釈がすこし異なります。ややこしい話ですが、下記の記事が分かりやすいのでご一読を。
developer.hatenastaff.com
結論からいうと、下記のような設定が現実的ではないかと思われます。(来年以降に使える一番ゆるい設定)

API通信 WebView内通信
iOS10 HTTPを許可しない WKWebView内の通信だけHTTPを許可する
〜iOS9 HTTPを許可する HTTPを許可する

ポイントはiOS10ではWKWebViewのみHTTPが使える点。まだWKWebViewは回避策があるというわけですね。

具体的な修正案

Info.plistには下記のような記述で対応できます。

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
    <key>NSAllowsArbitraryLoadsInWebContent</key>
    <true/>
</dict>

「NSAllowsArbitraryLoadsInWebContent」というのがiOS10のみに適用される設定となります。これがtrueだと、iOS10では「WKWebViewのみHTTPを許可、それ以外はHTTPSを使う」という設定になります。falseだとiOS9と同様に、「NAAllowsArbitraryLoads」の設定に従います。じゃあfalseでもいいのではと思ってしまいますが、その場合はAppleになぜATSを無効化しているのかを説明しなければなりません。
【2016.09.14 追記】
NSAllowsArbitraryLoadsInWebContentがWKWebViewのみ適用されると記載していましたが、UIWebViewでも適用されます。コメントにてご指摘ありがとうございました。

APIがATSに対応しているかどうかの確認する

APIがATSに対応しているかどうかは下記のコマンドで調べることができます。

$ nscurl --ats-diagnostics https://hogehoge.com

色んな項目をチェックしてくれ、すべて「PASS」するとATSに対応されています。どの項目がATSの条件を満たせていないか教えてくれるので便利。

ATS対応の進め方

最初に述べましたが、上記のような設定にしないと来年以降審査に通らないという話なので、現状利用しているATSの設定で年内は審査に出すことができます。その設定のまま来年になると突然API通信ができないということはないのでご安心を。あくまでAppleの審査が通るかどうかということですね。
上記の設定はAPIがATSに準拠しおわってからの対応となります。できれば年内、遅くても年始にはAPIがATSを満たし、新しいATSの設定をアプリ側で行えばよいかと思われます。

3.Push通知(User Notification Framework)

iOS10になり、User Notifications Frameworkという新しいフレームワークが登場します。Notificationの管理の仕方が少し変わったり、今までより多機能なNotificationの作成が可能となります。
iOS10からはNotificationにタイトル、サブタイトル、本文の3種類のコンテンツを表示できるようになり、より多くの情報を詰め込めます。
f:id:Kamekiti:20160911191519p:plain
さらに、過去のNotificationを書き換えることも可能です。
f:id:Kamekiti:20160911191205g:plain
以前に送信された「Score Update」というNotificationの本文が更新され、新着Notificationとして再表示されています。また、タップすると画像やカレンダーを表示したり、Notification内でより多くのアクションをとることも可能です。画像はGIFアニメも対応だそうですよ。
f:id:Kamekiti:20160911191901p:plain
Notificationを多用しているアプリを運営している方は、User Notifications Frameworkでより多機能なNotificationを実装してみてはいかがでしょうか。

4.ウィジェット

f:id:Kamekiti:20160912004516p:plain
iOS8から登場した「App Extensions」です。「ウィジェット」と呼ばれており、iOS10では下記の場所に表示されます。

  • ロック画面を左にスワイプして出てくる画面
  • ホーム画面の一番左端
  • 通知センターの左側

iOS10からロック解除が「左にスワイプ」ではなく、「ホームボタンクリック」になりました。いつものようにロック解除しようとすると、ウィジェット一覧が表示されます。上記のように、いたるところでウィジェットを見かけることになります。特にロック画面からロック解除せずに閲覧できるので、利用するユーザは多くなりそうですね。ウィジェットを実装することで、より自分のアプリの露出を増やすこともできますし、便利な機能を実装すればアプリの利用率も高まるでしょう。次に紹介するMapItemとの相性もよいです。
ちなみにAppleウィジェット用のヒューマンインタフェースガイドラインを用意しています。実装する前に目を通しておくとよいかと。
Widgets - Extensions - iOS Human Interface Guidelines

5.MapItem

iOS9でCore Spotlightというフレームワークが登場しSpotlightが強化されました。iOS10でNSUserActivity内に「mapItem」という項目が追加され、位置情報をアプリ間で受け渡しすることが可能になります。
ユーザがレストランアプリでレストラン情報を開き、地図アプリでその場所を検索したいとしましょう。現状だとレストランアプリ内で住所をコピーして地図アプリでペースト→検索をしますが、これは少々煩わしい作業ですよね。
f:id:Kamekiti:20160912011539g:plain
そこで「mapItem」です。「mapItem」に位置情報を入れておけば、地図アプリがその情報を読み取り、ユーザにレストランの場所を提案させることができます。
f:id:Kamekiti:20160912011901p:plain
地図アプリに遷移する前にHand Offでルート探索を起動させることもできるようです。

実装方法

具体的な実装方法は以下のようになります。ViewController内の記述例です。

let coordinate = CLLocationCoordinate2DMake(35.0000, 135.0000);
if #available(iOS 10.0, *) {
    let placemark = MKPlacemark(coordinate: coordinate)
    userActivity = NSUserActivity.init(activityType: "group.com.hogehoge")
    userActivity?.mapItem = MKMapItem(placemark: placemark)
    userActivity?.isEligibleForHandoff = true
    userActivity?.isEligibleForSearch = true
    userActivity?.isEligibleForPublicIndexing = true
    userActivity?.webpageURL = URL(string: "https://hogehoge.com/fuga")
    
    let a = CSSearchableItemAttributeSet(itemContentType: "hoge")
    a.title = "レストランの名前"
    a.contentDescription = "レストランの詳細情報"
    a.namedLocation = "レストランの場所"
    a.subThoroughfare = "レストランの住所1"
    a.thoroughfare = "レストランの住所2"
    a.city = "レストランの都道府県"
    a.country = "レストランの国名"
    a.latitude = 35.0000
    a.longitude = 135.0000
    a.phoneNumbers = 09012345678
    a.supportsPhoneCall = true
    a.supportsNavigation = true
    a.thumbnailURL = URL(string: "https://image.hogehoge.com/fuga.jpg");
    a.keywords = ["hogehoge", "レストラン"];
    
    userActivity?.contentAttributeSet = a;
    userActivity?.becomeCurrent()
}

こうしておくと、becomeCurrent()された後、地図アプリや地図のウィジェットに上記の位置情報が表示されるようになりますよ。ちょっとおせっかいな機能だと思うかもしれませんが、位置情報を扱うアプリを運営している方は一度検討してみてはいかがでしょうか。

6.デザイン崩れ、Warning解消、その他新機能

ちょっとしたデザイン崩れ

iOS6 → iOS7のようなひどいデザイン崩れはないと思いますが、文字が見きれてしまったりすることがあります。Auto Layoutで対応するのもよし、UILabelなら最小サイズ(minimumScaleFactor)を設定してあげるのも手です。

非推奨のクラスを置き換える

iOS10でビルドすることでDeprecatedになった部分がWarningとして出てきます。後回しにするといつになってもやらないので、今のうちに全部解消しておきましょう。

その他新機能

NotificationやMapItemなど、先ほど紹介したもの以外にもiOS10で登場した新機能はたくさんあります。目玉としてはSiriですかね。「Intents」という名前のフレームワークとして提供されています。
Intents | Apple Developer Documentation
新機能を実装しておくと、App Storeの特集に挙げられることもあるので、余力のある方はぜひ。

Swift 3.0に対応する

f:id:Kamekiti:20160912014632p:plain

Swift 3.0

Swiftを扱っているプロジェクトをXcode 8で開くと、「Swift 2.3もしくはSwift 3.0にコンバートしよう!」と出ます。コンバートしないとにっちもさっちもいかないので、まずは2.3もしくは3.0に対応させるところから始めなければなりません。おすすめはSwift 3.0です。どうせやるなら3.0へあげちゃいましょう。一部のライブラリは2.3には対応せず3.0のみに対応しています。
Xcode 8 に自動コンバート機能があるので、自分のプロジェクトをSwift 3.0へ対応させるのはそんなに時間はかからないはず。「Edit」→「Convert」→「Convert To Current Swift Syntax」から行えます。
コンバートは自分のプロジェクトのみを対象にしましょう。(後述しますが、ライブラリは大元のリポジトリで対応されているはずなので。)

Swift 3.0を対応するときの注意点

コンバートするとほぼ全ファイルに差分がでますので、Swift 3.0対応する際は他の作業を一旦中止したほうがよいです
現在のSwiftの仕様上、バージョンが違うSwiftで書かれた別のプロジェクトを混在させることができません。したがって、ライブラリも同時にSwift 3.0へ対応させなければなりません。有名どころのライブラリはすでに「swift3」などSwift 3.0対応させたブランチが切られているので、そちらを使うようにしましょう。
Swift 3.0対応が完了したら、ようやく上記のiOS10対応が始められます。iOS10対応よりもSwift 3.0対応のほうがおおがかりかも……。

(おまけ)Xcode8について

f:id:Kamekiti:20160912014527p:plain
Xcode 8 beta を使っていて新しくなったと思われる点をいくつか紹介します。

フォントが変わった

ソースコードのフォントが変わってます。Sanfranciscoでしょうか。

プラグインが動かない

Xcodeプラグインを入れられている方、動かなくなります。無念。回避策があるようですので下記をご参考ください。
Xcode Editor Extension と Xcode8 で Plugin が動かなくなったことについて発表してきました - NANAIRO

Size Classesがわかりやすくなった

iOS8から登場したSize Classesという概念があります。画面の形状によってデザインを出し分けようというもの。今までCompactだのRegularだの分かりづらい表現になっていたものが、実際のデバイスの形状が表示されるようになり理解しやすくなりました

メニューから「Project」がなくなった

「Derived Data」というiOSアプリ開発者なら一度は耳にしたことがあるディレクトリが存在します。突然ビルドがうまくいかなくなったときに、このディレクトリを消してあげるとビルドが成功することがあります。
nsblogger.hatenablog.com

個人的にこのディレクトリを消すことが多く、Xcode 7では「Window」→「Project」→「Derived Data」から辿れるのですが、Xcode 8では「Project」がメニューから消えました。どこに行ったんだろうと探したんですが、見当たりませんでした。

Xcodeの設定の「Locations」内にDerived Dataのパスが書かれており、そこからFinderでディレクトリを開くことができます。Finderで「Derived Data」をまるごと消すことで今は対応してます。

おわりに

iOS10やSwift 3.0の対応を進めつつ、新型Mac Book Proの発表を待ちましょう!