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>
<OutputType>Library</OutputType>
<RootNamespace>DeviceTests.Droid</RootNamespace>
<AssemblyName>XamarinEssentialsDeviceTestsAndroid</AssemblyName>
<AssemblyName>DeviceTestsAndroid</AssemblyName>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
<AndroidApplication>True</AndroidApplication>
<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>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DeviceTests.UWP</RootNamespace>
<AssemblyName>XamarinEssentialsDeviceTestsUWP</AssemblyName>
<AssemblyName>DeviceTestsUWP</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
@ -17,7 +17,9 @@
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
<FileAlignment>512</FileAlignment>
<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 Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols>
@ -113,25 +115,14 @@
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="UnitTests.HeadlessRunner" Version="2.0.0" />
<PackageReference Include="Xamarin.Forms" Version="4.8.0.1451" />
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.2.9" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.devices" Version="2.5.25" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
</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">
<Project>{be0de9a3-d92c-47c5-9ec4-dfb546bbdf77}</Project>
<Project>{E049A504-C168-41DC-80DF-0C4C6F363761}</Project>
<Name>DeviceTests</Name>
</ProjectReference>
</ItemGroup>
@ -153,9 +144,6 @@
</AppxManifest>
</ItemGroup>
<ItemGroup>
<Content Include="AppBundleFile.txt" />
<Content Include="Folder\AppBundleFile_Nested.txt" />
<Content Include="AppBundleFile_NoExtension" />
<Content Include="Properties\Default.rd.xml" />
<Content Include="Assets\LockScreenLogo.scale-100.png" />
<Content Include="Assets\LockScreenLogo.scale-125.png" />
@ -190,10 +178,10 @@
<Content Include="Assets\Wide310x150Logo.scale-400.png" />
</ItemGroup>
<ItemGroup>
<None Include="DeviceTests.UWP_TemporaryKey.pfx" />
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
<None Include="DeviceTests.UWP_TemporaryKey.pfx" />
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<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"?>
<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" />
<Properties>
<DisplayName>Tests</DisplayName>
<PublisherDisplayName>Microsoft</PublisherDisplayName>
<PublisherDisplayName>dotnet-devices</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
@ -31,8 +31,5 @@
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<Capability Name="internetClientServer" />
<Capability Name="privateNetworkClientServer" />
<DeviceCapability Name="location" />
</Capabilities>
</Package>

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

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

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

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

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

@ -1,6 +1,6 @@
using System;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using Microsoft.Extensions.Logging;
namespace DotNetDevices.Android
{
@ -24,11 +24,12 @@ namespace DotNetDevices.Android
return sdkRoot;
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);
// return the full path to the tool
return path;
return foundPath;
}
foreach (var envvar in envvars)
@ -48,17 +49,34 @@ namespace DotNetDevices.Android
return varSdkRoot;
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}'.");
continue;
}
// return the full path to the tool
return path;
return foundPath;
}
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.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using DotNetDevices.Processes;
using Microsoft.Extensions.Logging;
namespace DotNetDevices.Android
{
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 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 readonly ProcessRunner processRunner;
private readonly ILogger? logger;
private readonly string emulator;
public EmulatorManager(string? sdkRoot = null, ILogger? logger = null)
{
this.logger = logger;
processRunner = new ProcessRunner(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.");
}
public async Task<int> BootVirtualDeviceAsync(string name, BootVirtualDeviceOptions? options = null, CancellationToken cancellationToken = default)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
logger?.LogInformation($"Booting virtual device '{name}'...");
var args = $"-avd {name} -verbose";
if (options?.NoWindow == true)
args += " -no-boot-anim -no-window";
if (options?.NoSnapshots == true)
args += " -no-snapshot";
if (options?.WipeData == true)
args += " -wipe-data";
var port = -1;
try
{
await processRunner.RunAsync(emulator, args, FindComplete, cancellationToken).ConfigureAwait(false);
}
catch (ProcessResultException ex) when (IsAlreadyLaunched(ex))
{
// no-op
}
return port;
bool FindComplete(ProcessOutput output)
{
if (!output.IsError && output.Data is string o)
{
if (port <= 0)
{
// first find port
var match = consoleListeningRegex.Match(o);
if (match.Success)
port = int.Parse(match.Groups[1].Value);
}
else
{
// then wait for the boot finished
var match = adbConnectedRegex.Match(o);
if (match.Success)
return false;
}
}
return true;
}
bool IsAlreadyLaunched(ProcessResultException ex)
{
foreach (var output in ex.ProcessResult.GetOutput())
{
var match = alreadyBootedRegex.Match(output);
if (match.Success)
return true;
}
return false;
}
}
public async Task<IEnumerable<VirtualDevice>> GetVirtualDevicesAsync(CancellationToken cancellationToken = default)
{
logger?.LogInformation("Retrieving all the virtual devices...");
var args = $"-list-avds";
var result = await processRunner.RunAsync(emulator, args, null, cancellationToken).ConfigureAwait(false);
var avd = new List<VirtualDevice>(result.OutputCount);
foreach (var output in result.GetOutput())
{
avd.Add(new VirtualDevice(output));
}
return avd;
}
}
}
using Microsoft.Extensions.Logging;
namespace DotNetDevices.Android
{
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 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 readonly ProcessRunner processRunner;
private readonly ILogger? logger;
private readonly string emulator;
public EmulatorManager(string? sdkRoot = null, ILogger? logger = null)
{
this.logger = logger;
processRunner = new ProcessRunner(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.");
}
public async Task<int> BootVirtualDeviceAsync(string name, BootVirtualDeviceOptions? options = null, CancellationToken cancellationToken = default)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
logger?.LogInformation($"Booting virtual device '{name}'...");
var args = $"-avd {name} -verbose";
if (options?.NoWindow == true)
args += " -no-boot-anim -no-window";
if (options?.NoSnapshots == true)
args += " -no-snapshot";
if (options?.WipeData == true)
args += " -wipe-data";
var port = -1;
try
{
await processRunner.RunAsync(emulator, args, FindComplete, cancellationToken).ConfigureAwait(false);
}
catch (ProcessResultException ex) when (IsAlreadyLaunched(ex))
{
// no-op
}
return port;
bool FindComplete(ProcessOutput output)
{
if (!output.IsError && output.Data is string o)
{
if (port <= 0)
{
// first find port
var match = consoleListeningRegex.Match(o);
if (match.Success)
port = int.Parse(match.Groups[1].Value);
}
else
{
// then wait for the boot finished
var match = adbConnectedRegex.Match(o);
if (match.Success)
return false;
}
}
return true;
}
bool IsAlreadyLaunched(ProcessResultException ex)
{
foreach (var output in ex.ProcessResult.GetOutput())
{
var match = alreadyBootedRegex.Match(output);
if (match.Success)
return true;
}
return false;
}
}
public async Task<IEnumerable<VirtualDevice>> GetVirtualDevicesAsync(CancellationToken cancellationToken = default)
{
logger?.LogInformation("Retrieving all the virtual devices...");
var args = $"-list-avds";
var result = await processRunner.RunAsync(emulator, args, null, cancellationToken).ConfigureAwait(false);
var avd = new List<VirtualDevice>(result.OutputCount);
foreach (var output in result.GetOutput())
{
avd.Add(new VirtualDevice(output));
}
return avd;
}
}
}

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

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

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

@ -1,231 +1,231 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using DotNetDevices.Apple;
using DotNetDevices.Testing;
using Microsoft.Extensions.Logging;
namespace DotNetDevices.Commands
{
public class AppleTestCommand
{
private readonly ILogger logger;
private readonly SimulatorControl simctl;
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)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using DotNetDevices.Apple;
using DotNetDevices.Testing;
using Microsoft.Extensions.Logging;
namespace DotNetDevices.Commands
{
public class AppleTestCommand
{
private readonly ILogger logger;
private readonly SimulatorControl simctl;
public AppleTestCommand(ILogger logger)
{
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;
}
}
}
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();
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;
}
}
}