9分钟阅读

如何在Mac上制作一个Android和iOS应用程序在C#上

Demir是一个开发者和项目经理,拥有超过15年的专业经验,在各种软件开发角色。

曾几何时,有一家拥有所有最好的工具的公司,并为其平台写作软件很棒。但慢慢地,他们对自己的问题漠不关心。当他们的系统崩溃时,他们并没有被震惊,但相当接受这种宇宙的状态作为生活的事实。他们认为,他们的计划在自己内部,宁静和优雅,他们的目的是不言而喻的。

哦,男孩,如果他们只知道他们有多错了......

当他们意识到他们的错误和他们的首席执行官哭了一下 带回所有开发人员 谁离开了他们的平台并航行了。公司是 微软 而且,对于一个人来说,她说的是他们的命运被密封,他们会慢慢地,但肯定会从技术景观的最前沿灭亡。

我很高兴我错了!

在过去的几年里,微软已经从他们的袖子上拉了几件衔铁。是的,他们搞砸了Skype(我仍然讨厌他们),失败了,智能手机,几乎成功了平板电脑。但是,他们也做了一些非常棒的事情。释放他们的封闭帝国方法,他们开放的.NET,加入了Linux基础,发布了Linux的SQL Server,并创建了这个名为的新工具 Mac Visual Studio.

那是对的,一个 真实的 微软 IDE不适合Windows,但是对于Mac。想象一下!

Mac Visual Studio

在Mac上使用C#写下您的第一个跨平台Android和iOS应用程序

您可以使用Mac Visual Studio以创建几乎所有类型的应用程序。它可以是iOS,TVOS,Android,Mac,.NET核心,甚至是ASP.NET。正如所有酷的孩子现在正在编写手机应用程序,让我们看看Mac Visual Studio以创建将在Android和iOS上运行的C#应用​​程序。

您需要做的第一件事就是选择应用程序模板。让我们从一个简单的“单视图应用程序”开始。

单视图应用程序。

在填写包名称并引导您的应用程序后,Visual Studio将创建具有三个项目的解决方案。第一个项目将是一个共享库,您应该保留与平台无关的代码,另外两个将是Android和iOS应用程序。

入门。

您可以使用应用程序栏中的“运行”菜单或命令来启动您的应用程序。

你好世界,点击我!

记录两次单击。

恭喜!您现在是一个iOS和Android开发人员,无论您从未写过一行Object-C,Swift或Java代码。

我们还没有用我们的应用程序真正完成。让我们更有趣,并合并地图和位置服务。

使用地图和位置服务

请记住,对MAC的vs仍然处于“预览”,并且您将在使用它时找到许多帮助和文档。参考如何做事的最佳地点仍然是官方XAMARIN文件。

Mac Visual Studio不使用与PC上可能看到的Xamarin工具相同的解决方案和应用程序结构。在大多数情况下,您需要尝试和工作若干障碍以使其示例工作。让我们希望微软将在他们的比赛之上,并在发布Mac的最终版本的VS的最终版本后,提供一个很棒的MSDN资源集合。

显示IOS上的当前位置

Accessing mobile device resources, such as current location, requires users to “manually” grant permissions to your app to use those resources. iOS uses the file info.plist to store these settings. VS for Mac provides a visual interface for editing this file. First thing we need to do is add a value for the setting named NSLocationWhenInUseUsageDescription.

在使用说明中添加位置的值。

笔记: VS将在设置属性名称时显示“NSLOCIOCWHENININUSESUSAGERACTION”的长名称。这是预期的,不担心它。

Our bootstrapped application was created with a simple button that was counting clicks. The first thing you will want to do is to remove it and replace the screen content with a map. In order to do this, look for the Main.storyboard file in the solution browser and double-click on it to open it in the editor.

故事板是应用程序的用户界面的可视化表示,显示内容的屏幕和这些屏幕之间的连接。故事板由一系列场景组成,每个场景都表示视图控制器及其视图; Segue对象连接的场景,它表示两个视图控制器之间的转换。

故事板由Apple引入并由Xamarin采用。参考 Apple文档 或者 XAMARIN文件 欲获得更多信息。

删除按钮并将地图视图组件添加到页面。

删除地图视图组件。

确保正确地命名“MapView”组件。

命名地图视图组件

全部 that is left now is to clean up your ViewController.cs file, and modify the ViewDidLoad() method to match the following:

        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上的当前位置

Unfortunately, Google and Microsoft decided to make this simple task a bit more complicated than it was with iOS. In order to use maps in the Android application, you will need to create Google Maps API key, and add it to your 安卓 Manifest.xml file.

Xamarin Guys创造了一个非常简单的指南 获取Google Maps API密钥. Please follow the steps in their guide before you proceed. When you’re done, your 安卓 Manifest.xml should contain a setting like this:

<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="YOUR KEY" />

您现在准备将地图添加到您的应用程序中。

The great thing with VS for Mac is that it is powered by NuGet, just like its big brother. As map handling libraries aren’t included by default, you will need to install the Xamarin.Forms.Maps package.

安装xamarin.forms.maps.

但是,没有“Map View”组件,您可以拖到“活动”。相反,将映射添加到屏幕需要手动更改资源 - >layout->Main.axml file. You can use the designer view to delete the button created before, but then switch to “Code View” and add the following fragment code in your LinearLayout:

    <fragment xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/map"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          class="com.google.android.gms.maps.MapFragment" />

As with iOS, you will need to configure your app to ask for proper permissions. To do so, open 安卓 Manifest.xml for editing and click the “Application” button on the bottom left side of the editor. VS will show you a visual interface for setting these values. There are a few of them you will need to enable, as shown below.

启用权限。

It is now time to write some real code. Find the MainActivity.cs file, open it for editing, and make the following changes:

添加命名空间引用:

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;

And cleanup the OnCreate() method to look like this:

        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);
        }

By calling the GetSystemService from within the OnCreate() method, your MainActivity will be activated as an ILocationListener and will thereby be able to handle all the events listed above.

运行您的Android应用程序,您应该将其定位在您的位置的地图,类似于以下图像。

地图位于萨拉热窝。

使用IOS和Android的共享库

VS for Mac的最大功能之一是IOS和Android应用程序之间具有共享代码的可能性。理想情况下,我们可以在共享库中拥有应用程序的所有业务逻辑,将任何IOS和Android特定代码限制为ui的一部分。

让我们创建一个共享类,它将异步执行HTTP请求并在调试控制台中显示内容。

Create a new class file in your shared library named RestClient.cs with the following code:

(确保使用项目中的正确名称空间)

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上使用库

Modify your ViewController.cs file in the iOS project to match the following code:

(确保使用项目中的正确名称空间)

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(" 全部  Done", UIControlState.Normal);
            });
        }

        public override void DidReceiveMemoryWarning()
        {
            base.DidReceiveMemoryWarning();
            // Release any cached data, images, etc that aren't in use.        
        }
    }
}

运行iOS应用程序,单击按钮,然后选中Visual Studio中的“应用程序输出”选项卡。它应该显示这样的东西:

应用程序输出选项卡。

在Android上使用库

Changes needed on an Android app are very similar to those needed on iOS. Modify the MainActivity.cs file to match the following:

(确保使用项目中的正确名称空间)

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 = " 全部  done";
                System.Diagnostics.Debug.WriteLine(content);
            });
        }
    }
}

笔记: The system architecture of both platforms, Android and iOS, requires that all UI interaction happen on the main application thread. This means that any change to UI elements should happen from within the main thread as well. That is where RunOnUiThread and InvokeOnMainThread come in. Since HTTP requests were executed in a separate thread and doneCallback() was called outside the main thread, we had to use these methods to be able to access the buttons and change the label.

C#开发人员正在接管Android和iOS

Mac Visual Studio仍然有几个皱纹来解决,但从第一个看它,我对未来非常兴奋。对移动应用程序的需求每天增长,并使用Mac Visual Studio,Microsoft进一步启用了一支军队 伟大的C#开发人员 填补这种需求。

SWIFT和Java / JVM现在有一个新的,非常强大,竞争对手的移动设备开发环境。