Cómo crear una aplicación para Android e iOS en C# en una Mac
Publicado: 2022-03-11Érase una vez una empresa que tenía las mejores herramientas y escribir software para su plataforma era increíble. Pero lentamente, se volvieron indiferentes a sus propios problemas. No se alarmaron cuando sus sistemas colapsaron, sino que aceptaron este estado del universo como un hecho de la vida. Creían que sus programas eran perfectos en sí mismos, serenos y elegantes, su propósito evidente.
Vaya, si supieran lo equivocados que estaban...
Ya era hora de que se dieran cuenta de sus errores y su CEO lloró para traer de vuelta a todos los desarrolladores que abandonaron su plataforma y se fueron. La empresa era Microsoft y yo, por mi parte, estaba convencido de que su destino estaba sellado y que desaparecerían lenta pero seguramente del frente del panorama tecnológico.
¡Estoy tan feliz de haberme equivocado!
En los últimos años, Microsoft ha sacado algunos ases de la manga. Sí, arruinaron Skype (todavía los odio por eso), fallaron con los teléfonos inteligentes y casi lo lograron con las tabletas. Pero, también hicieron algunas cosas realmente asombrosas. Renunciando a su enfoque de imperio cerrado, crearon .NET de código abierto, se unieron a Linux Foundation, lanzaron SQL Server para Linux y crearon esta gran herramienta nueva llamada Visual Studio para Mac.
Así es, un verdadero IDE de Microsoft no para Windows, sino para Mac. ¡Imagina eso!
Escribiendo su primera aplicación multiplataforma para Android e iOS usando C# en Mac
Puede usar Visual Studio para Mac para crear casi cualquier tipo de aplicación. Puede ser iOS, tvOS, Android, Mac, .NET Core o incluso ASP.NET. Como todos los chicos geniales ahora escriben aplicaciones móviles, veamos qué se necesita en Visual Studio para Mac para crear una aplicación C# que se ejecutará en Android e iOS.
Lo primero que debe hacer es elegir la plantilla de la aplicación. Comencemos con una simple "aplicación de vista única".
Después de completar el nombre del paquete y arrancar su aplicación, Visual Studio creará una solución con tres proyectos. El primer proyecto será una biblioteca compartida en la que debe guardar el código independiente de la plataforma, y los otros dos serán aplicaciones de Android e iOS.
Puede usar el menú "Ejecutar" o los comandos en la barra de la aplicación para iniciar su aplicación.
¡Felicidades! Ahora es un desarrollador de iOS y Android, independientemente del hecho de que nunca escribió una línea de código Objective-C, Swift o Java.
Sin embargo, aún no hemos logrado mucho con nuestra aplicación. Hagamos las cosas más interesantes e incorporemos mapas y servicios de localización.
Uso de mapas y servicios de ubicación
Tenga en cuenta que VS para Mac todavía está en "Vista previa" y no encontrará mucha ayuda ni documentación sobre su uso. El mejor lugar para referencias sobre cómo hacer las cosas sigue siendo la documentación oficial de Xamarin.
Visual Studio para Mac no usa la misma estructura de solución y aplicación que las herramientas de Xamarin que podría haber visto en la PC. En la mayoría de los casos, necesitará experimentar y sortear algunos obstáculos para que sus ejemplos funcionen. Esperemos que Microsoft se mantenga al tanto de su juego y proporcione una increíble colección de recursos de MSDN una vez que se lance la versión final de VS para Mac.
Mostrando la ubicación actual en iOS
El acceso a los recursos del dispositivo móvil, como la ubicación actual, requiere que los usuarios otorguen permisos "manualmente" a su aplicación para usar esos recursos. iOS usa el archivo info.plist
para almacenar estas configuraciones. VS para Mac proporciona una interfaz visual para editar este archivo. Lo primero que debemos hacer es agregar un valor para la configuración denominada NSLocationWhenInUseUsageDescription
.
Nota: VS mostrará un nombre largo para "NSLocationWhenInUseUsageDescription" cuando establezca el nombre de la propiedad. Esto es de esperar y no te preocupes por ello.
Nuestra aplicación de arranque se creó con un simple botón que contaba los clics. Lo primero que querrá hacer es eliminarlo y reemplazar el contenido de la pantalla con un mapa. Para hacer esto, busque el archivo Main.storyboard
en el navegador de soluciones y haga doble clic en él para abrirlo en el editor.
Los guiones gráficos son introducidos por Apple y también adoptados por Xamarin. Consulte la documentación de Apple o la documentación de Xamarin para obtener más información.
Quite el botón y agregue un componente Vista de mapa a la página.
Asegúrese de nombrar correctamente su componente "mapView".
Todo lo que queda ahora es limpiar su archivo ViewController.cs
y modificar el método ViewDidLoad()
para que coincida con lo siguiente:
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; }
Puede usar la función "Corrección rápida" para que VS agregue automáticamente una referencia a la biblioteca CoreLocation o puede agregarla manualmente.
Después de ejecutar su aplicación iOS, debería ver la solicitud para acceder a su ubicación. Una vez que se otorga el permiso, su mapa se cargará con un punto azul estándar que muestra dónde se encuentra (o dónde finge estar usando el simulador de iOS :)).
Mostrando la ubicación actual en Android
Desafortunadamente, Google y Microsoft decidieron hacer esta simple tarea un poco más complicada que con iOS. Para usar mapas en la aplicación de Android, deberá crear la clave API de Google Maps y agregarla a su archivo AndroidManifest.xml
.
Los chicos de Xamarin crearon una guía bastante sencilla para obtener una clave API de Google Maps. Siga los pasos en su guía antes de continuar. Cuando haya terminado, su AndroidManifest.xml
debe contener una configuración como esta:
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="YOUR KEY" />
Ahora está listo para agregar un mapa a su aplicación.
Lo mejor de VS para Mac es que funciona con NuGet, al igual que su hermano mayor. Como las bibliotecas de manejo de mapas no se incluyen de forma predeterminada, deberá instalar el paquete Xamarin.Forms.Maps
.
Sin embargo, no hay un componente de "Vista de mapa" que pueda arrastrar a su "Actividad". En cambio, agregar un mapa a la pantalla requiere cambiar manualmente su archivo Resources->layout->Main.axml. Puede usar la vista de diseñador para eliminar el botón creado anteriormente, pero luego cambie a "Vista de código" y agregue el siguiente código de fragmento en su LinearLayout
:
<fragment xmlns:andro android: android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.MapFragment" />
Al igual que con iOS, deberá configurar su aplicación para solicitar los permisos adecuados. Para hacerlo, abra AndroidManifest.xml
para editar y haga clic en el botón "Aplicación" en la parte inferior izquierda del editor. VS le mostrará una interfaz visual para configurar estos valores. Hay algunos de ellos que deberá habilitar, como se muestra a continuación.

Ahora es el momento de escribir algo de código real. Busque el archivo MainActivity.cs
, ábralo para editarlo y realice los siguientes cambios:
Agregar referencias de espacios de nombres:
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); } }
Agregue las siguientes dos variables como variables de nivel de clase:
LocationManager locMgr; string locationProvider;
Y limpie el método OnCreate()
para que se vea así:
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); }
Al llamar a GetSystemService desde dentro del método OnCreate()
, su MainActivity
se activará como ILocationListener
y, por lo tanto, podrá manejar todos los eventos enumerados anteriormente.
Ejecute su aplicación de Android y debería colocar el mapa en su ubicación, similar a la siguiente imagen.
Uso de bibliotecas compartidas para iOS y Android
Una de las mejores características de VS para Mac es la posibilidad de tener código compartido entre las aplicaciones de iOS y Android. Idealmente, podríamos tener toda la lógica comercial de la aplicación en una biblioteca compartida, limitando cualquier código específico de iOS y Android a ser parte de la interfaz de usuario.
Vamos a crear una clase compartida que realizará de forma asíncrona una solicitud HTTP y mostrará el contenido en una consola de depuración.
Cree un nuevo archivo de clase en su biblioteca compartida llamado RestClient.cs
con el siguiente código:
(Asegúrese de usar el espacio de nombres correcto de su proyecto)
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); } } } }
Uso de la biblioteca en iOS
Modifique su archivo ViewController.cs
en el proyecto de iOS para que coincida con el siguiente código:
(Asegúrese de usar el espacio de nombres correcto de su proyecto)
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. } } }
Ejecute su aplicación iOS, haga clic en el botón y marque la pestaña "Resultado de la aplicación" en Visual Studio. Debería mostrar algo como esto:
Uso de la biblioteca en Android
Los cambios necesarios en una aplicación de Android son muy similares a los que se necesitan en iOS. Modifique el archivo MainActivity.cs
para que coincida con lo siguiente:
(Asegúrese de usar el espacio de nombres correcto de su proyecto)
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); }); } } }
Nota: La arquitectura del sistema de ambas plataformas, Android e iOS, requiere que toda la interacción de la interfaz de usuario ocurra en el subproceso principal de la aplicación. Esto significa que cualquier cambio en los elementos de la interfaz de usuario también debe ocurrir desde el hilo principal. Ahí es donde RunOnUiThread
e InvokeOnMainThread
. Dado que las solicitudes HTTP se ejecutaron en un hilo separado y se llamó a doneCallback()
fuera del hilo principal, tuvimos que usar estos métodos para poder acceder a los botones y cambiar la etiqueta.
Los desarrolladores de C# se están haciendo cargo de Android e iOS
Visual Studio para Mac todavía tiene algunas arrugas que resolver, pero desde el primer vistazo, estoy muy entusiasmado con su futuro. La necesidad de aplicaciones móviles crece cada día y, con Visual Studio para Mac, Microsoft ha habilitado aún más un ejército de grandes desarrolladores de C# para satisfacer esta necesidad.