Delphi の Android Log を正しく表示する


Delphi の Log

Log.d が Info で出力される

Delphi では FMX.Types に Log クラスが定義され、そこにメソッドがいくつか定義されています。
最終的には下記のメソッドが呼ばれて IFMXLoggingService の Log メソッドが呼ばれます。

class procedure Log.d(const Fmt: string; const Args: array of const);
begin
  if Logger <> nil then
    IFMXLoggingService(Logger).Log(Fmt, Args);
end;

ですが!
Delphi Android が出力する Log レベルがおかしいのです。
というのは、Log.d というメソッド名であるならば Debug レベルで出力しないといけないのに、Log レベルが Info で出てきます。
これは、FMX.Platform.Logger.Android.pas で、

FMX.Platform.Logger.Android.pas
procedure TAndroidLoggerService.Log(const AFormat: string; const Params: array of const);
begin
  // (中略)
  LOGI(M.AsUtf8(Msg).ToPointer);
end;

となっており、LOGI を呼んでいるからです。
ADB のログを見ても Info レベルになってしまうので非常に気持ち悪い!

そこで、Debug レベルで出力する方法を紹介します。

Debug レベルで出力する

Androidapi.Log.pas に __android_log_write が定義されているので、コレを使います。
具体的には

uses
  System.SysUtils,
  Androidapi.Log;

class procedure Log.d(const iMsg: String);
var
  M: TMarshaller;
begin
  __android_log_write(
    android_LogPriority.ANDROID_LOG_DEBUG,
    M.AsUtf8('TAG').ToPointer,
    M.AsUtf8(iMsg).ToPointer);
end;

こんな感じです。

__android_log_write について

第一引数の

android_LogPriority.ANDROID_LOG_DEBUG

で、DEBUG レベルを指定しています。
ここには、

type
  android_LogPriority = (
    ANDROID_LOG_UNKNOWN,
    ANDROID_LOG_DEFAULT,
    ANDROID_LOG_VERBOSE,
    ANDROID_LOG_DEBUG,
    ANDROID_LOG_INFO,
    ANDROID_LOG_WARN,
    ANDROID_LOG_ERROR,
    ANDROID_LOG_FATAL,
    ANDROID_LOG_SILENT
 );

が定義されているので使いたいレベルを指定します。

第二引数は TAG です。
ここは任意の文字列ですが、プロジェクト名だったり、ロググループを表す文字列にすると良いと思います。
(Log を表示する側でフィルタリングできるため)

第三引数が、表示するメッセージです。

TMarshaller

ここで、第2,3引数には M.AsUtf8 というモノがついています。
これは TMarshaller の提供する文字列変換メソッドです。

Android は文字コードを UTF8 として扱うので、Delphi の文字列を UTF8 に変換しなければなりません。
そこで、TMarshaller を使って変更しています。
ただ、TMarshaller が返してくる値はメモリ上の値(TPtrWrapper)なので、ToPointer メソッドでポインタ値を渡してやります。

なお、マーシャリングとは ASCII デジタル用語辞典によると

異なる2つのシステム間で、データを交換できるようにデータを操作する処理

とあります。
つまり、今回の場合は Delphi の文字列を Android が扱う UTF8 に変換した、ということです。

まとめ

これらをまとめて、Windows, macOS, Android, iOS で使えるようにした FMX.Log を公開しています。
コレを使うと、楽ちんです!

FMX.Log.pas - https://bitbucket.org/JunHosokawa/fmx.log