buildConfig上の値の直接参照について
はじめに
- release.apk でstoreにアップ済みのapkに対して、アップグレードテストをしたい
- でも一部の処理は処理ログとかで動作も確認したい
な用途で毎回コード上の定義値を変更してビルドするのも面倒なので、
buildConfigFieldあたりの挙動を調べてみた
現在のBuildConfigの状態
public final class BuildConfig { public static final boolean DEBUG = Boolean.parseBoolean("true"); public static final String APPLICATION_ID = "hoge.fuga.irof_history"; public static final String BUILD_TYPE = "debug"; public static final String FLAVOR = ""; //★ public static final int VERSION_CODE = 1; public static final String VERSION_NAME = "1.0"; //buildConfigFieldで指定されたものが追加 }
★ がandroid gradle pluginで新規追加されたもので、
- BuildConfig.FLAVORを使ったライブラリ、コードが存在
- ADTでコンパイルできない
- =>ASに移行しましょうね
みたいな凶悪な移行推奨ステマが昔流行った時期がありました・・
独自BuildConfig変数の追加というと
下記なサンプルがよくでてきます。
buildTypes { debug { buildConfigField "Boolean", "DEBUG_LOG", 'true' } release { buildConfigField "Boolean", "DEBUG_LOG", 'false' } releaseOut.initWith(buildTypes.release) releaseOut { buildConfigField "Boolean", "DEBUG_LOG", 'true' } }
or
- app/build.gradle
defaultConfig{ buildConfigField "Boolean", "DEBUG_LOG", 'false' } buildTypes { debug { } release { } releaseOut.initWith(buildTypes.release) releaseOut { buildConfigField "Boolean", "DEBUG_LOG", 'true' } }
でもこれすごく微妙。どうせ書くなら使うところだけ書きたい
- app/build.gradle
buildTypes { debug { } release { } releaseOut.initWith(buildTypes.release) releaseOut { buildConfigField "Boolean", "DEBUG_LOG", 'true' } }
この場合、動的に参照したくなるわけです
BuildConfigというと
<<アプリパッケージ名>>.BuildConfig.java として生成されます
したがってこのクラスを動的に参照できればいいわけです
public static Object getBuildConfigValue(Context context, String fieldName) { try { Class<?> clazz = Class.forName(context.getPackageName() + ".BuildConfig"); Field field = clazz.getField(fieldName); return field.get(null); } catch (ClassNotFoundException e) { } catch (NoSuchFieldException e) { } catch (IllegalAccessException e) { } return null; }
boolean debugLog = (Boolean) getBuildConfigValue(getApplicationContext(), "DEBUG_LOG");//★
なコードがStackOverFlowで出てきますが、
- ★の第1引数は getApplicationContext() でないと<<アプリケーションパッケージ名>> はとれません*1
- 多分参考元の想定は、下記なんだろうな・・と
- カスタムApplication上に記載
- カスタムApplicationはプロジェクト直下
- 多分参考元の想定は、下記なんだろうな・・と
- 例えば 下記の場合は hoge.fuga.util.BuildConfig.java のクラスを参照しようとしてしまいます
package hoge.fuga.util class hogeActivity extends Activity{ void onCreate(){ boolean debugLog = (Boolean) getBuildConfigValue(this, "DEBUG_LOG");//◎ } }
でもまあ app本体側のパッケージの位置さえわかればいいのですから、下記のほうがシンプルかも・・
参考元の趣旨と外れるかもしれませんが・・
public static Object getBuildConfigValue(String fieldName) { try { Field field = BuildConfig.class.getField(fieldName); return field.get(null); } catch (ClassNotFoundException e) { } catch (NoSuchFieldException e) { } catch (IllegalAccessException e) { } return null; }
これだけではもちろん足りなくて
- proguard-rules.pro
-keep public class hoge.fuga.BuildConfig { *; }
指定しないとBuildConfigクラス自体が生成されない*2
の指定は必要。support-v4とかも、JD-GUIとかで見ると
実は BuildConfigはそのまま残ってるんですよね・・
参考元
参考元の話は、
aar化した libraryProjectでどう遣ったら本体側の BuildConfig.DEBUGと連動できるか? の話なんですけど、
下手に難しいことするより、自分的所感としては昔のjar版みたいに、setDebugMode みたいな関数を作って渡せば良くない?
とか思って読んでました。そもそもココらへんの話って,
gradlew assembleDebug
しても ソース同梱しているはずのlibraryProject側のaarがrelease.aarがくっつくからログが出ない
というG様のよくわかんない挙動仕様によるものだったり・・
- ソース同梱型のlibraryProject側の指定が
あたりによるものだったりする気がするのは気のせいなのかな〜
まあ
android{ publishNonDefault true defaultPublishConfig "debug" }
とか libraryProject側のbuild.gradle にちゃんと書いて固定化制御しろ というお話は有るようですが、
AS上のlibraryProject側のBuidTypeが意味をなしていないという・・・
2017/03/01追記メモ
- buildConfigのフィールドって、
- ASだと ${XXXX} で AndroidManifest.xml で参照できる機能があり
- <= ManifestMargerによる置換処理が働くようになるらしい
という話で、
GlideModuleとかClassLoaderで動的に参照する系はフルパス指定がし易い
- activityとかだと .activity.HogeActivity とか相対指定できるけどたまに落ちることが・・
- これもフルパッケージ指定すれば問題なかったりする*5
app/AndroidManifest.xml
<application> <meta-data android:name="${applicationid}.application.LimitCacheSizeGlideModule" android:value="GlideModule" /> </application>