Xamarin.Forms で System.Diagnostics.Trace を使ってログファイルに出力する方法は、iOS版と同じなので省略、、、したいところですが、実は落とし穴があります。
Androidでログファイルは何処に出力されるのか?
Xamarin.Forms の共通プロジェクトで、Appクラスのコンストラクタ(App.xaml.cs)に以下のように書いておくとiOSでもAndroidでも統一的に Trace の結果をファイルに出力することができます。
var dir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var filename = Path.Combine(dir, $"log-{DateTime.Now.ToString("yyyyMMdd-HHmm")}.txt");
var tw = System.IO.File.OpenWrite(filename);
var tr1 = new TextWriterTraceListener(tw);
System.Diagnostics.Trace.AutoFlush = true;
System.Diagnostics.Trace.Listeners.Add(tr1);
ここで、Environment.SpecialFolder.MyDocumentsで取得できる場所は、iOSのほうは「ファイル/アプリ名」の中になるのですが、Androidの場合にはアプリ自身のfilesのフォルダーになっています。このフォルダはアプリ自身しか見えなくて、テストをしたときにログファイルを手軽に見ることができません。ログファイルを閲覧する作るとなると結構面倒です。
Xamarin.Droid ではどうするのか?
先にAndroid固有のプロジェクト(Xamarin.Droid)のほうを解決しておきます。
iOSと同じ様に、Androidにも「ファイル」というアイコンがあります。この「ファイル」からAndroid内部のファイルを直接閲覧できます。そこで、この「ファイル」の場所から見えるところに、ログファイルを置くように工夫します。
var contextRef = new WeakReference<Context>(this);
contextRef.TryGetTarget(out var c);
var dir = c.GetExternalFilesDir(null).AbsolutePath;
var filename = Path.Combine(dir, $"droid-{DateTime.Now.ToString("yyyyMMdd-HHmm")}.txt");
var tw = System.IO.File.OpenWrite(filename);
this.tr1 = new TextWriterTraceListener(tw);
DroidTrace.AutoFlush = true;
DroidTrace.Listeners.Add(tr1);
DroidTrace.WriteLine("ios Application Trace mode " + DateTime.Now.ToString());
ちょっとややこしいですが、GetExternalFilesDir関数を使うとアプリが公開しているフォルダを取得できます。このフォルダはアプリが他のアプリと共有するためのフォルダーになります。
このコードは、MainActivity::OnCreate に書いておけばよいです。
/storage/emulated/0/Android/data/<バンドル名>/files
「ファイル」のほうからは、スマホの機種名のとところから「/Andorid」のフォルダーから見つけることができます。アプリのバンドル名(net.moonmile.sample.testapp のようなもの)が含まれるので、かなり奥深いところになってしまいますが、一般ユーザーでもファイルを見ることができます。
public class DroidTrace
{
static DroidTrace()
{
Listeners = new List<TraceListener>();
}
public static List<TraceListener> Listeners { get; }
public static bool AutoFlush { get; set; } = true;
public static void WriteLine(string message)
{
foreach (var it in Listeners)
{
it.WriteLine(message);
if (AutoFlush == true) it.Flush();
}
}
}
DroidTrace クラスは共有プロジェクトの System.Diagnostics.Trace と重なっていしまうために、独自に作った簡易クラスです。作り方はiOS版と同じですね。
このように、GetExternalFilesDir で取得したパスに書き込むと Android の「ファイル」からログファイルを閲覧できるようになります。
Xamarin.Forms 側のパスを決める
となると、共有プロジェクトの方でも GetExternalFilesDir のパスに出力すれば良いことが分かるのですが、このパスは Android 内部で決まるものなので、共有プロジェクトでは使えません。
真面目にはるならば、DependencyService で DI するのが筋なんでしょうが、所詮 iOS と Android の違いしかないので、次のように直接パスを指定してしまいます。
var dir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
if ( Device.RuntimePlatform == Device.Android )
{
// Android の場合は決め打ちにする
dir = "/storage/emulated/0/Android/data/<バンドル名>/files";
}
var filename = Path.Combine(dir, $"log-{DateTime.Now.ToString("yyyyMMdd-HHmm")}.txt");
var tw = System.IO.File.OpenWrite(filename);
var tr1 = new TextWriterTraceListener(tw);
System.Diagnostics.Trace.AutoFlush = true;
System.Diagnostics.Trace.Listeners.Add(tr1);
というわけで、ちょっと雑ではありますが、ひとまず iOS と Android のログ出力環境がこれで整います。