Android向けライブラリでは当然のごとく依存関係に含まれている。OSから独立した、Androidのリリース全体に渡る下位互換性の提供」であり、アプリが実行されるOSバージョン自体がどんなバージョンであってもつつがなく動作することを保証するためのライブラリであるからだ。LibraryしかりAndroidXのAPIを利用すべきである。機能ごとにモジュールを分離したモジュールごとに独立したsemverを採用したをはじめとする複数の修正を行いイチから再スタートしたのがAndroidX、ということになる。Jetifierとはなにか当然ながら、AndroidXはこれから更新が重ねられていく。新たな機能を利用したい場合、AndroidXへの移行を余儀なくされる。Libraryへ依存しているライブラリ実装AndroidXへ依存しているライブラリ実装AndroidXへ依存しているアプリ実装などが混在してしまう可能性がある。これを解決するため、GoogleがJetifierというツールを提供している。v28を利用していることを前提にそれらのクラス参照たちをAndroidXのものへ繋ぎ変えてくれる。スタンドアロン版を直接利用することも可能だが、ビルドスクリプトでフラグを立てるだけで自動で実行させることができる。AndroidX対応はいつやるのか本題。これらの前提のもと、じゃあいつ自分たちの作っているアプリでAndroidXに対応するのか、という話がいつかは出てくる。実際自分の関わっているいくつかの事業者を見ていると、AndroidXへの本格対応は未だ行っていないケースが散見される。いくらでも例外はあるものの、筆者としては「早めにやるに越したことはないが、最悪AndroidXの機能が必要になるまではJetifier以上の対応はしなくてよい」という意見を推していきたい。この「AndroidXの機能が必要になるまで」に外的要因も含まれうるという点で、いくらかの危険性をはらんでいることも無視できないのが難しい部分だ。下記のようなアプリがあるとする。OSにおけるbackgroundTintの実現にAppCompatを利用している。Libraryとして提供されていた期間までの機能で必要十分である。executedこのアプリでandroid.useAndroidXをenableにしてみる。android.enableJetifier=falseこの時点ではアプリ側のコードを書き換えずビルドが可能である。それもそのはず、依存関係の書き換えは行われないのだ。Developersの記述が全てだ。ライブラリを使用します。Pluginが当該ライブラリを利用する箇所としてわかりやすいものには、DataBindingが存在する。下記のようなDataBindingを用いたアプリの場合。executeduseAndroidXをenabledにしてみる。android.enableJetifier=falseこの状態でビルドを試みると失敗することが確認できるだろう。executed内部で利用されるライブラリがAndroidXの置き換わるとは、依存関係に下記のような差分が発生することを指しているのである。1sJetifierの挙動android.enableJetifierによる影響はもう少しわかりやすい。Libraryによるアプリで有効にしてみる。kotlin.code.style=official-android.useAndroidX=false-android.enableJetifier=false+android.useAndroidX=true+android.enableJetifier=trueこれにより、依存関係ツリーが書き換わる。LibraryがAndroidXのものに置換されるのである。プロジェクト内のソースコードや出力されるバイトコードそのものには影響が出ないことには注意が必要だ。コードの書換えは必要である。up-to-dateさて、では依存するライブラリではどうだろうか。Libraryを依存関係に持つライブラリを追加する。Jetifierを有効にしていない場合は下記のような依存関係が出力される。(*)この時、この依存するライブラリをデコンパイルすると下記のようなものが確認できるだろう。}ではJetifierを有効にしてみる。ネストした依存関係も適切に処理され、下記のようになる。(*)さきほど検証したとおり、自身のプロジェクトにおけるソースコードは書き換わらない。この依存ライブラリが持つコードをデコンパイルすると、下記のようなものが確認できる。}ライブラリ内での参照は自動で書き換わることが確認できた。有効にする壊れたプロジェクト内の参照を修正する依存するライブラリは自動で書き換わるので気にしなくてよいの4点を押さえれば十分ということになる。対応は簡単だが、問題はこの判断を行うタイミングや要因である。LibraryではなくAndroidXを利用する形へ移行した1は完全にプロジェクトのコントローラブルな範囲であるため割愛する。2に関しては一般的なライブラリにおける破壊的変更が実施された以降とほぼ同じと捉えてよい。3はほぼ2と同じ事由になることが想像されるが、少し問題があるため後述する。これらを総合して言えることは、やはり「やれる内に更新をしていないと工数の確保が難しくなる」という点は他のライブラリと変わらないということだ。アプリのロジックやビジネスが特定ライブラリに密に依存していて、それらのアップデートが必要となった際に雪だるま式にやることが増えてしまうかもしれない。非アプリにおける対応では非アプリ、具体的には複数アプリに導入されうるモジュールの場合にはどうだろうか?対応の判断面は変わらない。要は「機能が必要になった」「依存するライブラリが移行した」場合に対応すればよい、ということだ。「早めに更新したほうがよいか」というと、そんなことはない。「できる限り対応を遅めたほうがよい」と筆者は考える。Libraryの間には名前空間やモジュールの分割といった変更があり、大きな変更のように思わせる。Libraryからの移行は容易に行える。Libraryを前提としたアプリで利用するのが容易かというと、これは難しい。Libraryを用いた参照をAndroidXのものに変換する機能こそ利用できるが、その逆は困難だからだ。AndroidXへの対応は簡単だが、それは十分にそのプロジェクトへアサインされたエンジニアのリソースが存在する場合に限られる。現実問題として、必ずしもプロジェクトにフルタイマーや十分な能力を持ったメンバーがアサインされている保証はない。複数のアプリで利用されるモジュールがAndroidXの利用を要求するようになった場合、必然的にこのモジュールを利用している全てのアプリは移行の作業を行うこととなる。「ではAndroidX対応しなくてもいいのか?」と聞かれそうになる。Libraryさえ使っていれば、実際にどちらを利用するかはアプリ側に判断を委ねることができるからだ。Jetifierを有効にするだけでよい。まとめ長々と書いてきたが、この記事における主張は下記のとおりだ。アプリにおけるAndroidX対応は、最悪必要になるまで対応しないという選択が可能である。外的要因に影響されないよう早めにやればよいし、通常は依存するライブラリに関わらず今からでも対応可能である。非アプリにおける対応は、可能な限り遅めたほうがよい。Libraryを使っている限りは実際のアプリに判断を委ねることができる。筆者は業務でエンドユーザ向けアプリからSDKまで様々な開発に携わっているが、AndroidXに関する対応は事業者によってまちまちである。エンジニアを対象としたプロダクトを作る事業者においては、ユーザであるエンジニアの利便性を損なわない対応を求めたいものだ。Libraryの利用へ戻すのは困難と記述したが、困難ではあっても可能ではある。Pluginと統合されているが、CLIからも利用ができる。場合は、これを利用するのもひとつの手段かもしれない。15:30結局AndroidX対応は簡単なので身構える必要はないが、外的要因で対応が前倒しになりうるTweetもっと読むコメントを書く2019-06-18Mavenリポジトリの指定は記述順序を考えないと解決時のパフォーマンスがじわじわ下がっていくAndroidアプリ開発などをしていれば、大概のプロジェクトはGradleを用いてライブラリの依存関係を解決しようとすることになる。開発・運用期間の長いアプリになればなるほど、後追いで導入されたサードパーティ製ライブラリとその取得元のMavenリポジトリ定義が肥大化していくケースが散見される。普段なんとなく設定しているMavenリポジトリの定義だが、実はビルド時のパフォーマンス低下の原因となるケースがあるため、注意が必要だ。以下のようなスクリプトがあるとする。'androidx.exifinterface:exifinterface:1.0.0'}これをビルドしてみる。13:50:50125秒。14:03:49188秒。この程度なら誤差かもしれない。大量に存在するとどうだろう。14:13:33338秒。元の125秒比較すると実に2.7倍近い時間が掛かるようになってしまった。試しに順序を変えてみる。14:19:34123秒。リポジトリ自体は定義されているにも関わらず、元の定義に匹敵する速度まで回復した。こんな現象が起こるのかは、ログを確認すればわかる。順にリポジトリを手繰っている。{}で定義するリポジトリは、純粋に上から下へ優先順位を持っており、それを順々に参照するのである。これを自身の参照したいライブラリ毎に行うため、当然ながらじわじわと解決の速度を低下させる要因になりうるのである。何かしらのプライベートリポジトリを利用している。複数のライブラリを併用する場合は、この参照先リポジトリがどんどん肥大化していくことが多い。成功するまで順々に投げられていくため、もし上位に(たとえば1つのライブラリしか置かれていないような)ほとんど使われないリポジトリが指定されていれば、すべての依存関係解決のために毎回無駄なリクエストを投げることになってしまう。信頼性の高いリポジトリ自身のアプリが持つ依存関係の中で最も利用数が多いリポジトリこの記事の趣旨で言うと、本来であれば2だけを気にすればよい。Android開発などの場合には特別な事情があるため併記しておく。Repository内に配置してあるChecksumが不正な内容になってしまった時がある。JCenterは仕組み上Checksumが不正な場合には404ではなく409を返すようになっている。その結果、google()よりもjcenter()の優先順位を高く設定していた場合には依存関係の解決に失敗してしまう、という問題が発生したことが過去にある。Repositoryを最優先にすべきである。Servicesがよしなに処理してくれるよう投げることになる。上で作成するということになる。Configを本格的に利用しようとした時にエイヤッと統合されたものへ移行する、というものがある。この記事は、既にFCMを利用しているアプリのプロジェクトを移行できるのか検証した時のログである。nameの変更)は行わないという前提のため、APK署名時に使う証明書は同じものとする。nameと証明書フィンガープリントのペアをグローバルに登録し、それと一致することを条件とするため。よって、FCMではマストではないSHA1フィンガープリントの登録ではあるが、他のプロジェクト(他の人物、というとわかりやすいか?)が同一の組み合わせを登録しようとするとエラーにで弾かれるようになっている。はじめにすることは、旧プロジェクトに紐付いた証明書に関する設定を削除すること。いう項目があるため、この内容を削除する。今回の場合は、89:E6:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:34:E5EA:F3:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:71:C3の2件。アプリの認証情報を削除するこの時点で既に旧アプリでの認証情報は不要になるため、削除してしまう。アプリ内に配置したgoogle-services.jsonを削除して、おしまい。移行先プロジェクトを作成する既に移行先プロジェクトが存在する場合はスキップ。新たな認証情報をアプリに入れる作成の途中でgoogle-services.jsonをダウンロードすることができるので、これをアプリに配置しておく。ステップ2で削除した分。リリース用のハッシュをプロジェクトに追加するステップ1で削除した分。本番の証明書から取ったSHA1ハッシュを追加する。SNSやReproなどを使っている場合、FCMへAPI経由でアクセスするためのサーバーキーを新しいものへ変更する必要がある。取得できるので、これを用いて変更作業をする。人間誰しも1度はProxyを通して通信内容をデバッグしたい時がある。7以降からは一筋縄では実現できない。customizations.https://android-developers.googleblog.com/2016/07/changes-to-trusted-certificate.html上記のとおり、AOSPで設定されたCA以外は信頼されず、ユーザが独自にインストールしたCAすらもデフォルトで無効になる。これらをオプトインで利用することも当然可能になっており、またアプリ内にderファイルを同梱させ利用させることも可能だ。これらは設定ファイルを記述して自分のアプリに組み込めば実現できる。内容を傍受できるようにする上記の内容を改竄し、アプリがへ届けられるようにするの2つの実現を目指す。)ので、実際に行うのは独自CAの許可のみだ。以降で実装手順を解説する。実際のコードはGitHubに掲載した。bodyを表示する簡単なアプリを作るまずは挙動が確認できないことには始まらないので、通信した結果を表示するだけの画面を作る。}}このような表示を期待する。構成ファイルを作成・配置する今回の設定はアプリ内でのみ有効になる。CAを追加する前項で設定したとおり、src/main/res/raw/myca.derとして追加する。