汎用ロガーを作ったが、リリース時にはバイナリから消え去ってほしいと思い、Inline Functionsを使ってみた。
実際には、そういった運用をするならProguardで消せばいいと思う。
Inline Functions
inline fun
を呼ぶとバイナリ上に組み込まれるようになる。C言語とかのマクロみたいな感じで使えるはず。
対象
Logger.kt
class Logger(val tag: String) {
inline fun println(priority: Int, msgCreator: () -> String, e: Throwable? = null) {
if (BuildConfig.DEBUG) {
// BuildConfig.DEBUGはconst扱いなので、inlineであればリリース時にはクラスファイルからも消えるはず
val msg = msgCreator() + (e?.let { "\n" + Log.getStackTraceString(it) } ?: "")
Log.println(priority, tag, msg)
}
}
inline fun v(msgCreator: () -> String) = println(Log.VERBOSE, msgCreator)
inline fun d(msgCreator: () -> String) = println(Log.DEBUG, msgCreator)
inline fun i(msgCreator: () -> String) = println(Log.INFO, msgCreator)
inline fun w(msgCreator: () -> String) = println(Log.WARN, msgCreator)
inline fun e(msgCreator: () -> String) = println(Log.ERROR, msgCreator)
inline fun v(msgCreator: () -> String, e: Throwable) = println(Log.VERBOSE, msgCreator, e)
inline fun d(msgCreator: () -> String, e: Throwable) = println(Log.DEBUG, msgCreator, e)
inline fun i(msgCreator: () -> String, e: Throwable) = println(Log.INFO, msgCreator, e)
inline fun w(msgCreator: () -> String, e: Throwable) = println(Log.WARN, msgCreator, e)
inline fun e(msgCreator: () -> String, e: Throwable) = println(Log.ERROR, msgCreator, e)
}
MyApplication.kt
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
Logger("foo").v { "bar" }
}
}
方法
出力されたapkをデコンパイルし、jadコマンドで吐かれたコードを比較する。
結果
MyApplication.debug.jad
public final class MyApplication extends Application
{
public MyApplication()
{
}
public void onCreate()
{
Object obj;
Logger logger;
super.onCreate();
logger = new Logger("foo");
if(false)
throw new UnsupportedOperationException("Super calls with default arguments not supported in this target, function: println");
obj = (Throwable)null;
if(!BuildConfig.DEBUG) goto _L2; else goto _L1
_L1:
StringBuilder stringbuilder = (new StringBuilder()).append((String)"bar");
if(obj == null) goto _L4; else goto _L3
_L3:
obj = (Throwable)obj;
obj = (String)(new StringBuilder()).append("\n").append(Log.getStackTraceString(((Throwable) (obj)))).toString();
if(obj == null) goto _L4; else goto _L5
_L5:
obj = stringbuilder.append(obj).toString();
Log.println(2, logger.getTag(), ((String) (obj)));
_L2:
return;
_L4:
obj = "";
if(true) goto _L5; else goto _L6
_L6:
}
}
MyApplication.release.jad
public final class MyApplication extends Application
{
public MyApplication()
{
}
public void onCreate()
{
super.onCreate();
new a("foo"); // 注:Logger
if(false)
{
throw new UnsupportedOperationException("Super calls with default arguments not supported in this target, function: println");
} else
{
Throwable throwable = (Throwable)null;
return;
}
}
}
という感じで、リリース時にログ内容がごっそり消せた。
UnsupportedOperationException
はKotlinによるものだと思うが、詳細は把握しきれていない。
ちなみに、app/build
に出力されるProguard前のバイトコードは大差がなかったので、Proguardによる最適化効果と思われる。