Mac에서 C#으로 Android 및 iOS 앱을 만드는 방법
게시 됨: 2022-03-11옛날 옛적에 최고의 도구를 모두 갖춘 회사가 있었고 해당 플랫폼용 소프트웨어를 작성하는 것은 굉장했습니다. 그러나 점차 그들은 자신의 문제에 무관심해졌습니다. 그들은 시스템이 고장났을 때 놀라지 않고 오히려 우주의 이 상태를 삶의 사실로 받아들였습니다. 그들은 그들의 프로그램이 그 자체로 완벽하고 고요하고 우아하며 목적이 자명하다고 믿었습니다.
오 이런, 그들이 얼마나 잘못되었는지 알기만 하면…
그들이 실수를 깨달았을 때 너무 늦었고 그들의 CEO는 플랫폼을 떠나 항해를 떠난 모든 개발자를 다시 불러오기 위해 울었습니다. 그 회사는 마이크로소프트 였고, 나는 그들의 운명이 정해져 있고 그들이 기술 환경의 최전선에서 천천히 그러나 확실하게 사라질 것이라고 확신했습니다.
내가 틀렸어 너무 기뻐!
지난 몇 년 동안 Microsoft는 소매에서 몇 가지 에이스를 뽑았습니다. 예, 그들은 Skype를 엉망으로 만들고(나는 여전히 그것을 싫어합니다), 스마트폰에서는 실패했고, 태블릿에서는 거의 성공했습니다. 그러나 그들은 정말 놀라운 일들도 했습니다. 폐쇄적 제국 접근 방식을 포기하고 .NET을 오픈 소스로 제공하고 Linux Foundation에 합류하여 Linux용 SQL Server를 출시하고 Mac용 Visual Studio라는 훌륭한 새 도구를 만들었습니다.
맞습니다. Windows가 아닌 Mac을 위한 실제 Microsoft IDE입니다. 상상 해봐!
Mac에서 C#을 사용하여 첫 번째 크로스 플랫폼 Android 및 iOS 애플리케이션 작성
Mac용 Visual Studio를 사용하여 거의 모든 유형의 응용 프로그램을 만들 수 있습니다. iOS, tvOS, Android, Mac, .NET Core 또는 ASP.NET일 수 있습니다. 이제 멋진 아이들이 모두 모바일 앱을 작성하고 있으므로 Mac용 Visual Studio에서 Android 및 iOS에서 실행되는 C# 애플리케이션을 만드는 데 필요한 사항을 살펴보겠습니다.
가장 먼저 해야 할 일은 애플리케이션 템플릿을 선택하는 것입니다. 간단한 "Single View App"부터 시작하겠습니다.
패키지 이름을 입력하고 앱을 부트스트랩하면 Visual Studio에서 세 개의 프로젝트가 있는 솔루션을 만듭니다. 첫 번째 프로젝트는 플랫폼 독립적인 코드를 유지해야 하는 공유 라이브러리이고 나머지 두 프로젝트는 Android 및 iOS 앱입니다.
"실행" 메뉴 또는 애플리케이션 표시줄의 명령을 사용하여 앱을 시작할 수 있습니다.
축하합니다! Objective-C, Swift 또는 Java 코드를 한 줄도 작성하지 않았다는 사실에 관계없이 이제 iOS 및 Android 개발자입니다.
우리는 아직 우리 앱으로 많은 것을 이루지 못했습니다. 좀 더 흥미롭게 만들고 지도와 위치 서비스를 통합해 보겠습니다.
지도 및 위치 서비스 사용
Mac용 VS는 아직 "미리 보기"에 있으며 사용에 대한 도움말과 설명서가 많지 않습니다. 작업 방법에 대한 참조를 위한 가장 좋은 장소는 여전히 공식 Xamarin 설명서입니다.
Mac용 Visual Studio는 PC에서 볼 수 있는 Xamarin 도구와 동일한 솔루션 및 응용 프로그램 구조를 사용하지 않습니다. 대부분의 경우 예제가 작동하도록 하려면 몇 가지 장애물을 실험하고 해결해야 합니다. Mac용 VS의 최종 버전이 출시되면 Microsoft가 최고의 게임을 유지하고 멋진 MSDN 리소스 컬렉션을 제공할 수 있기를 바랍니다.
iOS에서 현재 위치 표시
현재 위치와 같은 모바일 장치 리소스에 액세스하려면 사용자가 해당 리소스를 사용할 수 있는 권한을 앱에 "수동으로" 부여해야 합니다. iOS는 info.plist
파일을 사용하여 이러한 설정을 저장합니다. Mac용 VS는 이 파일을 편집하기 위한 시각적 인터페이스를 제공합니다. 가장 먼저 해야 할 일은 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 사용자는 Google Maps API 키를 얻기 위한 매우 간단한 가이드를 만들었습니다. 계속하기 전에 가이드의 단계를 따르세요. 완료되면 AndroidManifest.xml
에 다음과 같은 설정이 포함되어야 합니다.
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="YOUR KEY" />
이제 애플리케이션에 지도를 추가할 준비가 되었습니다.
Mac용 VS의 가장 큰 장점은 형과 마찬가지로 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); } }
다음 두 변수를 클래스 수준 변수로 추가합니다.

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용 공유 라이브러리 사용
Mac용 VS의 가장 큰 기능 중 하나는 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 앱을 실행하고 버튼을 클릭한 다음 Visual Studio에서 "응용 프로그램 출력" 탭을 확인합니다. 다음과 같이 표시되어야 합니다.
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를 인수하고 있습니다.
Mac용 Visual Studio에는 아직 해결해야 할 몇 가지 주름이 있지만, 처음 봤을 때부터 그 미래가 매우 기대됩니다. 모바일 응용 프로그램에 대한 필요성은 날로 증가하고 있으며 Mac용 Visual Studio를 통해 Microsoft는 뛰어난 C# 개발자 군대가 이러한 요구를 충족할 수 있도록 지원했습니다.