App Extension 上で UINavigationBar.appearance() が HostApp から影響を受ける問題を回避する

ちょっとマニアックな情報ですが、ドキュメントのどこにも書かれていないとっておきのネタです。

Action Extension、またはShare Extensionを開発していて、UINavigationBarを利用しているという方はぜひご覧ください。


この記事は Cocoa Advent Calendar 2016 6日目の記事です。昨日の記事はnaochi___さんの[iOS] Xibを使って自前のダイアログを作るでした。

この記事では、id:kaniza さんの4日目の記事 第 70 回 Cocoa 勉強会関西に行ってきた - kanizaのブログ で触れられている、 第70回 Cocoa勉強会関西 で私が発表した内容について書きます。

"App Extension 上で UINavigationBar.appearance() が HostApp の影響を受ける問題" とは?

このような画面のAction Extensionを作成したとします。以降このTargetを"Action" Extensionと呼びます。

f:id:niwatako:20161204190651j:plain

NavigationBarのBar Tintがオレンジに、DoneボタンのTintが白になっています。

f:id:niwatako:20161204190655j:plain

予定では、このエクステンションを起動するとこのような画面になるはずです。ここで見えているオレンジ色のNavigationBarがこの問題の主役です。

f:id:niwatako:20161204190658j:plain

実際に起動するとどうなるでしょうか。Safari上で試してみます。共有ボタンから開いたアクションシートで今作成した "Action" Extensionを開きます。すると設定通りの画面が表示されます。

f:id:niwatako:20161204190702j:plain

同じことをPocketというアプリの上でやってみます。共有ボタンから "次を使用して共有:" を選んで開いたアクションシートで、"Action" Extensionを開きます。そうすると今度は、NavigationBarが意図した色になっていません。

f:id:niwatako:20161204190705j:plain

これが "AppExtension上でUINavigationBar.appearance()がHostAppの影響を受ける問題" です。

何が原因か

原因は UINavigationBar.appearance() 周りにあります。

Pocket上でNavigationBarが白くなってしまったのは、Pocketが自身のアプリ上のNavigationBarの見た目をカスタマイズするために、UINavigationBar.appearance().barTintColorを白に設定しているため、と考えられます。

f:id:niwatako:20161204190708j:plain

試しにUINavigationBar.appearance().barTintColorを赤にするアプリを自作し、そのアプリからExtensionを起動すると、今度はNavigationBarが赤くなります。

UIAppearanceの設定は、そのアプリ上で利用するApp Extensionにまで影響を及ぼすのです。

f:id:niwatako:20161204190712j:plain

この問題にどうやって対応するのか

この問題を防ぐ方法は、密かにiOS10から利用できるようになっています。App ExtensionのInfo.plistに設定することが出来る NSExtensionOverridesHostUIAppearance キーです。 NSExtensionのDictionaryの中にBooleanでYESを設定します。

f:id:niwatako:20161204190716j:plain

これを設定した "Action" Extensionをもう一度Pocket上で起動してみます。すると、今度は意図した通りのカラーでNavigationBarが表示されました。

f:id:niwatako:20161204190719j:plain

この NSExtensionOverridesHostUIAppearance については、ドキュメントには書かれていません。しかしiOS10から機能します。また、このキーを利用してもAppStoreの審査で問題になることはありません。

UINavigationBar.appearance()がHostAppの影響を受ける問題はShare Extensionでも発生します。Extension上でUINavigationBarを利用している場合は、Info.plistに NSExtensionOverridesHostUIAppearance を追加しておくと良いと思います。

参考

ここのIssueでも言及されています。調査中ステータスのままですが。

github.com

インターネット上で NSExtensionOverridesHostUIAppearance に言及しているサイトはこの記事が2番目のはず...