rksoftware

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

Android アプリを Xamarin.Android に移植する (1)

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

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

Xamarin.Android のアプリを作るので最初はプロジェクト(ソリューション)の新規作成からです。

Mac の場合

・Visual Studio for Mac を起動します。
・メニューの ファイル > 新しいソリューション を選択します。
・[新しいプロジェクト用のテンプレートを選択する] で Android > アプリ > (全般) の Android アプリ (C#) を選択し、[次へ] をクリックします。
・[アプリ名] に適当な名前を入力し、[次へ] をクリックします。
・[プロジェクト名] [ソリューション名] は特に変える必要はありません。[場所] は好みの場所があれば変更してください。
・[作成] をクリックします。

Windows の場合

・Visual Studio (2017) を起動します。
・メニューの ファイル > 新規作成 > プロジェクト を選択します。
・[新しいプロジェクト] で Visual C# > Android > からのアプリ(Android) を選択します。
・[名前] に適当なアプリケーション名を入力します。[場所] は好みの場所があれば変更してください。
・[OK] をクリックします。

■ UI の移植

Xamarin はネイティブの UI 定義が使えることが特徴です。
ネイティブの UI 定義が使えるとは、Android で言えば、Android(Java) のプロジェクトで res フォルダー内にある .axml や .xml、画像ファイル などをそのまま使うということです。

Mac の場合

res フォルダーは Xamrin では Resources フォルダになります。
・Android(Java) プロジェクトの res フォルダーの中身(フォルダー、ファイル)を、Xamarin プロジェクトの Resources フォルダーにコピーします。
・Visual Studio for Mac の [ソリューション] の Resources を右クリック(二本指タップ)します。
追加 > フォルダーからファイルを追加 を選択します。
Resources フォルダーを選択し、[開く] をクリックします。
・[Resources から追加するファイルを選ぶ] で [すべて含める] をクリックします。
・全てチェック ON になっていることを確認し、[OK] をクリックします。

Windows の場合

res フォルダーは Xamrin では Resources フォルダーになります。
・Android(Java) プロジェクトの res フォルダーの中身(フォルダー、ファイル)を、Xamarin プロジェクトの Resources フォルダーにコピーします。
・(Win+e などで)エクスプローラーを開き、Resources フォルダー内のフォルダーをすべて選択しドラッグ、Visual Studio のソリューションエクスプローラー上の Resources フォルダーにドロップします。
・タイトル「ファイルを新しい場所に移動しますか?」メッセージ「1つ以上のファイルを "XXXXXXX\Resources" に移動します。この操作は長時間かかることがあります。」のダイアログで [OK] をクリックします。

共通

・「ファイルが見つかりません」というエラーが出て、Resources\layout\Main.axml 無いとされる場合、ソリューションエクスプローラーから Main.axml ファイルを削除します。

■ UI の適用

Xamarin はネイティブの UI 定義が使えることが特徴です。
axml などのファイルを使えるばかりでなく、Activity も Activity クラスで定義します。
また、先程コピーしたリソースファイルも、自動生成される Resource クラスに定数として定義されます。
(Android(Java) では R でしたが Xamarin では Resource になります)
また、Activity クラスのメソッドなども基本、Java と同じものが定義されており、同じ使い方になります。
ただし、メソッド名などは C# の流儀に変わっているので少し名前が変更されています。
例えば Java では onCreate メソッドでしたが、C# では OnCreate メソッドになっています。

Activity の書き換え

・ソリューションエクスプローラー上で、MainActivisy.cs をバブルクリックして開きます。
・7 行目あたりに

[Activity(Label = "XamMediaRecorder", MainLauncher = true, ...

という記述があります。
これが Activity に対する設定になります。Android では AndroidManifest.xml 内に記述していましたが、Xamarin では Activity クラスの属性として設定します。
属性とは、Java で言うところのアノテーションに当たる機能です。
この属性を先程追加したリソースを参照するよう、次のように変更します。

[Activity(Label = "@string/app_name", MainLauncher = true, ScreenOrientation = ScreenOrientation.Landscape)]

・ここでビルドを行うと「ScreenOrientation が見つからない」という様なエラーになります。
ScreenOrientation クラスの存在する名前空間(Java のパッケージに当たる機能)を using (Java でいう import に当たる機能) で宣言します。
ファイルの先頭の using の塊に次を追加します。

using Android.Content.PM;

この追加はエラーの発生している View にカーソルを合わせて、Mac の場合は alt+enter > クイック修正、Windows の場合は ctrl+. から自動で追加することもできます。
・また、Export 属性を使用する場合、dll の参照を追加する必要があります。
Mac の場合は、ソリューション上の [参照] を右クリック(二本指タップ) > [参照の編集] で開くダイアログで。
Windows の場合は、[参照] を右クリック > [参照の追加] で開くダイアログで [アセンブリ] を選択し。
Mono.Android.Export にチェックをつけて [OK] をクリックします。
・画面レイアウトの定義も、先程追加したリソースを参照するよう、次のように変更します。
変更箇所は15〜17行目あたりにあります。
変更前

SetContentView(Resource.Layout.Main);

変更後

SetContentView(Resource.Layout.sample_main);

・Mac の場合、OnCreate メソッド内に次のようなコードが書かれています。

Button button = FindViewById<Button(Resource.Id.button_capture);

button.Click += delegate {button.Text = $"{count++} clicks!";

このコードは、不要なので削除します。

イベントハンドラメソッドの作成

サンプルの画面定義にはボタンクリックのイベントが設定されています。
このイベントのハンドラとなるメソッドを MainActivity に作成します。
・MainActivity クラスに次のメソッド定義を追加します。
Java.Interop.Export 属性で定義に設定されているメソッド名を設定することがポイントです。

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

・ここでビルドを行うと「View が見つからない」という様なエラーになります。
View クラスの存在する名前空間(Java のパッケージに当たる機能)を using (Java でいう import に当たる機能) で宣言します。
ファイルの先頭の using の塊に次を追加します。

using Android.Views;

この追加はエラーの発生している View にカーソルを合わせて、Mac の場合は alt+enter > クイック修正、Windows の場合は ctrl+. から自動で追加することもできます。
・また、Export 属性を使用する場合、dll の参照を追加する必要があります。
Mac の場合は、ソリューション上の [参照] を右クリック(二本指タップ) > [参照の編集] で開くダイアログで。
Windows の場合は、[参照] を右クリック > [参照の追加] で開くダイアログで [アセンブリ] を選択し。
Mono.Android.Export にチェックをつけて [OK] をクリックします。

ここまでで、MainActivity.cs は次の様になります。

using Android.App;
using Android.Widget;
using Android.OS;
using Android.Content.PM;
using Android.Views;

namespace XamMediaRecorder
{
    [Activity(Label = "@string/app_name", MainLauncher = true, ScreenOrientation = ScreenOrientation.Landscape)]
    public class MainActivity : Activity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            SetContentView(Resource.Layout.sample_main);
        }

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

■ UI の確認

これだけで、UI の移植が完了しました。
F5 キーで実行し画面を確認しましょう。
次の様な画面が表示されていれば成功です。

■ 次回予定

ここまでで UI の移植は完了しました。
次回以降でロジックの移植を行って行きます。

Android アプリ開発の MediaRecorder サンプルを Xamarin.Android に書き換えてみました

Xamarin がどれほど AndroidAPI をそのまま使えるか試すために、アプリ開発のサンプルを Xamarin.Android に書き換えてみました。

Android のサンプル

Android のカメラ、マイクを使って動画を撮る単純なアプリです。
 

Xamarin.Android に書き換えたプロジェクト

■ 書き換えの概要

Xamarin.Android の空のプロジェクトを作る
Android のサンプルからソースをまるごと持ってくる
C# (Xamarin.Android) に書き換える
という簡単な作業です。

■ 書き換えポイント

ロジック的には全く書き換えるポイントはありません。
if 文の一つすら追加も削除もなく書き換えることができました。

書き換えた点は概ね次の点です。
Android(Java) の世界ではメソッドの頭は小文字ですが、Xamarin(C#) の世界では大文字なので書き換えます。
Android(Java) では getter メソッドだったものが Xamarin(C#) ではプロパティになっていることがあるので書き換えます。
・一部の Java のクラスを .NET のライブラリのクラスに書き換えます。
・その他、言語仕様の差などを少々書き換えます。

■ 注意点

・最低限の書き換えで済ますために、変更しなくて済むメソッド名は変更していません(小文字始まりになっています)。
・最低限の書き換えで済ますために、型エイリアスを使っています。
・元のコードの雰囲気を残すために型推論を使っていません。

■ 書き換えの詳細

後日書きます。

Android の Sample が NullPointerException で終了する (part2)

次の Android のアプリ開発の Sample を実行すると、みんな大好き NullPointerException が発生することがあります。
・MediaRecorder
https://developer.android.com/samples/index.html

Android のエミュレーターでは、カメラの有無も設定できます。
カメラが無い設定でエミュレーターを作っている場合、カメラ機能を使おうとするとエラーになります。
このカメラの有無の確認が実装されていないため、存在しないカメラを使おうとして NullPointerException が発生します。

確認方法

・Android Virtual Device Manager(AVD マネージャー)を開き、使用しているデバイスの Edit this AVD をクリック。

・左下の方にある Show Advanced Setting ボタンをクリック。

Camera が None になっていたらカメラがありません。

対策

AVD を新しく作ってください。

Android の Sample が NullPointerException で終了する

次の Android のアプリ開発の Sample を実行すると、みんな大好き NullPointerException が発生します。

・MediaRecorder
https://developer.android.com/samples/index.html から検索

正確には、発生する場合がある、でしょうか。

Android ではアプリがカメラなどを使う際、ユーザーが許可をする必要があります。
ユーザーの許可はインストール時、不許可になっています。 このユーザーによる許可を確認するチェックが実装されていないため、不許可の機能を使おうとして NullPointerException が発生します。

対策

端末またはエミュレーター上で MediaRecorder アプリに対して機能の許可をします。

・設定から

・アプリの設定

・MediaRecorder

・Permissions

・全てを許可(ON)します

.NET Stabdard 2.0 のライブラリを NuGet にアップしてみました。

.NET Stabdard 2.0 のライブラリを NuGet にアップしてみました。
今回アップしたものは、以前に書いたオブジェクト間でプロパティの値をコピーするクラスです。

日付を見ると、どうやら2ヶ月以上経過していたようです。
驚きですね。

■ NuGet パッケージの作成

.NET Stabdard のパッケージ作成は非常に簡単です。
プロジェクトの プロパティ > パッケージ の中の
・「構築時に NuGet パッケージを生成する
にチェックを付けてビルドするだけの簡単な作業です。
f:id:rksoftware:20171031003802j:plain:w300

bin フォルダーの中にパッケージが生成されます。
f:id:rksoftware:20171031003815j:plain:w300

■ NuGet にアップ

パッケージができていれば後は簡単。
https://www.nuget.org/
.nupkg ファイルをアップすれば終了です。

 
これからは .NET Standard 2.0 ですね。

Oracle で Sql の実行時にエラー

Entity Framework を使っていて、DB が Oracle の際に、「文字が無効です」というエラーになる場合があります。
エラーになる SQL を DB 管理ソフトなどで直接流すときちんと成功するにもかかわらず、です。
Entity Framework でなくても発生するでしょうし、ほかの原因の事もあるでしょうが。
とりあえず、今回は SQL の文末に ; がついていることが理由でした。
Oracle の場合は、; を付けない。何度も忘れて悩むのでメモを残しておきます。

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

■ 城東.NET

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

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

 興味があったら覗いてみてください。

■ 次回予定

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

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