rksoftware

Visual Studio とか C# とかが好きです

Visual Studio (Win) で F# が .NET Core/.NET Standard に対応したらしいので試してみた

Visual Studio (Win) で F# が .NET Core/.NET Standard に対応したらしいので試して見ました。

Visual Studio 2017 15.5 Preview 4 が必要らしいのでインストールします。
今の Visual Studio は同一メジャーバージョン/エディションでも複数インストールできるのではかどりますね。

■ プロジェクトの新規作成

■ .NET Core

・F# で新規作成時

f:id:rksoftware:20171128011321j:plain
なるほど・・・。
ちなみに、VS for Mac の場合は次のようになっています。

・マルチプラットフォーム アプリ (Xamarin.Forms)

f:id:rksoftware:20171128011343j:plain

・ASP.NET Core Web アプリ (ASP.NET Core)

f:id:rksoftware:20171128011403j:plain

おまけ .NET 標準ライブラリ

これを選ぶと、.NET Standard のプロジェクトが生まれます。標準・・・。
f:id:rksoftware:20171128011419j:plain

■ まとめ

このプレビュー版でサポートするのは
・コンソールアプリ
・ライブラリ
・ユニットテスト プロジェクト
だそうです。 あと、ASP.NET Core のプロジェクトは dotnet コマンドで作れるとのこと。

dotnet new webapi -lang F#
dotnet new web -lang F#
dotnet new mvc -lang F#

他人におすすめするには、まだ早い感じがありますね。

.NETラボ 勉強会 で LT をさせていただきました

先日開催の

にて XAML Standard というタイトルで LT をさせていただきました。

XAML Standard の概要と現状、それと試しに作ってみようかなと思っているライブラリ案についての話です。
良かったら XAML Standard のことも気にかけてみてください。まだ化けるかもしれませんよ!

JXUG Xamarin もくもく会 東京秋葉原 11月 を開催しました。

■ JXUG Xamarin もくもく会 東京秋葉原

JXUG Xamarin もくもく会 東京秋葉原 11月 を開催しました。

Xamarin もくもく会 は もくもくしたり、情報交換したりする会です。
今回も、何人もの方にご参加いただき、皆さん進捗をだされました。

不定期ではありますが、ぼちぼち開催していきますので、ご興味があれば是非参加してみてください。

城東.NET #14 勉強会で話をしてきました

先日開催した

にて Android アプリ → Xamarin.Android の書き換えを試す というタイトルで話をしました。

Android アプリ開発のサンプルを Xamarin.Android へ移植してみた際の作業手順などの概要です。

■ 次回予定

来月は 12月20日(水)に開催の予定です。

.NET に関心のある方、是非遊びに来てください。

Android アプリを Xamarin.Android に移植する (5) [完成]

前々々々回 Android アプリを Xamarin.Android に移植する (1) で UI を移植しました。
出来上がった画面。

今回 3 つ目のクラスの移植を行って行きます。一番のメイン、Activity クラスです。

■ 今回移植するクラス

今回は
com.example.android.mediarecorder.MainActivity クラス を C# で書き換えます。

■ MainActivity クラスの編集

MainActivity クラス

MainActivity クラスは既に生成されているクラスを書き換えて行きます。

using の追加

今回も必要な using は最初に追加してしまいます。ファイルの先頭の using の部分が次のようになるようコピー&ペーストしてください。

using System;
using Android.App;
using Android.Content.PM;
using Android.Hardware;
using Android.OS;
using Android.Views;
using Java.IO;
using Android.Media;
using Android.Widget;
using Java.Lang;
using Android.Util;
using System.Collections.Generic;
using String = System.String;

データメンバー の移植

Java のクラスの先頭で定義されているデータメンバーを移植します。
MainActivity.java の 46 行目からの次のコードを、C# の MainActivity.cs の同じ位置 (クラスの宣言と OnCreate メソッドの宣言の間) に追加します。
下記の C# のコードをコピー&ペーストしてください。
・Java のコード

private Camera mCamera;
private TextureView mPreview;
private MediaRecorder mMediaRecorder;
private File mOutputFile;

private boolean isRecording = false;
private static final String TAG = "Recorder";
private Button captureButton;

・C# のコード

private Camera mCamera;
private TextureView mPreview;
private Android.Media.MediaRecorder mMediaRecorder;
private File mOutputFile;

private bool isRecording = false;
private static readonly string TAG = "Recorder";
private Button captureButton;

コントロールのインスタンス取得の追加

OnCreate での処理を追加します。OnCreate は画面生成時の処理で、今回は画面上のコントロールの実態をデータメンバーに保持します。

SetContentView(Resource.Layout.sample_main);

の下に下記の C# コードをコピー&ペーストします。これまで同様、Java では小文字始まりだったメソッド名が、大文字始まりになります。 ・Java のコード

mPreview = (TextureView) findViewById(R.id.surface_view);
captureButton = (Button) findViewById(R.id.button_capture);

・C# のコード

mPreview = (TextureView)FindViewById(Resource.Id.surface_view);
captureButton = (Button)FindViewById(Resource.Id.button_capture);

OnCreate は次のようになります。

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);
 
    SetContentView(Resource.Layout.sample_main);
 
    mPreview = (TextureView)FindViewById(Resource.Id.surface_view);
    captureButton = (Button)FindViewById(Resource.Id.button_capture);
}

OnCaptureClick メソッドのコピー&ペースト

既に作成済みの OnCaptureClick メソッドに実装を追加します。作成済みの OnCaptureClick メソッドは次のようになっているはずです。

[Java.Interop.Export("onCaptureClick")]
public void OnCaptureClick(View view)
{
}

このメソッドの中に、MainActivity.java の 71 行目 onCaptureClick メソッドの内容をコピー&ペーストします。
いくらかのエラーが出ますが、構わず先へ進みます。

その他のメソッド等のコピー&ペースト

OnCaptureClick の下に、MainActivity.java の 105 行目 setCaptureButtonText メソッド以降のコードを最後の } を除いてコピー&ペーストします。

メソッド名の変更

Java ではメソッド名は小文字で始まりますが、C# では大文字で始まります。
小文字で始まっているメソッド名を、大文字始まりに一気に変更して行きます。

置換は Mac の場合は option+command+F、Windows の場合は ctrl+H で行えます。

mMediaRecorder.stop()mMediaRecorder.Stop()
mOutputFile.delete()mOutputFile.Delete()
mCamera.lockmCamera.Lock
mMediaRecorder.reset()mMediaRecorder.Reset()
mMediaRecorder.release()mMediaRecorder.Release()
mCamera.release()mCamera.Release()
mCamera.getParameters()mCamera.GetParameters()
CamcorderProfile.get(CamcorderProfile.Get(
parameters.setPreviewSize(parameters.SetPreviewSize(
mCamera.setParameters(mCamera.SetParameters(
mCamera.setPreviewTexture(mCamera.SetPreviewTexture(
mCamera.unlock()mCamera.Unlock()
mMediaRecorder.setmMediaRecorder.Set
mMediaRecorder.prepare()mMediaRecorder.Prepare()
mMediaRecorder.start()mMediaRecorder.Start()

string クラスへの変更

Java の String クラスは C# の string を使用するよう変更します。

置換は Mac の場合は option+command+F、Windows の場合は ctrl+H で行えます。

Stringstring

プロパティへの変更 (setter)

Java の setter メソッドはなるべく、プロパティに変更されています。

置換は Mac の場合は option+command+F、Windows の場合は ctrl+H で行えます。

captureButton.setText(title)captureButton.Text = title

メソッドの orverride の変更

Java ではスーパークラスのメソッドをサブクラスで orverride する場合はアノテーションを設定しました。C# では return 値の型の前に orverride キーワードを記述します。
スーパークラスは C# に移植されたクラスのため、メソッド名の先頭が大文字になる点に注意してください。
・Java のコード

@Override
protected void onPause()

・C# のコード

protected override void OnPause()

base への書き換え

Java ではスーパークラスのメソッドを呼び出す場合、super キーワードを使用します。C# では同様の機能は base になります。
スーパークラスは C# に移植されたクラスのため、メソッド名の先頭が大文字になる点に注意してください。

置換は Mac の場合は option+command+F、Windows の場合は ctrl+H で行えます。

super.onPause()base.OnPause()

bool への変更

Java では真偽値型は boolean キーワードですが、C# では bool になります。

置換は Mac の場合は option+command+F、Windows の場合は ctrl+H で行えます。

booleanbool
Booleanbool

IList への書き換え

List<> は Java のインタフェースですが、C# ではインタフェースは頭に I が付いた IList<> という名前になります。

置換は Mac の場合は option+command+F、Windows の場合は ctrl+H で行えます。

List<IList<

プロパティへの変更

Java の getter メソッドはなるべく、プロパティに変更されています。

置換は Mac の場合は option+command+F、Windows の場合は ctrl+H で行えます。

parameters.getSupportedPreviewSizes()parameters.SupportedPreviewSizes
parameters.getSupportedVideoSizes()parameters.SupportedVideoSizes
mPreview.getWidth()mPreview.Width
mPreview.getHeight()mPreview.Height
mPreview.getSurfaceTexture()mPreview.SurfaceTexture
e.getMessage()e.Message
mOutputFile.getPath()mOutputFile.Path

プロパティ名の変更

Java では公開データメンバは小文字で始まりますが、C# ではプロパティになり、大文字始まりになります。

置換は Mac の場合は option+command+F、Windows の場合は ctrl+H で行えます。

profile.videoFrameWidthprofile.VideoFrameWidth
profile.videoFrameHeightprofile.VideoFrameHeight
optimalSize.widthoptimalSize.Width
optimalSize.heightoptimalSize.Height

列挙体への変更

Java では公開フォールドはなるべく列挙体に変更されています。

置換は Mac の場合は option+command+F、Windows の場合は ctrl+H で行えます。

CamcorderProfile.QUALITY_HIGHCamcorderQuality.High
MediaRecorder.AudioSource.DEFAULTAudioSource.Default
MediaRecorder.VideoSource.CAMERAVideoSource.Camera

メソッド定義の変更

MainActivity.cs の 133 行目あたりの次の文でエラーが発生しているはずです。
これは、CameraHelper クラス移植の際に手数を減らすために、本来行うべき Java の List<> から C# の IList<T> への置き換えを行っていないために発生しました。
※まずは、CameraHelper を一度ビルドできる状態にするため省略しました。

Camera.Size optimalSize = CameraHelper.getOptimalVideoSize(mSupportedVideoSizes,
    mSupportedPreviewSizes, mPreview.Width, mPreview.Height);

メソッド名 getOptimalVideoSize にカーソルをあわせて F12 キーを押し、メソッドの定義へ移動します。
移動した先のメソッド定義を次のように変更します。

public static Camera.Size getOptimalVideoSize(IList<Camera.Size> supportedVideoSizes,
    IList<Camera.Size> previewSizes, int w, int h)

この書き換えにより、10 行程下の行でエラーが発生します。このエラーを正すために、エラー行の 3 つ上の行の型定義も IList<Camera.Size> に変更します。
・変更前

List<Camera.Size> videoSizes;

・変更後

IList<Camera.Size> videoSizes;

CameraHelper.cs にエラーがないことを確認し、MainActivity.cs に戻ります。

デバッグ出力メソッドの変更

デバッグ出力メソッドのメソッド名 dDebug になっているので変更します。
また、エラー出力のメソッド名 eError になります。

置換は Mac の場合は option+command+F、Windows の場合は ctrl+H で行えます。

Log.d(Log.Debug(
Log.e(Log.Error(

クラス継承のキーワードの変更

Java ではクラスの継承は extends キーワードですが、C# では : になります。

置換は Mac の場合は option+command+F、Windows の場合は ctrl+H で行えます。

extends:

型引数 Void の変更

AsyncTask<> の型引数 VoidJava.Lang.Void であることを明示します。

置換は Mac の場合は option+command+F、Windows の場合は ctrl+H で行えます。

AsyncTask<Void, Void, bool>AsyncTask<Java.Lang.Void, Java.Lang.Void, bool>

MediaPrepareTask クラスの変更

MediaPrepareTask クラスは Android API のクラスで、非同期処理を行う AsyncTask クラスのサブクラスです。
この MediaPrepareTask クラス内の変更も基本はこれまでのパターンで良いのですが、このクラスがインナークラスとして実装されているという大きな違いがあります。
Java のインナークラスは親クラスのインスタンスを参照できますが、C# ではそのようなことができません。
C# へ置き換える際に、MediaPrepareTask クラスが親クラスである MainActivity クラスのインスタンスを明示的に持つよう変更します。

少し複雑な書き換えを行うため MediaPrepareTask クラスは完成コードをまるごとコピー&ペーストします。
次のコードへコピー&ペーストで置き換えてください。

class MediaPrepareTask : AsyncTask<Java.Lang.Void, Java.Lang.Void, bool>
{
    private readonly WeakReference<MainActivity> _activity;
    public MediaPrepareTask(MainActivity activity)
    {
        _activity = new WeakReference<MainActivity>(activity);
    }
    protected override Java.Lang.Object DoInBackground(params Java.Lang.Object[] voids)
    {
        MainActivity activity;
        _activity.TryGetTarget(out activity);
        if (activity.prepareVideoRecorder())
        {
            activity.mMediaRecorder.Start();
            activity.isRecording = true;
        }
        else
        {
            activity.releaseMediaRecorder();
            return false;
        }
        return true;
    }
    protected override void OnPostExecute(bool result)
    {
        MainActivity activity;
        _activity.TryGetTarget(out activity);
        if (!result)
        {
            activity.Finish();
        }
        activity.setCaptureButtonText("Stop");
    }
    protected override bool RunInBackground(params Java.Lang.Void[] @params)
    {
        throw new NotImplementedException();
    }
}

MediaPrepareTask クラス使用の変更

MediaPrepareTask クラスを MainActivity クラスのインスタンスを保持するよう変更しました。
そのため、MediaPrepareTask クラスの使用されている場所で、MainActivity クラスのインスタンスを設定するよう変更します。

置換は Mac の場合は option+command+F、Windows の場合は ctrl+H で行えます。

new MediaPrepareTask().execute(null, null, null);new MediaPrepareTask(this).Execute(null, null, null);

■ MainActivity クラスの完成

これで MainActivity クラスは完成です。
ビルドを行いエラーが出ないことを確認してください。(警告は大量に出ますが、今回はそのままにします)
エラーが出た場合は、エラーの内容と上記の書き換えを見比べて頑張ってエラーに対処してください。

■ 実行

ここまでで、一度アプリを実行してみましょう。
Visual Studio (for Mac) のツールバーの 右三角 アイコンをクリックします。
次の画面が表示されるはずです。

前回出来上がった画面

ここで、[capture] ボタンをタップするとエラーが発生します。
これはまだこのアプリがカメラ等を使うためのパーミッションを設定していないためです。
パーミッションを正しく設定していない場合、該当する機能を使用しようとするとエラーが発生するのがスマートデバイスの特徴です。

■ 設定ファイルの設定

編集する設定ファイルは、Properties フォルダー内の AndroidManifest.xml ファイルです。
・ソリューションエクスプローラー上で AndroidManifest.xml をダブルクリックします。
・エディターで XML ファイルが開くので次のように編集します。ソースが開かない場合、[ソース]タブを選択してください。
<manifest> タグの中に次の要素を追加します。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_VIDEO" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
AndroidManifest.xml 全体は例えば次のようになります。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.example.android.XamMediaRecorder">
    <uses-sdk android:minSdkVersion="16" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RECORD_VIDEO" />
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" />
    <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name"/>
</manifest>

■ 実行

これでアプリが正しく動作するはずです。
もし、activity.mMediaRecorder.Start(); で例外が発生する場合は、AndroidManifest.xml<uses-sdk の設定値を確認してみてください。

お疲れ様でした! これで Android アプリの Xamarin.Android への移植ができました。
この経験をもとにぜひ Xamarin で Android アプリを開発してください!

城東.NET #14 勉強会を開催しました。

■ 城東.NET

 城東.NET #14 を開催しました。

 城東.NET は東京の最近は秋葉原で毎月第3水曜日に開催している .NET 系の勉強会です。
 発表を中心として、発表でなくとも最近やった事や新しい情報などを参加者で共有している会です。

 今月の内容も、上記イベントサイトに資料やコメントが載っているものもあります。
 興味があったら覗いてみてください。

■ 次回予定

 来月は 12月20日(水)に開催の予定です。

 .NET に関心のある方、是非遊びに来てください。

Android アプリを Xamarin.Android に移植する (インデックス)

Android アプリを Xamarin.Android に書き換えるシリーズ (1〜5) の目次です。
※Android サンプルアプリ MediaRecorder ( https://github.com/googlesamples/android-MediaRecorder )

内容としては非常にタンポポ度が高いのですが、元のコードがサンプルにしては少々長編なので耐えてください。
この書き換えを通じて、Xamarin の
・「ネイティブ API カバー率 100%」や
・「ネイティブ経験者はネイティブ開発の経験が活かせる」
の一端を感じてもらえたらと思います。

なお、この移植は Android アプリと Xamarin しか出てきません。
クロスプラットフォーム開発には一切触れないのでその点はご了承ください。
クロスプラットフォームを体験したい場合は、文末に掲載するハンズオンがおすすめです。

■ もくじ

1.プロジェクトの新規作成・UI の移植

2.アプリケーションアイコンの設定

3.CameraHelper クラスの移植

4.MediaCodecWrapper クラスの移植

5.MainActivity クラスの移植 (完成)

この手順で Android アプリの Xamarin.Android への移植ができました。
これを参考にぜひ Xamarin で Android アプリを開発してください!

■ クロスプラットフォームを体験したい場合

Xamarin によるクロスプラットフォーム開発を体験したい場合は、以下のハンズオンがおすすめです。

また、このハンズオンはオフラインイベントでも開催しています。
もしご興味を持たれた場合、とりあえず参加登録がおすすめです。
日程などは、登録してから調整しても遅くはないですきっと!