Takahiro Octopress Blog

-1から始める情弱プログラミング

iPhoneX時代のNetwork Indicatorについて

はじめに

これまでのiPhone8/8Plus/SEなどでは通信中に下図のような Network Indicator が表示されていました。

従来のNetwork Indicator

しかしながら、iPhoneX系統では、下図のように Network Indicator の表示がなくなってしまいました。

iPhoneX系統ではNetwork Indicatorがない

今回は、この Network Indicator に焦点を当てたいと思います。

iPhoneX時代のNetwork Indicatorは?

『iPhoneXではステータスバーにNetwork Indicatorを表示しない』方針を取ったのは、
紛れもなくAppleなわけですから、何らかの他の方法でユーザに通信中であることを伝えていると思われます。

そこで幾つかのApple標準アプリを見ていきたいと思います。

まず、App Store を見てみると、

  • 読み込まれるまでは真っ白
  • 読み込みの早い文字を先に表示し、画像系は枠だけ表示する

ようになっていました。
Apple標準アプリ以外でも、上記手法を取り入れているアプリは結構多そうでした。

アプリの読み込み例:Placeholder

続いて、Safari を見てみると、

  • アドレスバー下にプログレスバーを表示する

ようになっていました。

アプリの読み込み例:ProgressBar

iPhoneXで従来型Network Indicatorを表示するためには?

このように現在のアプリでは、従来のような密やかなNetwork Indicatorよりも、
この先にどんな画面が表示されるか想像させたり、
あとどの程度で読み込みが終わるのか進捗を伝えたりなど、
より具体性を伝達するように変わってきている気がします。

しかしながら、従来のような密やかな通信状態の伝達が完全に不要になったかと言うと、それはアプリ仕様に依存するところでしょう。
では、そんなアプリを開発するときに、どうすればよいかと言うと、
FTLinearActivityIndicatorを利用してみるのも一つの手かなと思います。

FTLinearActivityIndicatorで密やかなNetworkIndicatorを出すためには

非常に簡単に実装ができます。

まずは、Indicatorconfigureを実行します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// AppDelegate.swift
import UIKit
import FTLinearActivityIndicator

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    ...
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
          UIApplication.configureLinearNetworkActivityIndicatorIfNeeded()
        return true
    }
    ...
}

続いて、必要なタイミングで、
UIApplication.shared.isNetworkActivityIndicatorVisibletrueにするだけです。
※非表示にする場合はfalseにセットし直すだけです。

FTLinearActivityIndicatorはどんなことをやっているのか

まず、ライブラリの構成としては、

1
2
3
FTLinearActivityIndicator
  ├── FTLinearActivityIndicator.swift
  └── UIApplication+LinearNetworkActivityIndicator.swift

となっています。
FTLinearActivityIndicator.swiftはクラス名通り、NetworkIndicatorの表現やアニメーション系のメソッドを提供しています。

一方で、UIApplication+LinearNetworkActivityIndicator.swiftは、

  • UIApplicationの拡張
  • UIViewControllerの拡張
  • DispatchQueueの拡張

と3つに分かれており、FTLinearActivityIndicatorを制御するためのメソッドが用意されています。

具体的に実装の中身を見ていきます。
先程のAppDelegatedidFinishLaunchingWithOptionsで実行していたconfigureLinearNetworkActivityIndicatorIfNeeded()内の処理は下記のようになっています。

1
2
3
4
5
6
7
8
9
10
@objc final public class func configureLinearNetworkActivityIndicatorIfNeeded() {
    if #available(iOS 11.0, *) {
          // detect iPhone X
          if let window = shared.windows.first, window.safeAreaInsets.bottom > 0.0 {
              if UIDevice.current.userInterfaceIdiom != .pad {
                  configureLinearNetworkActivityIndicator()
              }
          }
      }
}

これを見ると、ライブラリ側でiPhoneX系端末なのか/iPadではない端末なのかを判別してくれていることがわかります。
既に全画面表示の iPad が世に出ているため、作成者にPullRequestを送るチャンスかもしれないですね!

続いて、もう少し深ぼると…
上記メソッド内で実行しているconfigureLinearNetworkActivityIndicator()の中身は、

1
2
3
4
5
6
7
8
9
10
11
12
class func configureLinearNetworkActivityIndicator() {
    // 説明(1)
      DispatchQueue.once {
      // 説明(2)
          let originalSelector = #selector(setter: UIApplication.isNetworkActivityIndicatorVisible)
          let swizzledSelector = #selector(ft_setNetworkActivityIndicatorVisible(visible:))
          let originalMethod = class_getInstanceMethod(self, originalSelector)
          let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
          method_exchangeImplementations(originalMethod!, swizzledMethod!)
      }
      UIViewController.configureLinearNetworkActivityIndicator()
}

になっています。

重要ポイントを説明すると、

  • 説明(1)
    • DispatchQueue.onceの内部実装を見ると、ファイル名/メソッド名/行数からトークンを作成し、実行回数を管理しています
    • これにより、誤って無駄に重複実行したとしても、防いでくれるようになっているようです
  • 説明(2)
    • ライブラリの存在を意識する必要なく機能を利用できるようにmethod_exchangeImplementationsを使っています  
    • class_getInstanceMethodでメソッド情報を取得します
    • method_exchangeImplementationsでメソッドの実装を入れ替えます
    • method_exchangeImplementationsによりUIApplication.isNetworkActivityIndicatorVisibleが実行されたら、ft_setNetworkActivityIndicatorVisible(visible:)が呼び出されるという状況を作ることができます

まとめ

以上をまとめます。

  • iPhoneX系端末では従来のNetworkIndicatorはデフォルト、表示されない
  • 従来型の通信表現を取り入れているアプリは最近少ないかもしれない
  • 従来型の通信表現を利用する場合はFTLinearActivityIndicatorがオススメ

ということで本日はここまで。

Comments