从Xamarin.Essentials谈Xamarin库的封装
編者語:Xamarin在國內(nèi)的推廣還需要努力,其實(shí)這真的是移動(dòng)端開發(fā)的一大福音,畢竟用一份代碼的時(shí)間可以生成iOS/Android/Windows/Linux/macOS/Tizen多個(gè)平臺(tái),而且是原生的性能。Xamarin在Build 2018發(fā)布的新功能有Xamarin.Essentials(點(diǎn)擊查看) , Hyper-V for Xamarin Android Emulator ,還有Xamarin.Forms 3.0。Xamarin.Forms 3.0 和 Xamarin.Essentials 都會(huì)是一個(gè)質(zhì)的飛躍。Xamarin.Forms 有全新的布局FlexLayout ,更好地和原生控件對(duì)接,還新增支持GTK+/Tizen。而Xamarin.Essentials的發(fā)布則大大提升開發(fā)的效率,把因?yàn)槠脚_(tái)差異造成的代碼不一致的底層接口重新做了歸一,這樣做提升了編碼效率。
? ? 在Build2018前的兩周左右,我拿到了Xamarin.Essentials的測(cè)試版本(基于nda我只能等到現(xiàn)在才能發(fā)布),這是一個(gè)為訪問一些設(shè)備硬件和底層給iOS/Android/UWP三個(gè)平臺(tái)做的統(tǒng)一接口,適配了.NET Standard 2.0(當(dāng)然也包含.NET Standard 1.0 / iOS / Android)。通過Xamarin.Essentails你可以非常快捷地訪問不同平臺(tái)的攝像頭,地理位置,網(wǎng)絡(luò)檢測(cè),更能調(diào)用如打電話,相冊(cè),通訊錄等相當(dāng)方便實(shí)用。如我需要了解設(shè)備信息的時(shí)候,通過Xamarin.Essentails就是一句非常簡單的話就可以完成了
?
?
? ? ? 運(yùn)行生成效果
? ? ??
? ? ?話說回來,在Xamarin.Essential之前,其實(shí)Xamarin也推出了Xamarin.Mobile(點(diǎn)擊查看)和Plugin(點(diǎn)擊查看) 。我們先來看看這兩位舊人所做的事,如果對(duì)比代碼其實(shí)也差不多,通過PCL的方式對(duì)設(shè)備底層API進(jìn)行訪問。(ps : 圖一是Xamarin.Mobile , 圖二Xamarin.Plugins)
? ? ??? ?
? ? ? 看看上面的代碼是比較有趣,可以預(yù)想到用原生方法寫一個(gè)攝像頭調(diào)用你可能需要更多的工作,而且這更接近.NET程序員的使用習(xí)慣。假若你希望為Xamarin打造一個(gè)跨平臺(tái)的,也能針對(duì)不同平臺(tái)底層操作,又有一個(gè)通用接口的庫,這三個(gè)通用組件的源碼就是很好的教程。
? ? ? 在Xamarin中實(shí)現(xiàn)跨平臺(tái)訪問,方法有幾種:
? ? ? 1. 通過檢測(cè)平臺(tái)的方式,最常用的是宏定義? ? ? ??
<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>
?這個(gè)方式除了在代碼也可以在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,在通過公用層生成接口,再在不同平臺(tái)上實(shí)現(xiàn)。這是在Xamarin中最常用的方法,
? ? ? ??
? ? ? 回到封裝庫,首先要定下一個(gè)目標(biāo)就是做個(gè).NET Standard的庫,而不再是做PCL. 還有做這種通用庫更應(yīng)該考慮兼容多平臺(tái),如iOS/Android/UWP等。以往的做法你可能需要搭建很多的目錄,然后去繼承一個(gè)公共接口去完成。現(xiàn)在通過MSBuild.Sdk.Extras(點(diǎn)擊查看), 通過MSBuild可以對(duì)不同平臺(tái)進(jìn)行快速編譯,生成跨平臺(tái)的庫。參考Xamarin.Essentials(點(diǎn)擊進(jìn)入),我自己開始編寫一個(gè)簡單的庫。先看看實(shí)現(xiàn)原理(如圖)? ? ? ?
? ? ? ?在.NET Standard 項(xiàng)目中你可以針對(duì)不同平臺(tái)進(jìn)行編譯,利用第三方的MSBuild.Sdk.Extras進(jìn)行不同平臺(tái)庫的生成工作,在這種方法上你不再需要上面提到的宏定義或Dependency Service,只需要針對(duì)預(yù)先設(shè)置好的文件進(jìn)行跨平臺(tái)編譯,這大大方便了代碼的管理和維護(hù)。xx.standard.cs是一個(gè)公用的文件,相當(dāng)于為不同平臺(tái)定義了一個(gè)接口,而具體實(shí)現(xiàn)放到各自平臺(tái)上如xx.ios.cs , xx.android.cs ..... 最后通過shared封裝公共方法暴露給不同項(xiàng)目訪問。
<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>
?剩下的事情,就是針對(duì)不同平臺(tái)作定義了
? ? ? 如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();
? ? ? ? }
? ? }
}
這樣你就可以進(jìn)行編譯了,在Windows上你直接用Visual Studio 編譯即可,在macOS上你需要編譯就需要用命令行了(請(qǐng)高人指點(diǎn)下,我不知道為啥VS for mac不能build跨平臺(tái)的.NET Stanard......),首先你得restore , 接著執(zhí)行
msbuild DNDemo.Lib.csproj /p:Configuration=Debug
這個(gè)時(shí)候,你就會(huì)得到四個(gè)庫.net standard 1.0 / .net standard 2.0 / ios / android 。找個(gè)項(xiàng)目調(diào)用一下,結(jié)果如下:
? ? ???
? ? ? 贈(zèng)送源碼一份:(點(diǎn)擊下載)
? ? ? 最后Xamarin的第三方庫在國外有不少,但國內(nèi)還是相對(duì)較少,希望各位愛好者都貢獻(xiàn)一下,為這個(gè)技術(shù)落地貢獻(xiàn)一份力量。
原文地址: https://blog.csdn.net/kinfey/article/details/80218291
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號(hào)文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的从Xamarin.Essentials谈Xamarin库的封装的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你关心才值得分享 | K8S网络安全之访
- 下一篇: qMISPlat入门级使用问题解答一