はじめに
クラス名の文字列を使わずにDynamic Feature ModuleのActivityを呼び出す - Qiita を参考に、普通のモジュール構成でこの activity-alias
のテクニックを使うにはどうすればいいのか検証してみました。
対象アプリのモジュール構成
巨大でモノリシックな app のみで構成されたアプリから legacy
モジュールや比較的独立性の高いモジュールをコツコツ分離しています。
ゴチャゴチャしていますが今回考える対象は config
と login
モジュールだけです。
この某アプリでは、login
モジュールに存在する「ログイン画面」(LoginActivity
)のメニューから、config
モジュールに属する「設定画面」(ConfigActivity
)を開くことができます。
この設定画面を開くコードは下記のようになっています。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
final Intent intent;
try {
intent = new Intent(this, Class.forName("com.twitpane.config.ui.ConfigActivity"));
startActivityForResult(intent, REQUEST_SETTINGS);
} catch (ClassNotFoundException ignored) {
}
return true;
}
別モジュールの Activity
なので Class.forName()
でクラス名を FQDN で指定しています。当然ながら補完は効かず、Activityのクラス名やパッケージ変更時にリファクタリングで追随してくれません。モジュール分離のような作業ではパッケージ変更が数多く発生するので、割と致命的です(何度もやらかしました)。
activity-alias を導入する
config
login
の両モジュールから見える core
モジュールに activity-alias
となるクラスを用意します。
package com.twitpane.core
sealed class ConfigActivityAlias
sealed class
として定義しているのは、インスタンス化を防ぐためです。
LoginActivity
から呼び出す部分には
ConfigActivityAlias
を指定することで Class.forName が不要になります。やったね!(しかも try-catch も不要になっています。Kotlin なら元から不要だけど)。
...
final Intent intent = new Intent(this, ConfigActivityAlias.class);
startActivityForResult(intent, REQUEST_SETTINGS);
...
そして肝心の activity-alias
を config
モジュールの AndroidManifest.xml
に追記します。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.twitpane.config">
<application>
<activity
android:name="com.twitpane.config.ui.ConfigActivity" ... />
<activity-alias
android:name="com.twitpane.core.ConfigActivityAlias"
android:targetActivity="com.twitpane.config.ui.ConfigActivity" />
</application>
</manifest>
これで実行してみると、ログイン画面から設定画面を無事呼び出すことができました。
ちなみに logcat には下記のように ConfigActivityAlias
のほうが出力されていました。
02-22 21:59:40.099 780-3022/? I/ActivityManager: START u0 {cmp=com.twitpane.debug/com.twitpane.core.ConfigActivityAlias} from uid 10083 on display 0
02-22 21:59:40.402 780-801/? I/ActivityManager: Displayed com.twitpane.debug/com.twitpane.core.ConfigActivityAlias: +275ms
実運用では、クラス名の文字列を使わずにDynamic Feature ModuleのActivityを呼び出す - Qiita で解説されているように、ProGuard/R8でリネームされないように、アプリケーションのproguard-rules.pro
に設定を追加すべきです。お忘れなく。
マルチモジュール化が捗りそうですね。
以上でございます。