编者语:Xamarin在国内的推广还需要努力,其实这真的是移动端开发的一大福音,毕竟用一份代码的时间可以生成iOS/Android/Windows/Linux/macOS/Tizen多个平台,而且是原生的性能。Xamarin在Build 2018发布的新功能有Xamarin.Essentials(点击查看) , Hyper-V for Xamarin Android Emulator ,还有Xamarin.Forms 3.0。Xamarin.Forms 3.0 和 Xamarin.Essentials 都会是一个质的飞跃。Xamarin.Forms 有全新的布局FlexLayout ,更好地和原生控件对接,还新增支持GTK+/Tizen。而Xamarin.Essentials的发布则大大提升开发的效率,把因为平台差异造成的代码不一致的底层接口重新做了归一,这样做提升了编码效率。
在Build2018前的两周左右,我拿到了Xamarin.Essentials的测试版本(基于nda我只能等到现在才能发布),这是一个为访问一些设备硬件和底层给iOS/Android/UWP三个平台做的统一接口,适配了.NET Standard 2.0(当然也包含.NET Standard 1.0 / iOS / Android)。通过Xamarin.Essentails你可以非常快捷地访问不同平台的摄像头,地理位置,网络检测,更能调用如打电话,相册,通讯录等相当方便实用。如我需要了解设备信息的时候,通过Xamarin.Essentails就是一句非常简单的话就可以完成了
运行生成效果
话说回来,在Xamarin.Essential之前,其实Xamarin也推出了Xamarin.Mobile(点击查看)和Plugin(点击查看) 。我们先来看看这两位旧人所做的事,如果对比代码其实也差不多,通过PCL的方式对设备底层API进行访问。(ps : 图一是Xamarin.Mobile , 图二Xamarin.Plugins)
看看上面的代码是比较有趣,可以预想到用原生方法写一个摄像头调用你可能需要更多的工作,而且这更接近.NET程序员的使用习惯。假若你希望为Xamarin打造一个跨平台的,也能针对不同平台底层操作,又有一个通用接口的库,这三个通用组件的源码就是很好的教程。
在Xamarin中实现跨平台访问,方法有几种:
1. 通过检测平台的方式,最常用的是宏定义
<span style="font-size:12px;">
#if __IOS__
// iOS-specific code
#endif
#if __TVOS__
// tv-specific stuff
#endif
#if __WATCHOS__
// watch-specific stuff
#endif
#if __ANDROID__
// Android-specific code
#endif
</span>
2. 或者通过代码的方式, Xamarin.Forms.Device.Idiom去完成
<span style="font-size:12px;">
if (Xamarin.Forms.Device.Idiom == TargetIdiom.Phone)
{
MainPage = new NavigationPage(new MyPage());
}
else if(Xamarin.Forms.Device.Idiom == TargetIdiom.Tablet)
{
// etc
}
else if(Xamarin.Forms.Device.Idiom == TargetIdiom.Desktop)
{
// etc
}
else if (Xamarin.Forms.Device.Idiom == TargetIdiom.Unsupported)
{
// etc
}
else
{
// etc
}</span>
这个方式除了在代码也可以在XAML
<span style="font-size:12px;">
<OnIdiom x:TypeArguments="View">
<OnIdiom.Phone>
<Grid>
<Label Text="Phone content view" />
</Grid>
</OnIdiom.Phone>
<OnIdiom.Tablet>
<Grid>
<Label Text="Tablet content view" />
</Grid>
</OnIdiom.Tablet>
</OnIdiom></span>
3. 用DependencyService,在通过公用层生成接口,再在不同平台上实现。这是在Xamarin中最常用的方法,
回到封装库,首先要定下一个目标就是做个.NET Standard的库,而不再是做PCL. 还有做这种通用库更应该考虑兼容多平台,如iOS/Android/UWP等。以往的做法你可能需要搭建很多的目录,然后去继承一个公共接口去完成。现在通过MSBuild.Sdk.Extras(点击查看), 通过MSBuild可以对不同平台进行快速编译,生成跨平台的库。参考Xamarin.Essentials(点击进入),我自己开始编写一个简单的库。先看看实现原理(如图)
在.NET Standard 项目中你可以针对不同平台进行编译,利用第三方的MSBuild.Sdk.Extras进行不同平台库的生成工作,在这种方法上你不再需要上面提到的宏定义或Dependency Service,只需要针对预先设置好的文件进行跨平台编译,这大大方便了代码的管理和维护。xx.standard.cs是一个公用的文件,相当于为不同平台定义了一个接口,而具体实现放到各自平台上如xx.ios.cs , xx.android.cs ..... 最后通过shared封装公共方法暴露给不同项目访问。
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<!--Work around so the conditions work below-->
<TargetFrameworks>netstandard1.0;netstandard2.0;Xamarin.iOS10;MonoAndroid71;</TargetFrameworks>
<Product>$(AssemblyName)($(TargetFramework))</Product>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<EnableDefaultItems>false</EnableDefaultItems>
<BuildOutputTargetFolder>$(TargetFramework)</BuildOutputTargetFolder>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)'=='Debug' ">
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)'=='Release' ">
<DebugType>pdbonly</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<OutputPath>bin\Debug\$(TargetFramework)</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<OutputPath>bin\Release\$(TargetFramework)</OutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MSBuild.Sdk.Extras" Version="1.4.0" PrivateAssets="All" />
<Compile Include="**\*.shared.cs" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard'))">
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors" />
<Compile Include="**\*.netstandard.cs" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('MonoAndroid'))">
<PackageReference Include="Xamarin.Android.Support.CustomTabs" Version="25.4.0.2" />
<PackageReference Include="Xamarin.Android.Support.Core.Utils" Version="25.4.0.2" />
<Reference Include="Mono.Android" />
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors" />
<Compile Include="**\*.android.cs" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.iOS'))">
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors" />
<Compile Include="**\*.ios.cs" />
</ItemGroup>
<Import Project="$(MSBuildSDKExtrasTargets)" Condition="Exists('$(MSBuildSDKExtrasTargets)')" />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
剩下的事情,就是针对不同平台作定义了
如Kinfey.ios.cs
using System;
namespace DNDemo.Lib
{
public static partial class Kinfey
{
internal static string Check(){
return "iOS";
}
}
}
如Kinfey.android.cs
using System;
namespace DNDemo.Lib
{
public static partial class Kinfey
{
internal static string Check()
{
return "Android";
}
}
}
而Kinfey.netstandard.cs
using System;
namespace DNDemo.Lib
{
public static partial class Kinfey
{
internal static string Check() => throw new NotImplementedException();
}
}
最后暴露的接口在Kinfey.shared.cs
using System;
namespace DNDemo.Lib
{
public static partial class Kinfey
{
public static string CheckInfo(){
return Check();
}
}
}
这样你就可以进行编译了,在Windows上你直接用Visual Studio 编译即可,在macOS上你需要编译就需要用命令行了(请高人指点下,我不知道为啥VS for mac不能build跨平台的.NET Stanard......),首先你得restore , 接着执行
msbuild DNDemo.Lib.csproj /p:Configuration=Debug
这个时候,你就会得到四个库.net standard 1.0 / .net standard 2.0 / ios / android 。找个项目调用一下,结果如下:
赠送源码一份:(点击下载)
最后Xamarin的第三方库在国外有不少,但国内还是相对较少,希望各位爱好者都贡献一下,为这个技术落地贡献一份力量。