Como fazer um aplicativo Android e iOS em C # em um Mac
Publicados: 2022-03-11Era uma vez uma empresa que tinha as melhores ferramentas, e escrever software para sua plataforma era incrível. Mas, lentamente, eles se tornaram indiferentes aos seus próprios problemas. Eles não ficaram alarmados quando seus sistemas falharam, mas aceitaram esse estado do universo como um fato da vida. Eles acreditavam que seus programas eram perfeitos em si mesmos, serenos e elegantes, seu propósito evidente por si mesmo.
Ah, cara, se eles soubessem o quanto estavam errados...
Já estava bem atrasado quando eles perceberam seus erros e seu CEO chorou para trazer de volta todos os desenvolvedores que deixaram sua plataforma e partiram. A empresa era a Microsoft e eu, por exemplo, estava convencido de que seu destino havia sido selado e que lenta mas seguramente pereceriam na vanguarda do cenário tecnológico.
Estou tão feliz que eu estava errado!
Nos últimos anos, a Microsoft tirou alguns ases da manga. Sim, eles estragaram o Skype (ainda os odeio por isso), falharam com smartphones e quase conseguiram com tablets. Mas, eles fizeram algumas coisas realmente incríveis também. Abandonando sua abordagem de império fechado, eles abriram o .NET, ingressaram na Linux Foundation, lançaram o SQL Server para Linux e criaram essa ótima nova ferramenta chamada Visual Studio para Mac.
Isso mesmo, um verdadeiro IDE da Microsoft não para Windows, mas para Mac. Imagine isso!
Escrevendo seu primeiro aplicativo Android e iOS de plataforma cruzada usando C# no Mac
Você pode usar o Visual Studio para Mac para criar praticamente qualquer tipo de aplicativo. Pode ser iOS, tvOS, Android, Mac, .NET Core ou mesmo ASP.NET. Como todas as crianças legais agora estão escrevendo aplicativos móveis, vamos ver o que é preciso no Visual Studio para Mac para criar um aplicativo C# que será executado no Android e no iOS.
A primeira coisa que você precisa fazer é escolher o modelo de aplicativo. Vamos começar com um simples “Single View App”.
Depois de preencher o nome do pacote e inicializar seu aplicativo, o Visual Studio criará uma solução com três projetos. O primeiro projeto será uma biblioteca compartilhada onde você deverá manter o código independente da plataforma, e os outros dois serão aplicativos Android e iOS.
Você pode usar o menu “Executar” ou comandos na barra de aplicativos para iniciar seu aplicativo.
Parabéns! Agora você é um desenvolvedor iOS e Android, independentemente do fato de nunca ter escrito uma linha de código Objective-C, Swift ou Java.
Ainda não conseguimos muito com nosso aplicativo. Vamos tornar as coisas mais interessantes e incorporar mapas e serviços de localização.
Usando Mapas e Serviços de Localização
Tenha em mente que o VS for Mac ainda está em “Preview” e não há muita ajuda e documentação que você encontrará sobre como usá-lo. O melhor lugar para referências sobre como fazer as coisas ainda é a documentação oficial do Xamarin.
O Visual Studio para Mac não usa a mesma solução e estrutura de aplicativo que as ferramentas Xamarin que você pode ter visto no PC. Na maioria dos casos, você precisará experimentar e contornar alguns obstáculos para que seus exemplos funcionem. Vamos torcer para que a Microsoft fique no topo de seu jogo e forneça uma coleção incrível de recursos do MSDN assim que a versão final do VS for Mac for lançada.
Mostrando a localização atual no iOS
O acesso aos recursos do dispositivo móvel, como a localização atual, exige que os usuários concedam permissões “manualmente” ao seu aplicativo para usar esses recursos. O iOS usa o arquivo info.plist para armazenar essas configurações. O VS para Mac fornece uma interface visual para editar este arquivo. A primeira coisa que precisamos fazer é adicionar um valor para a configuração chamada NSLocationWhenInUseUsageDescription .
Observação: o VS mostrará um nome longo para “NSLocationWhenInUseUsageDescription” quando você definir o nome da propriedade. Isso é esperado e não se preocupe com isso.
Nosso aplicativo bootstrap foi criado com um simples botão que contava cliques. A primeira coisa que você vai querer fazer é removê-lo e substituir o conteúdo da tela por um mapa. Para fazer isso, procure o arquivo Main.storyboard no navegador da solução e clique duas vezes nele para abri-lo no editor.
Os storyboards são introduzidos pela Apple e adotados pelo Xamarin também. Consulte a documentação da Apple ou a documentação do Xamarin para obter mais informações.
Remova o botão e adicione um componente Map View à página.
Certifique-se de nomear seu componente “mapView” corretamente.
Tudo o que resta agora é limpar seu arquivo ViewController.cs e modificar o método ViewDidLoad() para corresponder ao seguinte:
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; }Você pode usar o recurso “Correção rápida” para que o VS adicione automaticamente uma referência à biblioteca CoreLocation ou pode adicioná-la manualmente.
Depois de executar seu aplicativo iOS, você deverá ver a solicitação para acessar sua localização. Assim que a permissão for concedida, seu mapa será carregado com um ponto azul padrão mostrando onde você está (ou onde você está fingindo estar usando o simulador do iOS :) ).
Mostrando a localização atual no Android
Infelizmente, o Google e a Microsoft decidiram tornar essa tarefa simples um pouco mais complicada do que com o iOS. Para usar mapas no aplicativo Android, você precisará criar uma chave de API do Google Maps e adicioná-la ao arquivo AndroidManifest.xml .
Os caras do Xamarin criaram um guia bastante direto para obter uma chave de API do Google Maps. Por favor, siga as etapas em seu guia antes de prosseguir. Quando terminar, seu AndroidManifest.xml deverá conter uma configuração como esta:
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="YOUR KEY" />Agora você está pronto para adicionar um mapa ao seu aplicativo.
O melhor do VS for Mac é que ele é desenvolvido pelo NuGet, assim como seu irmão mais velho. Como as bibliotecas de manipulação de mapas não são incluídas por padrão, você precisará instalar o pacote Xamarin.Forms.Maps .
No entanto, não há um componente “Map View” que você possa simplesmente arrastar para sua “Atividade”. Em vez disso, adicionar um mapa à tela requer a alteração manual do arquivo Resources->layout->Main.axml. Você pode usar a visualização do designer para excluir o botão criado antes, mas depois mude para “Code View” e adicione o seguinte código de fragmento em seu LinearLayout :
<fragment xmlns:andro android: android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.MapFragment" /> Assim como no iOS, você precisará configurar seu aplicativo para solicitar as permissões adequadas. Para isso, abra o AndroidManifest.xml para edição e clique no botão “Aplicativo” no canto inferior esquerdo do editor. O VS mostrará uma interface visual para definir esses valores. Existem alguns deles que você precisará habilitar, conforme mostrado abaixo.

Agora é hora de escrever algum código real. Encontre o arquivo MainActivity.cs , abra-o para edição e faça as seguintes alterações:
Adicione referências de namespace:
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); } }Adicione as duas variáveis a seguir como variáveis de nível de classe:
LocationManager locMgr; string locationProvider; E limpe o método OnCreate() para ficar assim:
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); } Ao chamar o GetSystemService de dentro do método OnCreate() , seu MainActivity será ativado como um ILocationListener e, assim, poderá lidar com todos os eventos listados acima.
Execute seu aplicativo Android e você deve posicionar o mapa em sua localização, semelhante à imagem a seguir.
Usando bibliotecas compartilhadas para iOS e Android
Uma das maiores características do VS for Mac é a possibilidade de ter código compartilhado entre aplicativos iOS e Android. Idealmente, poderíamos ter toda a lógica de negócios do aplicativo em uma biblioteca compartilhada, limitando qualquer código específico de iOS e Android a fazer parte da interface do usuário.
Vamos criar uma classe compartilhada que executará de forma assíncrona uma solicitação HTTP e mostrará o conteúdo em um console de depuração.
Crie um novo arquivo de classe em sua biblioteca compartilhada chamado RestClient.cs com o seguinte código:
(Certifique-se de usar o namespace correto do seu projeto)
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); } } } }Usando a Biblioteca no iOS
Modifique seu arquivo ViewController.cs no projeto iOS para corresponder ao seguinte código:
(Certifique-se de usar o namespace correto do seu projeto)
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. } } }Execute seu aplicativo iOS, clique no botão e verifique a guia “Saída do Aplicativo” no Visual Studio. Ele deve exibir algo assim:
Usando a Biblioteca no Android
As alterações necessárias em um aplicativo Android são muito semelhantes às necessárias no iOS. Modifique o arquivo MainActivity.cs para corresponder ao seguinte:
(Certifique-se de usar o namespace correto do seu projeto)
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: A arquitetura do sistema de ambas as plataformas, Android e iOS, requer que toda interação da UI aconteça no encadeamento principal do aplicativo. Isso significa que qualquer alteração nos elementos da interface do usuário também deve ocorrer dentro do thread principal. É aí que RunOnUiThread e InvokeOnMainThread . Como as solicitações HTTP eram executadas em uma thread separada e doneCallback() era chamado fora da thread principal, tivemos que usar esses métodos para poder acessar os botões e alterar o rótulo.
Desenvolvedores C# estão dominando o Android e o iOS
O Visual Studio para Mac ainda tem alguns problemas para resolver, mas desde o primeiro olhar, estou muito animado com seu futuro. A necessidade de aplicativos móveis cresce a cada dia e, com o Visual Studio para Mac, a Microsoft possibilitou ainda mais um exército de grandes desenvolvedores C# para suprir essa necessidade.
