こんにちは、メディア事業本部の @masuP9(ますぴー)こと桝田です。最近はメディア事業本部のサービス、特にABEMAとAmebaのアクセシビリティ向上に取り組んでいます。この記事では、ABEMAのiOSアプリにおいてアクセシビリティ改善をリリースしましたので、それに至る取り組みをお伝えします。

目次

  1. 個人から組織へ – ABEMA Accessibility Taskforceの立ち上げ
  2. 実際のABEMA iOS アプリの改善と技術的解説
  3. 改善したUIの検証 – ユーザーによる検証
  4. 品質の再現性を高める – conte 実装要件への追加
  5. これから

個人から組織へ – ABEMA Accessibility Taskforceの立ち上げ

ABEMAでは「個人の能力の限界がデザインの限界になっている」という課題を解決するために、デザインされてないものをデザインする仕組みとしてデザインシステム「conte」を作っています。conteについて詳しくは、conte – ABEMA’s Design System を見てください。

アクセシビリティも conte が解決しようとしている課題と同じように、個人での取り組みは行われていましたが個人の能力の限界がアクセシビリティの限界となっていて、プロセスや仕組みがデザインされていないものでした。

それを解決するべく、conte の取り組みの一環で「アクセシビリティ向上のためのプロセスや文化を作る」を目的とした ABEMA Accessibility Taskforce(以下タスクフォース)を立ち上げました。

幸いタスクフォースには立ち上げ時からウェブフロントエンドエンジニアとデザイナーが参画してくれました。この2つのチームには従来よりアクセシビリティに意識的に取り組んでいるメンバーがいたためです。

参加してくれているメンバーの職能、また私のこれまでの経験から取り組みやすいプロダクトのUIを中心に進めていくこととなりました。ただプロダクトのUIを改善するにあたりABEMAにおいて重要なiOS/Androidのネイティブアプリエンジニアがメンバーにいないのはやはり飛車角落ちです。

そこでネイティブアプリエンジニアにもアクセシビリティ向上へ意欲的になってもらいタスクフォースに参加してもらうための施策を考えました。

アクセシビリティ向上をモチベート – エッジユーザーデモ

これまでの私の経験ではアクセシビリティ向上へモチベーションを持つきっかけには、高いアクセシビリティを必要とする当事者が利用しているシーンを見た経験というものが非常に多く、また大きなインパクトを持って受け入れられることを知っていました。

ならば手っ取り早く実際に使っているところを見てもらおう!と、株式会社コンセント インクルーシブデザインチームのアクセシビリティエンジニアで自身も視覚障害当事者である辻さんに協力いただき、ABEMAのiOSアプリを視覚障害当事者がどのように使っているかというデモを企画しました。

辻さんにお願いした理由は、辻さんがABEMAのユーザーであることを以前から知っていたからです。単に視覚障害当事者、というだけでなく自分たちのプロダクトのユーザーの一人である、ということは取り組むモチベーションに大きく影響します。このデザイン、実装で辻さんは使えるのかな、そんな想起を得てもらうにも実際のユーザーであることはとても大事でした。

ZOOMを利用したオンラインによる操作デモの様子

このデモはオンラインで行いました。当初はオンラインで簡易的なユーザビリティテストを実施しょうと思ったのですが、スクリーンリーダーの音声と手元の操作、解説を届ける配信環境を用意するのが難しく、事前に収録したデモ動画を解説するという方法にしました。結果的に私も辻さんも余裕を持って解説できてよかったように感じます。

デモの効果

デモには社内の多くのメンバーが参加してくれました。目の見えないユーザーが合成音声のナビゲーションを頼りに自分たちがデザインし開発したプロダクトを使っている、その初めて見る光景に、驚嘆と尊敬と懺悔が入り混じった反応を得ることができ、小さくないインパクトを残せたのではないかと考えています。

その証左にデモを実施した直後、ネイティブアプリチームにタスクフォース参加の呼びかけをしたところ、すぐにiOS/Androidともに一人ずつ開発者が手を挙げてくれました。その後も自ら参加したいと言ってくれるメンバーが増え、プロダクトのUIの改善を始められる体制が整いました。

まずはこのデモにおいて実際に課題として上げられた点、またAppStoreに寄せられたレビューで指摘いただいている点から改善をスタートしました。

次の章から技術的な解説をABEMA iOSアプリエンジニアの井原さんに解説してもらいます。

実際のABEMA iOS アプリの改善と技術的解説

「ABEMA」のiOSエンジニアの井原(@nonchalant0303)です。この章ではiOSアプリの実装について解説します。

メニュー/設定

AppStoreのレビューに記載されていて発覚したのですが、テレビやビデオ、設定に遷移する「メニュー画面」とアカウントや通信量などの様々な設定をする「設定画面」のVoiceOver対応がされていないという問題がありました。事象としてはどちらの画面もVoiceOver有効時にフォーカスは当たるものの合成音声による読み上げがされないというものでした。しかし、それらの原因は異なるものでした。

設定

2020年9月現在、ABEMAの対応OSはiOS11以上ですが、より古いOSをサポートしていた時にそのOSで特定の画面の描画速度が遅いという問題がありました。設定画面もそのうちの1つでした。その改善のため、UILabelではなくAttributedLabelというライブラリを採用しました。このライブラリはUILabelを活用するのではなく、CALayerに文字の形を直接描くことにより高速化を実現していました。この仕組みのため、通常VoiceOver有効時にはUILabelなどに自動で紐付いているaccessibilityLabelを読み上げてくれるのですが、そのプロパティの値が存在しないため読み上げられないという問題が発生していました。

このライブラリは古いOSの対応のためだったので、AttributedLabelではなくUILabelを活用することで設定画面のVoiceOver対応が実現できました。

メニュー

メニュー画面で読み上げられない問題は、表示のアニメーション周りが原因でした。メニュー画面を開く際、下から上がってくるようなアニメーションで表示されるのですが、合わせてテキストのopacityも0から1に変化するようなアニメーションがあります。こちらのアニメーションはCABasicAnimationを用いているのですが、CABasicAnimationには終了時に値を設定しないと画面上の表示とメモリ上のオブジェクトの値がずれるという事象がありました。この事象により、VoiceOver有効時にViewコンポーネントを読み取る際にopacityが0のものは描画されていないと見なされ、読み上げされないという問題が発生していました。

以下のコードのように、アニメーションが終了した際に、Viewコンポーネントにアニメーションの終了地点の値をセットして画面上の表示とメモリ上のオブジェクトの値を揃えることでVoiceOver対応が実現できました。

import UIKit
import PlaygroundSupport

class View: UIView {

    let view = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 10))

    override init(frame: CGRect) {
        super.init(frame: frame)

        view.backgroundColor = .blue
        view.layer.opacity = 0
        addSubview(view)

        let opacityAnimation = CABasicAnimation(keyPath: "opacity")
        opacityAnimation.duration = 1.0
        opacityAnimation.fillMode = .forwards
        opacityAnimation.fromValue = 0
        opacityAnimation.toValue = 1
        opacityAnimation.isRemovedOnCompletion = false

        CATransaction.begin()

        CATransaction.setCompletionBlock {
            // 画面には描画されているが「opactity = 0.0」
            print("didFinish: \(self.view.layer.opacity)")

            // アニメーションの終了地点の値をセットする必要がある
            self.view.layer.opacity = 1.0
        }

        view.layer.add(opacityAnimation, forKey: "animation")

        CATransaction.commit()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

PlaygroundPage.current.liveView = View(frame: CGRect(x: 0, y: 0, width: 100, height: 100))

テレビチャンネル選択UI

ABEMAのテレビ画面において、上部にチャンネルを選択できるスクロール可能なUIがあります。このUIは各チャンネルの情報が画像で表現されており、テキスト情報がなくVoiceOver有効時に合成音声で読み上げる対象の文字列がありませんでした。

そのためVoiceOverユーザーはチャンネルを切り替えるのに一度VoiceOverをオフにし、スワイプ操作でチャンネルを切り替えていました。そのため、現在どのチャンネルが選択されているかが分からず、再生されているコンテンツ(主に音声のみ)で判断するしかありませんでした。

ABEMA iOS アプリのチャンネル選択UI。画面の一番上、動画のすぐ上にある。

各チャンネルの情報にチャンネル名があるため、それをaccessibilityLabelで設定してチャンネル名を読み上げるようにしました。また、上部のチャンネル選択UIは各チャンネルが画像として表示されているので、VoiceOverユーザーはクリックが可能だと気づかない可能性があります。

そのため、画像のaccessibilityTraitsをボタンに設定して、ユーザーにクリックが可能であることを気づけるようにしました。さらに、現在選択されているチャンネルの画像のaccessibilityTraitsにはボタンだけではなく選択済みの情報も含めて、よりユーザーが現在の状態を把握しやすくしました。これらの設定をすることによりVoiceOver対応が実現できました。

改善したUIの検証 – ユーザーによる検証

ここからまた桝田に戻って実装後の流れについてお話します。

今回、改善したテレビチャンネル選択UIの改善について、デモをしていただいたコンセントさんに再びご協力いただき、実際に改善したUIについて検証を行いました。実際に改善した実装がユーザーにとって役立つものであるかどうか検証することで取り組む意義を強化し、さらに取り組むべき次の課題を発見できます。

今回は特定のユーザーにのみ機能をリリースできる機能を用いて辻さんが利用している端末にのみテレビチャンネル選択UIの改善をリリースして検証いただきました。結果、課題はあるが、VoiceOverでチャンネルが切り替えられ、選択しているチャンネルを知ることができ、使えるものであると判断し全ユーザーに向けてリリースをしています。

その他に見つかった課題 – 名前をつける

今回、検証してもらった「テレビチャンネル選択UI」に関しては、実は正式な名称が決まっていません。このエリアにスクリーンリーダーの機能を利用してジャンプできたらいいね、そうするとこのエリアの正式名称を決めないと…という話から発覚しました。

名前が無いせいで、領域を特定するコストがかかってしまいます。それは実際にスクリーンリーダーユーザーだけが不便なのでなく、今回のような外部の方とUIについてコミュニケーションするときや、カスタマーサポート、開発者間のやりとり全てに少しずつ負担がかかります。ちゃんとした名前があること、それはアクセスするための基本だと改めて認識できました。

品質の再現性を高める – conte 実装要件への追加

無事改善をリリースできたわけですが、これまでの改善も一度行っただけでは、また同じような問題が産まれますし特定の人しか改善できないなど、アクセシビリティ向上をデザインできているとは言えません。そのため改善で実施したことを再現できるようにするため、改善で行った「代替テキストを付与する」や「UIに名前をつける」などを実装要件としてまとめています。

これらはiOSだけでなくデザイン、ウェブ、Androidも同じ実装要件を参照しますので、iOSで行われた改善がAndroidでも実施されるなど、職域をまたいだ効果が発揮されます。

これから

まずは小さな改善でも世に出すことができてホッとしていますが、ABEMAに寄せられている期待はもっともっと大きなものだと感じています。

今後も徐々に取り組みを大きくしていき、いずれはチーム横断、そして組織全体で取り組めるよう色々と考えていきたいと思っています。