MacのC#でAndroidおよびiOSアプリを作成する方法
公開: 2022-03-11昔々、最高のツールをすべて備えている会社があり、彼らのプラットフォーム用のソフトウェアを書くことは素晴らしかった。 しかし、ゆっくりと、彼らは自分たちの問題に無関心になりました。 彼らのシステムがクラッシュしたとき、彼らは心配することはありませんでしたが、むしろこの宇宙の状態を人生の事実として受け入れました。 彼らは、彼らのプログラムは彼ら自身の中で完璧であり、穏やかでエレガントであり、彼らの目的は自明であると信じていました。
ああ、彼らがどれほど間違っているかを知っているだけなら…
彼らが彼らの過ちに気づき、彼らのCEOが彼らのプラットフォームを離れて出航したすべての開発者を連れ戻すことを叫んだとき、それはかなり遅れていました。 会社はマイクロソフトであり、私は、彼らの運命は封印されており、テクノロジー業界の最前線からゆっくりと、しかし確実に滅びると確信していました。
私は間違っていたのでとても幸せです!
過去数年間で、マイクロソフトは彼らの袖からいくつかのエースを引っ張ってきました。 はい、彼らはSkypeを台無しにし(私はまだそれが嫌いです)、スマートフォンで失敗し、タブレットでほぼ成功しました。 しかし、彼らはいくつかの本当に素晴らしいこともしました。 クローズドエンパイアアプローチを放棄し、.NETをオープンソース化し、Linux Foundationに参加し、Linux用のSQL Serverをリリースし、Visual StudioforMacと呼ばれるこの優れた新しいツールを作成しました。
そうです、Windows用ではなくMac用の本当のMicrosoftIDEです。 想像してみろ!
MacでC#を使用して最初のクロスプラットフォームAndroidおよびiOSアプリケーションを作成する
Visual Studio for Macを使用して、ほぼすべての種類のアプリケーションを作成できます。 iOS、tvOS、Android、Mac、.NET Core、さらにはASP.NETでもかまいません。 すべてのクールな子供たちがモバイルアプリを書いているので、AndroidとiOSで実行されるC#アプリケーションを作成するためにVisual StudioforMacで何が必要かを見てみましょう。
最初に行う必要があるのは、アプリケーションテンプレートを選択することです。 簡単な「シングルビューアプリ」から始めましょう。
パッケージ名を入力してアプリをブートストラップした後、VisualStudioは3つのプロジェクトでソリューションを作成します。 最初のプロジェクトは、プラットフォームに依存しないコードを保持する必要がある共有ライブラリであり、他の2つはAndroidアプリとiOSアプリです。
「実行」メニューまたはアプリケーションバーのコマンドを使用して、アプリを起動できます。
おめでとう! これで、Objective-C、Swift、またはJavaコードの行を作成したことがないという事実に関係なく、iOSおよびAndroidの開発者になります。
ただし、このアプリではまだ多くのことを達成していません。 物事をもっと面白くして、地図と位置情報サービスを取り入れましょう。
マップと位置情報サービスの使用
VS for Macはまだ「プレビュー」にあり、それを使用する上で役立つヘルプやドキュメントはあまりないことを覚えておいてください。 物事の実行方法に関するリファレンスとして最適な場所は、Xamarinの公式ドキュメントです。
Visual Studio For Macは、PCで見た可能性のあるXamarinツールと同じソリューションとアプリケーション構造を使用していません。 ほとんどの場合、例を機能させるには、いくつかのハードルを実験して回避する必要があります。 VS for Macの最終バージョンがリリースされたら、Microsoftがゲームのトップを維持し、MSDNリソースのすばらしいコレクションを提供することを期待しましょう。
iOSで現在地を表示
現在地などのモバイルデバイスリソースにアクセスするには、ユーザーがそれらのリソースを使用するための権限をアプリに「手動で」付与する必要があります。 iOSは、ファイルinfo.plist
を使用してこれらの設定を保存します。 VS for Macは、このファイルを編集するためのビジュアルインターフェイスを提供します。 最初に行う必要があるのは、 NSLocationWhenInUseUsageDescription
という名前の設定の値を追加することです。
注:プロパティ名を設定すると、VSは「NSLocationWhenInUseUsageDescription」の長い名前を表示します。 これは予想されることであり、心配する必要はありません。
ブートストラップされたアプリケーションは、クリック数をカウントするシンプルなボタンで作成されました。 最初にやりたいことは、それを削除して、画面のコンテンツを地図に置き換えることです。 これを行うには、ソリューションブラウザでMain.storyboard
ファイルを探し、それをダブルクリックしてエディタで開きます。
ストーリーボードはAppleによって導入され、Xamarinでも採用されています。 詳細については、AppleのドキュメントまたはXamarinのドキュメントを参照してください。
ボタンを削除し、マップビューコンポーネントをページに追加します。
「mapView」コンポーネントに適切な名前を付けてください。
あとは、 ViewController.cs
ファイルをクリーンアップし、 ViewDidLoad()
メソッドを次のように変更するだけです。
using CoreLocation; public override void ViewDidLoad() { base.ViewDidLoad(); // Perform any additional setup after loading the view, typically from a nib. CLLocationManager locationManager = new CLLocationManager(); locationManager.RequestWhenInUseAuthorization(); mapView.ShowsUserLocation = true; }
「クイック修正」機能を使用して、VSにCoreLocationライブラリへの参照を自動的に追加させるか、手動で追加することができます。
iOSアプリを実行すると、現在地にアクセスするためのリクエストが表示されます。 許可が与えられると、マップはあなたがどこにいるのか(またはiOSシミュレーターを使用してどこにいるのかを示す標準の青い点でロードされます:))。
Androidで現在地を表示
残念ながら、GoogleとMicrosoftは、この単純なタスクをiOSの場合よりも少し複雑にすることにしました。 Androidアプリケーションでマップを使用するには、Google Maps APIキーを作成し、それをAndroidManifest.xml
ファイルに追加する必要があります。
Xamarinの連中は、GoogleMapsAPIキーを取得するための非常に簡単なガイドを作成しました。 続行する前に、ガイドの手順に従ってください。 完了すると、 AndroidManifest.xml
に次のような設定が含まれるはずです。
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="YOUR KEY" />
これで、アプリケーションにマップを追加する準備が整いました。
VS for Macの優れている点は、兄貴と同じようにNuGetを搭載していることです。 マップ処理ライブラリはデフォルトで含まれていないため、 Xamarin.Forms.Maps
パッケージをインストールする必要があります。
ただし、「アクティビティ」にドラッグするだけの「マップビュー」コンポーネントはありません。 代わりに、画面にマップを追加するには、Resources->layout->Main.axmlファイルを手動で変更する必要があります。 デザイナビューを使用して、前に作成したボタンを削除できますが、「コードビュー」に切り替えて、 LinearLayout
に次のフラグメントコードを追加します。
<fragment xmlns:andro android: android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.MapFragment" />
iOSと同様に、適切な権限を要求するようにアプリを構成する必要があります。 これを行うには、編集用にAndroidManifest.xml
を開き、エディターの左下にある[アプリケーション]ボタンをクリックします。 VSは、これらの値を設定するための視覚的なインターフェイスを表示します。 以下に示すように、有効にする必要があるものがいくつかあります。
次に、実際のコードを記述します。 MainActivity.cs
ファイルを見つけて開き、編集して、次の変更を加えます。
名前空間参照を追加します。
using Android.Gms.Maps.Model; using Android.Gms.Maps; using Android.Locations; Make your MainActivity also a ILocationListener. public class MainActivity : Activity, ILocationListener Implement the ILocationListener methods within your MainActivity: public void OnProviderEnabled(string provider) {} public void OnProviderDisabled(string provider) {} public void OnStatusChanged(string provider, Availability status, Bundle extras) {} public void OnLocationChanged(Android.Locations.Location location) { LatLng latLng = new LatLng(location.Latitude, location.Longitude); CameraPosition.Builder builder = CameraPosition.InvokeBuilder(); builder.Target(latLng); builder.Zoom(15); builder.Bearing(155); builder.Tilt(10); CameraPosition cameraPosition = builder.Build(); CameraUpdate cameraUpdate = CameraUpdateFactory.NewCameraPosition(cameraPosition); MapFragment mapFrag = (MapFragment)FragmentManager.FindFragmentById(Resource.Id.map); GoogleMap map = mapFrag.Map; if (map != null) { map.MoveCamera(cameraUpdate); } }
次の2つの変数をクラスレベルの変数として追加します。

LocationManager locMgr; string locationProvider;
そして、 OnCreate()
メソッドを次のようにクリーンアップします。
protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); locMgr = GetSystemService(LocationService) as LocationManager; Criteria locationCriteria = new Criteria(); locationCriteria.Accuracy = Accuracy.Coarse; locationCriteria.PowerRequirement = Power.Medium; locationProvider = locMgr.GetBestProvider(locationCriteria, true); locMgr.RequestLocationUpdates(locationProvider, 2000, 1, this); }
OnCreate()
メソッド内からGetSystemServiceを呼び出すことにより、 MainActivity
がILocationListener
としてアクティブ化され、上記のすべてのイベントを処理できるようになります。
Androidアプリケーションを実行すると、次の画像のように、地図が現在地に配置されます。
iOSおよびAndroid用の共有ライブラリの使用
VS for Macの最大の機能の1つは、iOSアプリとAndroidアプリの間でコードを共有できることです。 理想的には、アプリのすべてのビジネスロジックを共有ライブラリに入れて、iOSおよびAndroid固有のコードをUIの一部に制限することができます。
HTTPリクエストを非同期的に実行し、デバッグコンソールにコンテンツを表示する共有クラスを作成しましょう。
次のコードを使用して、 RestClient.cs
という名前の共有ライブラリに新しいクラスファイルを作成します。
(プロジェクトの正しい名前空間を使用してください)
using System; using System.Net; namespace testshared { public delegate void callback(string responseText); class ReqState { public ReqState(HttpWebRequest req, callback cb) { request = req; callback = cb; } public HttpWebRequest request { get; set; } public callback callback; } public class RestClient { public RestClient() {} public void FetchPage(string url, callback cb) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.BeginGetResponse(new AsyncCallback(FinishWebRequest), new ReqState(request, cb)); } private void FinishWebRequest(IAsyncResult result) { ReqState reqState = (result.AsyncState as ReqState); HttpWebResponse response = reqState.request.EndGetResponse(result) as HttpWebResponse; using (var reader = new System.IO.StreamReader(response.GetResponseStream())) { string responseText = reader.ReadToEnd(); reqState.callback(responseText); } } } }
iOSでライブラリを使用する
次のコードに一致するように、iOSプロジェクトのViewController.cs
ファイルを変更します。
(プロジェクトの正しい名前空間を使用してください)
using System; using UIKit; using System.Diagnostics; namespace testshared.iOS { public partial class ViewController : UIViewController { RestClient rest = new RestClient(); public ViewController(IntPtr handle) : base(handle) {} public override void ViewDidLoad() { base.ViewDidLoad(); // Perform any additional setup after loading the view, typically from a nib. Button.AccessibilityIdentifier = "myButton"; Button.TouchUpInside += delegate { Button.SetTitle("Loading...", UIControlState.Normal); rest.FetchPage("http://www.google.com", doneCallback); }; } public void doneCallback(string content) { InvokeOnMainThread(() => { Debug.Write(content); Button.SetTitle("All Done", UIControlState.Normal); }); } public override void DidReceiveMemoryWarning() { base.DidReceiveMemoryWarning(); // Release any cached data, images, etc that aren't in use. } } }
iOSアプリを実行し、ボタンをクリックして、VisualStudioの[アプリケーション出力]タブを確認します。 次のように表示されます。
Androidでライブラリを使用する
Androidアプリで必要な変更は、iOSで必要な変更と非常によく似ています。 MainActivity.cs
ファイルを次のように変更します。
(プロジェクトの正しい名前空間を使用してください)
using Android.App; using Android.Widget; using Android.OS; namespace testshared.Droid { [Activity(Label = "testshared", MainLauncher = true, Icon = "@mipmap/icon")] public class MainActivity : Activity { RestClient rest = new RestClient(); protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); // Get our button from the layout resource, // and attach an event to it Button button = FindViewById<Button>(Resource.Id.myButton); button.Click += delegate { button.Text = $"Loading..."; rest.FetchPage("http://www.google.com", doneCallback); }; } public void doneCallback(string content) { RunOnUiThread(() => { Button button = FindViewById<Button>(Resource.Id.myButton); button.Text = "All done"; System.Diagnostics.Debug.WriteLine(content); }); } } }
注: AndroidとiOSの両方のプラットフォームのシステムアーキテクチャでは、すべてのUI操作がメインアプリケーションスレッドで行われる必要があります。 つまり、UI要素への変更は、メインスレッド内からも行う必要があります。 そこでRunOnUiThread
とInvokeOnMainThread
が登場します。HTTPリクエストは別のスレッドで実行され、 doneCallback()
がメインスレッドの外部で呼び出されたため、ボタンにアクセスしてラベルを変更できるようにするには、これらのメソッドを使用する必要がありました。
C#開発者はAndroidとiOSを引き継いでいます
Visual Studio for Macにはまだ解決すべきいくつかのしわがありますが、最初に見てから、その将来に非常に興奮しています。 モバイルアプリケーションの必要性は日々高まっており、MicrosoftはVisual Studio for Macを使用して、優れたC#開発者の軍隊がこの必要性を満たすことをさらに可能にしました。