Slide 1

Slide 1 text

App Store用スクリーンショットの自動生成をアラ ビア語対応してSwiftUIで実装してみた 生井智司 / ainame

Slide 2

Slide 2 text

自己紹介 生井智司/ Satoshi Namai / @ainame ● Senior iOS Engineer at Cookpad Ltd ● イギリス地方都市ブリストル在住 ● 今年からfastlane core contributor ○ Ruby 3 対応 ○ deliverの高速化・改善など...

Slide 3

Slide 3 text

レシピサービス クックパッドの海外展開

Slide 4

Slide 4 text

海外版Cookpad iOSアプリ ● 日本国内版とは別のコードベース/Bundle ID ● 日本のストア以外へ公開 ● アプリ内言語で30言語対応 (日本語除く) ● App Store上のメタデータは22言語対応(同上) * 2021年8月末現在

Slide 5

Slide 5 text

発表内容 ● App Store スクリーンショットとは ● i18nでの運用について ● App Storeスクリーンショットの自動生成 ● 既存ツールの課題 ● SwiftUIでスクリーンショット自動生成 ○ SwiftUIを用いた画像の生成 ○ TestPlanを用いたUIテスト ○ CLI化〜運用

Slide 6

Slide 6 text

App Store スクリーンショットとは https://developer.apple.com/app-store/product-page/

Slide 7

Slide 7 text

App Store スクリーンショットとは https://developer.apple.com/app-store/product-page/

Slide 8

Slide 8 text

App Store スクリーンショットとは ● アプリの体験を視覚的に伝える手段 ● 各言語の画面サイズ毎に各10枚まで ● アプリの申請の際の審査の対象 ● 対応デバイスごとに以下の画面サイズ向けの物が必要 ○ iPhone - 6.5inch, 5.5inch ○ iPad - iPad Pro 12.9 inchの2nd genと4th gen

Slide 9

Slide 9 text

App Store スクリーンショットとは 2.3.3 Screenshots should show the app in use, and not merely the title art, login page, or splash screen. They may also include text and image overlays (e.g. to demonstrate input mechanisms, such as an animated touch point or Apple Pencil) and show extended functionality on device, such as Touch Bar. (意訳)スクリーンショットは使用中のアプリを見せべき。テキストや画 像のオーバーレイで、使い方を説明したりTouch Barなどのデバイス の機能の説明もしても良い https://developer.apple.com/app-store/review/guidelines/

Slide 10

Slide 10 text

App Store スクリーンショットとは 発表ではテキスト/背景画像/アプリ画面 を組み合わせたパターンを解説 またスクリーンショット => スクショと略して、 App Store スクショ、アプリ画面スクショのように表記する

Slide 11

Slide 11 text

i18nでの運用について ● i18n = internationalization (国際化) ● 以下の対応が必要となる ○ アプリ内のテキストの翻訳 ○ App Storeスクショ上のテキストの翻訳 ○ アプリ画面スクショ用のアプリ内コンテンツの準備 アプリの翻訳だけでなくApp Storeスクショ専用の 翻訳/ローカライズの準備が必要

Slide 12

Slide 12 text

i18nでの運用について 運用上必要なスクリーンショットの枚数について考える ただしアプリはiPad対応済のユニバーサルアプリとする ● (PM・デザイナー)App Storeスクショで訴求する機能を考えデザインに落とし込む ○ 例:6枚分のデザインを考える ● (誰か)アプリ画面スクショを収集 ○ 6レイアウト x 4デバイス分 ○ iPhone 8 plus/12 Pro MaxとfiPad Pro 12.9 inch 2nd gen/4th gen ● (デザイナー)各画面のスクショのはめ込み+テキスト+背景画像の作成 ○ 6レイアウト x 4デバイス x 対応言語数(N)分

Slide 13

Slide 13 text

i18nでの運用について 6レイアウト x 4デバイス x N言語 枚分の作成が必要 ● N=1 -> 24枚 ● N=2 -> 48枚 ● …… ● N=22 -> 528枚 (弊社・2021年8月現在) ● …… ● N=39 -> 936枚(App Storeの対応言語数・2021年8月現在) 頻繁な更新が必要になると人々のリソースを圧迫

Slide 14

Slide 14 text

i18nでの運用について(弊社での問題) アプリ内コンテンツのローカライズ => 言語・地域の知識がないと難しい

Slide 15

Slide 15 text

i18nでの運用について(弊社での問題) アプリ内コンテンツのローカライズ => 言語・地域の知識がないと難しい

Slide 16

Slide 16 text

i18nでの運用について(弊社での問題) アプリ内コンテンツのローカライズ => 言語・地域の知識がないと難しい 弊社では各地域のコミュニティーマネージャーに依頼していた。 しかし全ての地域で必要なiOSデバイスを持っているわけでは ない🥲 そもそもアプリ画面のスクショが集まらない問題

Slide 17

Slide 17 text

i18nでの運用について(弊社での問題2) 一部の地域でデザインを完全外注したが、担当者のApp Store スクショに関する知識・経験がなく手戻りが発生 ● 画像が仕様に沿ってない(解像度、alphaチャンネルなど) ● 拡張子と画像フォーマットが不一致 (xxx.jpgだけど中身がpngなど) ● ステータスバーが中途半端(バッテリーが赤、キャリア名が残るなど) ● そもそもAndroid版の画面を使われる 自前のガイドラインを準備はしたがそれでも難しい

Slide 18

Slide 18 text

i18nでの運用について(まとめ) ● App Storeスクショ用の翻訳・コンテンツの準備が必要 ● 頻繁な更新が必要になると人々のリソースを圧迫 ● 多言語のアプリ画面のスクショを人手で集めるのが難しい ● 外注も大変 弊社では自動化への機運が高まった

Slide 19

Slide 19 text

App Storeスクリーンショットの自動生成 自動化していくアプローチが複数存在 ● UIテストでアプリ画面スクショを取る+画像の合成 ○ fastlaneのsnapshot(screengrab)とframeitが人気 ● 他にも撮影済みのアプリ画面スクショをはめこむだけのWebサイトや Sketch/Figmaプラグインなども => UIテスト+画像合成のパターンを紹介

Slide 20

Slide 20 text

App Storeスクリーンショットの自動生成 snapshot - ローカライズされたアプリのスクショをUIテストで撮 影して集めることが出来るテストランナー ● 並列実行をサポートしたりリトライも出来る ● ローディング中の撮影を回避出来るヘルパー ● ステータスバーの上書き (9:41の表示など)

Slide 21

Slide 21 text

https://docs.fastlane.tools/actions/snapshot/

Slide 22

Slide 22 text

App Storeスクリーンショットの自動生成 frameit - アプリ画面スクショをデバイスのフレームにはめ込む +テキスト+背景画像との合成が出来る ● 前処理されたデバイスフレーム画像 ● テキストの良い感じの配置・改行と フォントサイズの調整 ● .stringsファイルによる翻訳

Slide 23

Slide 23 text

https://docs.fastlane.tools/actions/frameit/

Slide 24

Slide 24 text

イメージ図 snapshot frameit https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/app-icon/

Slide 25

Slide 25 text

既存ツールの課題 (snapshot) snapshot/frameitを試したが実運用するための課題が散見される ● 言語数が多いと遅すぎる ○ 言語毎にシュミレーター向けの設定をしていて時間がかかってる ○ 4コアCPUだと3並列でしか実行できない (cpuコア数 - 1の並列数が設定される) ● 依存している技術が古いままなため現代のアプリの挙動に対応しきれていない ○ スクショを撮るタイミングを調整するために iOS13で廃止されたNetwork activity indicatorの監視処理を利用している ● リトライしても失敗し続ける場合、後にどこで失敗したかわからないので 一部の言語・環境特有のエラーが再現し続けた時にデバッグしづらい

Slide 26

Slide 26 text

既存ツールの課題 (frameit) snapshot/frameitを試したが実運用するための課題が散見される ● 画像の出力に利用されているImageMagick単体では アラビア文字の反転・リガチャー処理が対応できない

Slide 27

Slide 27 text

https://github.com/mpcabd/python-arabic-reshaper 素朴にアラビア語のテキストを CLIに渡した場合: 左右が反転されていない =デー タ順に左から右へ表示 入力の文字を無理やり反転 した場合: リガチャー(合字)が考慮され ていない データを反転・リガチャー分の code pointを修正: 正しい表記 ImageMagickでアラビア語を画像として出力する例

Slide 28

Slide 28 text

既存ツールの課題 (frameit) snapshot/frameitを試したが実運用するための課題が散見される ● 内部で画像の出力に利用されている ImageMagick単体では アラビア文字の反転・リガチャー (合字)処理が対応できない ● 入力の文字列に応じてフォントサイズを自動で調整するが、 翻訳テキストの長さが言語ごとに違いすぎて言語間で全く見た目が変わる (逆にフォントサイズを固定できない )

Slide 29

Slide 29 text

既存ツールの課題 (frameit) snapshot/frameitを試したが実運用するための課題が散見される ● 内部で画像の出力に利用されている ImageMagick単体では アラビア文字の反転・リガチャー (合字)処理が対応できない ● 入力の文字列に応じてフォントサイズを自動で調整するが、 翻訳テキストの長さが言語ごとに違いすぎて言語間で全く見た目が変わる (逆にフォントサイズを固定できない )

Slide 30

Slide 30 text

既存ツールの課題 (frameit) snapshot/frameitを試したが実運用するための課題が散見される ● 内部で画像の出力に利用されている ImageMagick単体では アラビア文字の反転・リガチャー (合字)処理が対応できない ● 入力の文字列に応じてフォントサイズを自動で調整するが、 翻訳テキストの長さが言語ごとに違いすぎて言語間で全く見た目が変わる (逆にフォントサイズを固定できない ) ● 全言語を正しくレンダリングするためには全言語分のフォントが必要

Slide 31

Slide 31 text

既存ツールの課題(まとめ) ● frameitでは弊社の要求を満たせなかった ● snapshotも痒いところに手が届かない でも自動化はしたい=> それぞれの代替を実装した 難しそうなframeitから考える

Slide 32

Slide 32 text

イメージ図 snapshot -> 何か1 frameit -> 何か2 https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/app-icon/ ImageMagickより 高級な何か... 試行錯誤しやすい テストランナー...

Slide 33

Slide 33 text

SwiftUIでスクショ自動生成 UIKit/AppKitで画像を生成すれば良いのでは? ● UIKitで普段アプリを作っていてアラビア語の表示は完璧 ● UIGraphicsImageRendererなどでUIViewの画像化は簡単 ● 実際にはCLIとしてmacOS上で実行したいのでAppKitを使ってみる ● NSView.bitmapImageRepForCachingDisplayで画像化可能

Slide 34

Slide 34 text

SwiftUIでスクショ自動生成 NSViewをPNGやJPEGなどのフォーマットに変換

Slide 35

Slide 35 text

SwiftUIでスクショ自動生成 ● AppKitとNSTextFieldとNSImageViewなどを 使えば画像生成いけそう ● でも(UIKitエンジニアには)AppKitは難しい😭😭😭

Slide 36

Slide 36 text

SwiftUIでスクショ自動生成 💡

Slide 37

Slide 37 text

SwiftUIでスクショ自動生成

Slide 38

Slide 38 text

SwiftUIでスクショ自動生成 SwiftUIならmacOSでもテキストの配置が簡単!

Slide 39

Slide 39 text

ViewにlayoutDirectionをセットすることでRTLも対応可能 NSHostingView経由で画像化出来る SwiftUIでスクショ自動生成

Slide 40

Slide 40 text

SwiftUIでスクショ自動生成 ViewにlayoutDirectionをセットすることでRTLも対応可能 NSHostingView経由で画像化出来る

Slide 41

Slide 41 text

SwiftUIでスクショ自動生成 アプリ画面スクショのフレーム埋め込みもSwiftUI ● fastlane/frameitの持つフレー ム画像を再利用 ● ZStackで2枚の画像を重ねるだ けでピッタリ埋まる(デバイスが 左右対称なため) ● iPad ProのみVolumeボタン分 のoffsetを調整

Slide 42

Slide 42 text

SwiftUIでスクショ自動生成 フレーム画像をpng化しNSImageとして全体のViewと合成

Slide 43

Slide 43 text

SwiftUIでスクショ自動生成 ● 背景色・画像もZStackで重ねるだけで実現 ● 複数枚のフレーム画像を重ねることも可

Slide 44

Slide 44 text

SwiftUIでスクショ自動生成 ● 背景色・画像もZStackで重ねるだけで実現 ● 複数枚のフレーム画像を重ねることも可

Slide 45

Slide 45 text

SwiftUIでスクショ自動生成 ● 背景色・画像もZStackで重ねるだけで実現 ● 複数枚のフレーム画像を重ねることも可 SwiftUIで実現できるレイアウトは何でも出来る!

Slide 46

Slide 46 text

SwiftUIでスクショ自動生成 SwiftUIをレンダリングエンジンとして利用するメリット ● アプリ開発と同じ感覚で作れるのでi18n対応しやすい ○ LTR/RTL、text wrapping、画像のリサイズ・合成何でも出来る ○ デフォでSystemフォントが使われ準備要らず ● 1つのViewで全スクリーンサイズ対応も可能 ● Previewを活用すればデバッグしやすい ● DSLなので可読性も高くてメンテしやすい

Slide 47

Slide 47 text

SwiftUIでスクショ自動生成 ainame/FrameKit App StoreスクショをSwiftUIのViewから生成するライブラリ ● SPMでインストールする ● ViewやLayoutの設定はSwiftで自分で定義 ● $ fastlane frameit download_frames のフレーム画像を再利用 ● 与えたデータに基づいてアプリ画面スクショのはめ込みと 画像の合成をやってくれる

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

AppStoreScreenshotView protocol

Slide 50

Slide 50 text

背景色 背景画像 フレーム済アプリ画面スクショ画像 テキスト * キーワード: 太文字で目立つやつ * タイトル: 短い機能の説明

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

pixel単位からmacOSで利用されるpointへ変換するヘルパー

Slide 53

Slide 53 text

固定フォントサイズ

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

先ほど定義したViewとLayout設定

Slide 56

Slide 56 text

出力先のファイルパス

Slide 57

Slide 57 text

SwiftUIでスクショ自動生成(まとめ1) ● frameitで対応してないRTL言語のためにSwiftUIを利用 ● SwiftUIで作ったViewは簡単に画像化出来るので、 画像生成のためのCLIツールへ利用可能 ● ainame/FrameKitはSwiftUIを活用したライブラリ ● アプリ開発の知識でスクショデザインを実装できる

Slide 58

Slide 58 text

SwiftUIでスクショ自動生成 どうせだからsnapshot相当の再実装も自前でやってみる Xcode 11から導入されたTest Plan + xcresult を利用 ● Test Plan - テスト条件をxctestplanファイルで一括管理 ○ 環境変数で言語ごとのアカウント情報などの管理が実現 ○ 特定のテスト条件を有効・無効が指定できる ● xcresult - XCTestのテスト結果、添付ファイルをまとめてくれる ○ xcresulltoolというCLIでデータを取得出来る ○ スクショを添付できる ○ どこでテストが失敗したかログが残る ○ 実行ごとの履歴が残るので便利

Slide 59

Slide 59 text

SwiftUIでスクショ自動生成 実装すべき機能/要件 ● iOSシュミレーターの準備 ○ 物理キーボードの無効化とステータスバーのオーバーライド ○ シュミレーターの事前起動 ● xctestplanの更新 ○ CLIで指定した言語のテスト条件のみを有効にする ● xcodebuildによるテスト実行 ○ CLIで指定したデバイスのみをdestinationに追加する ○ 再実行する際にbuildをskip出来るようにする ● xcresultからスクリーンショットの抽出

Slide 60

Slide 60 text

SwiftUIでスクショ自動生成 iOSシュミレーターの準備

Slide 61

Slide 61 text

xctestplanの更新 ● 中身がJSONなのでテスト条件は Encodableなモデルで生成可能 ● コマンドラインオプションに 応じて値を動的に変える SwiftUIでスクショ自動生成

Slide 62

Slide 62 text

SwiftUIでスクショ自動生成 xctestplanの更新 ● 中身がJSONなのでテスト条件は Encodableなモデルで生成可能 ● コマンドラインオプションに 応じて値を動的に変える UUID

Slide 63

Slide 63 text

SwiftUIでスクショ自動生成 xctestplanの更新 ● 中身がJSONなのでテスト条件は Encodableなモデルで生成可能 ● コマンドラインオプションに 応じて値を動的に変える 環境変数の設定

Slide 64

Slide 64 text

SwiftUIでスクショ自動生成 xctestplanの更新 ● 中身がJSONなのでテスト条件は Encodableなモデルで生成可能 ● コマンドラインオプションに 応じて値を動的に変える 対象の言語・地域の設定

Slide 65

Slide 65 text

SwiftUIでスクショ自動生成 xctestplanの更新 ● 中身がJSONなのでテスト条件は Encodableなモデルで生成可能 ● コマンドラインオプションに 応じて値を動的に変える ● CLIから一部のロケールのみの テストを実行するために利用 有効・無効の切り替え

Slide 66

Slide 66 text

SwiftUIでスクショ自動生成 xcodebuildによるテスト実行 ● -resultBundlePathで.xcresultファイルの出力先を指定 ● -destinationで先ほど作ったシュミレーターを指定

Slide 67

Slide 67 text

SwiftUIでスクショ自動生成 xcodebuildによるテスト実行 ● -resultBundlePathで.xcresultファイルの出力先を指定 ● -destinationで先ほど作ったシュミレーターを指定 ○ 複数指定すると並列に実行してくれる

Slide 68

Slide 68 text

SwiftUIでスクショ自動生成 xcresultからスクリーンショットの抽出 ● Swift製のCLI ChargePoint/xcparse をmint経由で インストールして利用

Slide 69

Slide 69 text

SwiftUIでスクショ自動生成 紹介したコマンドなどを呼び出すCLIをSwiftで実装 ● apple/swift-argument-parser コマンドのオプションの解析に利用 ● ainame/FrameKit も内部で直接利用しているので 最終的には画像の生成まで行っている

Slide 70

Slide 70 text

YouTube Demo動画

Slide 71

Slide 71 text

SwiftUIでスクショ自動生成(まとめ2) ● SPMプロジェクトとしてTestPlanとxcresultファイルを利用しsnapshot相 当のテストランナーとなるCLIツールを構築 ● ほとんどの処理は外部のコマンドの呼び出しで完結 ● TestPlan(.xctestplan)はJSONなので簡単にコードで制御出来る ● UIテストの並列実行はデバイスごとの並列化はお手軽に出来る

Slide 72

Slide 72 text

SwiftUIでスクショ自動生成 実際に運用してみた 1. デザイナーとApp Storeスクショのデザインをすり合わせ 2. SwiftUIでApp Storeスクショのレイアウトを実装 3. 翻訳管理ツール上でスクショ内のテキストの翻訳を 各地のコミュニティーマネージャーに依頼 4. 自作ツールの実行 5. 完成したスクショを各コミュニティーマネージャーに確認 6. fastlane/deliverでApp Storeへ反映

Slide 73

Slide 73 text

SwiftUIでスクショ自動生成 Pros ● 2年弱更新してなかった状態から2、3ヶ月に1度の更新に! ● 一度デザイン・翻訳などが決まればあとはスクリプトを実行するだけでス クショの更新が可能で楽 ● 生成した画像のフォーマットは必ず仕様通りなので手戻り無し Cons ● アプリUIの変更ごとにUIテストも追従していくのはそこそこ大変 ● 各種設定値までSwiftで書いているのでCLIツールそのもののコンパイ ルが修正ごとに必要になっていてポータビリティが低すぎる

Slide 74

Slide 74 text

Make everyday cooking fun! ご静聴ありがとうございました

Slide 75

Slide 75 text

想定Q&A Q: CIで実行しないのか A: 難しそう(翻訳依存でUIテストが落ちることがある)+ 毎リ リース更新のニーズはないのでやってない Q: 実行時間どれぐらい? A: MacBook Pro 2019 16-inch (2.4 Ghz - 8 cores)で40分ぐら いで20言語分終わるけどUIテストの実行内容依存 (APIのスタブを作るためUIテストを2回走らせてる)

Slide 76

Slide 76 text

想定Q&A Q: 表示コンテンツどうしているの? A: APIのスタブを用いて表示されるコンテンツは権利上OKなも のだけを表示するようにしてる Q: UIテストは不安定じゃない? A: UIテスト専任のエンジニアが頑張ってくれてある程度安定的 に書けている。UIテストの不安定さ以上に言語毎の環境差によ るエラーが多い。

Slide 77

Slide 77 text

OSS化について ● 公開する気持ちがある ● ただしfastlaneのpluginとしてRubyで再実装中 ○ 公開済みのainame/FrameKitはframeitのように単独では利用不 可なので何らかのラッパーとなるツールが必要 ○ fastlane-community/xcresultでRubyでスクショを抽出できるよう になる見込み 興味がある方は @ainame までご一報ください