This commit is contained in:
Matthew Leibowitz 2020-10-15 22:57:01 +02:00
Родитель 72a3039011
Коммит 21cb3c162a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: ECDB25CC0E22FC46
12 изменённых файлов: 768 добавлений и 619 удалений

Просмотреть файл

@ -7,7 +7,7 @@
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<RootNamespace>DeviceTests.Droid</RootNamespace> <RootNamespace>DeviceTests.Droid</RootNamespace>
<AssemblyName>XamarinEssentialsDeviceTestsAndroid</AssemblyName> <AssemblyName>DeviceTestsAndroid</AssemblyName>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion> <TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
<AndroidApplication>True</AndroidApplication> <AndroidApplication>True</AndroidApplication>
<AndroidUseIntermediateDesignerFile>true</AndroidUseIntermediateDesignerFile> <AndroidUseIntermediateDesignerFile>true</AndroidUseIntermediateDesignerFile>

Просмотреть файл

@ -1 +0,0 @@
This file was in the app bundle.

Просмотреть файл

@ -1 +0,0 @@
This file was in the app bundle.

Просмотреть файл

@ -8,7 +8,7 @@
<OutputType>AppContainerExe</OutputType> <OutputType>AppContainerExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DeviceTests.UWP</RootNamespace> <RootNamespace>DeviceTests.UWP</RootNamespace>
<AssemblyName>XamarinEssentialsDeviceTestsUWP</AssemblyName> <AssemblyName>DeviceTestsUWP</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage> <DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier> <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion> <TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
@ -17,7 +17,9 @@
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile> <EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled> <AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<PackageCertificateThumbprint>7301D596D36DC7AD797E01BBF93CC2789AEA96C0</PackageCertificateThumbprint>
<PackageCertificateKeyFile>DeviceTests.UWP_TemporaryKey.pfx</PackageCertificateKeyFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -113,25 +115,14 @@
<Prefer32Bit>true</Prefer32Bit> <Prefer32Bit>true</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="UnitTests.HeadlessRunner" Version="2.0.0" />
<PackageReference Include="Xamarin.Forms" Version="4.8.0.1451" /> <PackageReference Include="Xamarin.Forms" Version="4.8.0.1451" />
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.2.9" /> <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.2.9" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.devices" Version="2.5.25" /> <PackageReference Include="xunit.runner.devices" Version="2.5.25" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<SDKReference Include="WindowsMobile, Version=10.0.16299.0">
<Name>Windows Mobile Extensions for the UWP</Name>
</SDKReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Xamarin.Essentials\Xamarin.Essentials.csproj">
<Project>{63a4f6a1-48bf-4d32-aed7-82f605edb042}</Project>
<Name>Xamarin.Essentials</Name>
</ProjectReference>
<ProjectReference Include="..\DeviceTests\DeviceTests.csproj"> <ProjectReference Include="..\DeviceTests\DeviceTests.csproj">
<Project>{be0de9a3-d92c-47c5-9ec4-dfb546bbdf77}</Project> <Project>{E049A504-C168-41DC-80DF-0C4C6F363761}</Project>
<Name>DeviceTests</Name> <Name>DeviceTests</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
@ -153,9 +144,6 @@
</AppxManifest> </AppxManifest>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="AppBundleFile.txt" />
<Content Include="Folder\AppBundleFile_Nested.txt" />
<Content Include="AppBundleFile_NoExtension" />
<Content Include="Properties\Default.rd.xml" /> <Content Include="Properties\Default.rd.xml" />
<Content Include="Assets\LockScreenLogo.scale-100.png" /> <Content Include="Assets\LockScreenLogo.scale-100.png" />
<Content Include="Assets\LockScreenLogo.scale-125.png" /> <Content Include="Assets\LockScreenLogo.scale-125.png" />
@ -190,10 +178,10 @@
<Content Include="Assets\Wide310x150Logo.scale-400.png" /> <Content Include="Assets\Wide310x150Logo.scale-400.png" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="DeviceTests.UWP_TemporaryKey.pfx" /> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> <None Include="DeviceTests.UWP_TemporaryKey.pfx" />
</ItemGroup> </ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' "> <PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion> <VisualStudioVersion>14.0</VisualStudioVersion>

Просмотреть файл

@ -1 +0,0 @@
This file was in the app bundle.

Просмотреть файл

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp"> <Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp">
<Identity Name="ec0cc741-fd3e-485c-81be-68815c480690" Publisher="CN=Microsoft" Version="1.0.1.0" /> <Identity Name="ec0cc741-fd3e-485c-81be-68815c480690" Publisher="CN=dotnet-devices" Version="1.0.1.0" />
<mp:PhoneIdentity PhoneProductId="ec0cc741-fd3e-485c-81be-68815c480690" PhonePublisherId="00000000-0000-0000-0000-000000000000" /> <mp:PhoneIdentity PhoneProductId="ec0cc741-fd3e-485c-81be-68815c480690" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties> <Properties>
<DisplayName>Tests</DisplayName> <DisplayName>Tests</DisplayName>
<PublisherDisplayName>Microsoft</PublisherDisplayName> <PublisherDisplayName>dotnet-devices</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo> <Logo>Assets\StoreLogo.png</Logo>
</Properties> </Properties>
<Dependencies> <Dependencies>
@ -31,8 +31,5 @@
</Applications> </Applications>
<Capabilities> <Capabilities>
<Capability Name="internetClient" /> <Capability Name="internetClient" />
<Capability Name="internetClientServer" />
<Capability Name="privateNetworkClientServer" />
<DeviceCapability Name="location" />
</Capabilities> </Capabilities>
</Package> </Package>

Просмотреть файл

@ -10,9 +10,4 @@
<PackageReference Include="xunit.runner.devices" Version="2.5.25" /> <PackageReference Include="xunit.runner.devices" Version="2.5.25" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Update="CombinedWriter.cs">
<SubType></SubType>
</Compile>
</ItemGroup>
</Project> </Project>

Просмотреть файл

@ -1,92 +1,246 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio Version 16
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnet-devices", "dotnet-devices\dotnet-devices.csproj", "{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}" VisualStudioVersion = 16.0.30523.141
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-devices", "dotnet-devices\dotnet-devices.csproj", "{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnet-devices.Tests", "dotnet-devices.Tests\dotnet-devices.Tests.csproj", "{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-devices.Tests", "dotnet-devices.Tests\dotnet-devices.Tests.csproj", "{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DeviceTests", "DeviceTests", "{BDAAACF1-1483-412C-A14C-A7976D0FBF3D}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DeviceTests", "DeviceTests", "{BDAAACF1-1483-412C-A14C-A7976D0FBF3D}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceTests", "DeviceTests\DeviceTests\DeviceTests.csproj", "{E049A504-C168-41DC-80DF-0C4C6F363761}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeviceTests", "DeviceTests\DeviceTests\DeviceTests.csproj", "{E049A504-C168-41DC-80DF-0C4C6F363761}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceTests.iOS", "DeviceTests\DeviceTests.iOS\DeviceTests.iOS.csproj", "{EE8FC716-27FC-405B-BD27-AF17E01A6671}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceTests.iOS", "DeviceTests\DeviceTests.iOS\DeviceTests.iOS.csproj", "{EE8FC716-27FC-405B-BD27-AF17E01A6671}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceTests.Android", "DeviceTests\DeviceTests.Android\DeviceTests.Android.csproj", "{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceTests.Android", "DeviceTests\DeviceTests.Android\DeviceTests.Android.csproj", "{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceTests.UWP", "DeviceTests\DeviceTests.UWP\DeviceTests.UWP.csproj", "{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU Debug|ARM = Debug|ARM
Debug|iPhoneSimulator = Debug|iPhoneSimulator Debug|ARM64 = Debug|ARM64
Release|iPhoneSimulator = Release|iPhoneSimulator
Debug|iPhone = Debug|iPhone Debug|iPhone = Debug|iPhone
Debug|iPhoneSimulator = Debug|iPhoneSimulator
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|iPhone = Release|iPhone Release|iPhone = Release|iPhone
Release|iPhoneSimulator = Release|iPhoneSimulator
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|Any CPU.Build.0 = Debug|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|Any CPU.ActiveCfg = Release|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|ARM.ActiveCfg = Debug|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|Any CPU.Build.0 = Release|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|ARM.Build.0 = Debug|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|ARM64.Build.0 = Debug|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|iPhone.ActiveCfg = Debug|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|iPhone.Build.0 = Debug|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|iPhone.Build.0 = Debug|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|x64.ActiveCfg = Debug|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|x64.Build.0 = Debug|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|x86.ActiveCfg = Debug|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|x86.Build.0 = Debug|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|Any CPU.Build.0 = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|ARM.ActiveCfg = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|ARM.Build.0 = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|ARM64.ActiveCfg = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|ARM64.Build.0 = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|iPhone.ActiveCfg = Release|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|iPhone.ActiveCfg = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|iPhone.Build.0 = Release|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|iPhone.Build.0 = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|x64.ActiveCfg = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|x64.Build.0 = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|x86.ActiveCfg = Release|Any CPU
{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|x86.Build.0 = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|Any CPU.Build.0 = Debug|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|Any CPU.ActiveCfg = Release|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|ARM.ActiveCfg = Debug|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|Any CPU.Build.0 = Release|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|ARM.Build.0 = Debug|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|ARM64.Build.0 = Debug|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|iPhone.ActiveCfg = Debug|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|iPhone.Build.0 = Debug|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|iPhone.Build.0 = Debug|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|x64.ActiveCfg = Debug|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|x64.Build.0 = Debug|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|x86.ActiveCfg = Debug|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|x86.Build.0 = Debug|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|Any CPU.Build.0 = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|ARM.ActiveCfg = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|ARM.Build.0 = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|ARM64.ActiveCfg = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|ARM64.Build.0 = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|iPhone.ActiveCfg = Release|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|iPhone.ActiveCfg = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|iPhone.Build.0 = Release|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|iPhone.Build.0 = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|x64.ActiveCfg = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|x64.Build.0 = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|x86.ActiveCfg = Release|Any CPU
{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|x86.Build.0 = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|Any CPU.Build.0 = Debug|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|Any CPU.ActiveCfg = Release|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|ARM.ActiveCfg = Debug|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|Any CPU.Build.0 = Release|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|ARM.Build.0 = Debug|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|ARM64.Build.0 = Debug|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|iPhone.ActiveCfg = Debug|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|iPhone.Build.0 = Debug|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|iPhone.Build.0 = Debug|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|x64.ActiveCfg = Debug|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|x64.Build.0 = Debug|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|x86.ActiveCfg = Debug|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|x86.Build.0 = Debug|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|Any CPU.Build.0 = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|ARM.ActiveCfg = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|ARM.Build.0 = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|ARM64.ActiveCfg = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|ARM64.Build.0 = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|iPhone.ActiveCfg = Release|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|iPhone.ActiveCfg = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|iPhone.Build.0 = Release|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|iPhone.Build.0 = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|x64.ActiveCfg = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|x64.Build.0 = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|x86.ActiveCfg = Release|Any CPU
{E049A504-C168-41DC-80DF-0C4C6F363761}.Release|x86.Build.0 = Release|Any CPU
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|ARM.ActiveCfg = Debug|iPhone
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|Any CPU.Build.0 = Release|iPhoneSimulator {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|ARM.Build.0 = Debug|iPhone
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|ARM64.ActiveCfg = Debug|iPhone
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|ARM64.Build.0 = Debug|iPhone
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|iPhone.ActiveCfg = Debug|iPhone {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|iPhone.ActiveCfg = Debug|iPhone
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|iPhone.Build.0 = Debug|iPhone {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|iPhone.Build.0 = Debug|iPhone
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|x64.ActiveCfg = Debug|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|x64.Build.0 = Debug|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|x86.ActiveCfg = Debug|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|x86.Build.0 = Debug|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|Any CPU.Build.0 = Release|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|ARM.ActiveCfg = Release|iPhone
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|ARM.Build.0 = Release|iPhone
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|ARM64.ActiveCfg = Release|iPhone
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|ARM64.Build.0 = Release|iPhone
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|iPhone.ActiveCfg = Release|iPhone {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|iPhone.ActiveCfg = Release|iPhone
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|iPhone.Build.0 = Release|iPhone {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|iPhone.Build.0 = Release|iPhone
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|x64.ActiveCfg = Release|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|x64.Build.0 = Release|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|x86.ActiveCfg = Release|iPhoneSimulator
{EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|x86.Build.0 = Release|iPhoneSimulator
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|Any CPU.Build.0 = Debug|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|Any CPU.ActiveCfg = Release|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|Any CPU.Build.0 = Release|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|ARM.ActiveCfg = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|ARM.Build.0 = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|ARM.Deploy.0 = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|ARM64.Build.0 = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|ARM64.Deploy.0 = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhone.ActiveCfg = Debug|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhone.Build.0 = Debug|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhone.Build.0 = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhone.Deploy.0 = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|x64.ActiveCfg = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|x64.Build.0 = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|x64.Deploy.0 = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|x86.ActiveCfg = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|x86.Build.0 = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|x86.Deploy.0 = Debug|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|Any CPU.Build.0 = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|Any CPU.Deploy.0 = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|ARM.ActiveCfg = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|ARM.Build.0 = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|ARM.Deploy.0 = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|ARM64.ActiveCfg = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|ARM64.Build.0 = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|ARM64.Deploy.0 = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhone.ActiveCfg = Release|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhone.ActiveCfg = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhone.Build.0 = Release|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhone.Build.0 = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhone.Deploy.0 = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|x64.ActiveCfg = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|x64.Build.0 = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|x64.Deploy.0 = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|x86.ActiveCfg = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|x86.Build.0 = Release|Any CPU
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|x86.Deploy.0 = Release|Any CPU
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|Any CPU.ActiveCfg = Debug|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|Any CPU.Build.0 = Debug|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|Any CPU.Deploy.0 = Debug|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|ARM.ActiveCfg = Debug|ARM
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|ARM.Build.0 = Debug|ARM
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|ARM.Deploy.0 = Debug|ARM
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|ARM64.ActiveCfg = Debug|ARM64
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|ARM64.Build.0 = Debug|ARM64
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|ARM64.Deploy.0 = Debug|ARM64
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|iPhone.ActiveCfg = Debug|ARM
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|iPhone.Build.0 = Debug|ARM
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|iPhone.Deploy.0 = Debug|ARM
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|iPhoneSimulator.ActiveCfg = Debug|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|iPhoneSimulator.Build.0 = Debug|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|iPhoneSimulator.Deploy.0 = Debug|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|x64.ActiveCfg = Debug|x64
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|x64.Build.0 = Debug|x64
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|x64.Deploy.0 = Debug|x64
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|x86.ActiveCfg = Debug|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|x86.Build.0 = Debug|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|x86.Deploy.0 = Debug|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|Any CPU.ActiveCfg = Release|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|Any CPU.Build.0 = Release|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|Any CPU.Deploy.0 = Release|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|ARM.ActiveCfg = Release|ARM
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|ARM.Build.0 = Release|ARM
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|ARM.Deploy.0 = Release|ARM
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|ARM64.ActiveCfg = Release|ARM64
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|ARM64.Build.0 = Release|ARM64
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|ARM64.Deploy.0 = Release|ARM64
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|iPhone.ActiveCfg = Release|ARM
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|iPhone.Build.0 = Release|ARM
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|iPhone.Deploy.0 = Release|ARM
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|iPhoneSimulator.ActiveCfg = Release|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|iPhoneSimulator.Build.0 = Release|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|iPhoneSimulator.Deploy.0 = Release|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|x64.ActiveCfg = Release|x64
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|x64.Build.0 = Release|x64
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|x64.Deploy.0 = Release|x64
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|x86.ActiveCfg = Release|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|x86.Build.0 = Release|x86
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|x86.Deploy.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{E049A504-C168-41DC-80DF-0C4C6F363761} = {BDAAACF1-1483-412C-A14C-A7976D0FBF3D} {E049A504-C168-41DC-80DF-0C4C6F363761} = {BDAAACF1-1483-412C-A14C-A7976D0FBF3D}
{EE8FC716-27FC-405B-BD27-AF17E01A6671} = {BDAAACF1-1483-412C-A14C-A7976D0FBF3D} {EE8FC716-27FC-405B-BD27-AF17E01A6671} = {BDAAACF1-1483-412C-A14C-A7976D0FBF3D}
{CB2072E0-A437-4811-AE17-16CAE0DDA1B1} = {BDAAACF1-1483-412C-A14C-A7976D0FBF3D} {CB2072E0-A437-4811-AE17-16CAE0DDA1B1} = {BDAAACF1-1483-412C-A14C-A7976D0FBF3D}
{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B} = {BDAAACF1-1483-412C-A14C-A7976D0FBF3D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {14623120-794D-4BBB-8509-B49876E6AF2A}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

Просмотреть файл

@ -1,6 +1,6 @@
using System; using Microsoft.Extensions.Logging;
using System;
using System.IO; using System.IO;
using Microsoft.Extensions.Logging;
namespace DotNetDevices.Android namespace DotNetDevices.Android
{ {
@ -24,11 +24,12 @@ namespace DotNetDevices.Android
return sdkRoot; return sdkRoot;
var path = Path.Combine(sdkRoot, toolPath); var path = Path.Combine(sdkRoot, toolPath);
if (!File.Exists(path)) var foundPath = FindFuzzyPath(path);
if (foundPath == null)
throw new FileNotFoundException($"Path to tool '{toolPath}' was not found in the SDK '{sdkRoot}'.", path); throw new FileNotFoundException($"Path to tool '{toolPath}' was not found in the SDK '{sdkRoot}'.", path);
// return the full path to the tool // return the full path to the tool
return path; return foundPath;
} }
foreach (var envvar in envvars) foreach (var envvar in envvars)
@ -48,17 +49,34 @@ namespace DotNetDevices.Android
return varSdkRoot; return varSdkRoot;
var path = Path.Combine(varSdkRoot, toolPath); var path = Path.Combine(varSdkRoot, toolPath);
if (!File.Exists(path)) var foundPath = FindFuzzyPath(path);
if (foundPath == null)
{ {
logger?.LogWarning($"Found SDK at '{varSdkRoot}', but it did not contan the tool '{toolPath}'."); logger?.LogWarning($"Found SDK at '{varSdkRoot}', but it did not contan the tool '{toolPath}'.");
continue; continue;
} }
// return the full path to the tool // return the full path to the tool
return path; return foundPath;
} }
return null; return null;
} }
private static string? FindFuzzyPath(string path)
{
if (File.Exists(path))
return path;
var otherPath = Path.ChangeExtension(path, ".exe");
if (File.Exists(otherPath))
return otherPath;
otherPath = Path.ChangeExtension(path, ".bat");
if (File.Exists(otherPath))
return otherPath;
return null;
}
} }
} }

Просмотреть файл

@ -1,109 +1,109 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using DotNetDevices.Processes; using DotNetDevices.Processes;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace DotNetDevices.Android namespace DotNetDevices.Android
{ {
public class EmulatorManager public class EmulatorManager
{ {
private static readonly Regex consoleListeningRegex = new Regex(@"emulator: control console listening on port (\d+), ADB on port (\d+)"); private static readonly Regex consoleListeningRegex = new Regex(@"emulator: control console listening on port (\d+), ADB on port (\d+)");
private static readonly Regex adbConnectedRegex = new Regex(@"emulator: onGuestSendCommand: \[(.+)\] Adb connected, start proxing data"); private static readonly Regex adbConnectedRegex = new Regex(@"emulator: onGuestSendCommand: \[(.+)\] Adb connected, start proxing data");
private static readonly Regex alreadyBootedRegex = new Regex(@"emulator: ERROR: Running multiple emulators with the same AVD is an experimental feature\."); private static readonly Regex alreadyBootedRegex = new Regex(@"emulator: ERROR: Running multiple emulators with the same AVD is an experimental feature\.");
private readonly ProcessRunner processRunner; private readonly ProcessRunner processRunner;
private readonly ILogger? logger; private readonly ILogger? logger;
private readonly string emulator; private readonly string emulator;
public EmulatorManager(string? sdkRoot = null, ILogger? logger = null) public EmulatorManager(string? sdkRoot = null, ILogger? logger = null)
{ {
this.logger = logger; this.logger = logger;
processRunner = new ProcessRunner(logger); processRunner = new ProcessRunner(logger);
emulator = AndroidSDK.FindPath(sdkRoot, Path.Combine("emulator", "emulator"), logger) emulator = AndroidSDK.FindPath(sdkRoot, Path.Combine("emulator", "emulator"), logger)
?? throw new ArgumentException($"Unable to locate the Android Emulator. Make sure that ANDROID_HOME or ANDROID_SDK_ROOT is set."); ?? throw new ArgumentException($"Unable to locate the Android Emulator. Make sure that ANDROID_HOME or ANDROID_SDK_ROOT is set.");
} }
public async Task<int> BootVirtualDeviceAsync(string name, BootVirtualDeviceOptions? options = null, CancellationToken cancellationToken = default) public async Task<int> BootVirtualDeviceAsync(string name, BootVirtualDeviceOptions? options = null, CancellationToken cancellationToken = default)
{ {
if (name == null) if (name == null)
throw new ArgumentNullException(nameof(name)); throw new ArgumentNullException(nameof(name));
logger?.LogInformation($"Booting virtual device '{name}'..."); logger?.LogInformation($"Booting virtual device '{name}'...");
var args = $"-avd {name} -verbose"; var args = $"-avd {name} -verbose";
if (options?.NoWindow == true) if (options?.NoWindow == true)
args += " -no-boot-anim -no-window"; args += " -no-boot-anim -no-window";
if (options?.NoSnapshots == true) if (options?.NoSnapshots == true)
args += " -no-snapshot"; args += " -no-snapshot";
if (options?.WipeData == true) if (options?.WipeData == true)
args += " -wipe-data"; args += " -wipe-data";
var port = -1; var port = -1;
try try
{ {
await processRunner.RunAsync(emulator, args, FindComplete, cancellationToken).ConfigureAwait(false); await processRunner.RunAsync(emulator, args, FindComplete, cancellationToken).ConfigureAwait(false);
} }
catch (ProcessResultException ex) when (IsAlreadyLaunched(ex)) catch (ProcessResultException ex) when (IsAlreadyLaunched(ex))
{ {
// no-op // no-op
} }
return port; return port;
bool FindComplete(ProcessOutput output) bool FindComplete(ProcessOutput output)
{ {
if (!output.IsError && output.Data is string o) if (!output.IsError && output.Data is string o)
{ {
if (port <= 0) if (port <= 0)
{ {
// first find port // first find port
var match = consoleListeningRegex.Match(o); var match = consoleListeningRegex.Match(o);
if (match.Success) if (match.Success)
port = int.Parse(match.Groups[1].Value); port = int.Parse(match.Groups[1].Value);
} }
else else
{ {
// then wait for the boot finished // then wait for the boot finished
var match = adbConnectedRegex.Match(o); var match = adbConnectedRegex.Match(o);
if (match.Success) if (match.Success)
return false; return false;
} }
} }
return true; return true;
} }
bool IsAlreadyLaunched(ProcessResultException ex) bool IsAlreadyLaunched(ProcessResultException ex)
{ {
foreach (var output in ex.ProcessResult.GetOutput()) foreach (var output in ex.ProcessResult.GetOutput())
{ {
var match = alreadyBootedRegex.Match(output); var match = alreadyBootedRegex.Match(output);
if (match.Success) if (match.Success)
return true; return true;
} }
return false; return false;
} }
} }
public async Task<IEnumerable<VirtualDevice>> GetVirtualDevicesAsync(CancellationToken cancellationToken = default) public async Task<IEnumerable<VirtualDevice>> GetVirtualDevicesAsync(CancellationToken cancellationToken = default)
{ {
logger?.LogInformation("Retrieving all the virtual devices..."); logger?.LogInformation("Retrieving all the virtual devices...");
var args = $"-list-avds"; var args = $"-list-avds";
var result = await processRunner.RunAsync(emulator, args, null, cancellationToken).ConfigureAwait(false); var result = await processRunner.RunAsync(emulator, args, null, cancellationToken).ConfigureAwait(false);
var avd = new List<VirtualDevice>(result.OutputCount); var avd = new List<VirtualDevice>(result.OutputCount);
foreach (var output in result.GetOutput()) foreach (var output in result.GetOutput())
{ {
avd.Add(new VirtualDevice(output)); avd.Add(new VirtualDevice(output));
} }
return avd; return avd;
} }
} }
} }

Просмотреть файл

@ -1,214 +1,214 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine; using System.CommandLine;
using System.CommandLine.Invocation; using System.CommandLine.Invocation;
using System.CommandLine.Parsing; using System.CommandLine.Parsing;
using System.CommandLine.Rendering; using System.CommandLine.Rendering;
using System.CommandLine.Rendering.Views; using System.CommandLine.Rendering.Views;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using DotNetDevices.Android; using DotNetDevices.Android;
using DotNetDevices.Apple; using DotNetDevices.Apple;
using DotNetDevices.Logging; using DotNetDevices.Logging;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace DotNetDevices.Commands namespace DotNetDevices.Commands
{ {
public class AndroidCommand public class AndroidCommand
{ {
public static Command Create() public static Command Create()
{ {
return new Command("android", "Work with Android virtual devices.") return new Command("android", "Work with Android virtual devices.")
{ {
new Command("list", "List the virtual devices.") new Command("list", "List the virtual devices.")
{ {
new Option<string?>(new[] { "--sdk" }, "Whether or not to only include the available simulators."), new Option<string?>(new[] { "--sdk" }, "Whether or not to only include the available simulators."),
new Option(new[] { "--available" }, "Whether or not to only include the available simulators."), new Option(new[] { "--available" }, "Whether or not to only include the available simulators."),
new Option(new[] { "--booted" }, "Whether or not to only include the booted simulators."), new Option(new[] { "--booted" }, "Whether or not to only include the booted simulators."),
new Option<SimulatorRuntime>(new[] { "--runtime" }, "The runtime to use when filtering."), new Option<SimulatorRuntime>(new[] { "--runtime" }, "The runtime to use when filtering."),
new Option<string?>(new[] { "--version" }, description: "The runtime version to use when filtering. This could be in either <major> or <major>.<minor> version formats.", new Option<string?>(new[] { "--version" }, description: "The runtime version to use when filtering. This could be in either <major> or <major>.<minor> version formats.",
parseArgument: CommandLine.ParseVersion), parseArgument: CommandLine.ParseVersion),
CommandLine.CreateVerbosity(), CommandLine.CreateVerbosity(),
new Argument<string?>("TERM", "The search term to use when filtering simulators. This could be any number of properties (UDID, runtime, version, availability, or state) as well as part of the simulator name.") new Argument<string?>("TERM", "The search term to use when filtering simulators. This could be any number of properties (UDID, runtime, version, availability, or state) as well as part of the simulator name.")
{ Arity = ArgumentArity.ZeroOrOne }, { Arity = ArgumentArity.ZeroOrOne },
}.WithHandler(CommandHandler.Create(typeof(AndroidCommand).GetMethod(nameof(HandleListAsync))!)), }.WithHandler(CommandHandler.Create(typeof(AndroidCommand).GetMethod(nameof(HandleListAsync))!)),
new Command("create", "Create a new virtual device.") new Command("create", "Create a new virtual device.")
{ {
new Option<string?>(new[] { "--sdk" }, "The path to the Android SDK directory."), new Option<string?>(new[] { "--sdk" }, "The path to the Android SDK directory."),
new Option(new[] { "--replace" }, "Replace any existing virtual devices with the same name."), new Option(new[] { "--replace" }, "Replace any existing virtual devices with the same name."),
CommandLine.CreateVerbosity(), CommandLine.CreateVerbosity(),
new Argument<string?>("NAME", "The name of the new virtual device."), new Argument<string?>("NAME", "The name of the new virtual device."),
new Argument<string?>("PACKAGE", "The package to use for the new virtual device."), new Argument<string?>("PACKAGE", "The package to use for the new virtual device."),
}.WithHandler(CommandHandler.Create(typeof(AndroidCommand).GetMethod(nameof(HandleCreateAsync))!)), }.WithHandler(CommandHandler.Create(typeof(AndroidCommand).GetMethod(nameof(HandleCreateAsync))!)),
new Command("boot", "Boot a particular simulator.") new Command("boot", "Boot a particular simulator.")
{ {
new Option<string?>(new[] { "--sdk" }, "Whether or not to only include the available simulators."), new Option<string?>(new[] { "--sdk" }, "Whether or not to only include the available simulators."),
CommandLine.CreateVerbosity(), CommandLine.CreateVerbosity(),
new Argument<string?>("NAME", "The UDID of the simulator to boot."), new Argument<string?>("NAME", "The UDID of the simulator to boot."),
}.WithHandler(CommandHandler.Create(typeof(AndroidCommand).GetMethod(nameof(HandleBootAsync))!)), }.WithHandler(CommandHandler.Create(typeof(AndroidCommand).GetMethod(nameof(HandleBootAsync))!)),
}; };
} }
public static async Task HandleListAsync( public static async Task HandleListAsync(
string? term = null, string? term = null,
string? sdk = null, string? sdk = null,
bool available = false, bool available = false,
bool booted = false, bool booted = false,
SimulatorRuntime? runtime = null, SimulatorRuntime? runtime = null,
string? version = null, string? version = null,
string? verbosity = null, string? verbosity = null,
IConsole console = null!, IConsole console = null!,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var logger = console.CreateLogger(verbosity); var logger = console.CreateLogger(verbosity);
var avdmanager = new AVDManager(sdk, logger); var avdmanager = new AVDManager(sdk, logger);
var devices = await avdmanager.GetDevicesAsync(); var devices = await avdmanager.GetDevicesAsync();
foreach (var device in devices) foreach (var device in devices)
{ {
logger?.LogInformation(" - " + device.ToString()); logger?.LogInformation(" - " + device.ToString());
} }
var targets = await avdmanager.GetTargetsAsync(); var targets = await avdmanager.GetTargetsAsync();
foreach (var target in targets) foreach (var target in targets)
{ {
logger?.LogInformation(" - " + target.ToString()); logger?.LogInformation(" - " + target.ToString());
} }
var avds = await avdmanager.GetVirtualDevicesAsync(); var avds = await avdmanager.GetVirtualDevicesAsync();
foreach (var avd in avds) foreach (var avd in avds)
{ {
logger?.LogInformation(" - " + avd.ToString()); logger?.LogInformation(" - " + avd.ToString());
} }
try try
{ {
await avdmanager.DeleteVirtualDeviceAsync("TESTING"); await avdmanager.DeleteVirtualDeviceAsync("TESTING");
} }
catch { } catch { }
try try
{ {
await avdmanager.DeleteVirtualDeviceAsync("TESTED"); await avdmanager.DeleteVirtualDeviceAsync("TESTED");
} }
catch { } catch { }
await avdmanager.CreateVirtualDeviceAsync("TESTING", "system-images;android-28;google_apis_playstore;x86_64"); await avdmanager.CreateVirtualDeviceAsync("TESTING", "system-images;android-28;google_apis_playstore;x86_64");
await avdmanager.CreateVirtualDeviceAsync("TESTING", "system-images;android-28;google_apis_playstore;x86_64", new VirtualDeviceCreateOptions { Overwrite = true }); await avdmanager.CreateVirtualDeviceAsync("TESTING", "system-images;android-28;google_apis_playstore;x86_64", new VirtualDeviceCreateOptions { Overwrite = true });
await avdmanager.RenameVirtualDeviceAsync("TESTING", "TESTED"); await avdmanager.RenameVirtualDeviceAsync("TESTING", "TESTED");
await avdmanager.MoveVirtualDeviceAsync("TESTED", "/Users/matthew/.android/avd/tested.avd"); await avdmanager.MoveVirtualDeviceAsync("TESTED", "/Users/matthew/.android/avd/tested.avd");
//await avdmanager.DeleteVirtualDeviceAsync("TESTING"); //await avdmanager.DeleteVirtualDeviceAsync("TESTING");
//term = term?.ToLowerInvariant()?.Trim(); //term = term?.ToLowerInvariant()?.Trim();
//var simctl = new SimulatorControl(logger); //var simctl = new SimulatorControl(logger);
//var simulators = await simctl.GetSimulatorsAsync(cancellationToken); //var simulators = await simctl.GetSimulatorsAsync(cancellationToken);
//var filtered = (IEnumerable<Simulator>)simulators; //var filtered = (IEnumerable<Simulator>)simulators;
//if (!string.IsNullOrWhiteSpace(term)) //if (!string.IsNullOrWhiteSpace(term))
//{ //{
// if (Guid.TryParse(term, out var guid)) // if (Guid.TryParse(term, out var guid))
// filtered = filtered.Where(s => s.Udid.ToLowerInvariant() == guid.ToString("d")); // filtered = filtered.Where(s => s.Udid.ToLowerInvariant() == guid.ToString("d"));
// else if (Version.TryParse(term, out var versionFull)) // else if (Version.TryParse(term, out var versionFull))
// filtered = filtered.Where(s => s.Version == versionFull); // filtered = filtered.Where(s => s.Version == versionFull);
// else if (int.TryParse(term, out var versionMjor)) // else if (int.TryParse(term, out var versionMjor))
// filtered = filtered.Where(s => s.Version.Major == versionMjor); // filtered = filtered.Where(s => s.Version.Major == versionMjor);
// else if (Enum.TryParse<SimulatorRuntime>(term, true, out var r)) // else if (Enum.TryParse<SimulatorRuntime>(term, true, out var r))
// filtered = filtered.Where(s => s.Runtime == r); // filtered = filtered.Where(s => s.Runtime == r);
// else if (Enum.TryParse<SimulatorState>(term, true, out var state)) // else if (Enum.TryParse<SimulatorState>(term, true, out var state))
// filtered = filtered.Where(s => s.State == state); // filtered = filtered.Where(s => s.State == state);
// else if (Enum.TryParse<SimulatorAvailability>(term, true, out var availability)) // else if (Enum.TryParse<SimulatorAvailability>(term, true, out var availability))
// filtered = filtered.Where(s => s.Availability == availability); // filtered = filtered.Where(s => s.Availability == availability);
// else if (Enum.TryParse<SimulatorType>(term, true, out var type)) // else if (Enum.TryParse<SimulatorType>(term, true, out var type))
// filtered = filtered.Where(s => s.Type == type); // filtered = filtered.Where(s => s.Type == type);
// else // else
// filtered = filtered.Where(s => s.Name.ToLowerInvariant().Contains(term)); // filtered = filtered.Where(s => s.Name.ToLowerInvariant().Contains(term));
//} //}
//if (booted) //if (booted)
// filtered = filtered.Where(s => s.State == SimulatorState.Booted); // filtered = filtered.Where(s => s.State == SimulatorState.Booted);
//if (available) //if (available)
// filtered = filtered.Where(s => s.Availability == SimulatorAvailability.Available); // filtered = filtered.Where(s => s.Availability == SimulatorAvailability.Available);
//if (runtime != null) //if (runtime != null)
// filtered = filtered.Where(s => s.Runtime == runtime); // filtered = filtered.Where(s => s.Runtime == runtime);
//if (version != null) //if (version != null)
//{ //{
// if (Version.TryParse(version, out var versionFull)) // if (Version.TryParse(version, out var versionFull))
// filtered = filtered.Where(s => s.Version == versionFull); // filtered = filtered.Where(s => s.Version == versionFull);
// else if (int.TryParse(version, out var versionMjor)) // else if (int.TryParse(version, out var versionMjor))
// filtered = filtered.Where(s => s.Version.Major == versionMjor); // filtered = filtered.Where(s => s.Version.Major == versionMjor);
//} //}
//var all = filtered.ToList(); //var all = filtered.ToList();
//logger.LogInformation($"Found {all.Count} simulator[s]."); //logger.LogInformation($"Found {all.Count} simulator[s].");
//var table = new TableView<Simulator>(); //var table = new TableView<Simulator>();
//table.AddColumn(s => s.Udid, "UDID"); //table.AddColumn(s => s.Udid, "UDID");
//table.AddColumn(s => s.Name, "Name"); //table.AddColumn(s => s.Name, "Name");
//table.AddColumn(s => s.Runtime, "Runtime"); //table.AddColumn(s => s.Runtime, "Runtime");
//table.AddColumn(s => s.Version, "Version"); //table.AddColumn(s => s.Version, "Version");
//table.AddColumn(s => s.Availability, "Availability"); //table.AddColumn(s => s.Availability, "Availability");
//table.AddColumn(s => s.State, "State"); //table.AddColumn(s => s.State, "State");
//table.Items = all; //table.Items = all;
//console.Append(new StackLayoutView { table }); //console.Append(new StackLayoutView { table });
} }
public static async Task HandleCreateAsync( public static async Task HandleCreateAsync(
string name, string name,
string package, string package,
bool replace = false, bool replace = false,
string? sdk = null, string? sdk = null,
string? verbosity = null, string? verbosity = null,
IConsole console = null!, IConsole console = null!,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var logger = console.CreateLogger(verbosity); var logger = console.CreateLogger(verbosity);
var avdmanager = new AVDManager(sdk, logger); var avdmanager = new AVDManager(sdk, logger);
var options = new VirtualDeviceCreateOptions var options = new VirtualDeviceCreateOptions
{ {
Overwrite = replace Overwrite = replace
}; };
await avdmanager.CreateVirtualDeviceAsync(name, package, options, cancellationToken); await avdmanager.CreateVirtualDeviceAsync(name, package, options, cancellationToken);
} }
public static async Task<int> HandleBootAsync( public static async Task<int> HandleBootAsync(
string name, string name,
string? sdk = null, string? sdk = null,
string? verbosity = null, string? verbosity = null,
IConsole console = null!, IConsole console = null!,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var logger = console.CreateLogger(verbosity); var logger = console.CreateLogger(verbosity);
var emulator = new EmulatorManager(sdk, logger); var emulator = new EmulatorManager(sdk, logger);
var avds = await emulator.GetVirtualDevicesAsync(cancellationToken); var avds = await emulator.GetVirtualDevicesAsync(cancellationToken);
if (avds.All(a => !a.Name.Equals(name, StringComparison.OrdinalIgnoreCase))) if (avds.All(a => !a.Name.Equals(name, StringComparison.OrdinalIgnoreCase)))
{
logger.LogError($"No virtual device with name {name} was found.");
return 1;
}
var options = new BootVirtualDeviceOptions
{ {
NoSnapshots = false, logger.LogError($"No virtual device with name {name} was found.");
WipeData = true, return 1;
}
var options = new BootVirtualDeviceOptions
{
NoSnapshots = false,
WipeData = true,
}; };
var port = await emulator.BootVirtualDeviceAsync(name, options, cancellationToken); var port = await emulator.BootVirtualDeviceAsync(name, options, cancellationToken);
if (port == -1) if (port == -1)
logger.LogInformation($"Virtual device was already booted."); logger.LogInformation($"Virtual device was already booted.");
else else
logger.LogInformation($"device was booted to port {port}."); logger.LogInformation($"device was booted to port {port}.");
return 0; return 0;
} }
} }
} }

Просмотреть файл

@ -1,231 +1,231 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using DotNetDevices.Apple; using DotNetDevices.Apple;
using DotNetDevices.Testing; using DotNetDevices.Testing;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace DotNetDevices.Commands namespace DotNetDevices.Commands
{ {
public class AppleTestCommand public class AppleTestCommand
{ {
private readonly ILogger logger; private readonly ILogger logger;
private readonly SimulatorControl simctl; private readonly SimulatorControl simctl;
public AppleTestCommand(ILogger logger) public AppleTestCommand(ILogger logger)
{
this.logger = logger;
simctl = new SimulatorControl(logger);
}
public async Task RunTestsAsync(
string app,
string? deviceResults = null, // "TestResults.trx"
string? outputResults = null, // "TestResults.trx"
string? runtimeString = null,
string? versionString = null,
bool latest = false,
string? deviceType = null,
string? deviceName = null,
bool reset = false,
bool shutdown = false,
CancellationToken cancellationToken = default)
{
// validate app / bundle
var plist = new PList(Path.Combine(app, "Info.plist"), logger);
var bundleId = await plist.GetBundleIdentifierAsync(cancellationToken);
// validate requested OS
var simulatorType = ParseSimulatorType(deviceType);
var runtime = ParseSimulatorRuntime(runtimeString);
var runtimeVersion = await ParseVersionAsync(versionString, runtime, cancellationToken);
logger.LogInformation($"Looking for an available {simulatorType} ({runtimeVersion}) simulator...");
var available = await GetAvailableSimulatorsAsync(simulatorType, runtime, runtimeVersion, latest, cancellationToken);
// first look for a booted device
var simulator = available.FirstOrDefault(s => s.State == SimulatorState.Booted) ?? available.FirstOrDefault();
logger.LogInformation($"Using simulator {simulator.Name} ({simulator.Runtime} {simulator.Version}): {simulator.Udid}");
try
{
if (reset)
await simctl.EraseSimulatorAsync(simulator.Udid, true, cancellationToken);
await simctl.InstallAppAsync(simulator.Udid, app, true, cancellationToken);
try
{
var parser = new TestResultsParser();
var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
var launched = await simctl.LaunchAppAsync(simulator.Udid, bundleId, new LaunchAppOptions
{
CaptureOutput = true,
BootSimulator = true,
HandleOutput = output =>
{
parser.ParseTestOutput(
output,
line => logger?.LogWarning(line),
async () =>
{
try
{
// wait a few seconds before terminating
await Task.Delay(1000, cts.Token);
await simctl.TerminateAppAsync(simulator.Udid, bundleId, cts.Token);
}
catch (OperationCanceledException)
{
// we expected this
}
});
},
}, cancellationToken);
cts.Cancel();
if (deviceResults != null)
{
var dest = outputResults ?? Path.GetFileName(deviceResults);
logger.LogInformation($"Copying test results from simulator to {dest}...");
var dataPath = await simctl.GetDataDirectoryAsync(simulator.Udid, bundleId, cancellationToken);
var results = Path.Combine(dataPath, "Documents", deviceResults);
if (File.Exists(results))
File.Copy(results, dest, true);
else
logger.LogInformation($"No test results found.");
}
else
{
logger.LogInformation($"Unable to determine the test results file.");
}
}
finally
{
await simctl.UninstallAppAsync(simulator.Udid, bundleId, false, cancellationToken);
}
}
finally
{
if (shutdown)
await simctl.ShutdownSimulatorAsync(simulator.Udid, cancellationToken);
}
}
private async Task<List<Simulator>> GetAvailableSimulatorsAsync(SimulatorType type, SimulatorRuntime runtime, Version version, bool useLatest = true, CancellationToken cancellationToken = default)
{
// load all simulators
var simulators = await simctl.GetSimulatorsAsync(cancellationToken);
// find ones that can be used
var available = simulators
.Where(s => s.Availability == SimulatorAvailability.Available)
.Where(s => s.Runtime == runtime)
.Where(s => s.Type == type);
logger.LogDebug($"Found some available simulators:");
foreach (var sim in available)
{
logger.LogDebug($" {sim.Name} ({sim.Runtime} {sim.Version}): {sim.Udid}");
}
// filter by version info
string matchingPattern;
if (useLatest)
{
var min = version;
var max = new Version(min.Major + 1, 0);
available = available.Where(s => s.Version >= min && s.Version < max);
matchingPattern = $"[{min}, {max})";
}
else
{
available = available.Where(s => s.Version == version);
matchingPattern = $"[{version}]";
}
var matching = available.ToList();
if (matching.Count > 0)
{
logger.LogDebug($"Found matching simulators {matchingPattern}:");
foreach (var sim in matching)
{
logger.LogDebug($" {sim.Name} ({sim.Runtime} {sim.Version}): {sim.Udid}");
}
}
else
{
throw new Exception($"Unable to find any simulators that match version {matchingPattern}.");
}
return matching;
}
private async Task<Version> ParseVersionAsync(string? version, SimulatorRuntime os, CancellationToken cancellationToken = default)
{
var osVersion = version?.ToLowerInvariant().Trim();
if (!Version.TryParse(osVersion, out var numberVersion))
{
if (int.TryParse(osVersion, out var v))
numberVersion = new Version(v, 0);
else if (string.IsNullOrEmpty(osVersion) || osVersion == "default")
numberVersion = await simctl.GetDefaultVersionAsync(os, cancellationToken);
else
throw new Exception($"Unable to determine the version for {osVersion}.");
}
return numberVersion;
}
private static SimulatorRuntime ParseSimulatorRuntime(string? runtime)
{ {
var osName = runtime?.ToLowerInvariant()?.Trim(); this.logger = logger;
var os = osName switch
{ simctl = new SimulatorControl(logger);
null => SimulatorRuntime.iOS, }
"" => SimulatorRuntime.iOS,
"ios" => SimulatorRuntime.iOS, public async Task RunTestsAsync(
"watchos" => SimulatorRuntime.watchOS, string app,
"tvos" => SimulatorRuntime.tvOS, string? deviceResults = null, // "TestResults.trx"
_ => throw new Exception($"Unable to determine the OS for {runtime}.") string? outputResults = null, // "TestResults.trx"
}; string? runtimeString = null,
return os; string? versionString = null,
} bool latest = false,
string? deviceType = null,
private static SimulatorType ParseSimulatorType(string? deviceType) string? deviceName = null,
{ bool reset = false,
var deviceTypeName = deviceType?.ToLowerInvariant()?.Trim(); bool shutdown = false,
var device = deviceTypeName switch CancellationToken cancellationToken = default)
{ {
// iPhone // validate app / bundle
null => SimulatorType.iPhone, var plist = new PList(Path.Combine(app, "Info.plist"), logger);
"" => SimulatorType.iPhone, var bundleId = await plist.GetBundleIdentifierAsync(cancellationToken);
"iphone" => SimulatorType.iPhone,
"phone" => SimulatorType.iPhone, // validate requested OS
// iPad var simulatorType = ParseSimulatorType(deviceType);
"ipad" => SimulatorType.iPad, var runtime = ParseSimulatorRuntime(runtimeString);
"tablet" => SimulatorType.iPad, var runtimeVersion = await ParseVersionAsync(versionString, runtime, cancellationToken);
// iPod
"ipod" => SimulatorType.iPod, logger.LogInformation($"Looking for an available {simulatorType} ({runtimeVersion}) simulator...");
// Apple TV var available = await GetAvailableSimulatorsAsync(simulatorType, runtime, runtimeVersion, latest, cancellationToken);
"tv" => SimulatorType.AppleTV,
"appletv" => SimulatorType.AppleTV, // first look for a booted device
// Apple Watch var simulator = available.FirstOrDefault(s => s.State == SimulatorState.Booted) ?? available.FirstOrDefault();
"watch" => SimulatorType.AppleWatch, logger.LogInformation($"Using simulator {simulator.Name} ({simulator.Runtime} {simulator.Version}): {simulator.Udid}");
"applewatch" => SimulatorType.AppleWatch,
// try
_ => throw new Exception($"Unable to determine the simulator type for {deviceType}.") {
}; if (reset)
return device; await simctl.EraseSimulatorAsync(simulator.Udid, true, cancellationToken);
}
} await simctl.InstallAppAsync(simulator.Udid, app, true, cancellationToken);
}
try
{
var parser = new TestResultsParser();
var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
var launched = await simctl.LaunchAppAsync(simulator.Udid, bundleId, new LaunchAppOptions
{
CaptureOutput = true,
BootSimulator = true,
HandleOutput = output =>
{
parser.ParseTestOutput(
output,
line => logger?.LogWarning(line),
async () =>
{
try
{
// wait a few seconds before terminating
await Task.Delay(1000, cts.Token);
await simctl.TerminateAppAsync(simulator.Udid, bundleId, cts.Token);
}
catch (OperationCanceledException)
{
// we expected this
}
});
},
}, cancellationToken);
cts.Cancel();
if (deviceResults != null)
{
var dest = outputResults ?? Path.GetFileName(deviceResults);
logger.LogInformation($"Copying test results from simulator to {dest}...");
var dataPath = await simctl.GetDataDirectoryAsync(simulator.Udid, bundleId, cancellationToken);
var results = Path.Combine(dataPath, "Documents", deviceResults);
if (File.Exists(results))
File.Copy(results, dest, true);
else
logger.LogInformation($"No test results found.");
}
else
{
logger.LogInformation($"Unable to determine the test results file.");
}
}
finally
{
await simctl.UninstallAppAsync(simulator.Udid, bundleId, false, cancellationToken);
}
}
finally
{
if (shutdown)
await simctl.ShutdownSimulatorAsync(simulator.Udid, cancellationToken);
}
}
private async Task<List<Simulator>> GetAvailableSimulatorsAsync(SimulatorType type, SimulatorRuntime runtime, Version version, bool useLatest = true, CancellationToken cancellationToken = default)
{
// load all simulators
var simulators = await simctl.GetSimulatorsAsync(cancellationToken);
// find ones that can be used
var available = simulators
.Where(s => s.Availability == SimulatorAvailability.Available)
.Where(s => s.Runtime == runtime)
.Where(s => s.Type == type);
logger.LogDebug($"Found some available simulators:");
foreach (var sim in available)
{
logger.LogDebug($" {sim.Name} ({sim.Runtime} {sim.Version}): {sim.Udid}");
}
// filter by version info
string matchingPattern;
if (useLatest)
{
var min = version;
var max = new Version(min.Major + 1, 0);
available = available.Where(s => s.Version >= min && s.Version < max);
matchingPattern = $"[{min}, {max})";
}
else
{
available = available.Where(s => s.Version == version);
matchingPattern = $"[{version}]";
}
var matching = available.ToList();
if (matching.Count > 0)
{
logger.LogDebug($"Found matching simulators {matchingPattern}:");
foreach (var sim in matching)
{
logger.LogDebug($" {sim.Name} ({sim.Runtime} {sim.Version}): {sim.Udid}");
}
}
else
{
throw new Exception($"Unable to find any simulators that match version {matchingPattern}.");
}
return matching;
}
private async Task<Version> ParseVersionAsync(string? version, SimulatorRuntime os, CancellationToken cancellationToken = default)
{
var osVersion = version?.ToLowerInvariant().Trim();
if (!Version.TryParse(osVersion, out var numberVersion))
{
if (int.TryParse(osVersion, out var v))
numberVersion = new Version(v, 0);
else if (string.IsNullOrEmpty(osVersion) || osVersion == "default")
numberVersion = await simctl.GetDefaultVersionAsync(os, cancellationToken);
else
throw new Exception($"Unable to determine the version for {osVersion}.");
}
return numberVersion;
}
private static SimulatorRuntime ParseSimulatorRuntime(string? runtime)
{
var osName = runtime?.ToLowerInvariant()?.Trim();
var os = osName switch
{
null => SimulatorRuntime.iOS,
"" => SimulatorRuntime.iOS,
"ios" => SimulatorRuntime.iOS,
"watchos" => SimulatorRuntime.watchOS,
"tvos" => SimulatorRuntime.tvOS,
_ => throw new Exception($"Unable to determine the OS for {runtime}.")
};
return os;
}
private static SimulatorType ParseSimulatorType(string? deviceType)
{
var deviceTypeName = deviceType?.ToLowerInvariant()?.Trim();
var device = deviceTypeName switch
{
// iPhone
null => SimulatorType.iPhone,
"" => SimulatorType.iPhone,
"iphone" => SimulatorType.iPhone,
"phone" => SimulatorType.iPhone,
// iPad
"ipad" => SimulatorType.iPad,
"tablet" => SimulatorType.iPad,
// iPod
"ipod" => SimulatorType.iPod,
// Apple TV
"tv" => SimulatorType.AppleTV,
"appletv" => SimulatorType.AppleTV,
// Apple Watch
"watch" => SimulatorType.AppleWatch,
"applewatch" => SimulatorType.AppleWatch,
//
_ => throw new Exception($"Unable to determine the simulator type for {deviceType}.")
};
return device;
}
}
}